Merge pull request #116 from fossunited/reindex-exercises

feat: actions to reindex lessons and exercises
This commit is contained in:
Jannat Patel
2021-06-01 11:40:52 +05:30
committed by GitHub
10 changed files with 114 additions and 14 deletions

View File

@@ -10,6 +10,6 @@ class Chapter(Document):
def get_lessons(self): def get_lessons(self):
rows = frappe.db.get_all("Lesson", rows = frappe.db.get_all("Lesson",
filters={"chapter": self.name}, filters={"chapter": self.name},
fields='*', fields='name',
order_by="index_") order_by="index_")
return [frappe.get_doc(dict(row, doctype='Lesson')) for row in rows] return [frappe.get_doc('Lesson', row['name']) for row in rows]

View File

@@ -15,7 +15,9 @@
"hints", "hints",
"tests", "tests",
"image", "image",
"lesson" "lesson",
"index_",
"index_label"
], ],
"fields": [ "fields": [
{ {
@@ -27,6 +29,7 @@
{ {
"fieldname": "course", "fieldname": "course",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1,
"label": "Course", "label": "Course",
"options": "LMS Course" "options": "LMS Course"
}, },
@@ -73,13 +76,27 @@
{ {
"fieldname": "lesson", "fieldname": "lesson",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1,
"label": "Lesson", "label": "Lesson",
"options": "Lesson" "options": "Lesson"
},
{
"fieldname": "index_",
"fieldtype": "Int",
"label": "Index",
"read_only": 1
},
{
"fieldname": "index_label",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Index Label",
"read_only": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-05-20 13:23:12.340928", "modified": "2021-06-01 05:22:15.656013",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Exercise", "name": "Exercise",
@@ -99,8 +116,8 @@
} }
], ],
"search_fields": "title", "search_fields": "title",
"sort_field": "modified", "sort_field": "index_label",
"sort_order": "DESC", "sort_order": "ASC",
"title_field": "title", "title_field": "title",
"track_changes": 1 "track_changes": 1
} }

View File

@@ -25,7 +25,6 @@ class Exercise(Document):
order_by="creation desc", order_by="creation desc",
page_length=1) page_length=1)
print("get_user_submission", result)
if result: if result:
return result[0] return result[0]

View File

@@ -10,6 +10,7 @@
"lesson_type", "lesson_type",
"title", "title",
"index_", "index_",
"index_label",
"body", "body",
"sections" "sections"
], ],
@@ -51,11 +52,18 @@
"fieldtype": "Table", "fieldtype": "Table",
"label": "Sections", "label": "Sections",
"options": "LMS Section" "options": "LMS Section"
},
{
"fieldname": "index_label",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Index Label",
"read_only": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-05-13 20:03:51.510605", "modified": "2021-06-01 05:30:48.127494",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Lesson", "name": "Lesson",

View File

@@ -16,10 +16,28 @@ class Lesson(Document):
e = s.get_exercise() e = s.get_exercise()
e.lesson = self.name e.lesson = self.name
e.save() e.save()
self.update_orphan_exercises()
def update_orphan_exercises(self):
"""Updates the exercises that were previously part of this lesson,
but not any more.
"""
linked_exercises = {row['name'] for row in frappe.get_all('Exercise', {"lesson": self.name})}
active_exercises = {s.id for s in self.get("sections") if s.type=="exercise"}
orphan_exercises = linked_exercises - active_exercises
for name in orphan_exercises:
ex = frappe.get_doc("Exercise", name)
ex.lesson = None
ex.index_ = 0
ex.index_label = ""
ex.save()
def get_sections(self): def get_sections(self):
return sorted(self.get('sections'), key=lambda s: s.index) return sorted(self.get('sections'), key=lambda s: s.index)
def get_exercises(self):
return [frappe.get_doc("Exercise", s.id) for s in self.get("sections") if s.type=="exercise"]
def make_lms_section(self, index, section): def make_lms_section(self, index, section):
s = frappe.new_doc('LMS Section', parent_doc=self, parentfield='sections') s = frappe.new_doc('LMS Section', parent_doc=self, parentfield='sections')
s.type = section.type s.type = section.type

View File

@@ -1,5 +1,18 @@
{ {
"actions": [], "actions": [
{
"action": "community.lms.doctype.lms_course.lms_course.reindex_lessons",
"action_type": "Server Action",
"group": "Reindex",
"label": "Reindex Lessons"
},
{
"action": "community.lms.doctype.lms_course.lms_course.reindex_exercises",
"action_type": "Server Action",
"group": "Reindex",
"label": "Reindex Exercises"
}
],
"allow_guest_to_view": 1, "allow_guest_to_view": 1,
"allow_rename": 1, "allow_rename": 1,
"creation": "2021-03-01 16:49:33.622422", "creation": "2021-03-01 16:49:33.622422",
@@ -86,7 +99,7 @@
"link_fieldname": "course" "link_fieldname": "course"
} }
], ],
"modified": "2021-05-23 18:14:32.602647", "modified": "2021-06-01 04:36:45.696776",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Course", "name": "LMS Course",

View File

@@ -5,6 +5,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
import json
from ...utils import slugify from ...utils import slugify
from community.query import find, find_all from community.query import find, find_all
@@ -157,6 +158,35 @@ class LMSCourse(Document):
chapter = frappe.get_doc("Chapter", lesson.chapter) chapter = frappe.get_doc("Chapter", lesson.chapter)
return f"{chapter.index_}.{lesson.index_}" return f"{chapter.index_}.{lesson.index_}"
def reindex_lessons(self):
for i, c in enumerate(self.get_chapters(), start=1):
c.index_ = i
c.save()
self._reindex_lessons_in_chapter(c)
def _reindex_lessons_in_chapter(self, c):
for i, lesson in enumerate(c.get_lessons(), start=1):
lesson.index = i
lesson.index_label = f"{c.index_}.{i}"
lesson.save()
def reindex_exercises(self):
for i, c in enumerate(self.get_chapters(), start=1):
if c.index_ != i:
c.index_ = i
c.save()
self._reindex_exercises_in_chapter(c)
def _reindex_exercises_in_chapter(self, c):
i = 1
for lesson in c.get_lessons():
for exercise in lesson.get_exercises():
exercise.index_ = i
exercise.index_label = f"{c.index_}.{i}"
exercise.save()
i += 1
def get_outline(self): def get_outline(self):
return CourseOutline(self) return CourseOutline(self)
@@ -187,7 +217,8 @@ class CourseOutline:
def get_chapters(self): def get_chapters(self):
return frappe.db.get_all("Chapter", return frappe.db.get_all("Chapter",
filters={"course": self.course.name}, filters={"course": self.course.name},
fields=["name", "title", "index_"]) fields=["name", "title", "index_"],
order_by="index_")
def get_lessons(self): def get_lessons(self):
chapters = [c['name'] for c in self.chapters] chapters = [c['name'] for c in self.chapters]
@@ -199,3 +230,17 @@ class CourseOutline:
for lesson in lessons: for lesson in lessons:
lesson['number'] = "{}.{}".format(chapter_numbers[lesson['chapter']], lesson['index_']) lesson['number'] = "{}.{}".format(chapter_numbers[lesson['chapter']], lesson['index_'])
return lessons return lessons
@frappe.whitelist()
def reindex_lessons(doc):
course_data = json.loads(doc)
course = frappe.get_doc("LMS Course", course_data['name'])
course.reindex_lessons()
frappe.msgprint("All lessons in this course have been re-indexed.")
@frappe.whitelist()
def reindex_exercises(doc):
course_data = json.loads(doc)
course = frappe.get_doc("LMS Course", course_data['name'])
course.reindex_exercises()
frappe.msgprint("All exercises in this course have been re-indexed.")

View File

@@ -1,7 +1,7 @@
{% from "www/macros/livecode.html" import LiveCodeEditorJS, LiveCodeEditor with context %} {% from "www/macros/livecode.html" import LiveCodeEditorJS, LiveCodeEditor with context %}
<div class="exercise"> <div class="exercise">
<h2>{{ exercise.title }}</h2> <h2>Exercise {{exercise.index_label}}: {{ exercise.title }}</h2>
<div class="exercise-description">{{frappe.utils.md_to_html(exercise.description)}}</div> <div class="exercise-description">{{frappe.utils.md_to_html(exercise.description)}}</div>
{% if exercise.image %} {% if exercise.image %}

View File

@@ -29,7 +29,7 @@
<h1>Batch Progress</h1> <h1>Batch Progress</h1>
{% for exercise in report.exercises %} {% for exercise in report.exercises %}
<div class="exercise-submissions"> <div class="exercise-submissions">
<h2>{{exercise.title}}</h2> <h2>Exercise {{exercise.index_label}}: {{exercise.title}}</h2>
{% for s in report.get_submissions_of_exercise(exercise.name) %} {% for s in report.get_submissions_of_exercise(exercise.name) %}
<div class="submission"> <div class="submission">
<h4><a href="/{{s.owner.username}}">{{s.owner.full_name}}</a></h4> <h4><a href="/{{s.owner.username}}">{{s.owner.full_name}}</a></h4>

View File

@@ -25,7 +25,7 @@ class BatchReport:
self.submissions_by_exercise[s.exercise].append(s) self.submissions_by_exercise[s.exercise].append(s)
def get_exercises(self, course_name): def get_exercises(self, course_name):
return frappe.get_all("Exercise", {"course": course_name}, ["name", "title"]) return frappe.get_all("Exercise", {"course": course_name, "lesson": ["!=", ""]}, ["name", "title", "index_label"], order_by="index_label")
def get_submissions_of_exercise(self, exercise_name): def get_submissions_of_exercise(self, exercise_name):
return self.submissions_by_exercise[exercise_name] return self.submissions_by_exercise[exercise_name]