mirror of
https://github.com/frappe/lms.git
synced 2026-05-02 13:39:31 +03:00
fix: permission issues when adding new members
This commit is contained in:
@@ -16,7 +16,12 @@
|
||||
<button
|
||||
class="flex w-full items-center justify-between focus:outline-none"
|
||||
:class="inputClasses"
|
||||
@click="() => togglePopover()"
|
||||
@click="
|
||||
() => {
|
||||
showOptions = !showOptions
|
||||
togglePopover()
|
||||
}
|
||||
"
|
||||
:disabled="attrs.readonly"
|
||||
>
|
||||
<div class="flex items-center w-[90%]">
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<div class="space-y-4">
|
||||
<div
|
||||
class="font-medium text-ink-gray-9"
|
||||
:class="{ 'mt-8': course.data.membership && !readOnlyMode }"
|
||||
:class="{ 'mt-8': !readOnlyMode }"
|
||||
>
|
||||
{{ __('This course has:') }}
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,15 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Avatar, Button, createResource, Dialog, FormControl } from 'frappe-ui'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
call,
|
||||
createResource,
|
||||
Dialog,
|
||||
FormControl,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, watch, reactive, inject } from 'vue'
|
||||
import { RefreshCw, Plus, Search, Shield } from 'lucide-vue-next'
|
||||
@@ -184,34 +192,29 @@ const openProfile = (username: string) => {
|
||||
})
|
||||
}
|
||||
|
||||
const newMember = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams() {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'User',
|
||||
first_name: member.first_name,
|
||||
email: member.email,
|
||||
},
|
||||
}
|
||||
},
|
||||
auto: false,
|
||||
onSuccess(data: Member) {
|
||||
show.value = false
|
||||
if (user?.data?.is_system_manager) updateOnboardingStep('invite_students')
|
||||
|
||||
router.push({
|
||||
name: 'ProfileRoles',
|
||||
params: {
|
||||
username: data.username,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const addMember = (close: () => void) => {
|
||||
newMember.reload()
|
||||
close()
|
||||
call('frappe.client.insert', {
|
||||
doc: {
|
||||
doctype: 'User',
|
||||
first_name: member.first_name,
|
||||
email: member.email,
|
||||
},
|
||||
})
|
||||
.then((data: Member) => {
|
||||
if (user?.data?.is_system_manager) updateOnboardingStep('invite_students')
|
||||
show.value = false
|
||||
router.push({
|
||||
name: 'ProfileRoles',
|
||||
params: {
|
||||
username: data.username,
|
||||
},
|
||||
})
|
||||
close()
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error(err)
|
||||
toast.error(__(err.messages?.[0] || err))
|
||||
})
|
||||
}
|
||||
|
||||
watch(search, () => {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<NumberChartGraph :title="__('Lessons')" :value="course.data?.lessons" />
|
||||
</div>
|
||||
<div class="grid grid-cols-[2fr_1fr] gap-5 items-start">
|
||||
<div v-if="course.data?.enrollments" class="border rounded-lg py-3 px-4">
|
||||
<div class="border rounded-lg py-3 px-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="text-lg text-ink-gray-9 font-semibold">
|
||||
{{ __('Students') }}
|
||||
@@ -244,6 +244,7 @@
|
||||
v-if="showEnrollmentModal"
|
||||
v-model="showEnrollmentModal"
|
||||
:course="course"
|
||||
:students="progressList"
|
||||
/>
|
||||
<StudentCourseProgress
|
||||
v-if="showProgressModal"
|
||||
|
||||
@@ -58,6 +58,7 @@ import Link from '@/components/Controls/Link.vue'
|
||||
|
||||
const show = defineModel<boolean>({ required: true, default: false })
|
||||
const student = ref<string | null>(null)
|
||||
const students = defineModel<any[]>('students')
|
||||
const payment = ref<string | null>(null)
|
||||
const purchasedCertificate = ref<boolean>(false)
|
||||
|
||||
@@ -79,6 +80,7 @@ const enrollStudent = (close: () => void) => {
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
students.value?.reload()
|
||||
toast.success(__('Student enrolled successfully'))
|
||||
close()
|
||||
})
|
||||
|
||||
+626
-633
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,7 @@ ALLOWED_PATHS = [
|
||||
"/api/method/frappe.core.doctype.user.user.reset_password",
|
||||
"/api/method/frappe.desk.doctype.notification_log.notification_log.mark_as_read",
|
||||
"/api/method/frappe.desk.doctype.notification_log.notification_log.mark_all_as_read",
|
||||
"/api/method/frappe.sessions.clear",
|
||||
]
|
||||
|
||||
|
||||
|
||||
+34
-7
@@ -7,6 +7,7 @@ from lms.lms.api import give_discussions_permission
|
||||
def after_install():
|
||||
create_batch_source()
|
||||
give_discussions_permission()
|
||||
give_user_list_permission()
|
||||
|
||||
|
||||
def after_sync():
|
||||
@@ -27,13 +28,6 @@ def create_lms_roles():
|
||||
create_lms_student_role()
|
||||
|
||||
|
||||
def delete_lms_roles():
|
||||
roles = ["Course Creator", "Moderator"]
|
||||
for role in roles:
|
||||
if frappe.db.exists("Role", role):
|
||||
frappe.db.delete("Role", role)
|
||||
|
||||
|
||||
def create_course_creator_role():
|
||||
if frappe.db.exists("Role", "Course Creator"):
|
||||
frappe.db.set_value("Role", "Course Creator", "desk_access", 0)
|
||||
@@ -185,3 +179,36 @@ def give_lms_roles_to_admin():
|
||||
doc.parentfield = "roles"
|
||||
doc.role = role
|
||||
doc.save()
|
||||
|
||||
|
||||
def give_user_list_permission():
|
||||
doctype = "User"
|
||||
roles = ["Course Creator", "Moderator", "Batch Evaluator"]
|
||||
for role in roles:
|
||||
permlevel = 0
|
||||
create_role(doctype, role, permlevel)
|
||||
create_role(doctype, "System Manager", 1)
|
||||
|
||||
|
||||
def create_role(doctype, role, permlevel):
|
||||
if not frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": role, "permlevel": permlevel}):
|
||||
doc = frappe.new_doc("Custom DocPerm")
|
||||
doc.update(
|
||||
{
|
||||
"doctype": "Custom DocPerm",
|
||||
"parent": doctype,
|
||||
"role": role,
|
||||
"read": 1,
|
||||
"write": 1 if role in ["Moderator", "System Manager"] else 0,
|
||||
"create": 1 if role == "Moderator" else 0,
|
||||
"permlevel": permlevel,
|
||||
}
|
||||
)
|
||||
doc.save()
|
||||
|
||||
|
||||
def delete_lms_roles():
|
||||
roles = ["Course Creator", "Moderator", "Batch Evaluator", "LMS Student"]
|
||||
for role in roles:
|
||||
if frappe.db.exists("Role", role):
|
||||
frappe.db.delete("Role", role)
|
||||
|
||||
@@ -8,9 +8,15 @@ from frappe.utils import ceil
|
||||
|
||||
|
||||
class LMSEnrollment(Document):
|
||||
def before_insert(self):
|
||||
def validate(self):
|
||||
self.validate_duplicate_enrollment()
|
||||
self.validate_course_enrollment_eligibility()
|
||||
self.validate_owner()
|
||||
|
||||
def validate_owner(self):
|
||||
"""Makes the member as the owner of the document so that users can update their progress"""
|
||||
if self.owner != self.member:
|
||||
self.owner = self.member
|
||||
|
||||
def on_update(self):
|
||||
update_program_progress(self.member)
|
||||
@@ -45,7 +51,7 @@ class LMSEnrollment(Document):
|
||||
if self.enrollment_from_batch:
|
||||
return
|
||||
|
||||
if not course_details.published:
|
||||
if not course_details.published and not is_admin():
|
||||
frappe.throw(_("You cannot enroll in an unpublished course."))
|
||||
|
||||
if course_details.paid_course:
|
||||
|
||||
+3
-1
@@ -115,4 +115,6 @@ lms.patches.v2_0.fix_scorm_lesson_reference_idx #02-09-2025
|
||||
lms.patches.v2_0.certified_members_to_certifications #05-10-2025
|
||||
lms.patches.v2_0.fix_job_application_resume_urls
|
||||
lms.patches.v2_0.open_to_opportunities
|
||||
lms.patches.v2_0.open_to_work
|
||||
lms.patches.v2_0.open_to_work
|
||||
lms.patches.v2_0.share_enrollment
|
||||
lms.patches.v2_0.give_user_list_permission #11-02-2026
|
||||
@@ -0,0 +1,5 @@
|
||||
from lms.install import give_user_list_permission
|
||||
|
||||
|
||||
def execute():
|
||||
give_user_list_permission()
|
||||
@@ -0,0 +1,20 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
enrollments = frappe.get_all("LMS Enrollment", ["name", "member", "owner"])
|
||||
|
||||
for enrollment in enrollments:
|
||||
if enrollment.owner == enrollment.member:
|
||||
continue
|
||||
filters = {
|
||||
"user": enrollment.member,
|
||||
"share_doctype": "LMS Enrollment",
|
||||
"share_name": enrollment.name,
|
||||
}
|
||||
is_shared = frappe.db.exists("DocShare", filters)
|
||||
if not is_shared:
|
||||
share = frappe.new_doc("DocShare")
|
||||
filters.update({"read": 1, "notify_by_email": 0})
|
||||
share.update(filters)
|
||||
share.save()
|
||||
Reference in New Issue
Block a user