fix: misc quiz submission issues
This commit is contained in:
@@ -186,18 +186,27 @@ const addQuizzes = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addPrograms = () => {
|
const addPrograms = () => {
|
||||||
if (settingsStore.learningPaths.data) {
|
let activeFor = ['Programs', 'ProgramForm']
|
||||||
let activeFor = ['Programs', 'ProgramForm']
|
let index = 1
|
||||||
let index = 1
|
let canAddProgram = false
|
||||||
if (!isInstructor.value && !isModerator.value) {
|
|
||||||
sidebarLinks.value = sidebarLinks.value.filter(
|
|
||||||
(link) => link.label !== 'Courses'
|
|
||||||
)
|
|
||||||
activeFor.push('CourseDetail')
|
|
||||||
activeFor.push('Lesson')
|
|
||||||
index = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isInstructor.value &&
|
||||||
|
!isModerator.value &&
|
||||||
|
settingsStore.learningPaths.data
|
||||||
|
) {
|
||||||
|
sidebarLinks.value = sidebarLinks.value.filter(
|
||||||
|
(link) => link.label !== 'Courses'
|
||||||
|
)
|
||||||
|
activeFor.push('CourseDetail')
|
||||||
|
activeFor.push('Lesson')
|
||||||
|
index = 0
|
||||||
|
canAddProgram = true
|
||||||
|
} else if (isInstructor.value || isModerator.value) {
|
||||||
|
canAddProgram = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canAddProgram) {
|
||||||
sidebarLinks.value.splice(index, 0, {
|
sidebarLinks.value.splice(index, 0, {
|
||||||
label: 'Programs',
|
label: 'Programs',
|
||||||
icon: 'Route',
|
icon: 'Route',
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<AppSidebar />
|
<AppSidebar />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full overflow-auto" id="scrollContainer">
|
<div class="w-full overflow-auto" id="scrollContainer">
|
||||||
<OnboardingBanner />
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -17,5 +16,4 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import AppSidebar from './AppSidebar.vue'
|
import AppSidebar from './AppSidebar.vue'
|
||||||
import OnboardingBanner from '@/components/OnboardingBanner.vue'
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
class="sticky top-0 z-10 flex flex-col md:flex-row md:items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
|
class="sticky top-0 z-10 flex flex-col md:flex-row md:items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
|
||||||
>
|
>
|
||||||
<Breadcrumbs :items="breadbrumbs" />
|
<Breadcrumbs :items="breadbrumbs" />
|
||||||
<Button variant="solid">
|
<Button variant="solid" @click="saveProgram()">
|
||||||
{{ __('Save') }}
|
{{ __('Save') }}
|
||||||
</Button>
|
</Button>
|
||||||
</header>
|
</header>
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
item-key="name"
|
item-key="name"
|
||||||
group="items"
|
group="items"
|
||||||
@end="updateOrder"
|
@end="updateOrder"
|
||||||
|
class="cursor-move"
|
||||||
>
|
>
|
||||||
<template #item="{ element: row }">
|
<template #item="{ element: row }">
|
||||||
<ListRow :row="row" />
|
<ListRow :row="row" />
|
||||||
@@ -175,7 +176,6 @@
|
|||||||
import {
|
import {
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
Button,
|
Button,
|
||||||
call,
|
|
||||||
createDocumentResource,
|
createDocumentResource,
|
||||||
Dialog,
|
Dialog,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -191,11 +191,13 @@ import { Plus, Trash2 } from 'lucide-vue-next'
|
|||||||
import Link from '@/components/Controls/Link.vue'
|
import Link from '@/components/Controls/Link.vue'
|
||||||
import { showToast } from '@/utils/'
|
import { showToast } from '@/utils/'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const currentForm = ref(null)
|
const currentForm = ref(null)
|
||||||
const course = ref(null)
|
const course = ref(null)
|
||||||
const member = ref(null)
|
const member = ref(null)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
programName: {
|
programName: {
|
||||||
@@ -302,6 +304,28 @@ const updateOrder = (e) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveProgram = () => {
|
||||||
|
program.setValue.submit(
|
||||||
|
{
|
||||||
|
title: program.doc.title,
|
||||||
|
program_courses: program.doc.program_courses,
|
||||||
|
program_members: program.doc.program_members,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess(data) {
|
||||||
|
router.push({
|
||||||
|
name: 'ProgramsForm',
|
||||||
|
params: { programName: data.name },
|
||||||
|
})
|
||||||
|
showToast(__('Success'), __('Program saved successfully'), 'check')
|
||||||
|
},
|
||||||
|
onError(err) {
|
||||||
|
showToast('Error', err.messages?.[0] || err, 'x')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const courseColumns = computed(() => {
|
const courseColumns = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -205,7 +205,6 @@ import {
|
|||||||
inject,
|
inject,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
watch,
|
watch,
|
||||||
isReactive,
|
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||||
import Question from '@/components/Modals/Question.vue'
|
import Question from '@/components/Modals/Question.vue'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div v-if="submisisonDetails.doc" class="w-1/2 mx-auto py-5 space-y-7">
|
<div v-if="submisisonDetails.doc" class="w-1/2 mx-auto py-5 space-y-5">
|
||||||
<div class="text-xl font-semibold">
|
<div class="text-xl font-semibold">
|
||||||
{{ submisisonDetails.doc.member_name }}
|
{{ submisisonDetails.doc.member_name }}
|
||||||
</div>
|
</div>
|
||||||
@@ -74,7 +74,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Badge,
|
Badge,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { computed, onMounted, inject } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, inject } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { showToast } from '@/utils'
|
import { showToast } from '@/utils'
|
||||||
|
|
||||||
@@ -84,8 +84,25 @@ const user = inject('$user')
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!user.data?.is_instructor && !user.data?.is_moderator)
|
if (!user.data?.is_instructor && !user.data?.is_moderator)
|
||||||
router.push({ name: 'Courses' })
|
router.push({ name: 'Courses' })
|
||||||
|
|
||||||
|
window.addEventListener('keydown', keyboardShortcut)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('keydown', keyboardShortcut)
|
||||||
|
})
|
||||||
|
|
||||||
|
const keyboardShortcut = (e) => {
|
||||||
|
if (
|
||||||
|
e.key === 's' &&
|
||||||
|
(e.ctrlKey || e.metaKey) &&
|
||||||
|
!e.target.classList.contains('ProseMirror')
|
||||||
|
) {
|
||||||
|
saveSubmission()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
submission: {
|
submission: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-11-20 12:26:02.214628",
|
"modified": "2024-11-28 22:06:16.742867",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Program",
|
"name": "LMS Program",
|
||||||
@@ -80,5 +80,6 @@
|
|||||||
],
|
],
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": []
|
"states": [],
|
||||||
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ class LMSProgram(Document):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_program_courses()
|
self.validate_program_courses()
|
||||||
self.validate_program_members()
|
self.validate_program_members()
|
||||||
|
self.validate_title()
|
||||||
|
|
||||||
def validate_program_courses(self):
|
def validate_program_courses(self):
|
||||||
courses = [row.course for row in self.program_courses]
|
courses = [row.course for row in self.program_courses]
|
||||||
@@ -30,3 +31,7 @@ class LMSProgram(Document):
|
|||||||
frappe.bold(next(iter(duplicates)))
|
frappe.bold(next(iter(duplicates)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_title(self):
|
||||||
|
if self.has_value_changed("title"):
|
||||||
|
frappe.rename_doc(self.doctype, self.name, self.title)
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ def quiz_summary(quiz, results):
|
|||||||
|
|
||||||
submission = frappe.new_doc("LMS Quiz Submission")
|
submission = frappe.new_doc("LMS Quiz Submission")
|
||||||
# Score and percentage are calculated by the controller function
|
# Score and percentage are calculated by the controller function
|
||||||
print(results)
|
|
||||||
submission.update(
|
submission.update(
|
||||||
{
|
{
|
||||||
"doctype": "LMS Quiz Submission",
|
"doctype": "LMS Quiz Submission",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
|
||||||
|
|
||||||
|
|
||||||
class LMSQuizSubmission(Document):
|
class LMSQuizSubmission(Document):
|
||||||
@@ -12,6 +13,9 @@ class LMSQuizSubmission(Document):
|
|||||||
self.validate_marks()
|
self.validate_marks()
|
||||||
self.set_percentage()
|
self.set_percentage()
|
||||||
|
|
||||||
|
def on_update(self):
|
||||||
|
self.notify_member()
|
||||||
|
|
||||||
def validate_marks(self):
|
def validate_marks(self):
|
||||||
for row in self.result:
|
for row in self.result:
|
||||||
if cint(row.marks) > cint(row.marks_out_of):
|
if cint(row.marks) > cint(row.marks_out_of):
|
||||||
@@ -26,3 +30,25 @@ class LMSQuizSubmission(Document):
|
|||||||
def set_percentage(self):
|
def set_percentage(self):
|
||||||
if self.score and self.score_out_of:
|
if self.score and self.score_out_of:
|
||||||
self.percentage = (self.score / self.score_out_of) * 100
|
self.percentage = (self.score / self.score_out_of) * 100
|
||||||
|
|
||||||
|
def notify_member(self):
|
||||||
|
print(self.is_new())
|
||||||
|
if self.score != 0 and self.has_value_changed("score"):
|
||||||
|
notification = frappe._dict(
|
||||||
|
{
|
||||||
|
"subject": _("You have got a score of {0} for the quiz {1}").format(
|
||||||
|
self.score, self.quiz_title
|
||||||
|
),
|
||||||
|
"email_content": _(
|
||||||
|
"There has been an update on your submission. You have got a score of {0} for the quiz {1}"
|
||||||
|
).format(self.score, self.quiz_title),
|
||||||
|
"document_type": self.doctype,
|
||||||
|
"document_name": self.name,
|
||||||
|
"for_user": self.member,
|
||||||
|
"from_user": "Administrator",
|
||||||
|
"type": "Alert",
|
||||||
|
"link": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
make_notification_logs(notification, [self.member])
|
||||||
|
|||||||
@@ -6,11 +6,7 @@ import razorpay
|
|||||||
import requests
|
import requests
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result
|
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result
|
||||||
from frappe.desk.doctype.notification_log.notification_log import (
|
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
|
||||||
make_notification_logs,
|
|
||||||
enqueue_create_notification,
|
|
||||||
get_title,
|
|
||||||
)
|
|
||||||
from frappe.desk.search import get_user_groups
|
from frappe.desk.search import get_user_groups
|
||||||
from frappe.desk.notifications import extract_mentions
|
from frappe.desk.notifications import extract_mentions
|
||||||
from frappe.utils import (
|
from frappe.utils import (
|
||||||
|
|||||||
Reference in New Issue
Block a user