Skip to content

Commit

Permalink
Merge pull request #1100 from pateljannat/issues-47
Browse files Browse the repository at this point in the history
fix: misc issues
  • Loading branch information
pateljannat authored Nov 6, 2024
2 parents 8004982 + 4a8c818 commit 08b2063
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 37 deletions.
4 changes: 2 additions & 2 deletions frontend/src/components/CourseCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
:style="{ backgroundImage: 'url(\'' + encodeURI(course.image) + '\')' }"
>
<div
class="flex items-center flex-wrap space-y-1 space-x-1 relative top-4 px-2 w-fit"
class="flex items-center flex-wrap space-x-1 relative top-4 px-2 w-fit"
>
<Badge v-if="course.featured" variant="subtle" theme="green" size="md">
{{ __('Featured') }}
</Badge>
<Badge
variant="outline"
variant="subtle"
theme="gray"
size="md"
v-for="tag in course.tags"
Expand Down
61 changes: 43 additions & 18 deletions frontend/src/pages/CourseForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
>
<Breadcrumbs class="h-7" :items="breadcrumbs" />
<div class="flex items-center mt-3 md:mt-0">
<Button v-if="courseResource.data?.name" @click="trashCourse()">
<template #prefix>
<Trash2 class="w-4 h-4 stroke-1.5" />
</template>
<span>
{{ __('Delete') }}
</span>
</Button>
<Button variant="solid" @click="submitCourse()" class="ml-2">
<span>
{{ __('Save') }}
Expand Down Expand Up @@ -247,10 +255,11 @@ import {
ref,
reactive,
watch,
getCurrentInstance,
} from 'vue'
import { convertToTitleCase, showToast, updateDocumentTitle } from '@/utils'
import { showToast, updateDocumentTitle } from '@/utils'
import Link from '@/components/Controls/Link.vue'
import { FileText, Image, X } from 'lucide-vue-next'
import { Image, Trash2, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import CourseOutline from '@/components/CourseOutline.vue'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
Expand All @@ -262,6 +271,8 @@ const newTag = ref('')
const router = useRouter()
const instructors = ref([])
const settingsStore = useSettings()
const app = getCurrentInstance()
const { $dialog } = app.appContext.config.globalProperties
const props = defineProps({
courseName: {
Expand Down Expand Up @@ -434,23 +445,37 @@ const submitCourse = () => {
}
}
const validateMandatoryFields = () => {
const mandatory_fields = [
'title',
'short_introduction',
'description',
'video_link',
'course_image',
]
for (const field of mandatory_fields) {
if (!course[field]) {
let fieldLabel = convertToTitleCase(field.split('_').join(' '))
return `${fieldLabel} is mandatory`
const deleteCourse = createResource({
url: 'lms.lms.api.delete_course',
makeParams(values) {
return {
course: props.courseName,
}
}
if (course.paid_course && (!course.course_price || !course.currency)) {
return __('Course price and currency are mandatory for paid courses')
}
},
onSuccess() {
showToast(__('Success'), __('Course deleted successfully'), 'check')
router.push({ name: 'Courses' })
},
})
const trashCourse = () => {
$dialog({
title: __('Delete Course'),
message: __(
'Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?'
),
actions: [
{
label: __('Delete'),
theme: 'red',
variant: 'solid',
onClick(close) {
deleteCourse.submit()
close()
},
},
],
})
}
watch(
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/Courses.vue
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
<div class="text-xl font-medium">
{{ __('No courses found') }}
</div>
<div>
<div class="leading-5">
{{
__(
'There are no courses available at the moment. Keep an eye out, fresh learning experiences are on the way soon!'
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/pages/Lesson.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ const lesson = createResource({
},
auto: true,
onSuccess(data) {
if (Object.keys(data).length === 0) {
router.push({ name: 'Courses' })
return
}
lessonProgress.value = data.membership?.progress
if (data.content) editor.value = renderEditor('editor', data.content)
if (
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/pages/Quizzes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@
</ListRows>
</ListView>
</div>
<div
v-else
class="text-center p-5 text-gray-600 mt-52 w-3/4 md:w-1/2 mx-auto space-y-2"
>
<BookOpen class="size-10 mx-auto stroke-1 text-gray-500" />
<div class="text-xl font-medium">
{{ __('No quizzes found') }}
</div>
<div class="leading-5">
{{
__(
'You have not created any quizzes yet. To create a new quiz, click on the "New Quiz" button above.'
)
}}
</div>
</div>
</template>
<script setup>
import {
Expand All @@ -61,7 +77,7 @@ import {
} from 'frappe-ui'
import { useRouter } from 'vue-router'
import { computed, inject, onMounted } from 'vue'
import { Plus } from 'lucide-vue-next'
import { BookOpen, Plus } from 'lucide-vue-next'
import { updateDocumentTitle } from '@/utils'
const user = inject('$user')
Expand Down
2 changes: 2 additions & 0 deletions lms/install.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import frappe
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
from lms.lms.api import give_dicussions_permission


def after_install():
add_pages_to_nav()
create_batch_source()
give_dicussions_permission()


def after_sync():
Expand Down
74 changes: 73 additions & 1 deletion lms/lms/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,15 @@ def delete_sidebar_item(webpage):

@frappe.whitelist()
def delete_lesson(lesson, chapter):
frappe.db.delete("Lesson Reference", {"parent": chapter, "lesson": lesson})
# Delete Reference
chapter = frappe.get_doc("Course Chapter", chapter)
chapter.lessons = [row for row in chapter.lessons if row.lesson != lesson]
chapter.save()

# Delete progress
frappe.db.delete("LMS Course Progress", {"lesson": lesson})

# Delete Lesson
frappe.db.delete("Course Lesson", lesson)


Expand Down Expand Up @@ -802,3 +810,67 @@ def get_announcements(batch):
],
order_by="communication_date desc",
)


@frappe.whitelist()
def delete_course(course):

chapters = frappe.get_all("Course Chapter", {"course": course}, pluck="name")

chapter_references = frappe.get_all(
"Chapter Reference", {"parent": course}, pluck="name"
)

for chapter in chapters:
lessons = frappe.get_all("Course Lesson", {"chapter": chapter}, pluck="name")

lesson_references = frappe.get_all(
"Lesson Reference", {"parent": chapter}, pluck="name"
)

for lesson in lesson_references:
frappe.delete_doc("Lesson Reference", lesson)

for lesson in lessons:
frappe.db.delete("LMS Course Progress", {"lesson": lesson})

topics = frappe.get_all(
"Discussion Topic",
{"reference_doctype": "Course Lesson", "reference_docname": lesson},
pluck="name",
)

for topic in topics:
frappe.db.delete("Discussion Reply", {"topic": topic})

frappe.db.delete("Discussion Topic", topic)

frappe.delete_doc("Course Lesson", lesson)

for chapter in chapter_references:
frappe.delete_doc("Chapter Reference", chapter)

for chapter in chapters:
frappe.delete_doc("Course Chapter", chapter)

frappe.db.delete("LMS Enrollment", {"course": course})
frappe.delete_doc("LMS Course", course)


def give_dicussions_permission():
doctypes = ["Discussion Topic", "Discussion Reply"]
roles = ["LMS Student", "Course Creator", "Moderator", "Batch Evaluator"]
for doctype in doctypes:
for role in roles:
if not frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": role}):
frappe.get_doc(
{
"doctype": "Custom DocPerm",
"parent": doctype,
"role": role,
"read": 1,
"write": 1,
"create": 1,
"delete": 1,
}
).save(ignore_permissions=True)
23 changes: 20 additions & 3 deletions lms/lms/doctype/course_chapter/course_chapter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt

# import frappe
import frappe
from frappe.model.document import Document
from frappe.utils.telemetry import capture
from lms.lms.utils import get_course_progress
from lms.lms.api import update_course_statistics


class CourseChapter(Document):
pass
def on_update(self):
self.recalculate_course_progress()
update_course_statistics()

def recalculate_course_progress(self):
previous_lessons = (
self.get_doc_before_save() and self.get_doc_before_save().as_dict().lessons
)
current_lessons = self.lessons

if previous_lessons and previous_lessons != current_lessons:
enrolled_members = frappe.get_all(
"LMS Enrollment", {"course": self.course}, ["member", "name"]
)
for enrollment in enrolled_members:
new_progress = get_course_progress(self.course, enrollment.member)
frappe.db.set_value("LMS Enrollment", enrollment.name, "progress", new_progress)
13 changes: 8 additions & 5 deletions lms/lms/doctype/lms_quiz/lms_quiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,15 @@ def validate_open_ended_questions(self):
types = [question.type for question in self.questions]
types = set(types)

if "Open Ended" in types and len(types) > 1:
frappe.throw(
_(
"If you want open ended questions then make sure each question in the quiz is of open ended type."
if "Open Ended" in types:
if len(types) > 1:
frappe.throw(
_(
"If you want open ended questions then make sure each question in the quiz is of open ended type."
)
)
)
else:
self.show_answers = 0

def autoname(self):
if not self.name:
Expand Down
8 changes: 3 additions & 5 deletions lms/lms/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,6 @@ def first_lesson_exists(course):
return True


def redirect_to_courses_list():
frappe.local.flags.redirect_location = "/lms/courses"
raise frappe.Redirect


def has_course_instructor_role(member=None):
return frappe.db.get_value(
"Has Role",
Expand Down Expand Up @@ -1153,6 +1148,9 @@ def get_lesson(course, chapter, lesson):
lesson_details = frappe.db.get_value(
"Course Lesson", lesson_name, ["include_in_preview", "title"], as_dict=1
)
if not lesson_details:
return {}

membership = get_membership(course)
course_title = frappe.db.get_value("LMS Course", course, "title")
if (
Expand Down
3 changes: 2 additions & 1 deletion lms/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,5 @@ lms.patches.v2_0.fix_progress_percentage
lms.patches.v2_0.add_discussion_topic_titles
lms.patches.v2_0.sidebar_settings
lms.patches.v2_0.delete_certificate_request_notification #18-09-2024
lms.patches.v2_0.add_course_statistics #21-10-2024
lms.patches.v2_0.add_course_statistics #21-10-2024
lms.patches.v2_0.give_discussions_permissions
6 changes: 6 additions & 0 deletions lms/patches/v2_0/give_discussions_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import frappe
from lms.lms.api import give_dicussions_permission


def execute():
give_dicussions_permission()

0 comments on commit 08b2063

Please sign in to comment.