Compare commits

..

34 Commits

Author SHA1 Message Date
Jannat Patel
224bb18d3e Merge pull request #1077 from pateljannat/issues-45
fix: show live class start button only to moderators and evaluators
2024-10-23 12:53:42 +05:30
Jannat Patel
aab7bdcc20 fix: show live class start button only to moderators and evaluators 2024-10-23 11:02:16 +05:30
Jannat Patel
c5ca428d98 Merge pull request #1076 from pateljannat/issues-44
fix: misc issues
2024-10-23 10:55:42 +05:30
Frappe PR Bot
af0cc7126b chore(release): Bumped to Version 2.9.0 2024-10-23 05:09:14 +00:00
Jannat Patel
a085050d27 build: removed frappe-ui package 2024-10-23 10:36:26 +05:30
Jannat Patel
2442f35f56 fix: added is_instructor to jinja 2024-10-23 10:35:26 +05:30
Jannat Patel
ed79ea536b Merge pull request #1072 from frappe/pot_develop_2024-10-18
chore: update POT file
2024-10-18 23:06:49 +05:30
frappe-pr-bot
b3d0aecd14 chore: update POT file 2024-10-18 16:04:26 +00:00
Jannat Patel
5f43e67c0b Merge pull request #1068 from pateljannat/payment-issues
fix: batch enrollment after payment completion
2024-10-17 10:39:46 +05:30
Jannat Patel
49a765a9a6 style: fix spacing 2024-10-17 10:31:56 +05:30
Jannat Patel
4d82bc86e8 style: fix spacing 2024-10-17 10:30:06 +05:30
Jannat Patel
8fe02b83b8 fix: batch enrollment after payment completion 2024-10-17 09:27:24 +05:30
Jannat Patel
9c9075606b Merge pull request #1059 from frappe/pot_develop_2024-10-11
chore: update POT file
2024-10-15 19:38:24 +05:30
Jannat Patel
53285a0d19 fix: misc issues 2024-10-14 19:17:32 +05:30
Jannat Patel
9cdeaebb47 Merge pull request #1062 from pateljannat/quiz-timer
feat: timer in quiz
2024-10-14 16:11:55 +05:30
Jannat Patel
a9cb52c68b fix: hide timer instructions if duration is not set 2024-10-14 15:49:27 +05:30
Jannat Patel
f33e950e83 feat: timer in quiz 2024-10-14 14:31:26 +05:30
Jannat Patel
9c9b5963fe Merge pull request #1060 from pateljannat/issues-43
fix: redirect to login before enrollment
2024-10-11 22:33:52 +05:30
Jannat Patel
1597054cc9 fix: redirect to login before enrollment 2024-10-11 22:18:18 +05:30
frappe-pr-bot
deba6aa845 chore: update POT file 2024-10-11 16:04:13 +00:00
Jannat Patel
2d8ba3b84e Merge pull request #1058 from pateljannat/issues-42
fix: batch self enrollment
2024-10-11 19:22:50 +05:30
Jannat Patel
e56b28abad chore: removed unnecessary lines 2024-10-11 19:17:56 +05:30
Jannat Patel
eb350c5a20 fix: batch self enrollment 2024-10-11 19:16:40 +05:30
Jannat Patel
961d5ec77b Merge pull request #1057 from pateljannat/settings-minor-changes
fix: misc ux issues
2024-10-11 16:18:19 +05:30
Jannat Patel
fa566514aa fix: image fetch for settings 2024-10-11 15:32:41 +05:30
Jannat Patel
6e97449bf7 fix: misc ux issues 2024-10-11 13:39:30 +05:30
Jannat Patel
016dafb3c3 Merge pull request #1056 from pateljannat/issues-41
fix: misc issues
2024-10-10 16:43:59 +05:30
Jannat Patel
675bcc8956 test: replaced FrappeTestCase with UnitTestCase 2024-10-10 16:20:53 +05:30
Jannat Patel
aba4c034fc fix: misc issues 2024-10-10 14:48:59 +05:30
Jannat Patel
c76d8c582f Merge pull request #1052 from pateljannat/issues-40
fix: misc quiz issues
2024-10-09 19:17:01 +05:30
Jannat Patel
f1cb0e6f3c fix: usd conversion 2024-10-09 19:07:25 +05:30
Jannat Patel
d296687456 fix: misc quiz issues 2024-10-09 16:03:56 +05:30
Jannat Patel
5b68001c94 Merge pull request #1049 from pateljannat/issues-39
fix: create order for razorpay
2024-10-09 11:59:57 +05:30
Jannat Patel
8b1d9bb5a9 fix: create order for razorpay 2024-10-09 11:31:31 +05:30
51 changed files with 872 additions and 315 deletions

View File

@@ -18,6 +18,7 @@
"@editorjs/nested-list": "^1.4.2", "@editorjs/nested-list": "^1.4.2",
"@editorjs/paragraph": "^2.11.3", "@editorjs/paragraph": "^2.11.3",
"@editorjs/simple-image": "^1.6.0", "@editorjs/simple-image": "^1.6.0",
"ace-builds": "^1.36.2",
"chart.js": "^4.4.1", "chart.js": "^4.4.1",
"codemirror-editor-vue3": "^2.8.0", "codemirror-editor-vue3": "^2.8.0",
"dayjs": "^1.11.6", "dayjs": "^1.11.6",

View File

@@ -56,7 +56,6 @@ const props = defineProps({
onMounted(() => { onMounted(() => {
setTimeout(() => { setTimeout(() => {
audio.value = document.querySelector('audio') audio.value = document.querySelector('audio')
console.log(audio.value)
audio.value.onloadedmetadata = () => { audio.value.onloadedmetadata = () => {
duration.value = audio.value.duration duration.value = audio.value.duration
} }

View File

@@ -75,6 +75,7 @@
variant="solid" variant="solid"
class="w-full mt-2" class="w-full mt-2"
v-else-if="batch.data.allow_self_enrollment && batch.data.seats_left" v-else-if="batch.data.allow_self_enrollment && batch.data.seats_left"
@click="enrollInBatch()"
> >
{{ __('Enroll Now') }} {{ __('Enroll Now') }}
</Button> </Button>
@@ -97,11 +98,13 @@
</template> </template>
<script setup> <script setup>
import { inject, computed } from 'vue' import { inject, computed } from 'vue'
import { Badge, Button } from 'frappe-ui' import { Badge, Button, createResource } from 'frappe-ui'
import { BookOpen, Clock, Globe } from 'lucide-vue-next' import { BookOpen, Clock, Globe } from 'lucide-vue-next'
import { formatNumberIntoCurrency, formatTime } from '@/utils' import { formatNumberIntoCurrency, formatTime, showToast } from '@/utils'
import DateRange from '@/components/Common/DateRange.vue' import DateRange from '@/components/Common/DateRange.vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const user = inject('$user') const user = inject('$user')
const props = defineProps({ const props = defineProps({
@@ -111,6 +114,39 @@ const props = defineProps({
}, },
}) })
const enroll = createResource({
url: 'lms.lms.utils.enroll_in_batch',
makeParams(values) {
return {
batch: props.batch.data.name,
}
},
})
const enrollInBatch = () => {
if (!user.data) {
window.location.href = `/login?redirect-to=/batches/details/${props.batch.data.name}`
}
enroll.submit(
{},
{
onSuccess(data) {
showToast(
__('Success'),
__('You have been enrolled in this batch'),
'check'
)
router.push({
name: 'Batch',
params: {
batchName: props.batch.data.name,
},
})
},
}
)
}
const seats_left = computed(() => { const seats_left = computed(() => {
if (props.batch.data?.seat_count) { if (props.batch.data?.seat_count) {
return props.batch.data?.seat_count - props.batch.data?.students?.length return props.batch.data?.seat_count - props.batch.data?.students?.length

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col justify-between h-full"> <div class="flex flex-col justify-between min-h-0">
<div> <div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="font-semibold mb-1"> <div class="font-semibold mb-1">
@@ -16,6 +16,7 @@
{{ __(description) }} {{ __(description) }}
</div> </div>
</div> </div>
<div class="overflow-y-auto">
<SettingFields :fields="fields" :data="data.data" /> <SettingFields :fields="fields" :data="data.data" />
<div class="flex flex-row-reverse mt-auto"> <div class="flex flex-row-reverse mt-auto">
<Button variant="solid" :loading="saveSettings.loading" @click="update"> <Button variant="solid" :loading="saveSettings.loading" @click="update">
@@ -23,6 +24,7 @@
</Button> </Button>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
import { createResource, Button, Badge } from 'frappe-ui' import { createResource, Button, Badge } from 'frappe-ui'
@@ -70,9 +72,16 @@ const update = () => {
fieldsToSave[f.name] = f.value fieldsToSave[f.name] = f.value
} }
}) })
saveSettings.submit({ saveSettings.submit(
{
fields: fieldsToSave, fields: fieldsToSave,
}) },
{
onSuccess(data) {
isDirty.value = false
},
}
)
} }
watch(props.data, (newData) => { watch(props.data, (newData) => {

View File

@@ -0,0 +1,204 @@
<template>
<div
class="editor flex flex-col gap-1"
:style="{
height: height,
}"
>
<span class="text-xs" v-if="label">
{{ label }}
</span>
<div
ref="editor"
class="h-auto flex-1 overflow-hidden overscroll-none !rounded border border-outline-gray-2 bg-surface-gray-2 dark:bg-gray-900"
/>
<span
class="mt-1 text-xs text-gray-600"
v-show="description"
v-html="description"
></span>
<Button
v-if="showSaveButton"
@click="emit('save', aceEditor?.getValue())"
class="mt-3"
>
{{ __('Save') }}
</Button>
</div>
</template>
<script setup lang="ts">
import { useDark } from '@vueuse/core'
import ace from 'ace-builds'
import 'ace-builds/src-min-noconflict/ext-searchbox'
import 'ace-builds/src-min-noconflict/theme-chrome'
import 'ace-builds/src-min-noconflict/theme-twilight'
import { PropType, onMounted, ref, watch } from 'vue'
import { Button } from 'frappe-ui'
const isDark = useDark({
attribute: 'data-theme',
})
const props = defineProps({
modelValue: {
type: [Object, String, Array],
},
type: {
type: String as PropType<'JSON' | 'HTML' | 'Python' | 'JavaScript' | 'CSS'>,
default: 'JSON',
},
label: {
type: String,
default: '',
},
readonly: {
type: Boolean,
default: false,
},
height: {
type: String,
default: '250px',
},
showLineNumbers: {
type: Boolean,
default: false,
},
autofocus: {
type: Boolean,
default: true,
},
showSaveButton: {
type: Boolean,
default: false,
},
description: {
type: String,
default: '',
},
})
const emit = defineEmits(['save', 'update:modelValue'])
const editor = ref<HTMLElement | null>(null)
let aceEditor = null as ace.Ace.Editor | null
onMounted(() => {
setupEditor()
})
const setupEditor = () => {
aceEditor = ace.edit(editor.value as HTMLElement)
resetEditor(props.modelValue as string, true)
aceEditor.setReadOnly(props.readonly)
aceEditor.setOptions({
fontSize: '12px',
useWorker: false,
showGutter: props.showLineNumbers,
wrap: props.showLineNumbers,
})
if (props.type === 'CSS') {
import('ace-builds/src-noconflict/mode-css').then(() => {
aceEditor?.session.setMode('ace/mode/css')
})
} else if (props.type === 'JavaScript') {
import('ace-builds/src-noconflict/mode-javascript').then(() => {
aceEditor?.session.setMode('ace/mode/javascript')
})
} else if (props.type === 'Python') {
import('ace-builds/src-noconflict/mode-python').then(() => {
aceEditor?.session.setMode('ace/mode/python')
})
} else if (props.type === 'JSON') {
import('ace-builds/src-noconflict/mode-json').then(() => {
aceEditor?.session.setMode('ace/mode/json')
})
} else {
import('ace-builds/src-noconflict/mode-html').then(() => {
aceEditor?.session.setMode('ace/mode/html')
})
}
aceEditor.on('blur', () => {
try {
let value = aceEditor?.getValue() || ''
if (props.type === 'JSON') {
value = JSON.parse(value)
}
if (value === props.modelValue) return
if (!props.showSaveButton && !props.readonly) {
emit('update:modelValue', value)
}
} catch (e) {
// do nothing
}
})
}
const getModelValue = () => {
let value = props.modelValue || ''
try {
if (props.type === 'JSON' || typeof value === 'object') {
value = JSON.stringify(value, null, 2)
}
} catch (e) {
// do nothing
}
return value as string
}
function resetEditor(value: string, resetHistory = false) {
value = getModelValue()
aceEditor?.setValue(value)
aceEditor?.clearSelection()
aceEditor?.setTheme(isDark.value ? 'ace/theme/twilight' : 'ace/theme/chrome')
props.autofocus && aceEditor?.focus()
if (resetHistory) {
aceEditor?.session.getUndoManager().reset()
}
}
watch(isDark, () => {
aceEditor?.setTheme(isDark.value ? 'ace/theme/twilight' : 'ace/theme/chrome')
})
watch(
() => props.type,
() => {
setupEditor()
}
)
watch(
() => props.modelValue,
() => {
resetEditor(props.modelValue as string)
}
)
defineExpose({ resetEditor })
</script>
<style scoped>
.editor .ace_editor {
height: 100%;
width: 100%;
border-radius: 5px;
overscroll-behavior: none;
}
.editor :deep(.ace_scrollbar-h) {
display: none;
}
.editor :deep(.ace_search) {
@apply dark:bg-gray-800 dark:text-gray-200;
@apply dark:border-gray-800;
}
.editor :deep(.ace_searchbtn) {
@apply dark:bg-gray-800 dark:text-gray-200;
@apply dark:border-gray-800;
}
.editor :deep(.ace_button) {
@apply dark:bg-gray-800 dark:text-gray-200;
}
.editor :deep(.ace_search_field) {
@apply dark:bg-gray-900 dark:text-gray-200;
@apply dark:border-gray-800;
}
</style>

View File

@@ -152,24 +152,11 @@ const filterOptions = createResource({
url: 'frappe.desk.search.search_link', url: 'frappe.desk.search.search_link',
method: 'POST', method: 'POST',
cache: [text.value, props.doctype], cache: [text.value, props.doctype],
auto: true,
params: { params: {
txt: text.value, txt: text.value,
doctype: props.doctype, doctype: props.doctype,
}, },
/* transform: (data) => {
let allData = data
.filter((c) => {
return c.description.split(', ')[1]
})
.map((option) => {
let email = option.description.split(', ')[1]
return {
label: option.label || email,
value: email,
}
})
return allData
}, */
}) })
const options = computed(() => { const options = computed(() => {

View File

@@ -21,7 +21,7 @@
<script setup> <script setup>
import { Star } from 'lucide-vue-next' import { Star } from 'lucide-vue-next'
import { computed, ref, watch } from 'vue' import { ref, watch } from 'vue'
const props = defineProps({ const props = defineProps({
id: { id: {

View File

@@ -116,7 +116,7 @@
import { BookOpen, Users, Star } from 'lucide-vue-next' import { BookOpen, Users, Star } from 'lucide-vue-next'
import { computed, inject } from 'vue' import { computed, inject } from 'vue'
import { Button, createResource } from 'frappe-ui' import { Button, createResource } from 'frappe-ui'
import { createToast } from '@/utils/' import { showToast } from '@/utils/'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
@@ -139,11 +139,11 @@ const video_link = computed(() => {
function enrollStudent() { function enrollStudent() {
if (!user.data) { if (!user.data) {
createToast({ showToast(
title: 'Please Login', __('Please Login'),
icon: 'alert-circle', __('You need to login first to enroll for this course'),
iconClasses: 'text-yellow-600 bg-yellow-100', 'circle-warn'
}) )
setTimeout(() => { setTimeout(() => {
window.location.href = `/login?redirect-to=${window.location.pathname}` window.location.href = `/login?redirect-to=${window.location.pathname}`
}, 2000) }, 2000)
@@ -159,11 +159,11 @@ function enrollStudent() {
capture('enrolled_in_course', { capture('enrolled_in_course', {
course: props.course.data.name, course: props.course.data.name,
}) })
createToast({ showToast(
title: 'Enrolled Successfully', __('Success'),
icon: 'check', __('You have been enrolled in this course'),
iconClasses: 'text-green-600 bg-green-100', 'check'
}) )
setTimeout(() => { setTimeout(() => {
router.push({ router.push({
name: 'Lesson', name: 'Lesson',
@@ -173,7 +173,7 @@ function enrollStudent() {
lessonNumber: 1, lessonNumber: 1,
}, },
}) })
}, 3000) }, 2000)
}) })
} }
} }
@@ -206,7 +206,6 @@ const certificate = createResource({
} }
}, },
onSuccess(data) { onSuccess(data) {
console.log(data)
window.open( window.open(
`/api/method/frappe.utils.print_format.download_pdf?doctype=LMS+Certificate&name=${ `/api/method/frappe.utils.print_format.download_pdf?doctype=LMS+Certificate&name=${
data.name data.name

View File

@@ -76,7 +76,7 @@
<Trash2 <Trash2
v-if="allowEdit" v-if="allowEdit"
@click.prevent="trashLesson(lesson.name, chapter.name)" @click.prevent="trashLesson(lesson.name, chapter.name)"
class="h-4 w-4 stroke-1.5 text-gray-700 ml-auto invisible group-hover:visible" class="h-4 w-4 text-red-500 ml-auto invisible group-hover:visible"
/> />
<Check <Check
v-if="lesson.is_complete" v-if="lesson.is_complete"
@@ -119,7 +119,7 @@
</template> </template>
<script setup> <script setup>
import { Button, createResource } from 'frappe-ui' import { Button, createResource } from 'frappe-ui'
import { ref } from 'vue' import { ref, getCurrentInstance } from 'vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue' import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
import { import {
@@ -138,6 +138,8 @@ const route = useRoute()
const expandAll = ref(true) const expandAll = ref(true)
const showChapterModal = ref(false) const showChapterModal = ref(false)
const currentChapter = ref(null) const currentChapter = ref(null)
const app = getCurrentInstance()
const { $dialog } = app.appContext.config.globalProperties
const props = defineProps({ const props = defineProps({
courseName: { courseName: {
@@ -202,10 +204,24 @@ const updateLessonIndex = createResource({
}) })
const trashLesson = (lessonName, chapterName) => { const trashLesson = (lessonName, chapterName) => {
$dialog({
title: __('Delete Lesson'),
message: __('Are you sure you want to delete this lesson?'),
actions: [
{
label: __('Delete'),
theme: 'red',
variant: 'solid',
onClick(close) {
deleteLesson.submit({ deleteLesson.submit({
lesson: lessonName, lesson: lessonName,
chapter: chapterName, chapter: chapterName,
}) })
close()
},
},
],
})
} }
const openChapterDetail = (index) => { const openChapterDetail = (index) => {

View File

@@ -37,6 +37,7 @@
</div> </div>
<div class="flex items-center space-x-2 text-gray-900 mt-auto"> <div class="flex items-center space-x-2 text-gray-900 mt-auto">
<a <a
v-if="user.data?.is_moderator || user.data?.is_evaluator"
:href="cls.start_url" :href="cls.start_url"
target="_blank" target="_blank"
class="w-1/2 cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-gray-800 bg-gray-100 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring focus-visible:ring-gray-400 h-7 text-base px-2 rounded" class="w-1/2 cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-gray-800 bg-gray-100 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring focus-visible:ring-gray-400 h-7 text-base px-2 rounded"

View File

@@ -179,26 +179,6 @@ const tabsStructure = computed(() => {
name: 'app_name', name: 'app_name',
type: 'text', type: 'text',
}, },
{
label: 'Copyright',
name: 'copyright',
type: 'text',
},
{
label: 'Address',
name: 'address',
type: 'textarea',
rows: 4,
},
{
label: 'Footer "Powered By"',
name: 'footer_powered',
type: 'textarea',
rows: 4,
},
{
type: 'Column Break',
},
{ {
label: 'Logo', label: 'Logo',
name: 'banner_image', name: 'banner_image',
@@ -214,6 +194,23 @@ const tabsStructure = computed(() => {
name: 'footer_logo', name: 'footer_logo',
type: 'Upload', type: 'Upload',
}, },
{
label: 'Address',
name: 'address',
type: 'textarea',
rows: 2,
},
{
label: 'Footer "Powered By"',
name: 'footer_powered',
type: 'textarea',
rows: 4,
},
{
label: 'Copyright',
name: 'copyright',
type: 'text',
},
], ],
}, },
{ {
@@ -292,9 +289,11 @@ const tabsStructure = computed(() => {
rows: 10, rows: 10,
}, },
{ {
label: 'Ask user category', label: 'Ask for Occupation',
name: 'user_category', name: 'user_category',
type: 'checkbox', type: 'checkbox',
description:
'Enable this option to ask users to select their occupation during the signup process.',
}, },
], ],
}, },

View File

@@ -1,11 +1,27 @@
<template> <template>
<div v-if="quiz.data"> <div v-if="quiz.data">
<div class="bg-blue-100 py-2 px-2 mb-4 rounded-md text-sm text-blue-800"> <div
<div class="leading-relaxed"> class="bg-blue-100 space-y-1 py-2 px-2 rounded-md text-sm text-blue-800"
>
<div class="leading-5">
{{ {{
__('This quiz consists of {0} questions.').format(questions.length) __('This quiz consists of {0} questions.').format(questions.length)
}} }}
</div> </div>
<div v-if="quiz.data?.duration" class="leading-5">
{{
__(
'Please ensure that you complete all the questions in {0} minutes.'
).format(quiz.data.duration)
}}
</div>
<div v-if="quiz.data?.duration" class="leading-5">
{{
__(
'If you fail to do so, the quiz will be automatically submitted when the timer ends.'
)
}}
</div>
<div v-if="quiz.data.passing_percentage" class="leading-relaxed"> <div v-if="quiz.data.passing_percentage" class="leading-relaxed">
{{ {{
__( __(
@@ -22,14 +38,16 @@
) )
}} }}
</div> </div>
<div v-if="quiz.data.time" class="leading-relaxed">
{{
__(
'The quiz has a time limit. For each question you will be given {0} seconds.'
).format(quiz.data.time)
}}
</div> </div>
<div v-if="quiz.data.duration" class="flex items-center space-x-2 my-4">
<span class="text-gray-600 text-xs"> {{ __('Time') }}: </span>
<ProgressBar :progress="timerProgress" />
<span class="font-semibold">
{{ formatTimer(timer) }}
</span>
</div> </div>
<div v-if="activeQuestion == 0"> <div v-if="activeQuestion == 0">
<div class="border text-center p-20 rounded-md"> <div class="border text-center p-20 rounded-md">
<div class="font-semibold text-lg"> <div class="font-semibold text-lg">
@@ -63,7 +81,7 @@
class="border rounded-md p-5" class="border rounded-md p-5"
> >
<div class="flex justify-between"> <div class="flex justify-between">
<div class="text-sm"> <div class="text-sm text-gray-600">
<span class="mr-2"> <span class="mr-2">
{{ __('Question {0}').format(activeQuestion) }}: {{ __('Question {0}').format(activeQuestion) }}:
</span> </span>
@@ -162,8 +180,8 @@
editorClass="prose-sm max-w-none border-b border-x bg-gray-100 rounded-b-md py-1 px-2 min-h-[7rem]" editorClass="prose-sm max-w-none border-b border-x bg-gray-100 rounded-b-md py-1 px-2 min-h-[7rem]"
/> />
</div> </div>
<div class="flex items-center justify-between mt-5"> <div class="flex items-center justify-between mt-4">
<div> <div class="text-sm text-gray-600">
{{ {{
__('Question {0} of {1}').format( __('Question {0} of {1}').format(
activeQuestion, activeQuestion,
@@ -250,20 +268,29 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { Badge, Button, createResource, ListView, TextEditor } from 'frappe-ui' import {
import { ref, watch, reactive, inject } from 'vue' Badge,
Button,
createResource,
ListView,
TextEditor,
FormControl,
} from 'frappe-ui'
import { ref, watch, reactive, inject, computed } from 'vue'
import { createToast } from '@/utils/' import { createToast } from '@/utils/'
import { CheckCircle, XCircle, MinusCircle } from 'lucide-vue-next' import { CheckCircle, XCircle, MinusCircle } from 'lucide-vue-next'
import { timeAgo } from '@/utils' import { timeAgo } from '@/utils'
import FormControl from 'frappe-ui/src/components/FormControl.vue' import ProgressBar from '@/components/ProgressBar.vue'
const user = inject('$user')
const user = inject('$user')
const activeQuestion = ref(0) const activeQuestion = ref(0)
const currentQuestion = ref('') const currentQuestion = ref('')
const selectedOptions = reactive([0, 0, 0, 0]) const selectedOptions = reactive([0, 0, 0, 0])
const showAnswers = reactive([]) const showAnswers = reactive([])
let questions = reactive([]) let questions = reactive([])
const possibleAnswer = ref(null) const possibleAnswer = ref(null)
const timer = ref(0)
let timerInterval = null
const props = defineProps({ const props = defineProps({
quizName: { quizName: {
@@ -284,6 +311,7 @@ const quiz = createResource({
auto: true, auto: true,
onSuccess(data) { onSuccess(data) {
populateQuestions() populateQuestions()
setupTimer()
}, },
}) })
@@ -299,6 +327,37 @@ const populateQuestions = () => {
} }
} }
const setupTimer = () => {
if (quiz.data.duration) {
timer.value = quiz.data.duration * 60
}
}
const startTimer = () => {
timerInterval = setInterval(() => {
timer.value--
if (timer.value == 0) {
clearInterval(timerInterval)
submitQuiz()
}
}, 1000)
}
const formatTimer = (seconds) => {
const hrs = Math.floor(seconds / 3600)
.toString()
.padStart(2, '0')
const mins = Math.floor((seconds % 3600) / 60)
.toString()
.padStart(2, '0')
const secs = (seconds % 60).toString().padStart(2, '0')
return hrs != '00' ? `${hrs}:${mins}:${secs}` : `${mins}:${secs}`
}
const timerProgress = computed(() => {
return (timer.value / (quiz.data.duration * 60)) * 100
})
const shuffleArray = (array) => { const shuffleArray = (array) => {
for (let i = array.length - 1; i > 0; i--) { for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)) const j = Math.floor(Math.random() * (i + 1))
@@ -383,6 +442,7 @@ watch(
const startQuiz = () => { const startQuiz = () => {
activeQuestion.value = 1 activeQuestion.value = 1
localStorage.removeItem(quiz.data.title) localStorage.removeItem(quiz.data.title)
if (quiz.data.duration) startTimer()
} }
const markAnswer = (index) => { const markAnswer = (index) => {
@@ -493,9 +553,15 @@ const submitQuiz = () => {
} }
const createSubmission = () => { const createSubmission = () => {
quizSubmission.reload().then(() => { quizSubmission.submit(
{},
{
onSuccess(data) {
if (quiz.data && quiz.data.max_attempts) attempts.reload() if (quiz.data && quiz.data.max_attempts) attempts.reload()
}) if (quiz.data.duration) clearInterval(timerInterval)
},
}
)
} }
const resetQuiz = () => { const resetQuiz = () => {
@@ -504,6 +570,7 @@ const resetQuiz = () => {
showAnswers.length = 0 showAnswers.length = 0
quizSubmission.reset() quizSubmission.reset()
populateQuestions() populateQuestions()
setupTimer()
} }
const getInstructions = (question) => { const getInstructions = (question) => {

View File

@@ -2,7 +2,7 @@
<div class="flex flex-col justify-between h-full"> <div class="flex flex-col justify-between h-full">
<div> <div>
<div class="flex itemsc-center justify-between"> <div class="flex itemsc-center justify-between">
<div class="font-semibold mb-1"> <div class="text-xl font-semibold leading-none mb-1">
{{ __(label) }} {{ __(label) }}
</div> </div>
<Badge <Badge

View File

@@ -17,17 +17,16 @@
/> />
<div v-else-if="field.type == 'Code'"> <div v-else-if="field.type == 'Code'">
<div> <CodeEditor
{{ __(field.label) }} :label="__(field.label)"
</div> type="HTML"
<Codemirror description="The HTML you add here will be shown on your sign up page."
v-model:value="data[field.name]" v-model="data[field.name]"
:height="200" height="250px"
:options="{ class="shrink-0"
mode: field.mode, :showLineNumbers="true"
theme: 'seti', >
}" </CodeEditor>
/>
</div> </div>
<div v-else-if="field.type == 'Upload'"> <div v-else-if="field.type == 'Upload'">
@@ -53,9 +52,11 @@
</template> </template>
</FileUploader> </FileUploader>
<div v-else> <div v-else>
<div class="flex items-center text-sm"> <div class="flex items-center text-sm space-x-2">
<div class="border rounded-md p-2 mr-2"> <div
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" /> class="flex items-center justify-center rounded border border-outline-gray-1 w-[15rem] py-5"
>
<img :src="data[field.name]?.file_url" class="h-6 rounded" />
</div> </div>
<div class="flex flex-col flex-wrap"> <div class="flex flex-col flex-wrap">
<span class="break-all"> <span class="break-all">
@@ -73,6 +74,14 @@
</div> </div>
</div> </div>
<Switch
v-else-if="field.type == 'checkbox'"
size="sm"
:label="__(field.label)"
:description="__(field.description)"
v-model="data[field.name]"
/>
<FormControl <FormControl
v-else v-else
:key="field.name" :key="field.name"
@@ -88,14 +97,12 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { FormControl, FileUploader, Button } from 'frappe-ui' import { FormControl, FileUploader, Button, Switch } from 'frappe-ui'
import { computed } from 'vue' import { computed } from 'vue'
import { getFileSize, validateFile } from '@/utils' import { getFileSize, validateFile } from '@/utils'
import { X, FileText } from 'lucide-vue-next' import { X, FileText } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import Codemirror from 'codemirror-editor-vue3' import CodeEditor from '@/components/Controls/CodeEditor.vue'
import 'codemirror/theme/seti.css'
import 'codemirror/mode/htmlmixed/htmlmixed.js'
const props = defineProps({ const props = defineProps({
fields: { fields: {

View File

@@ -3,13 +3,14 @@
<video <video
@timeupdate="updateTime" @timeupdate="updateTime"
@ended="videoEnded" @ended="videoEnded"
class="rounded-lg border border-gray-100" @click="togglePlay"
class="rounded-lg border border-gray-100 group cursor-pointer"
ref="videoRef" ref="videoRef"
> >
<source :src="fileURL" :type="type" /> <source :src="fileURL" :type="type" />
</video> </video>
<div <div
class="flex items-center space-x-2 bg-gray-200 rounded-md p-0.5 absolute bottom-3 w-[98%] left-0 right-0 mx-auto" class="flex items-center space-x-2 bg-gray-200 rounded-md p-0.5 absolute bottom-3 w-[98%] left-0 right-0 mx-auto invisible group-hover:visible"
> >
<Button variant="ghost"> <Button variant="ghost">
<template #icon> <template #icon>
@@ -106,6 +107,14 @@ const pauseVideo = () => {
playing.value = false playing.value = false
} }
const togglePlay = () => {
if (playing.value) {
pauseVideo()
} else {
playVideo()
}
}
const videoEnded = () => { const videoEnded = () => {
playing.value = false playing.value = false
} }

View File

@@ -5,6 +5,7 @@ import router from './router'
import App from './App.vue' import App from './App.vue'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import dayjs from '@/utils/dayjs' import dayjs from '@/utils/dayjs'
import { createDialog } from '@/utils/dialogs'
import translationPlugin from './translation' import translationPlugin from './translation'
import { usersStore } from './stores/user' import { usersStore } from './stores/user'
import { sessionStore } from './stores/session' import { sessionStore } from './stores/session'
@@ -36,3 +37,4 @@ let { isLoggedIn } = sessionStore()
app.provide('$user', userResource) app.provide('$user', userResource)
app.provide('$allUsers', allUsers) app.provide('$allUsers', allUsers)
app.config.globalProperties.$user = userResource app.config.globalProperties.$user = userResource
app.config.globalProperties.$dialog = createDialog

View File

@@ -149,7 +149,7 @@ const newJob = createResource({
return { return {
doc: { doc: {
doctype: 'Job Opportunity', doctype: 'Job Opportunity',
company_logo: job.image.file_url, company_logo: job.image?.file_url,
...job, ...job,
}, },
} }

View File

@@ -52,46 +52,88 @@
</header> </header>
<div v-if="job.data" class="max-w-3xl mx-auto"> <div v-if="job.data" class="max-w-3xl mx-auto">
<div class="p-4"> <div class="p-4">
<div class="flex mb-10"> <div class="space-y-5 mb-10">
<div class="flex items-center">
<img <img
:src="job.data.company_logo" :src="job.data.company_logo"
class="w-16 h-16 rounded-lg object-contain mr-4" class="w-16 h-16 rounded-lg object-contain mr-4"
:alt="job.data.company_name" :alt="job.data.company_name"
/> />
<div>
<div class="text-2xl font-semibold mb-4"> <div class="text-2xl font-semibold mb-4">
{{ job.data.job_title }} {{ job.data.job_title }}
</div> </div>
</div>
<div>
<div <div
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-10 gap-y-2 md:gap-y-4" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-10 gap-y-5 md:gap-y-5"
> >
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<Building2 class="h-4 w-4 stroke-1.5" /> <span class="p-4 bg-green-50 rounded-full">
<span>{{ job.data.company_name }}</span> <Building2 class="h-4 w-4 text-green-500" />
</span>
<div class="flex flex-col space-y-2">
<span class="text-xs text-gray-600 font-medium uppercase">
{{ __('Organisation') }}
</span>
<span class="text-sm font-semibold">
{{ job.data.company_name }}
</span>
</div>
</div> </div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<MapPin class="h-4 w-4 stroke-1.5" /> <span class="p-4 bg-red-50 rounded-full">
<span>{{ job.data.location }}</span> <MapPin class="h-4 w-4 text-red-500" />
</span>
<div class="flex flex-col space-y-2">
<span class="text-xs text-gray-600 font-medium uppercase">
{{ __('Location') }}
</span>
<span class="text-sm font-semibold">
{{ job.data.location }}
</span>
</div>
</div> </div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<ClipboardType class="h-4 w-4 stroke-1.5" /> <span class="p-4 bg-yellow-50 rounded-full">
<span>{{ job.data.type }}</span> <ClipboardType class="h-4 w-4 text-yellow-500" />
</span>
<div class="flex flex-col space-y-2">
<span class="text-xs font-medium text-gray-600 uppercase">
{{ __('Category') }}
</span>
<span class="text-sm font-semibold">
{{ job.data.type }}
</span>
</div>
</div> </div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<CalendarDays class="h-4 w-4 stroke-1.5" /> <span class="p-4 bg-blue-50 rounded-full">
<span> <CalendarDays class="h-4 w-4 text-blue-500" />
</span>
<div class="flex flex-col space-y-2">
<span class="text-xs text-gray-600 font-medium uppercase">
{{ __('Posted on') }}
</span>
<span class="text-sm font-semibold">
{{ dayjs(job.data.creation).format('DD MMM YYYY') }} {{ dayjs(job.data.creation).format('DD MMM YYYY') }}
</span> </span>
</div> </div>
</div>
<div <div
v-if="applicationCount.data" v-if="applicationCount.data"
class="flex items-center space-x-2" class="flex items-center space-x-2"
> >
<SquareUserRound class="h-4 w-4 stroke-1.5" /> <span class="p-4 bg-purple-50 rounded-full">
<span <SquareUserRound class="h-4 w-4 text-purple-500" />
>{{ applicationCount.data }} </span>
{{ __('applications received') }}</span <div class="flex flex-col space-y-2">
> <span class="text-xs text-gray-600 font-medium uppercase">
{{ __('Applications Received') }}
</span>
<span class="text-sm font-semibold">
{{ applicationCount.data }}
</span>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -120,6 +120,7 @@
</div> </div>
<div <div
v-if=" v-if="
lesson.data.instructor_content &&
JSON.parse(lesson.data.instructor_content)?.blocks?.length > 1 && JSON.parse(lesson.data.instructor_content)?.blocks?.length > 1 &&
allowInstructorContent() allowInstructorContent()
" "
@@ -278,7 +279,7 @@ const renderEditor = (holder, content) => {
} }
const markProgress = () => { const markProgress = () => {
if (user.data && !lesson.data?.progress) { if (user.data && lesson.data && !lesson.data.progress) {
progress.submit() progress.submit()
} }
} }

View File

@@ -4,6 +4,19 @@
> >
<Breadcrumbs :items="breadcrumbs" /> <Breadcrumbs :items="breadcrumbs" />
<div class="space-x-2"> <div class="space-x-2">
<router-link
v-if="quizDetails.data?.name"
:to="{
name: 'QuizPage',
params: {
quizID: quizDetails.data.name,
},
}"
>
<Button>
{{ __('Open') }}
</Button>
</router-link>
<router-link <router-link
v-if="quizDetails.data?.name" v-if="quizDetails.data?.name"
:to="{ :to="{
@@ -25,7 +38,7 @@
<div class="w-3/4 mx-auto py-5"> <div class="w-3/4 mx-auto py-5">
<!-- Details --> <!-- Details -->
<div class="mb-8"> <div class="mb-8">
<div class="text-sm font-semibold mb-4"> <div class="font-semibold mb-4">
{{ __('Details') }} {{ __('Details') }}
</div> </div>
<FormControl <FormControl
@@ -37,11 +50,17 @@
" "
/> />
<div v-if="quizDetails.data?.name"> <div v-if="quizDetails.data?.name">
<div class="grid grid-cols-3 gap-5 mt-4 mb-8"> <div class="grid grid-cols-2 gap-5 mt-4 mb-8">
<FormControl <FormControl
type="number"
v-model="quiz.max_attempts" v-model="quiz.max_attempts"
:label="__('Maximun Attempts')" :label="__('Maximun Attempts')"
/> />
<FormControl
type="number"
v-model="quiz.duration"
:label="__('Duration (in minutes)')"
/>
<FormControl <FormControl
v-model="quiz.total_marks" v-model="quiz.total_marks"
:label="__('Total Marks')" :label="__('Total Marks')"
@@ -55,7 +74,7 @@
<!-- Settings --> <!-- Settings -->
<div class="mb-8"> <div class="mb-8">
<div class="text-sm font-semibold mb-4"> <div class="font-semibold mb-4">
{{ __('Settings') }} {{ __('Settings') }}
</div> </div>
<div class="grid grid-cols-3 gap-5 my-4"> <div class="grid grid-cols-3 gap-5 my-4">
@@ -73,7 +92,7 @@
</div> </div>
<div class="mb-8"> <div class="mb-8">
<div class="text-sm font-semibold mb-4"> <div class="font-semibold mb-4">
{{ __('Shuffle Settings') }} {{ __('Shuffle Settings') }}
</div> </div>
<div class="grid grid-cols-3"> <div class="grid grid-cols-3">
@@ -93,7 +112,7 @@
<!-- Questions --> <!-- Questions -->
<div> <div>
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<div class="text-sm font-semibold"> <div class="font-semibold">
{{ __('Questions') }} {{ __('Questions') }}
</div> </div>
<Button @click="openQuestionModal()"> <Button @click="openQuestionModal()">
@@ -213,6 +232,7 @@ const quiz = reactive({
total_marks: 0, total_marks: 0,
passing_percentage: 0, passing_percentage: 0,
max_attempts: 0, max_attempts: 0,
duration: 0,
limit_questions_to: 0, limit_questions_to: 0,
show_answers: true, show_answers: true,
show_submission_history: false, show_submission_history: false,

View File

@@ -82,10 +82,13 @@ export function getFileSize(file_size) {
export function showToast(title, text, icon, iconClasses = null) { export function showToast(title, text, icon, iconClasses = null) {
if (!iconClasses) { if (!iconClasses) {
iconClasses = if (icon == 'check') {
icon == 'check' iconClasses = 'bg-green-600 text-white rounded-md p-px'
? 'bg-green-600 text-white rounded-md p-px' } else if (icon == 'circle-warn') {
: 'bg-red-600 text-white rounded-md p-px' iconClasses = 'bg-yellow-600 text-white rounded-md p-px'
} else {
iconClasses = 'bg-red-600 text-white rounded-md p-px'
}
} }
createToast({ createToast({
title: title, title: title,

View File

@@ -852,6 +852,11 @@
dependencies: dependencies:
vue-demi ">=0.14.8" vue-demi ">=0.14.8"
ace-builds@^1.36.2:
version "1.36.2"
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.36.2.tgz#9499bd59e839a335ac4850e74549ca8d849dc554"
integrity sha512-eqqfbGwx/GKjM/EnFu4QtQ+d2NNBu84MGgxoG8R5iyFpcVeQ4p9YlTL+ZzdEJqhdkASqoqOxCSNNGyB6lvMm+A==
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"

View File

@@ -1 +1 @@
__version__ = "2.8.0" __version__ = "2.9.0"

View File

@@ -185,6 +185,7 @@ jinja = {
"lms.lms.utils.get_lesson_url", "lms.lms.utils.get_lesson_url",
"lms.page_renderers.get_profile_url", "lms.page_renderers.get_profile_url",
"lms.overrides.user.get_palette", "lms.overrides.user.get_palette",
"lms.lms.utils.is_instructor",
], ],
"filters": [], "filters": [],
} }

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSJobApplication(FrappeTestCase): class TestLMSJobApplication(UnitTestCase):
pass pass

View File

@@ -293,7 +293,10 @@ def get_branding():
image_fields = ["banner_image", "footer_logo", "favicon"] image_fields = ["banner_image", "footer_logo", "favicon"]
for field in image_fields: for field in image_fields:
if website_settings.get(field):
website_settings.update({field: get_file_info(website_settings.get(field))}) website_settings.update({field: get_file_info(website_settings.get(field))})
else:
website_settings.update({field: None})
return website_settings return website_settings
@@ -322,7 +325,7 @@ def get_evaluator_details(evaluator):
) )
if frappe.db.exists("Course Evaluator", {"evaluator": evaluator}): if frappe.db.exists("Course Evaluator", {"evaluator": evaluator}):
doc = frappe.get_doc("Course Evaluator", evaluator, as_dict=1) doc = frappe.get_doc("Course Evaluator", evaluator)
else: else:
doc = frappe.new_doc("Course Evaluator") doc = frappe.new_doc("Course Evaluator")
doc.evaluator = evaluator doc.evaluator = evaluator
@@ -576,14 +579,17 @@ def get_members(start=0, search=""):
""" """
filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]} filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]}
or_filters = {}
if search: if search:
filters["full_name"] = ["like", f"%{search}%"] or_filters["full_name"] = ["like", f"%{search}%"]
or_filters["email"] = ["like", f"%{search}%"]
members = frappe.get_all( members = frappe.get_all(
"User", "User",
filters=filters, filters=filters,
fields=["name", "full_name", "user_image", "username", "last_active"], fields=["name", "full_name", "user_image", "username", "last_active"],
or_filters=or_filters,
page_length=20, page_length=20,
start=start, start=start,
) )

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestBatchStudent(FrappeTestCase): class TestBatchStudent(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestCourseEvaluator(FrappeTestCase): class TestCourseEvaluator(UnitTestCase):
pass pass

View File

@@ -15,20 +15,22 @@
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 1,
"label": "Assessment Type", "label": "Assessment Type",
"options": "DocType" "options": "DocType",
"reqd": 1
}, },
{ {
"fieldname": "assessment_name", "fieldname": "assessment_name",
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"in_list_view": 1, "in_list_view": 1,
"label": "Assessment Name", "label": "Assessment Name",
"options": "assessment_type" "options": "assessment_type",
"reqd": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2023-05-29 14:56:36.602399", "modified": "2024-10-11 19:16:01.630524",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Assessment", "name": "LMS Assessment",

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSAssignment(FrappeTestCase): class TestLMSAssignment(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSBadge(FrappeTestCase): class TestLMSBadge(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSBadgeAssignment(FrappeTestCase): class TestLMSBadgeAssignment(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSClass(FrappeTestCase): class TestLMSBatch(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase import unittest
class TestLMSBatchTimetable(FrappeTestCase): class TestLMSBatchTimetable(unittest.TestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSCategory(FrappeTestCase): class TestLMSCategory(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSCertificateEvaluation(FrappeTestCase): class TestLMSCertificateEvaluation(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSCertificateRequest(FrappeTestCase): class TestLMSCertificateRequest(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSLiveClass(FrappeTestCase): class TestLMSLiveClass(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSPayment(FrappeTestCase): class TestLMSPayment(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSQuestion(FrappeTestCase): class TestLMSQuestion(UnitTestCase):
pass pass

View File

@@ -10,10 +10,11 @@
"title", "title",
"max_attempts", "max_attempts",
"show_answers", "show_answers",
"show_submission_history",
"column_break_gaac", "column_break_gaac",
"total_marks", "total_marks",
"passing_percentage", "passing_percentage",
"show_submission_history", "duration",
"section_break_tzbu", "section_break_tzbu",
"shuffle_questions", "shuffle_questions",
"column_break_clsh", "column_break_clsh",
@@ -128,11 +129,16 @@
{ {
"fieldname": "column_break_clsh", "fieldname": "column_break_clsh",
"fieldtype": "Column Break" "fieldtype": "Column Break"
},
{
"fieldname": "duration",
"fieldtype": "Duration",
"label": "Duration"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2024-08-09 12:21:36.256522", "modified": "2024-10-11 22:39:40.381183",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Quiz", "name": "LMS Quiz",

View File

@@ -100,6 +100,16 @@ def quiz_summary(quiz, results):
score = 0 score = 0
results = results and json.loads(results) results = results and json.loads(results)
is_open_ended = False is_open_ended = False
percentage = 0
quiz_details = frappe.db.get_value(
"LMS Quiz",
quiz,
["total_marks", "passing_percentage", "lesson", "course"],
as_dict=1,
)
score_out_of = quiz_details.total_marks
for result in results: for result in results:
question_details = frappe.db.get_value( question_details = frappe.db.get_value(
@@ -113,17 +123,6 @@ def quiz_summary(quiz, results):
result["question"] = question_details.question_detail result["question"] = question_details.question_detail
result["marks_out_of"] = question_details.marks result["marks_out_of"] = question_details.marks
quiz_details = frappe.get_doc(
"LMS Quiz",
quiz,
["total_marks", "passing_percentage", "lesson", "course"],
as_dict=1,
)
score = 0
percentage = 0
score_out_of = quiz_details.total_marks
if question_details.type != "Open Ended": if question_details.type != "Open Ended":
correct = result["is_correct"][0] correct = result["is_correct"][0]
for point in result["is_correct"]: for point in result["is_correct"]:
@@ -135,24 +134,26 @@ def quiz_summary(quiz, results):
score += marks score += marks
del result["question_name"] del result["question_name"]
percentage = (score / score_out_of) * 100
else: else:
result["is_correct"] = 0 result["is_correct"] = 0
is_open_ended = True is_open_ended = True
percentage = (score / score_out_of) * 100
result["answer"] = re.sub( result["answer"] = re.sub(
r'<img[^>]*src\s*=\s*["\'](?=data:)(.*?)["\']', _save_file, result["answer"] r'<img[^>]*src\s*=\s*["\'](?=data:)(.*?)["\']', _save_file, result["answer"]
) )
submission = frappe.get_doc( submission = frappe.new_doc("LMS Quiz Submission")
# Score and percentage are calculated by the controller function
submission.update(
{ {
"doctype": "LMS Quiz Submission", "doctype": "LMS Quiz Submission",
"quiz": quiz, "quiz": quiz,
"result": results, "result": results,
"score": score, "score": 0,
"score_out_of": score_out_of, "score_out_of": score_out_of,
"member": frappe.session.user, "member": frappe.session.user,
"percentage": percentage, "percentage": 0,
"passing_percentage": quiz_details.passing_percentage, "passing_percentage": quiz_details.passing_percentage,
} }
) )

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSSidebarItem(FrappeTestCase): class TestLMSSidebarItem(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSSource(FrappeTestCase): class TestLMSSource(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSTimetableLegend(FrappeTestCase): class TestLMSTimetableLegend(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestLMSTimetableTemplate(FrappeTestCase): class TestLMSTimetableTemplate(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestPaymentCountry(FrappeTestCase): class TestPaymentCountry(UnitTestCase):
pass pass

View File

@@ -2,8 +2,8 @@
# See license.txt # See license.txt
# import frappe # import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests import UnitTestCase
class TestZoomSettings(FrappeTestCase): class TestZoomSettings(UnitTestCase):
pass pass

View File

@@ -42,6 +42,10 @@ def get_payment_link(doctype, docname, title, amount, total_amount, currency, ad
"redirect_to": redirect_to, "redirect_to": redirect_to,
"payment": payment.name, "payment": payment.name,
} }
if payment_gateway == "Razorpay":
order = controller.create_order(**payment_details)
payment_details.update({"order_id": order.get("id")})
url = controller.get_payment_url(**payment_details) url = controller.get_payment_url(**payment_details)
return url return url

View File

@@ -17,6 +17,7 @@ from frappe.utils import (
add_months, add_months,
cint, cint,
cstr, cstr,
ceil,
flt, flt,
fmt_money, fmt_money,
format_date, format_date,
@@ -948,7 +949,7 @@ def check_multicurrency(amount, currency, country=None, amount_usd=None):
if apply_rounding and amount % 100 != 0: if apply_rounding and amount % 100 != 0:
amount = amount + 100 - amount % 100 amount = amount + 100 - amount % 100
return amount, currency return ceil(amount), currency
def apply_gst(amount, country=None): def apply_gst(amount, country=None):
@@ -1677,7 +1678,7 @@ def update_payment_record(doctype, docname):
if doctype == "LMS Course": if doctype == "LMS Course":
enroll_in_course(data.payment, docname) enroll_in_course(data.payment, docname)
else: else:
enroll_in_batch(data.payment, docname) enroll_in_batch(docname, data.payment)
except Exception as e: except Exception as e:
frappe.log_error(frappe.get_traceback(), _("Enrollment Failed")) frappe.log_error(frappe.get_traceback(), _("Enrollment Failed"))
@@ -1701,25 +1702,33 @@ def enroll_in_course(payment_name, course):
enrollment.save(ignore_permissions=True) enrollment.save(ignore_permissions=True)
def enroll_in_batch(payment_name, batch): @frappe.whitelist()
def enroll_in_batch(batch, payment_name=None):
if not frappe.db.exists( if not frappe.db.exists(
"Batch Student", {"parent": batch, "student": frappe.session.user} "Batch Student", {"parent": batch, "student": frappe.session.user}
): ):
student = frappe.new_doc("Batch Student") student = frappe.new_doc("Batch Student")
current_count = frappe.db.count("Batch Student", {"parent": batch}) current_count = frappe.db.count("Batch Student", {"parent": batch})
payment = frappe.db.get_value(
"LMS Payment", payment_name, ["name", "source"], as_dict=True
)
student.update( student.update(
{ {
"student": frappe.session.user, "student": frappe.session.user,
"payment": payment.name,
"source": payment.source,
"parent": batch, "parent": batch,
"parenttype": "LMS Batch", "parenttype": "LMS Batch",
"parentfield": "students", "parentfield": "students",
"idx": current_count + 1, "idx": current_count + 1,
} }
) )
if payment_name:
payment = frappe.db.get_value(
"LMS Payment", payment_name, ["name", "source"], as_dict=True
)
student.update(
{
"payment": payment.name,
"source": payment.source,
}
)
student.save(ignore_permissions=True) student.save(ignore_permissions=True)

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Frappe LMS VERSION\n" "Project-Id-Version: Frappe LMS VERSION\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2024-10-04 16:04+0000\n" "POT-Creation-Date: 2024-10-18 16:04+0000\n"
"PO-Revision-Date: 2024-10-04 16:04+0000\n" "PO-Revision-Date: 2024-10-18 16:04+0000\n"
"Last-Translator: jannat@frappe.io\n" "Last-Translator: jannat@frappe.io\n"
"Language-Team: jannat@frappe.io\n" "Language-Team: jannat@frappe.io\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -128,8 +128,8 @@ msgstr ""
msgid "Add a course" msgid "Add a course"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:137 #: frontend/src/components/Modals/Question.vue:141
#: frontend/src/pages/QuizForm.vue:147 #: frontend/src/pages/QuizForm.vue:181
msgid "Add a new question" msgid "Add a new question"
msgstr "" msgstr ""
@@ -193,7 +193,7 @@ msgstr ""
msgid "All Submissions" msgid "All Submissions"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz/lms_quiz.py:41 #: lms/lms/doctype/lms_quiz/lms_quiz.py:46
msgid "All questions should have the same marks if the limit is set." msgid "All questions should have the same marks if the limit is set."
msgstr "" msgstr ""
@@ -267,6 +267,10 @@ msgstr ""
msgid "Answer" msgid "Answer"
msgstr "" msgstr ""
#: frontend/src/pages/JobDetail.vue:131
msgid "Applications Received"
msgstr ""
#: frontend/src/pages/JobDetail.vue:42 #: frontend/src/pages/JobDetail.vue:42
msgid "Apply" msgid "Apply"
msgstr "" msgstr ""
@@ -298,6 +302,10 @@ msgstr ""
msgid "Apps" msgid "Apps"
msgstr "" msgstr ""
#: frontend/src/components/CourseOutline.vue:209
msgid "Are you sure you want to delete this lesson?"
msgstr ""
#. Label of the user_category (Check) field in DocType 'LMS Settings' #. Label of the user_category (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json #: lms/lms/doctype/lms_settings/lms_settings.json
msgid "Ask User Category during Signup" msgid "Ask User Category during Signup"
@@ -626,6 +634,7 @@ msgstr ""
#. Label of the category (Link) field in DocType 'LMS Course' #. Label of the category (Link) field in DocType 'LMS Course'
#: frontend/src/pages/BatchForm.vue:179 frontend/src/pages/Batches.vue:16 #: frontend/src/pages/BatchForm.vue:179 frontend/src/pages/Batches.vue:16
#: frontend/src/pages/CourseForm.vue:116 frontend/src/pages/Courses.vue:17 #: frontend/src/pages/CourseForm.vue:116 frontend/src/pages/Courses.vue:17
#: frontend/src/pages/JobDetail.vue:102
#: lms/lms/doctype/lms_batch/lms_batch.json #: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_category/lms_category.json #: lms/lms/doctype/lms_category/lms_category.json
#: lms/lms/doctype/lms_course/lms_course.json #: lms/lms/doctype/lms_course/lms_course.json
@@ -714,7 +723,7 @@ msgstr ""
msgid "Chapters" msgid "Chapters"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:176 lms/templates/quiz/quiz.html:120 #: frontend/src/components/Quiz.vue:201 lms/templates/quiz/quiz.html:120
msgid "Check" msgid "Check"
msgstr "" msgstr ""
@@ -731,11 +740,13 @@ msgid "Checkout Courses"
msgstr "" msgstr ""
#. Option for the 'Type' (Select) field in DocType 'LMS Question' #. Option for the 'Type' (Select) field in DocType 'LMS Question'
#. Option for the 'Type' (Select) field in DocType 'LMS Quiz Question'
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
msgid "Choices" msgid "Choices"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:76 lms/templates/quiz/quiz.html:53 #: frontend/src/components/Quiz.vue:578 lms/templates/quiz/quiz.html:53
msgid "Choose all answers that apply" msgid "Choose all answers that apply"
msgstr "" msgstr ""
@@ -743,7 +754,7 @@ msgstr ""
msgid "Choose an icon" msgid "Choose an icon"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:77 lms/templates/quiz/quiz.html:53 #: frontend/src/components/Quiz.vue:579 lms/templates/quiz/quiz.html:53
msgid "Choose one answer" msgid "Choose one answer"
msgstr "" msgstr ""
@@ -973,7 +984,7 @@ msgstr ""
msgid "Contract" msgid "Contract"
msgstr "" msgstr ""
#: lms/lms/utils.py:422 #: lms/lms/utils.py:423
msgid "Cookie Policy" msgid "Cookie Policy"
msgstr "" msgstr ""
@@ -989,7 +1000,7 @@ msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Exercise Latest #. Option for the 'Status' (Select) field in DocType 'Exercise Latest
#. Submission' #. Submission'
#. Option for the 'Status' (Select) field in DocType 'Exercise Submission' #. Option for the 'Status' (Select) field in DocType 'Exercise Submission'
#: frontend/src/components/Quiz.vue:150 #: frontend/src/components/Quiz.vue:161
#: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json #: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json
#: lms/lms/doctype/exercise_submission/exercise_submission.json #: lms/lms/doctype/exercise_submission/exercise_submission.json
msgid "Correct" msgid "Correct"
@@ -1314,6 +1325,14 @@ msgstr ""
msgid "Degree Type" msgid "Degree Type"
msgstr "" msgstr ""
#: frontend/src/components/CourseOutline.vue:212
msgid "Delete"
msgstr ""
#: frontend/src/components/CourseOutline.vue:208
msgid "Delete Lesson"
msgstr ""
#. Label of the description (Text Editor) field in DocType 'Job Opportunity' #. Label of the description (Text Editor) field in DocType 'Job Opportunity'
#. Label of the description (Small Text) field in DocType 'Certification' #. Label of the description (Small Text) field in DocType 'Certification'
#. Label of the description (Markdown Editor) field in DocType 'Cohort' #. Label of the description (Markdown Editor) field in DocType 'Cohort'
@@ -1351,7 +1370,7 @@ msgstr ""
#: frontend/src/components/Modals/DiscussionModal.vue:22 #: frontend/src/components/Modals/DiscussionModal.vue:22
#: frontend/src/pages/BatchForm.vue:14 frontend/src/pages/CourseForm.vue:20 #: frontend/src/pages/BatchForm.vue:14 frontend/src/pages/CourseForm.vue:20
#: frontend/src/pages/QuizForm.vue:14 #: frontend/src/pages/QuizForm.vue:42
msgid "Details" msgid "Details"
msgstr "" msgstr ""
@@ -1401,13 +1420,19 @@ msgstr ""
#. Label of the duration (Data) field in DocType 'Cohort' #. Label of the duration (Data) field in DocType 'Cohort'
#. Label of the duration (Data) field in DocType 'LMS Batch Timetable' #. Label of the duration (Data) field in DocType 'LMS Batch Timetable'
#. Label of the duration (Int) field in DocType 'LMS Live Class' #. Label of the duration (Int) field in DocType 'LMS Live Class'
#. Label of the duration (Duration) field in DocType 'LMS Quiz'
#: frontend/src/components/Modals/LiveClassModal.vue:58 #: frontend/src/components/Modals/LiveClassModal.vue:58
#: lms/lms/doctype/cohort/cohort.json #: lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json #: lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Duration" msgid "Duration"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:62
msgid "Duration (in minutes)"
msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:54 #: frontend/src/components/Modals/LiveClassModal.vue:54
msgid "Duration of the live class in minutes" msgid "Duration of the live class in minutes"
msgstr "" msgstr ""
@@ -1422,7 +1447,7 @@ msgstr ""
msgid "E-mail" msgid "E-mail"
msgstr "" msgstr ""
#: frontend/src/components/BatchOverlay.vue:92 #: frontend/src/components/BatchOverlay.vue:93
#: frontend/src/components/CourseCardOverlay.vue:86 #: frontend/src/components/CourseCardOverlay.vue:86
#: frontend/src/pages/JobDetail.vue:31 frontend/src/pages/Lesson.vue:70 #: frontend/src/pages/JobDetail.vue:31 frontend/src/pages/Lesson.vue:70
#: frontend/src/pages/Profile.vue:32 #: frontend/src/pages/Profile.vue:32
@@ -1438,7 +1463,7 @@ msgstr ""
msgid "Edit Profile" msgid "Edit Profile"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:146 #: frontend/src/pages/QuizForm.vue:180
msgid "Edit the question" msgid "Edit the question"
msgstr "" msgstr ""
@@ -1537,7 +1562,7 @@ msgstr ""
msgid "End Time" msgid "End Time"
msgstr "" msgstr ""
#: frontend/src/components/BatchOverlay.vue:79 #: frontend/src/components/BatchOverlay.vue:80
msgid "Enroll Now" msgid "Enroll Now"
msgstr "" msgstr ""
@@ -1560,7 +1585,7 @@ msgstr ""
msgid "Enrollment Count" msgid "Enrollment Count"
msgstr "" msgstr ""
#: lms/lms/utils.py:1682 #: lms/lms/utils.py:1683
msgid "Enrollment Failed" msgid "Enrollment Failed"
msgstr "" msgstr ""
@@ -1578,7 +1603,7 @@ msgstr ""
msgid "Enter a URL" msgid "Enter a URL"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:21 #: frontend/src/pages/QuizForm.vue:49
msgid "Enter a title and save the quiz to proceed" msgid "Enter a title and save the quiz to proceed"
msgstr "" msgstr ""
@@ -1586,11 +1611,12 @@ msgstr ""
msgid "Enter the correct answer" msgid "Enter the correct answer"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:242 #: frontend/src/components/Modals/Question.vue:246
#: frontend/src/components/Modals/Question.vue:262 #: frontend/src/components/Modals/Question.vue:266
#: frontend/src/components/Modals/Question.vue:319 #: frontend/src/components/Modals/Question.vue:323
#: frontend/src/pages/Billing.vue:255 frontend/src/pages/QuizForm.vue:314 #: frontend/src/pages/Billing.vue:264 frontend/src/pages/QuizForm.vue:349
#: frontend/src/pages/QuizForm.vue:329 #: frontend/src/pages/QuizForm.vue:364
#: frontend/src/pages/QuizSubmission.vue:117
msgid "Error" msgid "Error"
msgstr "" msgstr ""
@@ -1778,7 +1804,7 @@ msgstr ""
msgid "Flexible Time" msgid "Flexible Time"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:427 #: frontend/src/pages/QuizForm.vue:462
msgid "Form to create and edit quizzes" msgid "Form to create and edit quizzes"
msgstr "" msgstr ""
@@ -1992,7 +2018,7 @@ msgstr ""
msgid "I am unavailable" msgid "I am unavailable"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:348 #: frontend/src/pages/QuizForm.vue:383
msgid "ID" msgid "ID"
msgstr "" msgstr ""
@@ -2006,6 +2032,10 @@ msgstr ""
msgid "If you are not any more interested to mentor the course" msgid "If you are not any more interested to mentor the course"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:20
msgid "If you fail to do so, the quiz will be automatically submitted when the timer ends."
msgstr ""
#: lms/templates/emails/batch_confirmation.html:33 #: lms/templates/emails/batch_confirmation.html:33
msgid "If you have any questions or require assistance, feel free to contact us." msgid "If you have any questions or require assistance, feel free to contact us."
msgstr "" msgstr ""
@@ -2018,6 +2048,10 @@ msgstr ""
msgid "If you set an amount here, then the USD equivalent setting will not get applied." msgid "If you set an amount here, then the USD equivalent setting will not get applied."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz/lms_quiz.py:62
msgid "If you want open ended questions then make sure each question in the quiz is of open ended type."
msgstr ""
#. Option for the 'File Type' (Select) field in DocType 'Course Lesson' #. Option for the 'File Type' (Select) field in DocType 'Course Lesson'
#. Label of the image (Code) field in DocType 'Exercise Latest Submission' #. Label of the image (Code) field in DocType 'Exercise Latest Submission'
#. Label of the image (Code) field in DocType 'Exercise Submission' #. Label of the image (Code) field in DocType 'Exercise Submission'
@@ -2040,6 +2074,10 @@ msgstr ""
msgid "Image search powered by" msgid "Image search powered by"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz/lms_quiz.py:221
msgid "Image: Corrupted Data Stream"
msgstr ""
#. Option for the 'Stage' (Select) field in DocType 'LMS Batch Old' #. Option for the 'Stage' (Select) field in DocType 'LMS Batch Old'
#. Option for the 'Status' (Select) field in DocType 'LMS Certificate #. Option for the 'Status' (Select) field in DocType 'LMS Certificate
#. Evaluation' #. Evaluation'
@@ -2069,7 +2107,7 @@ msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Exercise Latest #. Option for the 'Status' (Select) field in DocType 'Exercise Latest
#. Submission' #. Submission'
#. Option for the 'Status' (Select) field in DocType 'Exercise Submission' #. Option for the 'Status' (Select) field in DocType 'Exercise Submission'
#: frontend/src/components/Quiz.vue:155 #: frontend/src/components/Quiz.vue:166
#: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json #: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json
#: lms/lms/doctype/exercise_submission/exercise_submission.json #: lms/lms/doctype/exercise_submission/exercise_submission.json
msgid "Incorrect" msgid "Incorrect"
@@ -2119,7 +2157,7 @@ msgstr ""
#. Label of the instructor_notes (Markdown Editor) field in DocType 'Course #. Label of the instructor_notes (Markdown Editor) field in DocType 'Course
#. Lesson' #. Lesson'
#: frontend/src/pages/Lesson.vue:129 frontend/src/pages/LessonForm.vue:33 #: frontend/src/pages/Lesson.vue:130 frontend/src/pages/LessonForm.vue:33
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
msgid "Instructor Notes" msgid "Instructor Notes"
msgstr "" msgstr ""
@@ -2559,11 +2597,11 @@ msgid "Letter Grade (e.g. A, B-)"
msgstr "" msgstr ""
#. Label of the limit_questions_to (Int) field in DocType 'LMS Quiz' #. Label of the limit_questions_to (Int) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:73 lms/lms/doctype/lms_quiz/lms_quiz.json #: frontend/src/pages/QuizForm.vue:107 lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Limit Questions To" msgid "Limit Questions To"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz/lms_quiz.py:35 #: lms/lms/doctype/lms_quiz/lms_quiz.py:40
msgid "Limit cannot be greater than or equal to the number of questions in the quiz." msgid "Limit cannot be greater than or equal to the number of questions in the quiz."
msgstr "" msgstr ""
@@ -2619,7 +2657,7 @@ msgstr ""
#. Label of the location (Data) field in DocType 'Job Opportunity' #. Label of the location (Data) field in DocType 'Job Opportunity'
#. Label of the location (Data) field in DocType 'Education Detail' #. Label of the location (Data) field in DocType 'Education Detail'
#. Label of the location (Data) field in DocType 'Work Experience' #. Label of the location (Data) field in DocType 'Work Experience'
#: frontend/src/pages/JobCreation.vue:23 #: frontend/src/pages/JobCreation.vue:23 frontend/src/pages/JobDetail.vue:89
#: lms/job/doctype/job_opportunity/job_opportunity.json #: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/lms/doctype/education_detail/education_detail.json #: lms/lms/doctype/education_detail/education_detail.json
#: lms/lms/doctype/work_experience/work_experience.json #: lms/lms/doctype/work_experience/work_experience.json
@@ -2651,6 +2689,10 @@ msgstr ""
msgid "Make an Announcement" msgid "Make an Announcement"
msgstr "" msgstr ""
#: frontend/src/pages/Billing.vue:128
msgid "Make sure to enter the right billing name as the same will be used in your invoice."
msgstr ""
#: frontend/src/components/BatchOverlay.vue:54 #: frontend/src/components/BatchOverlay.vue:54
msgid "Manage Batch" msgid "Manage Batch"
msgstr "" msgstr ""
@@ -2665,7 +2707,7 @@ msgstr ""
msgid "Manager (Sales/Marketing/Customer)" msgid "Manager (Sales/Marketing/Customer)"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:83 #: frontend/src/components/Quiz.vue:94
msgid "Mark" msgid "Mark"
msgstr "" msgstr ""
@@ -2680,20 +2722,31 @@ msgstr ""
#. Label of the marks (Int) field in DocType 'LMS Quiz Question' #. Label of the marks (Int) field in DocType 'LMS Quiz Question'
#. Label of the marks (Int) field in DocType 'LMS Quiz Result' #. Label of the marks (Int) field in DocType 'LMS Quiz Result'
#: frontend/src/components/Modals/Question.vue:50 #: frontend/src/components/Modals/Question.vue:50
#: frontend/src/components/Modals/Question.vue:92 #: frontend/src/components/Modals/Question.vue:96
#: frontend/src/components/Quiz.vue:83 frontend/src/pages/QuizForm.vue:358 #: frontend/src/components/Quiz.vue:94 frontend/src/pages/QuizForm.vue:393
#: frontend/src/pages/QuizSubmission.vue:52
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json #: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
#: lms/lms/doctype/lms_quiz_result/lms_quiz_result.json #: lms/lms/doctype/lms_quiz_result/lms_quiz_result.json
#: lms/templates/quiz/quiz.html:59 #: lms/templates/quiz/quiz.html:59
msgid "Marks" msgid "Marks"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py:19
msgid "Marks for question number {0} cannot be greater than the marks allotted for that question."
msgstr ""
#. Label of the marks_out_of (Int) field in DocType 'LMS Quiz Result'
#: frontend/src/pages/QuizSubmission.vue:55
#: lms/lms/doctype/lms_quiz_result/lms_quiz_result.json
msgid "Marks out of"
msgstr ""
#. Label of the max_attempts (Int) field in DocType 'LMS Quiz' #. Label of the max_attempts (Int) field in DocType 'LMS Quiz'
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Max Attempts" msgid "Max Attempts"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:28 #: frontend/src/pages/QuizForm.vue:57
msgid "Maximun Attempts" msgid "Maximun Attempts"
msgstr "" msgstr ""
@@ -2726,6 +2779,8 @@ msgstr ""
#. Label of the member (Link) field in DocType 'LMS Mentor Request' #. Label of the member (Link) field in DocType 'LMS Mentor Request'
#. Label of the member (Link) field in DocType 'LMS Payment' #. Label of the member (Link) field in DocType 'LMS Payment'
#. Label of the member (Link) field in DocType 'LMS Quiz Submission' #. Label of the member (Link) field in DocType 'LMS Quiz Submission'
#: frontend/src/pages/QuizSubmission.vue:27
#: frontend/src/pages/QuizSubmissionList.vue:77
#: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json #: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json
#: lms/lms/doctype/exercise_submission/exercise_submission.json #: lms/lms/doctype/exercise_submission/exercise_submission.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
@@ -2913,6 +2968,7 @@ msgid "My calendar"
msgstr "" msgstr ""
#. Option for the 'Event' (Select) field in DocType 'LMS Badge' #. Option for the 'Event' (Select) field in DocType 'LMS Badge'
#: frontend/src/pages/Batches.vue:30 frontend/src/pages/Courses.vue:44
#: lms/lms/doctype/lms_badge/lms_badge.json #: lms/lms/doctype/lms_badge/lms_badge.json
msgid "New" msgid "New"
msgstr "" msgstr ""
@@ -2921,12 +2977,11 @@ msgstr ""
msgid "New Assignment Submission" msgid "New Assignment Submission"
msgstr "" msgstr ""
#: frontend/src/pages/Batches.vue:30 lms/public/js/common_functions.js:255 #: lms/public/js/common_functions.js:255 lms/www/lms.py:86
#: lms/www/lms.py:86
msgid "New Batch" msgid "New Batch"
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:44 lms/www/lms.py:37 #: lms/www/lms.py:37
msgid "New Course" msgid "New Course"
msgstr "" msgstr ""
@@ -2938,11 +2993,11 @@ msgstr ""
msgid "New Job Applicant" msgid "New Job Applicant"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:88 #: frontend/src/pages/QuizForm.vue:122
msgid "New Question" msgid "New Question"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:418 frontend/src/pages/QuizForm.vue:426 #: frontend/src/pages/QuizForm.vue:453 frontend/src/pages/QuizForm.vue:461
#: frontend/src/pages/Quizzes.vue:18 #: frontend/src/pages/Quizzes.vue:18
msgid "New Quiz" msgid "New Quiz"
msgstr "" msgstr ""
@@ -2951,11 +3006,11 @@ msgstr ""
msgid "New Sign Up" msgid "New Sign Up"
msgstr "" msgstr ""
#: lms/lms/utils.py:612 #: lms/lms/utils.py:613
msgid "New comment in batch {0}" msgid "New comment in batch {0}"
msgstr "" msgstr ""
#: lms/lms/utils.py:605 #: lms/lms/utils.py:606
msgid "New reply on the topic {0} in course {1}" msgid "New reply on the topic {0} in course {1}"
msgstr "" msgstr ""
@@ -2964,7 +3019,7 @@ msgstr ""
msgid "New {0}" msgid "New {0}"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:184 frontend/src/pages/Lesson.vue:89 #: frontend/src/components/Quiz.vue:209 frontend/src/pages/Lesson.vue:89
msgid "Next" msgid "Next"
msgstr "" msgstr ""
@@ -3072,6 +3127,7 @@ msgstr ""
#: frontend/src/components/BrandSettings.vue:10 #: frontend/src/components/BrandSettings.vue:10
#: frontend/src/components/PaymentSettings.vue:9 #: frontend/src/components/PaymentSettings.vue:9
#: frontend/src/components/SettingDetails.vue:10 #: frontend/src/components/SettingDetails.vue:10
#: frontend/src/pages/QuizSubmission.vue:9
msgid "Not Saved" msgid "Not Saved"
msgstr "" msgstr ""
@@ -3120,12 +3176,13 @@ msgstr ""
msgid "Only files of type {0} will be accepted." msgid "Only files of type {0} will be accepted."
msgstr "" msgstr ""
#: frontend/src/pages/CourseForm.vue:449 frontend/src/utils/index.js:506 #: frontend/src/pages/CourseForm.vue:449 frontend/src/utils/index.js:509
msgid "Only image file is allowed." msgid "Only image file is allowed."
msgstr "" msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Job Opportunity' #. Option for the 'Status' (Select) field in DocType 'Job Opportunity'
#. Option for the 'Membership' (Select) field in DocType 'LMS Batch Old' #. Option for the 'Membership' (Select) field in DocType 'LMS Batch Old'
#: frontend/src/pages/QuizForm.vue:17
#: lms/job/doctype/job_opportunity/job_opportunity.json #: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/lms/doctype/lms_batch_old/lms_batch_old.json #: lms/lms/doctype/lms_batch_old/lms_batch_old.json
msgid "Open" msgid "Open"
@@ -3139,6 +3196,13 @@ msgstr ""
msgid "Open Course" msgid "Open Course"
msgstr "" msgstr ""
#. Option for the 'Type' (Select) field in DocType 'LMS Question'
#. Option for the 'Type' (Select) field in DocType 'LMS Quiz Question'
#: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
msgid "Open Ended"
msgstr ""
#: lms/lms/widgets/MemberCard.html:16 #: lms/lms/widgets/MemberCard.html:16
msgid "Open Network" msgid "Open Network"
msgstr "" msgstr ""
@@ -3178,6 +3242,10 @@ msgstr ""
msgid "Ordered Item" msgid "Ordered Item"
msgstr "" msgstr ""
#: frontend/src/pages/JobDetail.vue:76
msgid "Organisation"
msgstr ""
#. Label of the organization (Data) field in DocType 'Certification' #. Label of the organization (Data) field in DocType 'Certification'
#: lms/lms/doctype/certification/certification.json #: lms/lms/doctype/certification/certification.json
msgid "Organization" msgid "Organization"
@@ -3254,7 +3322,7 @@ msgstr ""
#. Label of the passing_percentage (Int) field in DocType 'LMS Quiz' #. Label of the passing_percentage (Int) field in DocType 'LMS Quiz'
#. Label of the passing_percentage (Int) field in DocType 'LMS Quiz Submission' #. Label of the passing_percentage (Int) field in DocType 'LMS Quiz Submission'
#: frontend/src/pages/QuizForm.vue:37 frontend/src/pages/Quizzes.vue:109 #: frontend/src/pages/QuizForm.vue:71 frontend/src/pages/Quizzes.vue:109
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
msgid "Passing Percentage" msgid "Passing Percentage"
@@ -3344,6 +3412,8 @@ msgid "Pending"
msgstr "" msgstr ""
#. Label of the percentage (Int) field in DocType 'LMS Quiz Submission' #. Label of the percentage (Int) field in DocType 'LMS Quiz Submission'
#: frontend/src/pages/QuizSubmission.vue:40
#: frontend/src/pages/QuizSubmissionList.vue:93
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
msgid "Percentage" msgid "Percentage"
msgstr "" msgstr ""
@@ -3357,6 +3427,10 @@ msgstr ""
msgid "Phone Number" msgid "Phone Number"
msgstr "" msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:143
msgid "Please Login"
msgstr ""
#: lms/lms/doctype/lms_settings/lms_settings.py:33 #: lms/lms/doctype/lms_settings/lms_settings.py:33
msgid "Please add <a href='{0}'>{1}</a> for <a href='{2}'>{3}</a> to send calendar invites for evaluations." msgid "Please add <a href='{0}'>{1}</a> for <a href='{2}'>{3}</a> to send calendar invites for evaluations."
msgstr "" msgstr ""
@@ -3377,6 +3451,10 @@ msgstr ""
msgid "Please enable Zoom Settings to use this feature." msgid "Please enable Zoom Settings to use this feature."
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:13
msgid "Please ensure that you complete all the questions in {0} minutes."
msgstr ""
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:38 #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:38
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:98 #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:98
msgid "Please enter a valid URL." msgid "Please enter a valid URL."
@@ -3398,7 +3476,7 @@ msgstr ""
msgid "Please install the Payments app to create a paid courses." msgid "Please install the Payments app to create a paid courses."
msgstr "" msgstr ""
#: frontend/src/pages/Billing.vue:247 #: frontend/src/pages/Billing.vue:256
msgid "Please let us know where you heard about us from." msgid "Please let us know where you heard about us from."
msgstr "" msgstr ""
@@ -3432,7 +3510,7 @@ msgstr ""
msgid "Point of Score (e.g. 70)" msgid "Point of Score (e.g. 70)"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:79 #: frontend/src/components/Modals/Question.vue:83
msgid "Possibility" msgid "Possibility"
msgstr "" msgstr ""
@@ -3465,6 +3543,10 @@ msgstr ""
msgid "Postal Code" msgid "Postal Code"
msgstr "" msgstr ""
#: frontend/src/pages/JobDetail.vue:115
msgid "Posted on"
msgstr ""
#. Name of a DocType #. Name of a DocType
#: lms/lms/doctype/preferred_function/preferred_function.json #: lms/lms/doctype/preferred_function/preferred_function.json
msgid "Preferred Function" msgid "Preferred Function"
@@ -3524,7 +3606,7 @@ msgstr ""
msgid "Primary Subgroup" msgid "Primary Subgroup"
msgstr "" msgstr ""
#: lms/lms/utils.py:421 #: lms/lms/utils.py:422
msgid "Privacy Policy" msgid "Privacy Policy"
msgstr "" msgstr ""
@@ -3539,7 +3621,7 @@ msgstr ""
msgid "Private Information includes your Grade and Work Environment Preferences" msgid "Private Information includes your Grade and Work Environment Preferences"
msgstr "" msgstr ""
#: frontend/src/pages/Billing.vue:126 #: frontend/src/pages/Billing.vue:134
msgid "Proceed to Payment" msgid "Proceed to Payment"
msgstr "" msgstr ""
@@ -3603,7 +3685,7 @@ msgstr ""
#. Label of the question (Text) field in DocType 'LMS Quiz Result' #. Label of the question (Text) field in DocType 'LMS Quiz Result'
#: frontend/src/components/Modals/Question.vue:38 #: frontend/src/components/Modals/Question.vue:38
#: frontend/src/pages/AssignmentSubmission.vue:26 #: frontend/src/pages/AssignmentSubmission.vue:26
#: frontend/src/pages/QuizForm.vue:353 #: frontend/src/pages/QuizForm.vue:388
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
#: lms/lms/doctype/lms_assignment/lms_assignment.json #: lms/lms/doctype/lms_assignment/lms_assignment.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
@@ -3628,34 +3710,35 @@ msgstr ""
msgid "Question Name" msgid "Question Name"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:257 #: frontend/src/components/Modals/Question.vue:261
msgid "Question added successfully" msgid "Question added successfully"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:309 #: frontend/src/components/Modals/Question.vue:313
msgid "Question updated successfully" msgid "Question updated successfully"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:68 #: frontend/src/components/Quiz.vue:86
msgid "Question {0}" msgid "Question {0}"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:165 #: frontend/src/components/Quiz.vue:186
msgid "Question {0} of {1}" msgid "Question {0} of {1}"
msgstr "" msgstr ""
#. Label of the questions (Table) field in DocType 'LMS Quiz' #. Label of the questions (Table) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:82 lms/lms/doctype/lms_quiz/lms_quiz.json #: frontend/src/pages/QuizForm.vue:116 lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Questions" msgid "Questions"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:395 #: frontend/src/pages/QuizForm.vue:430
msgid "Questions deleted successfully" msgid "Questions deleted successfully"
msgstr "" msgstr ""
#. Label of the quiz (Link) field in DocType 'LMS Quiz Submission' #. Label of the quiz (Link) field in DocType 'LMS Quiz Submission'
#. Label of a Link in the LMS Workspace #. Label of a Link in the LMS Workspace
#: frontend/src/utils/quiz.js:24 #: frontend/src/pages/QuizSubmission.vue:22
#: frontend/src/pages/QuizSubmissionList.vue:82 frontend/src/utils/quiz.js:24
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
#: lms/lms/workspace/lms/lms.json #: lms/lms/workspace/lms/lms.json
msgid "Quiz" msgid "Quiz"
@@ -3667,15 +3750,26 @@ msgid "Quiz ID"
msgstr "" msgstr ""
#. Label of a Link in the LMS Workspace #. Label of a Link in the LMS Workspace
#: frontend/src/pages/QuizSubmission.vue:46 lms/lms/workspace/lms/lms.json #: frontend/src/pages/QuizPage.vue:47 frontend/src/pages/QuizPage.vue:53
#: lms/lms/workspace/lms/lms.json
msgid "Quiz Submission" msgid "Quiz Submission"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:198 #: frontend/src/pages/QuizSubmission.vue:98
#: frontend/src/pages/QuizSubmissionList.vue:102
msgid "Quiz Submissions"
msgstr ""
#: frontend/src/components/Quiz.vue:223
msgid "Quiz Summary" msgid "Quiz Summary"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:307 #. Label of the quiz_title (Data) field in DocType 'LMS Quiz Submission'
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
msgid "Quiz Title"
msgstr ""
#: frontend/src/pages/QuizForm.vue:342
msgid "Quiz created successfully" msgid "Quiz created successfully"
msgstr "" msgstr ""
@@ -3683,7 +3777,7 @@ msgstr ""
msgid "Quiz is not available to Guest users. Please login to continue." msgid "Quiz is not available to Guest users. Please login to continue."
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:326 #: frontend/src/pages/QuizForm.vue:361
msgid "Quiz updated successfully" msgid "Quiz updated successfully"
msgstr "" msgstr ""
@@ -3692,7 +3786,7 @@ msgstr ""
msgid "Quiz will appear at the bottom of the lesson." msgid "Quiz will appear at the bottom of the lesson."
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:406 frontend/src/pages/Quizzes.vue:120 #: frontend/src/pages/QuizForm.vue:441 frontend/src/pages/Quizzes.vue:120
#: frontend/src/pages/Quizzes.vue:130 #: frontend/src/pages/Quizzes.vue:130
msgid "Quizzes" msgid "Quizzes"
msgstr "" msgstr ""
@@ -3859,7 +3953,7 @@ msgstr ""
msgid "Row #{0} Start time cannot be outside the batch duration." msgid "Row #{0} Start time cannot be outside the batch duration."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_quiz/lms_quiz.py:29 #: lms/lms/doctype/lms_quiz/lms_quiz.py:34
msgid "Rows {0} have the duplicate questions." msgid "Rows {0} have the duplicate questions."
msgstr "" msgstr ""
@@ -3874,13 +3968,15 @@ msgstr ""
msgid "Saturday" msgid "Saturday"
msgstr "" msgstr ""
#: frontend/src/components/Controls/CodeEditor.vue:25
#: frontend/src/components/Modals/Event.vue:101 #: frontend/src/components/Modals/Event.vue:101
#: frontend/src/components/Modals/Event.vue:129 #: frontend/src/components/Modals/Event.vue:129
#: frontend/src/components/QuizPlugin.vue:23 #: frontend/src/components/QuizPlugin.vue:23
#: frontend/src/pages/AssignmentSubmission.vue:7 #: frontend/src/pages/AssignmentSubmission.vue:7
#: frontend/src/pages/BatchForm.vue:8 frontend/src/pages/CourseForm.vue:12 #: frontend/src/pages/BatchForm.vue:8 frontend/src/pages/CourseForm.vue:12
#: frontend/src/pages/JobCreation.vue:8 frontend/src/pages/LessonForm.vue:10 #: frontend/src/pages/JobCreation.vue:8 frontend/src/pages/LessonForm.vue:10
#: frontend/src/pages/QuizForm.vue:7 lms/public/js/common_functions.js:405 #: frontend/src/pages/QuizForm.vue:34 frontend/src/pages/QuizSubmission.vue:14
#: lms/public/js/common_functions.js:405
msgid "Save" msgid "Save"
msgstr "" msgstr ""
@@ -3905,6 +4001,8 @@ msgid "Scope"
msgstr "" msgstr ""
#. Label of the score (Int) field in DocType 'LMS Quiz Submission' #. Label of the score (Int) field in DocType 'LMS Quiz Submission'
#: frontend/src/pages/QuizSubmission.vue:35
#: frontend/src/pages/QuizSubmissionList.vue:87
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
#: lms/templates/quiz/quiz.html:148 #: lms/templates/quiz/quiz.html:148
msgid "Score" msgid "Score"
@@ -3940,7 +4038,7 @@ msgstr ""
msgid "Seats Left" msgid "Seats Left"
msgstr "" msgstr ""
#: frontend/src/components/Modals/Question.vue:87 #: frontend/src/components/Modals/Question.vue:91
msgid "Select a question" msgid "Select a question"
msgstr "" msgstr ""
@@ -3969,7 +4067,7 @@ msgstr ""
#: frontend/src/components/Modals/Settings.vue:7 #: frontend/src/components/Modals/Settings.vue:7
#: frontend/src/pages/BatchForm.vue:143 frontend/src/pages/CourseForm.vue:128 #: frontend/src/pages/BatchForm.vue:143 frontend/src/pages/CourseForm.vue:128
#: frontend/src/pages/ProfileRoles.vue:4 frontend/src/pages/QuizForm.vue:44 #: frontend/src/pages/ProfileRoles.vue:4 frontend/src/pages/QuizForm.vue:78
msgid "Settings" msgid "Settings"
msgstr "" msgstr ""
@@ -3989,12 +4087,12 @@ msgid "Show Answer"
msgstr "" msgstr ""
#. Label of the show_answers (Check) field in DocType 'LMS Quiz' #. Label of the show_answers (Check) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:50 lms/lms/doctype/lms_quiz/lms_quiz.json #: frontend/src/pages/QuizForm.vue:84 lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Show Answers" msgid "Show Answers"
msgstr "" msgstr ""
#. Label of the show_submission_history (Check) field in DocType 'LMS Quiz' #. Label of the show_submission_history (Check) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:55 lms/lms/doctype/lms_quiz/lms_quiz.json #: frontend/src/pages/QuizForm.vue:89 lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Show Submission History" msgid "Show Submission History"
msgstr "" msgstr ""
@@ -4019,11 +4117,11 @@ msgid "Show live class"
msgstr "" msgstr ""
#. Label of the shuffle_questions (Check) field in DocType 'LMS Quiz' #. Label of the shuffle_questions (Check) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:68 lms/lms/doctype/lms_quiz/lms_quiz.json #: frontend/src/pages/QuizForm.vue:102 lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Shuffle Questions" msgid "Shuffle Questions"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:62 #: frontend/src/pages/QuizForm.vue:96
msgid "Shuffle Settings" msgid "Shuffle Settings"
msgstr "" msgstr ""
@@ -4135,7 +4233,7 @@ msgstr ""
msgid "Stage" msgid "Stage"
msgstr "" msgstr ""
#: frontend/src/components/LiveClass.vue:45 frontend/src/components/Quiz.vue:47 #: frontend/src/components/LiveClass.vue:45 frontend/src/components/Quiz.vue:65
#: lms/templates/quiz/quiz.html:39 #: lms/templates/quiz/quiz.html:39
msgid "Start" msgid "Start"
msgstr "" msgstr ""
@@ -4306,11 +4404,15 @@ msgstr ""
msgid "Submission" msgid "Submission"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:30
msgid "Submission List"
msgstr ""
#: frontend/src/components/Modals/AssessmentModal.vue:9 #: frontend/src/components/Modals/AssessmentModal.vue:9
#: frontend/src/components/Modals/BatchCourseModal.vue:9 #: frontend/src/components/Modals/BatchCourseModal.vue:9
#: frontend/src/components/Modals/EvaluationModal.vue:9 #: frontend/src/components/Modals/EvaluationModal.vue:9
#: frontend/src/components/Modals/Question.vue:331 #: frontend/src/components/Modals/Question.vue:335
#: frontend/src/components/Quiz.vue:189 lms/templates/assignment.html:9 #: frontend/src/components/Quiz.vue:214 lms/templates/assignment.html:9
#: lms/templates/livecode/extension_footer.html:25 #: lms/templates/livecode/extension_footer.html:25
#: lms/templates/quiz/quiz.html:128 lms/templates/reviews.html:163 #: lms/templates/quiz/quiz.html:128 lms/templates/reviews.html:163
#: lms/www/new-sign-up.html:32 #: lms/www/new-sign-up.html:32
@@ -4327,14 +4429,16 @@ msgid "Submitted {0}"
msgstr "" msgstr ""
#: frontend/src/components/BatchCourses.vue:150 #: frontend/src/components/BatchCourses.vue:150
#: frontend/src/components/BatchOverlay.vue:135
#: frontend/src/components/BatchStudents.vue:157 #: frontend/src/components/BatchStudents.vue:157
#: frontend/src/components/CourseCardOverlay.vue:163
#: frontend/src/components/Modals/AssessmentModal.vue:73 #: frontend/src/components/Modals/AssessmentModal.vue:73
#: frontend/src/components/Modals/Event.vue:255 #: frontend/src/components/Modals/Event.vue:255
#: frontend/src/components/Modals/Event.vue:310 #: frontend/src/components/Modals/Event.vue:310
#: frontend/src/components/Modals/Question.vue:257 #: frontend/src/components/Modals/Question.vue:261
#: frontend/src/components/Modals/Question.vue:308 #: frontend/src/components/Modals/Question.vue:312
#: frontend/src/pages/QuizForm.vue:307 frontend/src/pages/QuizForm.vue:326 #: frontend/src/pages/QuizForm.vue:342 frontend/src/pages/QuizForm.vue:361
#: frontend/src/pages/QuizForm.vue:395 #: frontend/src/pages/QuizForm.vue:430
msgid "Success" msgid "Success"
msgstr "" msgstr ""
@@ -4429,7 +4533,7 @@ msgstr ""
msgid "Temporarily Disabled" msgid "Temporarily Disabled"
msgstr "" msgstr ""
#: lms/lms/utils.py:420 #: lms/lms/utils.py:421
msgid "Terms of Use" msgid "Terms of Use"
msgstr "" msgstr ""
@@ -4469,7 +4573,7 @@ msgstr ""
msgid "The evaluator of this course is unavailable from {0} to {1}. Please select a date after {1}" msgid "The evaluator of this course is unavailable from {0} to {1}. Please select a date after {1}"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:27 lms/templates/quiz/quiz.html:24 #: lms/templates/quiz/quiz.html:24
msgid "The quiz has a time limit. For each question you will be given {0} seconds." msgid "The quiz has a time limit. For each question you will be given {0} seconds."
msgstr "" msgstr ""
@@ -4516,7 +4620,7 @@ msgstr ""
msgid "This course has:" msgid "This course has:"
msgstr "" msgstr ""
#: lms/lms/utils.py:1562 #: lms/lms/utils.py:1563
msgid "This course is free." msgid "This course is free."
msgstr "" msgstr ""
@@ -4532,7 +4636,7 @@ msgstr ""
msgid "This lesson is not available for preview. Please join the course to access it." msgid "This lesson is not available for preview. Please join the course to access it."
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:6 lms/templates/quiz/quiz.html:6 #: frontend/src/components/Quiz.vue:8 lms/templates/quiz/quiz.html:6
msgid "This quiz consists of {0} questions." msgid "This quiz consists of {0} questions."
msgstr "" msgstr ""
@@ -4546,6 +4650,7 @@ msgstr ""
#. Label of the time (Time) field in DocType 'LMS Live Class' #. Label of the time (Time) field in DocType 'LMS Live Class'
#: frontend/src/components/Modals/Event.vue:48 #: frontend/src/components/Modals/Event.vue:48
#: frontend/src/components/Modals/LiveClassModal.vue:36 #: frontend/src/components/Modals/LiveClassModal.vue:36
#: frontend/src/components/Quiz.vue:44
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
msgid "Time" msgid "Time"
msgstr "" msgstr ""
@@ -4614,7 +4719,7 @@ msgstr ""
#: frontend/src/components/Modals/DiscussionModal.vue:18 #: frontend/src/components/Modals/DiscussionModal.vue:18
#: frontend/src/components/Modals/LiveClassModal.vue:23 #: frontend/src/components/Modals/LiveClassModal.vue:23
#: frontend/src/pages/BatchForm.vue:18 frontend/src/pages/CourseForm.vue:24 #: frontend/src/pages/BatchForm.vue:18 frontend/src/pages/CourseForm.vue:24
#: frontend/src/pages/JobCreation.vue:20 frontend/src/pages/QuizForm.vue:20 #: frontend/src/pages/JobCreation.vue:20 frontend/src/pages/QuizForm.vue:48
#: frontend/src/pages/Quizzes.vue:98 lms/lms/doctype/cohort/cohort.json #: frontend/src/pages/Quizzes.vue:98 lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/cohort_subgroup/cohort_subgroup.json #: lms/lms/doctype/cohort_subgroup/cohort_subgroup.json
#: lms/lms/doctype/cohort_web_page/cohort_web_page.json #: lms/lms/doctype/cohort_web_page/cohort_web_page.json
@@ -4650,7 +4755,7 @@ msgstr ""
msgid "To Date is mandatory in Work Experience." msgid "To Date is mandatory in Work Experience."
msgstr "" msgstr ""
#: lms/lms/utils.py:1573 #: lms/lms/utils.py:1574
msgid "To join this batch, please contact the Administrator." msgid "To join this batch, please contact the Administrator."
msgstr "" msgstr ""
@@ -4667,7 +4772,7 @@ msgid "Total"
msgstr "" msgstr ""
#. Label of the total_marks (Int) field in DocType 'LMS Quiz' #. Label of the total_marks (Int) field in DocType 'LMS Quiz'
#: frontend/src/pages/QuizForm.vue:32 frontend/src/pages/Quizzes.vue:103 #: frontend/src/pages/QuizForm.vue:66 frontend/src/pages/Quizzes.vue:103
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Total Marks" msgid "Total Marks"
msgstr "" msgstr ""
@@ -4682,7 +4787,7 @@ msgstr ""
msgid "Travel" msgid "Travel"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:220 lms/templates/quiz/quiz.html:131 #: frontend/src/components/Quiz.vue:252 lms/templates/quiz/quiz.html:131
msgid "Try Again" msgid "Try Again"
msgstr "" msgstr ""
@@ -4701,6 +4806,7 @@ msgstr ""
#. Label of the type (Select) field in DocType 'LMS Assignment' #. Label of the type (Select) field in DocType 'LMS Assignment'
#. Label of the type (Select) field in DocType 'LMS Assignment Submission' #. Label of the type (Select) field in DocType 'LMS Assignment Submission'
#. Label of the type (Select) field in DocType 'LMS Question' #. Label of the type (Select) field in DocType 'LMS Question'
#. Label of the type (Select) field in DocType 'LMS Quiz Question'
#: frontend/src/components/Modals/AssessmentModal.vue:22 #: frontend/src/components/Modals/AssessmentModal.vue:22
#: frontend/src/components/Modals/Question.vue:54 #: frontend/src/components/Modals/Question.vue:54
#: frontend/src/pages/JobCreation.vue:28 #: frontend/src/pages/JobCreation.vue:28
@@ -4708,11 +4814,12 @@ msgstr ""
#: lms/lms/doctype/lms_assignment/lms_assignment.json #: lms/lms/doctype/lms_assignment/lms_assignment.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
#: lms/templates/assessments.html:14 #: lms/templates/assessments.html:14
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:71 #: frontend/src/components/Quiz.vue:580
msgid "Type your answer" msgid "Type your answer"
msgstr "" msgstr ""
@@ -4779,7 +4886,7 @@ msgstr ""
msgid "Upcoming Evaluations" msgid "Upcoming Evaluations"
msgstr "" msgstr ""
#: frontend/src/components/BrandSettings.vue:22 #: frontend/src/components/BrandSettings.vue:23
#: frontend/src/components/PaymentSettings.vue:27 #: frontend/src/components/PaymentSettings.vue:27
#: frontend/src/components/SettingDetails.vue:23 #: frontend/src/components/SettingDetails.vue:23
msgid "Update" msgid "Update"
@@ -4817,7 +4924,9 @@ msgid "User Field"
msgstr "" msgstr ""
#. Option for the 'Type' (Select) field in DocType 'LMS Question' #. Option for the 'Type' (Select) field in DocType 'LMS Question'
#. Option for the 'Type' (Select) field in DocType 'LMS Quiz Question'
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
msgid "User Input" msgid "User Input"
msgstr "" msgstr ""
@@ -4987,7 +5096,7 @@ msgstr ""
msgid "You can attempt this quiz only {0} {1}" msgid "You can attempt this quiz only {0} {1}"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:18 #: frontend/src/components/Quiz.vue:34
msgid "You can attempt this quiz {0}." msgid "You can attempt this quiz {0}."
msgstr "" msgstr ""
@@ -5015,7 +5124,7 @@ msgstr ""
msgid "You got" msgid "You got"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:202 #: frontend/src/components/Quiz.vue:234
#, python-format #, python-format
msgid "You got {0}% correct answers with a score of {1} out of {2}" msgid "You got {0}% correct answers with a score of {1} out of {2}"
msgstr "" msgstr ""
@@ -5024,7 +5133,7 @@ msgstr ""
msgid "You have already applied for this job." msgid "You have already applied for this job."
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:52 lms/templates/quiz/quiz.html:43 #: frontend/src/components/Quiz.vue:70 lms/templates/quiz/quiz.html:43
msgid "You have already exceeded the maximum number of attempts allowed for this quiz." msgid "You have already exceeded the maximum number of attempts allowed for this quiz."
msgstr "" msgstr ""
@@ -5032,6 +5141,14 @@ msgstr ""
msgid "You have already reviewed this course" msgid "You have already reviewed this course"
msgstr "" msgstr ""
#: frontend/src/components/BatchOverlay.vue:136
msgid "You have been enrolled in this batch"
msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:164
msgid "You have been enrolled in this course"
msgstr ""
#: lms/lms/widgets/NoPreviewModal.html:12 lms/public/js/common_functions.js:126 #: lms/lms/widgets/NoPreviewModal.html:12 lms/public/js/common_functions.js:126
msgid "You have opted to be notified for this course. You will receive an email when the course becomes available." msgid "You have opted to be notified for this course. You will receive an email when the course becomes available."
msgstr "" msgstr ""
@@ -5040,7 +5157,11 @@ msgstr ""
msgid "You haven't enrolled for any courses" msgid "You haven't enrolled for any courses"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:11 lms/templates/quiz/quiz.html:11 #: frontend/src/components/CourseCardOverlay.vue:144
msgid "You need to login first to enroll for this course"
msgstr ""
#: frontend/src/components/Quiz.vue:27 lms/templates/quiz/quiz.html:11
#, python-format #, python-format
msgid "You will have to get {0}% correct answers in order to pass the quiz." msgid "You will have to get {0}% correct answers in order to pass the quiz."
msgstr "" msgstr ""
@@ -5093,20 +5214,20 @@ msgstr ""
msgid "Your score is" msgid "Your score is"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:227
msgid "Your submission has been successfully saved. The instructor will review and grade it shortly, and you'll be notified of your final result."
msgstr ""
#. Name of a DocType #. Name of a DocType
#: lms/lms/doctype/zoom_settings/zoom_settings.json #: lms/lms/doctype/zoom_settings/zoom_settings.json
msgid "Zoom Settings" msgid "Zoom Settings"
msgstr "" msgstr ""
#: frontend/src/pages/JobDetail.vue:93
msgid "applications received"
msgstr ""
#: lms/templates/emails/mentor_request_creation_email.html:5 #: lms/templates/emails/mentor_request_creation_email.html:5
msgid "cancel your application" msgid "cancel your application"
msgstr "" msgstr ""
#: frontend/src/pages/Lesson.vue:174 #: frontend/src/pages/Lesson.vue:175
msgid "completed" msgid "completed"
msgstr "" msgstr ""
@@ -5138,7 +5259,7 @@ msgstr ""
msgid "posted by" msgid "posted by"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:354 #: frontend/src/pages/QuizForm.vue:389
msgid "question_detail" msgid "question_detail"
msgstr "" msgstr ""
@@ -5154,7 +5275,7 @@ msgstr ""
msgid "you can" msgid "you can"
msgstr "" msgstr ""
#: lms/lms/api.py:725 lms/lms/api.py:733 #: lms/lms/api.py:731 lms/lms/api.py:739
msgid "{0} Settings not found" msgid "{0} Settings not found"
msgstr "" msgstr ""
@@ -5190,7 +5311,7 @@ msgstr ""
msgid "{0} is your evaluator" msgid "{0} is your evaluator"
msgstr "" msgstr ""
#: lms/lms/utils.py:689 #: lms/lms/utils.py:690
msgid "{0} mentioned you in a comment" msgid "{0} mentioned you in a comment"
msgstr "" msgstr ""
@@ -5198,11 +5319,11 @@ msgstr ""
msgid "{0} mentioned you in a comment in your batch." msgid "{0} mentioned you in a comment in your batch."
msgstr "" msgstr ""
#: lms/lms/utils.py:642 lms/lms/utils.py:648 #: lms/lms/utils.py:643 lms/lms/utils.py:649
msgid "{0} mentioned you in a comment in {1}" msgid "{0} mentioned you in a comment in {1}"
msgstr "" msgstr ""
#: lms/lms/utils.py:460 #: lms/lms/utils.py:461
msgid "{0}k" msgid "{0}k"
msgstr "" msgstr ""