Merge pull request #1882 from frappe/develop

chore: merge 'develop' into 'main'
This commit is contained in:
Jannat Patel
2025-12-05 12:16:51 +05:30
committed by GitHub
37 changed files with 3269 additions and 1541 deletions
+44 -41
View File
@@ -10,52 +10,55 @@
"copy-html-entry": "cp ../lms/public/frontend/index.html ../lms/www/lms.html"
},
"dependencies": {
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.4",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-python": "^6.2.1",
"@editorjs/checklist": "^1.6.0",
"@editorjs/code": "^2.9.0",
"@editorjs/editorjs": "^2.29.0",
"@codemirror/lang-html": "6.4.9",
"@codemirror/lang-javascript": "6.2.4",
"@codemirror/lang-json": "6.0.1",
"@codemirror/lang-python": "6.2.1",
"@editorjs/checklist": "1.6.0",
"@editorjs/code": "2.9.0",
"@editorjs/editorjs": "2.29.0",
"@editorjs/embed": "2.7.0",
"@editorjs/header": "^2.8.1",
"@editorjs/inline-code": "^1.5.0",
"@editorjs/nested-list": "^1.4.2",
"@editorjs/paragraph": "^2.11.3",
"@editorjs/simple-image": "^1.6.0",
"@editorjs/table": "^2.4.2",
"@vueuse/core": "^10.4.1",
"@vueuse/router": "^12.7.0",
"ace-builds": "^1.36.2",
"apexcharts": "^4.3.0",
"chart.js": "^4.4.1",
"codemirror": "^6.0.1",
"dayjs": "^1.11.6",
"dompurify": "^3.2.6",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.227",
"highlight.js": "^11.11.1",
"lucide-vue-next": "^0.383.0",
"markdown-it": "^14.0.0",
"pinia": "^2.0.33",
"plyr": "^3.7.8",
"socket.io-client": "^4.7.2",
"@editorjs/header": "2.8.1",
"@editorjs/inline-code": "1.5.0",
"@editorjs/nested-list": "1.4.2",
"@editorjs/paragraph": "2.11.3",
"@editorjs/simple-image": "1.6.0",
"@editorjs/table": "2.4.2",
"@vueuse/core": "10.4.1",
"@vueuse/router": "12.7.0",
"ace-builds": "1.36.2",
"apexcharts": "4.3.0",
"chart.js": "4.4.1",
"codemirror": "6.0.1",
"dayjs": "1.11.10",
"dompurify": "3.2.6",
"feather-icons": "4.28.0",
"frappe-ui": "0.1.227",
"highlight.js": "11.11.1",
"lucide-vue-next": "0.383.0",
"markdown-it": "14.0.0",
"pinia": "2.0.33",
"plyr": "3.7.8",
"socket.io-client": "4.7.2",
"tailwindcss": "3.4.15",
"thememirror": "^2.0.1",
"typescript": "^5.7.2",
"vue": "^3.4.23",
"vue-chartjs": "^5.3.0",
"vue-codemirror": "^6.1.1",
"vue-draggable-next": "^2.2.1",
"vue-router": "^4.0.12",
"vue3-apexcharts": "^1.8.0",
"thememirror": "2.0.1",
"typescript": "5.7.2",
"vue": "^3.5.0",
"vue-chartjs": "5.3.0",
"vue-codemirror": "6.1.1",
"vue-draggable-next": "2.2.1",
"vue-router": "4.2.2",
"vue3-apexcharts": "1.8.0",
"vuedraggable": "4.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.3",
"autoprefixer": "^10.4.2",
"postcss": "^8.4.5",
"vite": "^5.0.11",
"@vitejs/plugin-vue": "5.0.3",
"autoprefixer": "10.4.2",
"postcss": "8.4.5",
"vite": "5.0.11",
"vite-plugin-pwa": "0.15.0"
},
"resolutions": {
"@iconify/utils": "2.1.7"
}
}
+3
View File
@@ -179,6 +179,9 @@
"
:editable="true"
:fixedMenu="true"
:uploadArgs="{
private: true,
}"
editorClass="prose-sm max-w-none border-b border-x bg-surface-gray-2 rounded-b-md py-1 px-2 min-h-[7rem]"
/>
</div>
@@ -20,7 +20,7 @@
class="w-4 h-4 text-ink-gray-7 stroke-1.5"
:is="icons.Folder"
/>
<span v-if="selectedIcon">
<span v-if="selectedIcon" class="text-ink-gray-7">
{{ selectedIcon }}
</span>
<span v-else class="text-ink-gray-5">
@@ -66,12 +66,18 @@
</Dialog>
</template>
<script setup>
import { Dialog, createResource, Select, FormControl, toast } from 'frappe-ui'
import {
dayjs,
Dialog,
createResource,
Select,
FormControl,
toast,
} from 'frappe-ui'
import { reactive, watch, inject } from 'vue'
import { formatTime } from '@/utils/'
const user = inject('$user')
const dayjs = inject('$dayjs')
const show = defineModel()
const evaluations = defineModel('reloadEvals')
+11 -10
View File
@@ -1,7 +1,6 @@
<template>
<Dialog
v-model="show"
class="text-base"
:options="{
title: __('Add web page to sidebar'),
size: 'lg',
@@ -17,15 +16,17 @@
}"
>
<template #body-content>
<Link
v-model="page.webpage"
doctype="Web Page"
:label="__('Web Page')"
:filters="{
published: 1,
}"
/>
<IconPicker v-model="page.icon" :label="__('Icon')" class="mt-4" />
<div class="text-base">
<Link
v-model="page.webpage"
doctype="Web Page"
:label="__('Web Page')"
:filters="{
published: 1,
}"
/>
<IconPicker v-model="page.icon" :label="__('Icon')" class="mt-4" />
</div>
</template>
</Dialog>
</template>
+3
View File
@@ -7,6 +7,9 @@
:placeholder="__('Make notes for quick revision. Press / for menu.')"
@change="(val: string) => updateNoteText(val)"
:editable="true"
:uploadArgs="{
private: true,
}"
editorClass="prose prose-sm min-h-[200px] max-w-none"
/>
</template>
+8 -16
View File
@@ -189,7 +189,7 @@ import { usersStore } from '@/stores/user'
import { sessionStore } from '@/stores/session'
import { useSidebar } from '@/stores/sidebar'
import { useSettings } from '@/stores/settings'
import { Button, call, createResource, Tooltip } from 'frappe-ui'
import { Button, call, createResource, Tooltip, toast } from 'frappe-ui'
import PageModal from '@/components/Modals/PageModal.vue'
import { capture } from '@/telemetry'
import LMSLogo from '@/components/Icons/LMSLogo.vue'
@@ -437,21 +437,13 @@ const openPageModal = (link) => {
}
const deletePage = (link) => {
createResource({
url: 'lms.lms.api.delete_sidebar_item',
makeParams(values) {
return {
webpage: link.web_page,
}
},
}).submit(
{},
{
onSuccess() {
sidebarSettings.reload()
},
}
)
call('lms.lms.api.delete_documents', {
doctype: 'LMS Sidebar Item',
documents: [link.name],
}).then(() => {
sidebarSettings.reload()
toast.success(__('Page deleted successfully'))
})
}
const toggleSidebar = () => {
+1 -1
View File
@@ -675,7 +675,7 @@ export const getMetaInfo = (type, route, meta) => {
export const updateMetaInfo = (type, route, meta) => {
call('lms.lms.api.update_meta_info', {
type: type,
meta_type: type,
route: route,
meta_tags: [
{ key: 'description', value: meta.description },
+520 -308
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
__version__ = "2.40.0"
__version__ = "2.41.0"
+4 -1
View File
@@ -101,7 +101,10 @@ doc_events = {
"lms.lms.doctype.lms_badge.lms_badge.process_badges",
]
},
"Discussion Reply": {"after_insert": "lms.lms.utils.handle_notifications"},
"Discussion Reply": {
"after_insert": "lms.lms.utils.handle_notifications",
"validate": "lms.lms.utils.validate_discussion_reply",
},
"Notification Log": {"on_change": "lms.lms.utils.publish_notifications"},
"User": {
"validate": "lms.lms.user.validate_username_duplicates",
+60 -17
View File
@@ -520,7 +520,7 @@ def get_sidebar_settings():
web_pages = frappe.get_all(
"LMS Sidebar Item",
{"parenttype": "LMS Settings", "parentfield": "sidebar_items"},
["web_page", "route", "title as label", "icon"],
["web_page", "route", "title as label", "icon", "name"],
)
for page in web_pages:
page.to = page.route
@@ -1014,6 +1014,7 @@ def give_discussions_permission():
"write": 1,
"create": 1,
"delete": 1,
"if_owner": 0 if role == "Moderator" else 1,
}
).save(ignore_permissions=True)
@@ -1303,7 +1304,24 @@ def get_notifications(filters):
@frappe.whitelist(allow_guest=True)
def get_lms_setting(field):
def get_lms_setting(field=None):
if not field:
frappe.throw(_("Field name is required"))
frappe.log_error("Field name is missing when accessing LMS Settings {0} {1} {2}").format(
frappe.local.request_ip, frappe.get_request_header("Referer"), frappe.get_request_header("Origin")
)
allowed_fields = [
"allow_guest_access",
"prevent_skipping_videos",
"contact_us_email",
"contact_us_url",
"livecode_url",
]
if field not in allowed_fields:
frappe.throw(_("You are not allowed to access this field"))
return frappe.get_cached_value("LMS Settings", None, field)
@@ -1451,11 +1469,11 @@ def get_meta_info(type, route):
@frappe.whitelist()
def update_meta_info(type, route, meta_tags):
parent_name = f"{type}/{route}"
if not isinstance(meta_tags, list):
frappe.throw(_("Meta tags should be a list."))
def update_meta_info(meta_type, route, meta_tags):
validate_meta_data_permissions()
validate_meta_tags(meta_tags)
parent_name = f"{meta_type}/{route}"
for tag in meta_tags:
existing_tag = frappe.db.exists(
"Website Meta Tag",
@@ -1482,18 +1500,43 @@ def update_meta_info(type, route, meta_tags):
parent_exists = frappe.db.exists("Website Route Meta", parent_name)
if not parent_exists:
route_meta = frappe.new_doc("Website Route Meta")
route_meta.update(
{
"__newname": parent_name,
}
)
route_meta.append("meta_tags", tag_properties)
route_meta.insert()
create_meta(parent_name, tag_properties)
else:
new_tag = frappe.new_doc("Website Meta Tag")
new_tag.update(tag_properties)
new_tag.insert()
create_meta_tag(tag_properties)
def validate_meta_tags(meta_tags):
if not isinstance(meta_tags, list):
frappe.throw(_("Meta tags should be a list."))
def create_meta(parent_name, tag_properties):
route_meta = frappe.new_doc("Website Route Meta")
route_meta.update(
{
"__newname": parent_name,
}
)
route_meta.append("meta_tags", tag_properties)
route_meta.insert()
def create_meta_tag(tag_properties):
new_tag = frappe.new_doc("Website Meta Tag")
new_tag.update(tag_properties)
new_tag.insert()
def validate_meta_data_permissions(meta_type):
roles = frappe.get_roles()
if meta_type == "courses":
if not ("Course Creator" in roles or "Moderator" in roles):
frappe.throw(_("You do not have permission to update meta tags."))
elif meta_type == "batches":
if not ("Batch Evaluator" in roles or "Moderator" in roles):
frappe.throw(_("You do not have permission to update meta tags."))
@frappe.whitelist()
@@ -4,7 +4,7 @@
import frappe
from frappe.model.document import Document
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role
from lms.lms.utils import has_course_instructor_role, has_moderator_role
class LMSAssignment(Document):
@@ -13,7 +13,7 @@ class LMSAssignment(Document):
@frappe.whitelist()
def save_assignment(assignment, title, type, question):
if not has_course_moderator_role() or not has_course_instructor_role():
if not has_moderator_role() or not has_course_instructor_role():
return
if assignment:
+1 -3
View File
@@ -30,9 +30,7 @@ frappe.ui.form.on("LMS Badge", {
const user_fields = fields
.filter(
(df) =>
(df.fieldtype === "Link" && df.options === "User") ||
df.fieldtype === "Data"
(df) => df.fieldtype === "Link" && df.options === "User"
)
.map(map_for_options)
.concat([
@@ -84,7 +84,7 @@
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-11-10 11:39:42.233779",
"modified": "2025-12-04 17:06:26.090276",
"modified_by": "sayali@frappe.io",
"module": "LMS",
"name": "LMS Badge Assignment",
@@ -116,25 +116,13 @@
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "LMS Student",
"share": 1,
"write": 1
"role": "LMS Student"
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "LMS Student",
"share": 1
"role": "LMS Student"
},
{
"create": 1,
@@ -1,9 +1,64 @@
# Copyright (c) 2024, Frappe and contributors
# For license information, please see license.txt
# import frappe
import frappe
from frappe import _
from frappe.model.document import Document
from lms.lms.doctype.lms_badge.lms_badge import eval_condition
class LMSBadgeAssignment(Document):
pass
def validate(self):
self.validate_owner()
self.validate_duplicate_badge_assignment()
self.validate_badge_criteria()
def validate_owner(self):
if self.owner == self.member:
return
roles = frappe.get_roles(self.owner)
if "Moderator" not in roles:
frappe.throw(_("You must be a Moderator to assign badges to users."))
def validate_duplicate_badge_assignment(self):
grant_only_once = frappe.db.get_value("LMS Badge", self.badge, "grant_only_once")
if not grant_only_once:
return
if frappe.db.exists(
"LMS Badge Assignment",
{"badge": self.badge, "member": self.member, "name": ["!=", self.name]},
):
frappe.throw(
_("Badge {0} has already been assigned to this {1}.").format(self.badge, self.member)
)
def validate_badge_criteria(self):
badge_details = frappe.db.get_value(
"LMS Badge", self.badge, ["reference_doctype", "user_field", "condition", "enabled"], as_dict=True
)
if badge_details:
if badge_details.reference_doctype and badge_details.user_field and badge_details.condition:
user_fieldname = frappe.db.get_value(
"DocField",
{"parent": badge_details.reference_doctype, "fieldname": badge_details.user_field},
"fieldname",
)
documents = frappe.get_all(
badge_details.reference_doctype,
{user_fieldname: self.member},
)
for document in documents:
reference_value = eval_condition(
frappe.get_doc(badge_details.reference_doctype, document.name),
badge_details.condition,
)
if reference_value:
return
frappe.throw(_("Member does not meet the criteria for the badge {0}.").format(self.badge))
+2 -7
View File
@@ -379,7 +379,7 @@
"link_fieldname": "batch_name"
}
],
"modified": "2025-05-26 15:30:55.083507",
"modified": "2025-12-04 12:54:11.190967",
"modified_by": "sayali@frappe.io",
"module": "LMS",
"name": "LMS Batch",
@@ -422,13 +422,8 @@
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "LMS Student",
"share": 1
"role": "LMS Student"
}
],
"row_format": "Dynamic",
@@ -73,8 +73,8 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-02-11 10:39:57.259526",
"modified_by": "Administrator",
"modified": "2025-12-04 12:53:38.246250",
"modified_by": "sayali@frappe.io",
"module": "LMS",
"name": "LMS Batch Enrollment",
"owner": "Administrator",
@@ -105,18 +105,14 @@
},
{
"create": 1,
"email": 1,
"export": 1,
"if_owner": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "LMS Student",
"share": 1
"role": "LMS Student"
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "member_name"
}
}
@@ -15,9 +15,19 @@ class LMSBatchEnrollment(Document):
self.add_member_to_live_class()
def validate(self):
self.validate_owner()
self.validate_duplicate_members()
self.validate_seat_availability()
self.validate_course_enrollment()
def validate_owner(self):
if self.owner == self.member:
return
roles = frappe.get_roles(self.owner)
if not ("Moderator" in roles or "Batch Evaluator" in roles):
frappe.throw(_("You must be a Moderator or Batch Evaluator to enroll users in a batch."))
def validate_duplicate_members(self):
if frappe.db.exists(
"LMS Batch Enrollment",
@@ -25,6 +35,12 @@ class LMSBatchEnrollment(Document):
):
frappe.throw(_("Member already enrolled in this batch"))
def validate_seat_availability(self):
seat_count = frappe.db.get_value("LMS Batch", self.batch, "seat_count")
enrolled_count = frappe.db.count("LMS Batch Enrollment", {"batch": self.batch})
if seat_count and enrolled_count >= seat_count:
frappe.throw(_("There are no seats available in this batch."))
def validate_course_enrollment(self):
courses = frappe.get_all("Batch Course", filters={"parent": self.batch}, fields=["course"])
@@ -115,29 +115,14 @@ def has_website_permission(doc, ptype, user, verbose=False):
@frappe.whitelist()
def create_certificate(course):
certificate = is_certified(course)
if certificate:
if is_certified(course):
return frappe.db.get_value(
"LMS Certificate", certificate, ["name", "course", "template"], as_dict=True
)
else:
default_certificate_template = frappe.db.get_value(
"Property Setter",
{
"doc_type": "LMS Certificate",
"property": "default_print_format",
},
"value",
)
if not default_certificate_template:
default_certificate_template = frappe.db.get_value(
"Print Format",
{
"doc_type": "LMS Certificate",
},
)
validate_certification_eligibility(course)
default_certificate_template = get_default_certificate_template()
certificate = frappe.get_doc(
{
"doctype": "LMS Certificate",
@@ -149,3 +134,37 @@ def create_certificate(course):
)
certificate.save(ignore_permissions=True)
return certificate
def get_default_certificate_template():
default_certificate_template = frappe.db.get_value(
"Property Setter",
{
"doc_type": "LMS Certificate",
"property": "default_print_format",
},
"value",
)
if not default_certificate_template:
default_certificate_template = frappe.db.get_value(
"Print Format",
{
"doc_type": "LMS Certificate",
},
)
return default_certificate_template
def validate_certification_eligibility(course):
if not frappe.db.exists("LMS Enrollment", {"course": course, "member": frappe.session.user}):
frappe.throw(_("You are not enrolled in this course."))
if not frappe.db.get_value("LMS Course", course, "enable_certification"):
frappe.throw(_("Certification is not enabled for this course."))
progress = frappe.db.get_value(
"LMS Enrollment", {"course": course, "member": frappe.session.user}, "progress"
)
if progress < 100:
frappe.throw(_("You have not completed the course yet."))
@@ -4,7 +4,7 @@
import unittest
import frappe
from frappe.utils import add_years, cint, nowdate
from frappe.utils import cint, nowdate
from lms.lms.doctype.lms_certificate.lms_certificate import create_certificate
from lms.lms.doctype.lms_course.test_lms_course import new_course
@@ -18,6 +18,7 @@ class TestLMSCertificate(unittest.TestCase):
"enable_certification": 1,
},
)
create_enrollment(course.name)
certificate = create_certificate(course.name)
self.assertEqual(certificate.member, "Administrator")
@@ -26,3 +27,11 @@ class TestLMSCertificate(unittest.TestCase):
frappe.db.delete("LMS Certificate", certificate.name)
frappe.db.delete("LMS Course", course.name)
def create_enrollment(course):
enrollment = frappe.new_doc("LMS Enrollment")
enrollment.course = course
enrollment.member = frappe.session.user
enrollment.progress = cint(100)
enrollment.save()
@@ -6,7 +6,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from lms.lms.utils import has_course_moderator_role
from lms.lms.utils import has_moderator_role
class LMSCertificateEvaluation(Document):
@@ -19,7 +19,7 @@ class LMSCertificateEvaluation(Document):
def has_website_permission(doc, ptype, user, verbose=False):
if has_course_moderator_role() or doc.member == frappe.session.user:
if has_moderator_role() or doc.member == frappe.session.user:
return True
return False
@@ -30,6 +30,7 @@ class TestLMSCourse(unittest.TestCase):
frappe.delete_doc("User", "tester@example.com")
if frappe.db.exists("LMS Course", "test-course"):
frappe.db.delete("Batch Course", {"course": "test-course"})
frappe.db.delete("Exercise Submission", {"course": "test-course"})
frappe.db.delete("Exercise Latest Submission", {"course": "test-course"})
frappe.db.delete("LMS Exercise", {"course": "test-course"})
@@ -77,8 +77,7 @@ def update_program_progress(member):
@frappe.whitelist()
def create_membership(course, batch=None, member=None, member_type="Student", role="Member"):
if frappe.db.get_value("LMS Course", course, "disable_self_learning"):
return False
validate_course_enrollment_eligibility(course, member)
enrollment = frappe.new_doc("LMS Enrollment")
enrollment.update(
@@ -95,6 +94,42 @@ def create_membership(course, batch=None, member=None, member_type="Student", ro
return enrollment
def validate_course_enrollment_eligibility(course, member):
if not member:
member = frappe.session.user
course_details = frappe.db.get_value(
"LMS Course",
course,
["published", "disable_self_learning", "paid_course", "paid_certificate"],
as_dict=True,
)
if course_details.disable_self_learning:
frappe.throw(
_(
"You cannot enroll in this course as self-learning is disabled. Please contact the Administrator."
)
)
if not course_details.published:
frappe.throw(_("You cannot enroll in an unpublished course."))
if course_details.paid_course:
payment = frappe.db.exists(
"LMS Payment",
{
"reference_doctype": "LMS Course",
"reference_docname": course,
"member": member,
"payment_receipt": True,
},
)
if not payment:
frappe.throw(_("You need to complete the payment for this course before enrolling."))
@frappe.whitelist()
def update_current_membership(batch, course, member):
all_memberships = frappe.get_all("LMS Enrollment", {"member": member, "course": course})
@@ -9,60 +9,15 @@ from lms.lms.doctype.lms_course.test_lms_course import new_course, new_user
class TestLMSEnrollment(unittest.TestCase):
def setUp(self):
frappe.db.delete("LMS Enrollment")
frappe.db.delete("LMS Batch Old")
frappe.db.delete("LMS Course Mentor Mapping")
frappe.db.delete("User", {"email": ("like", "%@test.com")})
def new_course_batch(self):
course = new_course("Test Course")
new_user("Test Mentor", "mentor@test.com")
# without this, the creating batch will fail
course.add_mentor("mentor@test.com")
frappe.session.user = "mentor@test.com"
batch = frappe.get_doc(
{
"doctype": "LMS Batch Old",
"name": "test-batch",
"title": "Test Batch",
"course": course.name,
}
)
batch.insert(ignore_permissions=True)
frappe.session.user = "Administrator"
return course, batch
def add_membership(self, batch_name, member_name, course, member_type="Student"):
doc = frappe.get_doc(
{
"doctype": "LMS Enrollment",
"batch_old": batch_name,
"member": member_name,
"member_type": member_type,
"course": course,
}
)
doc.insert()
return doc
def test_membership(self):
course, batch = self.new_course_batch()
member = new_user("Test", "test01@test.com")
membership = self.add_membership(batch.name, member.name, course.name)
course = new_course("Test Enrollment")
enrollment = frappe.new_doc("LMS Enrollment")
enrollment.course = course.name
enrollment.member = frappe.session.user
assert membership.course == course.name
assert membership.member_name == member.full_name
enrollment.save()
def test_membership_change_role(self):
course, batch = self.new_course_batch()
member = new_user("Test", "test01@test.com")
membership = self.add_membership(batch.name, member.name, course.name)
# it should be possible to change role
membership.role = "Admin"
membership.save()
self.assertEqual(enrollment.course, course.name)
self.assertEqual(enrollment.member, "Administrator")
frappe.db.delete("LMS Enrollment", enrollment.name)
frappe.db.delete("LMS Course", course.name)
@@ -3,52 +3,8 @@
import unittest
import frappe
from lms.lms.doctype.lms_course.test_lms_course import new_course
# import frappe
class TestLMSExercise(unittest.TestCase):
def new_exercise(self):
course = new_course("Test Course")
member = frappe.get_doc(
{
"doctype": "LMS Enrollment",
"course": course.name,
"member": frappe.session.user,
}
)
member.insert()
e = frappe.get_doc(
{
"doctype": "LMS Exercise",
"name": "test-problem",
"course": course.name,
"title": "Test Problem",
"description": "draw a circle",
"code": "# draw a single cicle",
"answer": ("# draw a single circle\n" + "circle(100, 100, 50)"),
}
)
e.insert()
return e
def test_exercise(self):
e = self.new_exercise()
assert e.get_user_submission() is None
def test_exercise_submission(self):
e = self.new_exercise()
submission = e.submit("circle(100, 100, 50)")
assert submission is not None
assert submission.exercise == e.name
assert submission.course == e.course
user_submission = e.get_user_submission()
assert user_submission is not None
assert user_submission.name == submission.name
def tearDown(self):
frappe.db.delete("LMS Enrollment")
frappe.db.delete("Exercise Submission")
frappe.db.delete("LMS Exercise")
pass
+2 -7
View File
@@ -92,7 +92,7 @@
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-08-20 12:28:57.238902",
"modified": "2025-12-04 12:56:14.249363",
"modified_by": "sayali@frappe.io",
"module": "LMS",
"name": "LMS Program",
@@ -136,13 +136,8 @@
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "LMS Student",
"share": 1
"role": "LMS Student"
}
],
"row_format": "Dynamic",
+2 -2
View File
@@ -5,7 +5,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role
from lms.lms.utils import has_course_instructor_role, has_moderator_role
class LMSQuestion(Document):
@@ -95,7 +95,7 @@ def get_correct_options(question):
@frappe.whitelist()
def get_question_details(question):
if not has_course_instructor_role() or not has_course_moderator_role():
if not has_course_instructor_role() or not has_moderator_role():
return
fields = ["question", "type", "name"]
+128 -39
View File
@@ -201,7 +201,7 @@ def get_lesson_icon(body, content):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_tags(course):
tags = frappe.db.get_value("LMS Course", course, "tags")
return tags.split(",") if tags else []
@@ -246,7 +246,7 @@ def get_average_rating(course):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_reviews(course):
reviews = frappe.get_all(
"LMS Course Review",
@@ -492,7 +492,7 @@ def can_create_courses(course, member=None):
if frappe.session.user == "Guest":
return False
if has_course_moderator_role(member):
if has_moderator_role(member):
return True
if has_course_instructor_role(member) and member in instructors:
@@ -508,14 +508,14 @@ def can_create_batches(member=None):
if not member:
member = frappe.session.user
if has_course_moderator_role(member):
if has_moderator_role(member):
return True
if has_course_evaluator_role(member):
if has_evaluator_role(member):
return True
return False
def has_course_moderator_role(member=None):
def has_moderator_role(member=None):
return frappe.db.get_value(
"Has Role",
{"parent": member or frappe.session.user, "role": "Moderator"},
@@ -523,7 +523,7 @@ def has_course_moderator_role(member=None):
)
def has_course_evaluator_role(member=None):
def has_evaluator_role(member=None):
return frappe.db.get_value(
"Has Role",
{"parent": member or frappe.session.user, "role": "Batch Evaluator"},
@@ -748,7 +748,7 @@ def has_lessons(course):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_chart_data(
chart_name,
timespan="Select Date Range",
@@ -796,7 +796,7 @@ def get_chart_data(
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_course_completion_data():
all_membership = frappe.db.count("LMS Enrollment")
completed = frappe.db.count("LMS Enrollment", {"progress": ["like", "%100%"]})
@@ -823,7 +823,7 @@ def get_telemetry_boot_info():
@frappe.whitelist()
def is_onboarding_complete():
if not has_course_moderator_role():
if not has_moderator_role():
return {"is_onboarded": True}
course_created = frappe.db.a_row_exists("LMS Course")
@@ -972,7 +972,7 @@ def change_currency(amount, currency, country=None):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_courses(filters=None, start=0):
"""Returns the list of courses."""
@@ -1113,7 +1113,7 @@ def get_course_fields():
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_course_details(course):
course_details = frappe.db.get_value(
"LMS Course",
@@ -1235,7 +1235,7 @@ def get_course_outline(course, progress=False):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_lesson(course, chapter, lesson):
chapter_name = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": chapter}, "chapter")
lesson_name = frappe.db.get_value("Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson")
@@ -1266,7 +1266,7 @@ def get_lesson(course, chapter, lesson):
if (
not lesson_details.include_in_preview
and not membership
and not has_course_moderator_role()
and not has_moderator_role()
and not is_instructor(course)
):
return {
@@ -1467,7 +1467,7 @@ def get_question_details(question):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_batch_courses(batch):
courses = []
course_list = frappe.get_all("Batch Course", {"parent": batch}, ["name", "course"])
@@ -1691,6 +1691,11 @@ def has_submitted_assessment(assessment, assessment_type, member=None):
docfield = "quiz"
fields = ["percentage"]
not_attempted = 0
elif assessment_type == "LMS Programming Exercise":
doctype = "LMS Programming Exercise Submission"
docfield = "exercise"
fields = ["status"]
not_attempted = "Not Attempted"
filters = {}
filters[docfield] = assessment
@@ -1954,9 +1959,9 @@ def get_lesson_creation_details(course, chapter, lesson):
def get_roles(name):
frappe.only_for("Moderator")
return {
"moderator": has_course_moderator_role(name),
"moderator": has_moderator_role(name),
"course_creator": has_course_instructor_role(name),
"batch_evaluator": has_course_evaluator_role(name),
"batch_evaluator": has_evaluator_role(name),
"lms_student": has_student_role(name),
}
@@ -2058,29 +2063,59 @@ def enroll_in_course(course, payment_name):
@frappe.whitelist()
def enroll_in_batch(batch, payment_name=None):
if not frappe.db.exists("LMS Batch Enrollment", {"batch": batch, "member": frappe.session.user}):
batch_doc = frappe.db.get_value("LMS Batch", batch, ["name", "seat_count"], as_dict=True)
students = frappe.db.count("LMS Batch Enrollment", {"batch": batch})
if batch_doc.seat_count and students >= batch_doc.seat_count:
frappe.throw(_("The batch is full. Please contact the Administrator."))
if not frappe.db.exists("LMS Batch", batch):
frappe.throw(_("The specified batch does not exist."))
new_student = frappe.new_doc("LMS Batch Enrollment")
batch_doc = frappe.db.get_value(
"LMS Batch", batch, ["name", "seat_count", "allow_self_enrollment"], as_dict=True
)
payment_doc = get_payment_details(payment_name)
validate_enrollment_eligibility(batch_doc, payment_doc)
create_enrollment(batch, payment_doc)
def get_payment_details(payment_name):
payment_doc = None
if payment_name:
payment_doc = frappe.db.get_value(
"LMS Payment", payment_name, ["name", "source", "payment_received"], as_dict=True
)
return payment_doc
def validate_enrollment_eligibility(batch_doc, payment_doc=None):
if frappe.db.exists("LMS Batch Enrollment", {"batch": batch_doc.name, "member": frappe.session.user}):
frappe.throw(_("You are already enrolled in this batch."))
if batch_doc.paid_batch:
if not payment_doc or not payment_doc.payment_received:
frappe.throw(_("Payment is required to enroll in this batch."))
elif not batch_doc.allow_self_enrollment:
frappe.throw(_("Enrollment in this batch is restricted. Please contact the Administrator."))
students = frappe.db.count("LMS Batch Enrollment", {"batch": batch_doc.name})
if batch_doc.seat_count and students >= batch_doc.seat_count:
frappe.throw(_("There are no seats available in this batch."))
def create_enrollment(batch, payment_doc=None):
new_student = frappe.new_doc("LMS Batch Enrollment")
new_student.update(
{
"member": frappe.session.user,
"batch": batch,
}
)
if payment_doc:
new_student.update(
{
"member": frappe.session.user,
"batch": batch,
"payment": payment_doc.name,
"source": payment_doc.source,
}
)
if payment_name:
payment = frappe.db.get_value("LMS Payment", payment_name, ["name", "source"], as_dict=True)
new_student.update(
{
"payment": payment.name,
"source": payment.source,
}
)
new_student.save()
new_student.save()
def update_certificate_purchase(course, payment_name):
@@ -2169,8 +2204,8 @@ def get_program_details(program_name):
@frappe.whitelist()
def enroll_in_program(program):
if frappe.session.user == "Guest":
frappe.throw(_("Please login to enroll in the program."))
validate_program_enrollment(program)
if not frappe.db.exists("LMS Program Member", {"parent": program, "member": frappe.session.user}):
program_member = frappe.new_doc("LMS Program Member")
program_member.update(
@@ -2184,8 +2219,17 @@ def enroll_in_program(program):
program_member.save(ignore_permissions=True)
def validate_program_enrollment(program):
if frappe.session.user == "Guest":
frappe.throw(_("Please login to enroll in the program."))
published = frappe.db.get_value("LMS Program", program, "published")
if not published:
frappe.throw(_("You cannot enroll in an unpublished program."))
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_batches(filters=None, start=0, order_by="start_date"):
if not filters:
filters = {}
@@ -2299,7 +2343,7 @@ def get_palette(full_name):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=50, seconds=60 * 60)
@rate_limit(limit=500, seconds=60 * 60)
def get_related_courses(course):
related_course_details = []
related_courses = frappe.get_all("Related Courses", {"parent": course}, order_by="idx", pluck="course")
@@ -2648,3 +2692,48 @@ def get_streak_info():
"current_streak": current_streak,
"longest_streak": longest_streak,
}
def validate_discussion_reply(doc, method):
topic = frappe.db.get_value(
"Discussion Topic", doc.topic, ["reference_doctype", "reference_docname"], as_dict=True
)
if topic.reference_doctype == "Course Lesson":
validate_course_access(topic.reference_docname)
elif topic.reference_doctype == "LMS Batch":
validate_batch_access(topic.reference_docname)
def validate_course_access(lesson):
if not frappe.db.exists("Course Lesson", lesson):
frappe.throw(_("The lesson does not exist."))
if has_moderator_role():
return
if has_course_instructor_role():
return
course = frappe.db.get_value("Course Lesson", lesson, "course")
enrollment_exists = frappe.db.exists("LMS Enrollment", {"member": frappe.session.user, "course": course})
if not enrollment_exists:
frappe.throw(_("You do not have access to this course."))
def validate_batch_access(batch):
if not frappe.db.exists("LMS Batch", batch):
frappe.throw(_("The batch does not exist."))
if has_moderator_role():
return
if has_evaluator_role():
return
enrollment_exists = frappe.db.exists(
"LMS Batch Enrollment", {"member": frappe.session.user, "batch": batch}
)
if not enrollment_exists:
frappe.throw(_("You do not have access to this batch."))
+9 -9
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2025-11-28 16:04+0000\n"
"PO-Revision-Date: 2025-12-02 16:12\n"
"PO-Revision-Date: 2025-12-04 17:07\n"
"Last-Translator: jannat@frappe.io\n"
"Language-Team: Bosnian\n"
"MIME-Version: 1.0\n"
@@ -1375,20 +1375,20 @@ msgstr "Zajednica"
#: lms/job/doctype/lms_job_application/lms_job_application.json
#: lms/lms/doctype/work_experience/work_experience.json
msgid "Company"
msgstr "Kompanija"
msgstr "Poduzeće"
#. Label of the section_break_6 (Section Break) field in DocType 'Job
#. Opportunity'
#: frontend/src/pages/JobForm.vue:63
#: lms/job/doctype/job_opportunity/job_opportunity.json
msgid "Company Details"
msgstr "Detalji o Kompaniji"
msgstr "Detalji o Poduzeću"
#. Label of the company_email_address (Data) field in DocType 'Job Opportunity'
#: frontend/src/pages/JobForm.vue:82
#: lms/job/doctype/job_opportunity/job_opportunity.json
msgid "Company Email Address"
msgstr "Adresa e-pošte Kompanije"
msgstr "Adresa e-pošte Poduzeća"
#. Label of the company_logo (Attach Image) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1396,7 +1396,7 @@ msgstr "Adresa e-pošte Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Logo"
msgstr "Logo Kompanije"
msgstr "Logo Poduzeća"
#. Label of the company_name (Data) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1404,12 +1404,12 @@ msgstr "Logo Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Name"
msgstr "Naziv Kompanije"
msgstr "Naziv Poduzeća"
#. Label of the company_type (Select) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Company Type"
msgstr "Tip Kompanije"
msgstr "Tip Poduzeća"
#. Label of the company_website (Data) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1417,7 +1417,7 @@ msgstr "Tip Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Website"
msgstr "Web stranica Kompanije"
msgstr "Web stranica Poduzeća"
#: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue:69
msgid "Compiler Message"
@@ -2258,7 +2258,7 @@ msgstr "Ne propusti priliku da unaprediš svoje veštine. Klikni ispod da završ
#. Label of the dream_companies (Data) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Dream Companies"
msgstr "San Snova Kompanije"
msgstr "Poduzeće iz Snova"
#: lms/lms/doctype/lms_question/lms_question.py:34
msgid "Duplicate options found for this question."
+9 -9
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2025-11-28 16:04+0000\n"
"PO-Revision-Date: 2025-12-02 16:12\n"
"PO-Revision-Date: 2025-12-04 17:07\n"
"Last-Translator: jannat@frappe.io\n"
"Language-Team: Croatian\n"
"MIME-Version: 1.0\n"
@@ -1375,20 +1375,20 @@ msgstr "Zajednica"
#: lms/job/doctype/lms_job_application/lms_job_application.json
#: lms/lms/doctype/work_experience/work_experience.json
msgid "Company"
msgstr "Kompanija"
msgstr "Tvrtka"
#. Label of the section_break_6 (Section Break) field in DocType 'Job
#. Opportunity'
#: frontend/src/pages/JobForm.vue:63
#: lms/job/doctype/job_opportunity/job_opportunity.json
msgid "Company Details"
msgstr "Detalji Kompanije"
msgstr "Detalji Tvrtke"
#. Label of the company_email_address (Data) field in DocType 'Job Opportunity'
#: frontend/src/pages/JobForm.vue:82
#: lms/job/doctype/job_opportunity/job_opportunity.json
msgid "Company Email Address"
msgstr "Adresa e-pošte Kompanije"
msgstr "Adresa e-pošte Tvrtke"
#. Label of the company_logo (Attach Image) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1396,7 +1396,7 @@ msgstr "Adresa e-pošte Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Logo"
msgstr "Logo Kompanije"
msgstr "Logo Tvrtke"
#. Label of the company_name (Data) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1404,12 +1404,12 @@ msgstr "Logo Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Name"
msgstr "Naziv Kompanije"
msgstr "Naziv Tvrtke"
#. Label of the company_type (Select) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Company Type"
msgstr "Tip Kompanije"
msgstr "Tip Tvrtke"
#. Label of the company_website (Data) field in DocType 'Job Opportunity'
#. Label of a field in the job-opportunity Web Form
@@ -1417,7 +1417,7 @@ msgstr "Tip Kompanije"
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Company Website"
msgstr "Web stranica Kompanije"
msgstr "Web stranica Tvrtke"
#: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue:69
msgid "Compiler Message"
@@ -2258,7 +2258,7 @@ msgstr "Ne propusti priliku da unaprediš svoje veštine. Klikni ispod da završ
#. Label of the dream_companies (Data) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Dream Companies"
msgstr "San Snova Kompanije"
msgstr "Tvrtke iz Snova"
#: lms/lms/doctype/lms_question/lms_question.py:34
msgid "Duplicate options found for this question."
+12 -12
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2025-11-28 16:04+0000\n"
"PO-Revision-Date: 2025-12-01 15:58\n"
"PO-Revision-Date: 2025-12-04 17:06\n"
"Last-Translator: jannat@frappe.io\n"
"Language-Team: Hungarian\n"
"MIME-Version: 1.0\n"
@@ -661,7 +661,7 @@ msgstr ""
#: frontend/src/pages/ProfileEvaluator.vue:146
msgid "Authorize Google Calendar Access"
msgstr ""
msgstr "Google Naptár Hozzáférés Engedélyezése"
#. Option for the 'Event' (Select) field in DocType 'LMS Badge'
#: lms/lms/doctype/lms_badge/lms_badge.json
@@ -919,14 +919,14 @@ msgstr ""
#: frontend/src/components/Modals/EditProfile.vue:81
msgid "Bio"
msgstr ""
msgstr "Életrajz"
#. Option for the 'Color' (Select) field in DocType 'LMS Course'
#. Option for the 'Color' (Select) field in DocType 'LMS Lesson Note'
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_lesson_note/lms_lesson_note.json
msgid "Blue"
msgstr ""
msgstr "Kék"
#. Label of the body (Markdown Editor) field in DocType 'Course Lesson'
#: lms/lms/doctype/course_lesson/course_lesson.json
@@ -1004,7 +1004,7 @@ msgstr "Kategória"
#: frontend/src/components/Settings/Categories.vue:39
msgid "Category Name"
msgstr ""
msgstr "Kategória Neve"
#: frontend/src/components/Settings/Categories.vue:133
msgid "Category added successfully"
@@ -1148,7 +1148,7 @@ msgstr ""
#: frontend/src/components/Quiz.vue:229
msgid "Check"
msgstr ""
msgstr "Jelölje be"
#: frontend/src/pages/ProgrammingExercises/ProgrammingExercises.vue:16
msgid "Check All Submissions"
@@ -1233,7 +1233,7 @@ msgstr "Kattints ide"
#: lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json
#: lms/lms/doctype/zoom_settings/zoom_settings.json
msgid "Client ID"
msgstr ""
msgstr "Ügyfél Azonosító"
#. Label of the client_secret (Password) field in DocType 'LMS Zoom Settings'
#. Label of the client_secret (Password) field in DocType 'Zoom Settings'
@@ -1241,7 +1241,7 @@ msgstr ""
#: lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json
#: lms/lms/doctype/zoom_settings/zoom_settings.json
msgid "Client Secret"
msgstr ""
msgstr "Ügyfél Jelszó"
#: frontend/src/components/Settings/Categories.vue:27
msgid "Close"
@@ -1270,7 +1270,7 @@ msgstr ""
#: lms/lms/doctype/lms_exercise/lms_exercise.json
#: lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.json
msgid "Code"
msgstr ""
msgstr "Kód"
#. Name of a DocType
#. Label of the cohort (Link) field in DocType 'Cohort Join Request'
@@ -1482,7 +1482,7 @@ msgstr ""
#: frontend/src/components/Sidebar/Configuration.vue:12
msgid "Configuration"
msgstr ""
msgstr "Beállítás"
#: frontend/src/pages/BatchForm.vue:148
msgid "Configurations"
@@ -2012,7 +2012,7 @@ msgstr ""
#. Option for the 'Color' (Select) field in DocType 'LMS Course'
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Cyan"
msgstr ""
msgstr "Cián"
#. Label of the show_dashboard (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
@@ -2241,7 +2241,7 @@ msgstr ""
#: lms/lms/doctype/lms_assignment/lms_assignment.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
msgid "Document"
msgstr ""
msgstr "Dokumentum"
#: frontend/src/components/Settings/Coupons/CouponItems.vue:11
msgid "Document Name"
+811 -811
View File
File diff suppressed because it is too large Load Diff
+91 -91
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2025-11-28 16:04+0000\n"
"PO-Revision-Date: 2025-12-01 15:58\n"
"PO-Revision-Date: 2025-12-04 17:06\n"
"Last-Translator: jannat@frappe.io\n"
"Language-Team: Slovenian\n"
"MIME-Version: 1.0\n"
@@ -24,11 +24,11 @@ msgstr "Brskaj i Oceni"
#: frontend/src/pages/Programs/ProgramEnrollment.vue:32
msgid " designed as a learning path to guide your progress. You may take the courses in any order that suits you. "
msgstr ""
msgstr " zasnovano kot učna pot, ki vas bo vodila skozi napredek. Tečaje lahko obiskujete v poljubnem vrstnem redu, ki vam ustreza. "
#: frontend/src/pages/Programs/ProgramEnrollment.vue:25
msgid " designed as a structured learning path to guide your progress. Courses in this program must be taken in order, and each course will unlock as you complete the previous one. "
msgstr ""
msgstr " zasnovan kot strukturirana učna pot, ki vas bo vodila skozi napredek. Tečaje v tem programu je treba obiskovati po vrsti, vsak tečaj pa se bo odklenil, ko boste zaključili prejšnjega. "
#: frontend/src/pages/Home/Streak.vue:21
msgid " you are on a"
@@ -84,7 +84,7 @@ msgstr "Tečaj ne more imeti hkrati plačanega potrdila in potrdila o opravljene
#: frontend/src/pages/CourseForm.vue:190
msgid "A one line introduction to the course that appears on the course card"
msgstr ""
msgstr "Enovrstični uvod v tečaj, ki se prikaže na kartici tečaja"
#: frontend/src/pages/ProfileAbout.vue:4
msgid "About"
@@ -232,15 +232,15 @@ msgstr "Dodajte vajo programiranja svoji lekciji"
#: frontend/src/components/AssessmentPlugin.vue:7
msgid "Add a quiz to your lesson"
msgstr ""
msgstr "Dodaj kviza v lekcijo"
#: frontend/src/components/Modals/AssessmentModal.vue:5
msgid "Add an assessment"
msgstr ""
msgstr "Dodaj oceno"
#: frontend/src/components/AssessmentPlugin.vue:8
msgid "Add an assignment to your lesson"
msgstr ""
msgstr "Dodaj nalogo lekciji"
#: lms/lms/doctype/lms_question/lms_question.py:67
msgid "Add at least one possible answer for this question: {0}"
@@ -252,7 +252,7 @@ msgstr "Dodaj tečaje v skupino"
#: frontend/src/components/Modals/QuizInVideo.vue:5
msgid "Add quiz to this video"
msgstr ""
msgstr "Dodaj kviz temu videoposnetku"
#: frontend/src/components/Sidebar/AppSidebar.vue:567
msgid "Add students to your batch"
@@ -264,19 +264,19 @@ msgstr "Dodaj v Opombe"
#: frontend/src/components/Modals/PageModal.vue:6
msgid "Add web page to sidebar"
msgstr ""
msgstr "Dodaj spletno stran v stransko vrstico"
#: frontend/src/components/Assignment.vue:68
msgid "Add your assignment as {0}"
msgstr ""
msgstr "Dodajte svojo nalogo kot {0}"
#: frontend/src/components/Sidebar/AppSidebar.vue:500
msgid "Add your first chapter"
msgstr ""
msgstr "Dodajte svoje prvo poglavje"
#: frontend/src/components/Sidebar/AppSidebar.vue:516
msgid "Add your first lesson"
msgstr ""
msgstr "Dodajte svojo prvo lekcijo"
#. Label of the address (Link) field in DocType 'LMS Payment'
#: frontend/src/components/Settings/Transactions/TransactionDetails.vue:103
@@ -322,21 +322,21 @@ msgstr "Vsi Tečaji"
#: frontend/src/pages/Programs/StudentPrograms.vue:5
msgid "All Programs"
msgstr ""
msgstr "Vsi Programi"
#: lms/lms/doctype/lms_quiz/lms_quiz.py:42
msgid "All questions should have the same marks if the limit is set."
msgstr ""
msgstr "Če je določena omejitev, bi morala imeti vsa vprašanja enako število točk."
#. Label of the allow_guest_access (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
msgid "Allow Guest Access"
msgstr ""
msgstr "Dovoli dostop gostom"
#. Label of the allow_posting (Check) field in DocType 'Job Settings'
#: lms/job/doctype/job_settings/job_settings.json
msgid "Allow Job Posting From Website"
msgstr ""
msgstr "Dovoli objavo delovnih mest s spletnega mesta"
#. Label of the allow_self_enrollment (Check) field in DocType 'LMS Batch'
#: lms/lms/doctype/lms_batch/lms_batch.json
@@ -423,7 +423,7 @@ msgstr "Odgovor"
#: frontend/src/pages/CourseForm.vue:104 frontend/src/pages/CourseForm.vue:123
msgid "Appears on the course card in the course list"
msgstr ""
msgstr "Prikaže se na kartici predmeta na seznamu predmetov"
#: frontend/src/pages/BatchForm.vue:250
msgid "Appears when the batch URL is shared on any online platform"
@@ -458,7 +458,7 @@ msgstr "Prijave"
#: frontend/src/pages/JobApplications.vue:292
msgid "Applied On"
msgstr ""
msgstr "Uporabljeno na"
#: frontend/src/pages/Billing.vue:81 frontend/src/pages/JobDetail.vue:62
msgid "Apply"
@@ -476,7 +476,7 @@ msgstr "Zaokroževanje na Ekvivalent"
#: frontend/src/components/Modals/JobApplicationModal.vue:6
msgid "Apply for this job"
msgstr ""
msgstr "Prijavite se za to delovno mesto"
#. Option for the 'Status' (Select) field in DocType 'LMS Course'
#. Option for the 'Status' (Select) field in DocType 'LMS Mentor Request'
@@ -600,7 +600,7 @@ msgstr ""
#. Submission'
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
msgid "Assignment Title"
msgstr ""
msgstr "Naslov Naloge"
#: frontend/src/components/Modals/AssignmentForm.vue:146
msgid "Assignment created successfully"
@@ -1196,7 +1196,7 @@ msgstr ""
#: frontend/src/components/Controls/IconPicker.vue:27
msgid "Choose an icon"
msgstr ""
msgstr "Izberi ikono"
#: frontend/src/components/Quiz.vue:655
msgid "Choose one answer"
@@ -1482,7 +1482,7 @@ msgstr "Izvedi Vrednotenje"
#: frontend/src/components/Sidebar/Configuration.vue:12
msgid "Configuration"
msgstr ""
msgstr "Konfiguracija"
#: frontend/src/pages/BatchForm.vue:148
msgid "Configurations"
@@ -1513,7 +1513,7 @@ msgstr "Predloga potrditvenega e-poštnega sporočila"
#: lms/lms/doctype/lms_certificate/lms_certificate.py:30
msgid "Congratulations on getting certified!"
msgstr ""
msgstr "Čestitamo za pridobitev certifikata!"
#. Label of the contact_us_tab (Tab Break) field in DocType 'LMS Settings'
#: frontend/src/components/ContactUsEmail.vue:5
@@ -1578,7 +1578,7 @@ msgstr "Pravilno"
#: frontend/src/components/Modals/Question.vue:79
msgid "Correct Answer"
msgstr ""
msgstr "Pravilen odgovor"
#. Label of the country (Link) field in DocType 'User'
#. Label of the country (Link) field in DocType 'Job Opportunity'
@@ -1814,7 +1814,7 @@ msgstr "Tečaj uspešno dodan v program"
#: frontend/src/pages/Programs/ProgramForm.vue:446
msgid "Course already added to program"
msgstr ""
msgstr "Tečaj je že dodan v program"
#: frontend/src/pages/CourseForm.vue:569
msgid "Course created successfully"
@@ -1834,7 +1834,7 @@ msgstr "Tečaj {0} je bil že dodan tej skupini."
#: lms/lms/doctype/lms_program/lms_program.py:20
msgid "Course {0} has already been added to this program."
msgstr ""
msgstr "Tečaj {0} je že dodan v ta program."
#. Label of the courses (Table) field in DocType 'LMS Batch'
#. Label of the show_courses (Check) field in DocType 'LMS Settings'
@@ -1962,7 +1962,7 @@ msgstr "Ustvari Skupino"
#: frontend/src/components/Sidebar/AppSidebar.vue:620
msgid "Creating a course"
msgstr ""
msgstr "Ustvarjanje tečaja"
#. Label of the currency (Link) field in DocType 'LMS Batch'
#. Label of the currency (Link) field in DocType 'LMS Course'
@@ -2022,7 +2022,7 @@ msgstr "Nadzorna Plošča"
#: frontend/src/components/Sidebar/Configuration.vue:33
#: frontend/src/pages/DataImport.vue:35
msgid "Data Import"
msgstr ""
msgstr "Uvoz Podatkov"
#. Label of the date (Date) field in DocType 'LMS Batch Timetable'
#. Label of the date (Date) field in DocType 'LMS Certificate Evaluation'
@@ -2099,27 +2099,27 @@ msgstr "Izbriši"
#: frontend/src/components/CourseOutline.vue:67
msgid "Delete Chapter"
msgstr ""
msgstr "Izbriši Poglavje"
#: frontend/src/pages/CourseForm.vue:613
msgid "Delete Course"
msgstr ""
msgstr "Izbriši Tečaj"
#: frontend/src/pages/Programs/ProgramForm.vue:561
msgid "Delete Program"
msgstr ""
msgstr "Izbriši Program"
#: frontend/src/components/CourseOutline.vue:354
msgid "Delete this chapter?"
msgstr ""
msgstr "Izbriši Poglavje?"
#: frontend/src/components/Settings/Coupons/CouponList.vue:127
msgid "Delete this coupon?"
msgstr ""
msgstr "Izbriši Kupon?"
#: frontend/src/components/CourseOutline.vue:288
msgid "Delete this lesson?"
msgstr ""
msgstr "Izbriši Lekcijo?"
#: frontend/src/pages/CourseForm.vue:614
msgid "Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?"
@@ -2170,7 +2170,7 @@ msgstr "Opis"
#: frontend/src/components/Sidebar/Apps.vue:50
msgid "Desk"
msgstr ""
msgstr "Pisalna miza"
#: frontend/src/components/Modals/DiscussionModal.vue:22
#: frontend/src/pages/BatchForm.vue:21 frontend/src/pages/CourseForm.vue:25
@@ -2199,17 +2199,17 @@ msgstr ""
#: frontend/src/components/Settings/ZoomSettings.vue:66
#: lms/job/doctype/job_opportunity/job_opportunity.json
msgid "Disabled"
msgstr ""
msgstr "Onemogočeno"
#: frontend/src/components/DiscussionReplies.vue:57
#: lms/lms/widgets/NoPreviewModal.html:25 lms/templates/reviews.html:159
msgid "Discard"
msgstr ""
msgstr "Zavrzi"
#: frontend/src/components/Settings/Coupons/CouponList.vue:169
#: frontend/src/pages/Billing.vue:41
msgid "Discount"
msgstr ""
msgstr "Popust"
#. Label of the discount_amount (Currency) field in DocType 'LMS Payment'
#: frontend/src/components/Settings/Coupons/CouponDetails.vue:53
@@ -2220,13 +2220,13 @@ msgstr "Znesek Popusta"
#: frontend/src/components/Settings/Coupons/CouponDetails.vue:46
msgid "Discount Percentage"
msgstr ""
msgstr "Odstotek popusta"
#. Label of the discount_type (Select) field in DocType 'LMS Coupon'
#: frontend/src/components/Settings/Coupons/CouponDetails.vue:30
#: lms/lms/doctype/lms_coupon/lms_coupon.json
msgid "Discount Type"
msgstr ""
msgstr "Tip Popusta"
#. Label of the show_discussions (Check) field in DocType 'LMS Settings'
#: frontend/src/pages/Batch.vue:91
@@ -2241,15 +2241,15 @@ msgstr "Razprave"
#: lms/lms/doctype/lms_assignment/lms_assignment.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
msgid "Document"
msgstr ""
msgstr "Dokument"
#: frontend/src/components/Settings/Coupons/CouponItems.vue:11
msgid "Document Name"
msgstr ""
msgstr "Ime Dokumenta"
#: frontend/src/components/Settings/Coupons/CouponItems.vue:8
msgid "Document Type"
msgstr ""
msgstr "Tip Dokumenta"
#: lms/templates/emails/payment_reminder.html:11
msgid "Dont miss this opportunity to enhance your skills. Click below to complete your enrollment"
@@ -2258,7 +2258,7 @@ msgstr ""
#. Label of the dream_companies (Data) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Dream Companies"
msgstr ""
msgstr "Sanjska Podjetja"
#: lms/lms/doctype/lms_question/lms_question.py:34
msgid "Duplicate options found for this question."
@@ -2311,7 +2311,7 @@ msgstr ""
#: frontend/src/components/Settings/BadgeForm.vue:5
msgid "Edit Badge"
msgstr ""
msgstr "Uredi Značko"
#: frontend/src/components/Settings/BadgeAssignmentForm.vue:8
msgid "Edit Badge Assignment"
@@ -2320,35 +2320,35 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:60
#: frontend/src/components/Modals/ChapterModal.vue:5
msgid "Edit Chapter"
msgstr ""
msgstr "Uredi poglavje"
#: frontend/src/components/Settings/Coupons/CouponDetails.vue:9
msgid "Edit Coupon"
msgstr ""
msgstr "Uredi Kupon"
#: frontend/src/components/Modals/EmailTemplateModal.vue:8
msgid "Edit Email Template"
msgstr ""
msgstr "Uredi predloge e-pošte"
#: frontend/src/components/Settings/PaymentGatewayDetails.vue:8
msgid "Edit Payment Gateway"
msgstr ""
msgstr "Uredi Plačilni Prehod"
#: frontend/src/pages/Profile.vue:80
msgid "Edit Profile"
msgstr ""
msgstr "Uredi Profil"
#: frontend/src/pages/Programs/ProgramForm.vue:12
msgid "Edit Program"
msgstr ""
msgstr "Uredi Program"
#: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue:8
msgid "Edit Programming Exercise"
msgstr ""
msgstr "Uredi Programsko Vaje"
#: frontend/src/components/Modals/ZoomAccountModal.vue:6
msgid "Edit Zoom Account"
msgstr ""
msgstr "Uredi Zoom Račun"
#: frontend/src/pages/QuizForm.vue:199
msgid "Edit the question"
@@ -2357,7 +2357,7 @@ msgstr ""
#. Label of the education (Table) field in DocType 'User'
#: lms/fixtures/custom_field.json
msgid "Education"
msgstr ""
msgstr "Izobrazba"
#. Name of a DocType
#: lms/lms/doctype/education_detail/education_detail.json
@@ -2373,7 +2373,7 @@ msgstr ""
#: frontend/src/components/Settings/Members.vue:103
#: frontend/src/pages/JobApplications.vue:286 lms/templates/signup-form.html:10
msgid "Email"
msgstr ""
msgstr "E-pošta"
#: frontend/src/components/Modals/Event.vue:16
msgid "Email ID"
@@ -2414,7 +2414,7 @@ msgstr ""
#. Label of the show_emails (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
msgid "Emails"
msgstr ""
msgstr "E-pošta"
#. Option for the 'User Category' (Select) field in DocType 'User'
#: lms/fixtures/custom_field.json lms/templates/signup-form.html:25
@@ -2424,7 +2424,7 @@ msgstr "Osebje"
#. Label of the enable (Check) field in DocType 'Zoom Settings'
#: lms/lms/doctype/zoom_settings/zoom_settings.json
msgid "Enable"
msgstr ""
msgstr "Omogoči"
#: lms/lms/doctype/lms_settings/lms_settings.py:22
msgid "Enable Google API in Google Settings to send calendar invites for evaluations."
@@ -2454,7 +2454,7 @@ msgstr ""
#: lms/lms/doctype/lms_coupon/lms_coupon.json
#: lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json
msgid "Enabled"
msgstr ""
msgstr "Omogočeno"
#: frontend/src/components/Modals/BulkCertificates.vue:53
msgid "Enabling this will publish the certificate on the certified participants page."
@@ -2493,7 +2493,7 @@ msgstr "Končni čas"
#: frontend/src/pages/Home/AdminHome.vue:186
#: frontend/src/pages/Home/StudentHome.vue:129
msgid "Ended"
msgstr ""
msgstr "Končano"
#. Label of the enforce_course_order (Check) field in DocType 'LMS Program'
#: frontend/src/pages/Programs/ProgramForm.vue:39
@@ -2541,7 +2541,7 @@ msgstr ""
#: frontend/src/pages/Programs/ProgramProgressSummary.vue:15
#: lms/lms/doctype/lms_course/lms_course.json lms/lms/workspace/lms/lms.json
msgid "Enrollments"
msgstr ""
msgstr "Vpisi"
#: lms/lms/doctype/lms_settings/lms_settings.py:27
msgid "Enter Client Id and Client Secret in Google Settings to send calendar invites for evaluations."
@@ -2690,7 +2690,7 @@ msgstr ""
#: lms/lms/doctype/lms_badge/lms_badge.json
#: lms/lms/doctype/lms_live_class/lms_live_class.json
msgid "Event"
msgstr ""
msgstr "Dogodek"
#: frontend/src/pages/BatchForm.vue:116
msgid "Example: IST (+5:30)"
@@ -2705,17 +2705,17 @@ msgstr "Primer: IST (+5:30)"
#: lms/lms/doctype/exercise_submission/exercise_submission.json
#: lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.json
msgid "Exercise"
msgstr ""
msgstr "Vaja"
#. Name of a DocType
#: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json
msgid "Exercise Latest Submission"
msgstr ""
msgstr "Vaja Najnovejša Oddaja"
#. Name of a DocType
#: lms/lms/doctype/exercise_submission/exercise_submission.json
msgid "Exercise Submission"
msgstr ""
msgstr "Oddaja Vaje"
#. Label of the exercise_title (Data) field in DocType 'Exercise Latest
#. Submission'
@@ -2726,11 +2726,11 @@ msgstr ""
#: lms/lms/doctype/exercise_submission/exercise_submission.json
#: lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.json
msgid "Exercise Title"
msgstr ""
msgstr "Naslov Vaje"
#: frontend/src/components/Sidebar/AppSidebar.vue:145
msgid "Expand"
msgstr ""
msgstr "Razširi"
#. Label of the expected_output (Data) field in DocType 'LMS Test Case'
#. Label of the expected_output (Data) field in DocType 'LMS Test Case
@@ -2751,18 +2751,18 @@ msgstr ""
#: frontend/src/components/Settings/Coupons/CouponList.vue:176
#: lms/lms/doctype/lms_coupon/lms_coupon.json
msgid "Expires On"
msgstr ""
msgstr "Poteče"
#. Label of the expiry_date (Date) field in DocType 'LMS Certificate'
#: frontend/src/components/Modals/BulkCertificates.vue:33
#: frontend/src/components/Modals/Event.vue:144
#: lms/lms/doctype/lms_certificate/lms_certificate.json
msgid "Expiry Date"
msgstr ""
msgstr "Datum Poteka"
#: lms/lms/doctype/lms_coupon/lms_coupon.py:23
msgid "Expiry date cannot be in the past"
msgstr ""
msgstr "Datum veljavnosti ne sme biti v preteklosti"
#. Label of the explanation_1 (Small Text) field in DocType 'LMS Question'
#. Label of the explanation_3 (Small Text) field in DocType 'LMS Question'
@@ -2770,17 +2770,17 @@ msgstr ""
#: frontend/src/components/Modals/Question.vue:75
#: lms/lms/doctype/lms_question/lms_question.json
msgid "Explanation"
msgstr ""
msgstr "Razlaga"
#. Label of the explanation_2 (Small Text) field in DocType 'LMS Question'
#: lms/lms/doctype/lms_question/lms_question.json
msgid "Explanation "
msgstr ""
msgstr "Razlaga "
#: lms/lms/web_template/course_cards/course_cards.html:15
#: lms/lms/web_template/recently_published_courses/recently_published_courses.html:16
msgid "Explore More"
msgstr ""
msgstr "Razišči več"
#. Option for the 'Status' (Select) field in DocType 'LMS Assignment
#. Submission'
@@ -2790,7 +2790,7 @@ msgstr ""
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
#: lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json
msgid "Fail"
msgstr ""
msgstr "Neuspeh"
#. Option for the 'Status' (Select) field in DocType 'LMS Programming Exercise
#. Submission'
@@ -2799,7 +2799,7 @@ msgstr ""
#: lms/lms/doctype/lms_programming_exercise_submission/lms_programming_exercise_submission.json
#: lms/lms/doctype/lms_test_case_submission/lms_test_case_submission.json
msgid "Failed"
msgstr ""
msgstr "Neuspešno"
#: frontend/src/components/Settings/BadgeAssignmentForm.vue:136
msgid "Failed to create badge assignment: "
@@ -2835,7 +2835,7 @@ msgstr ""
#: frontend/src/pages/CourseForm.vue:169
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Featured"
msgstr ""
msgstr "Izabrano"
#. Label of the feedback (Small Text) field in DocType 'LMS Batch Feedback'
#: frontend/src/components/BatchFeedback.vue:30
@@ -2912,7 +2912,7 @@ msgstr ""
#: lms/lms/widgets/CourseCard.html:114
msgid "Free"
msgstr ""
msgstr "Brezplačno"
#. Option for the 'Type' (Select) field in DocType 'Job Opportunity'
#. Option in a Select field in the job-opportunity Web Form
@@ -2920,35 +2920,35 @@ msgstr ""
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Freelance"
msgstr ""
msgstr "Samostojni delavec"
#. Option for the 'User Category' (Select) field in DocType 'User'
#: lms/fixtures/custom_field.json lms/templates/signup-form.html:27
msgid "Freelancer/Just looking"
msgstr ""
msgstr "Samostojni delavec/Samo iščem"
#. Option for the 'Grade Type' (Select) field in DocType 'Education Detail'
#: lms/lms/doctype/education_detail/education_detail.json
msgid "French (e.g. Distinction)"
msgstr ""
msgstr "Francoščina (npr. Razlikovanje)"
#. Option for the 'Day' (Select) field in DocType 'Evaluator Schedule'
#. Option for the 'Day' (Select) field in DocType 'LMS Certificate Request'
#: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json
msgid "Friday"
msgstr ""
msgstr "Petek"
#. Label of the unavailable_from (Date) field in DocType 'Course Evaluator'
#: frontend/src/pages/ProfileEvaluator.vue:106
#: lms/lms/doctype/course_evaluator/course_evaluator.json
msgid "From"
msgstr ""
msgstr "Od"
#. Label of the from_date (Date) field in DocType 'Work Experience'
#: lms/lms/doctype/work_experience/work_experience.json
msgid "From Date"
msgstr ""
msgstr "Od datuma"
#. Label of the full_name (Data) field in DocType 'Course Evaluator'
#. Label of the full_name (Data) field in DocType 'LMS Program Member'
@@ -2957,7 +2957,7 @@ msgstr ""
#: lms/lms/doctype/lms_program_member/lms_program_member.json
#: lms/templates/signup-form.html:5
msgid "Full Name"
msgstr ""
msgstr "Polno ime"
#. Option for the 'Type' (Select) field in DocType 'Job Opportunity'
#. Option in a Select field in the job-opportunity Web Form
@@ -2965,7 +2965,7 @@ msgstr ""
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/job/web_form/job_opportunity/job_opportunity.json
msgid "Full Time"
msgstr ""
msgstr "Polni delovni čas"
#. Name of a DocType
#. Label of the function (Data) field in DocType 'Function'
@@ -2973,30 +2973,30 @@ msgstr ""
#: lms/lms/doctype/function/function.json
#: lms/lms/doctype/preferred_function/preferred_function.json
msgid "Function"
msgstr ""
msgstr "Funkcija"
#: frontend/src/pages/Billing.vue:46
msgid "GST Amount"
msgstr ""
msgstr "Znesek DDV"
#: frontend/src/pages/Billing.vue:145
msgid "GST Number"
msgstr ""
msgstr "Številka DDV"
#. Label of the gstin (Data) field in DocType 'LMS Payment'
#: frontend/src/components/Settings/Transactions/TransactionDetails.vue:107
#: lms/lms/doctype/lms_payment/lms_payment.json
msgid "GSTIN"
msgstr ""
msgstr "GSTIN"
#: frontend/src/components/Settings/PaymentGateways.vue:134
msgid "Gateway"
msgstr ""
msgstr "Prehod"
#. Label of the general_tab (Tab Break) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
msgid "General"
msgstr ""
msgstr "Splošno"
#: frontend/src/components/Modals/BulkCertificates.vue:5
#: frontend/src/pages/Batch.vue:12
@@ -3348,7 +3348,7 @@ msgstr ""
#: frontend/src/components/InstallPrompt.vue:18
msgid "Install"
msgstr ""
msgstr "Namesti"
#: frontend/src/components/InstallPrompt.vue:4
#: frontend/src/components/InstallPrompt.vue:32
+1 -1
View File
@@ -1,6 +1,6 @@
{% set onboarding_status = is_onboarding_complete() %}
{% if has_course_moderator_role() and not onboarding_status.is_onboarded %}
{% if has_moderator_role() and not onboarding_status.is_onboarded %}
<div class="onboarding-parent">
<div class="container">
<div class="onboarding-skip">{{ _("Skip") }}</div>
+1 -1
View File
@@ -25,7 +25,7 @@
},
"homepage": "https://github.com/frappe/lms#readme",
"devDependencies": {
"cypress": "^14.5.2",
"cypress": "^15.7.1",
"cypress-file-upload": "^5.0.8",
"cypress-real-events": "^1.14.0"
},
+1355
View File
File diff suppressed because it is too large Load Diff