feat: students view for classes
This commit is contained in:
@@ -242,6 +242,10 @@ jinja = {
|
||||
# "lms.plugins.LiveCodeExtension"
|
||||
# ]
|
||||
|
||||
has_website_permission = {
|
||||
"LMS Certificate Evaluation": "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.has_website_permission"
|
||||
}
|
||||
|
||||
profile_mandatory_fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
|
||||
@@ -100,9 +100,10 @@ def delete_custom_fields():
|
||||
def add_pages_to_nav():
|
||||
pages = [
|
||||
{"label": "Courses", "url": "/courses", "parent": "Explore", "idx": 2},
|
||||
{"label": "Statistics", "url": "/statistics", "parent": "Explore", "idx": 3},
|
||||
{"label": "Jobs", "url": "/jobs", "parent": "Explore", "idx": 4},
|
||||
{"label": "People", "url": "/community", "parent": "Explore", "idx": 5},
|
||||
{"label": "Classes", "url": "/classes", "parent": "Explore", "idx": 3},
|
||||
{"label": "Statistics", "url": "/statistics", "parent": "Explore", "idx": 4},
|
||||
{"label": "Jobs", "url": "/jobs", "parent": "Explore", "idx": 5},
|
||||
{"label": "People", "url": "/community", "parent": "Explore", "idx": 6},
|
||||
]
|
||||
|
||||
if not frappe.db.exists("Top Bar Item", {"label": "Explore"}):
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from lms.lms.utils import has_course_moderator_role
|
||||
|
||||
|
||||
class LMSCertificateEvaluation(Document):
|
||||
pass
|
||||
|
||||
|
||||
def has_website_permission(doc, ptype, user, verbose=False):
|
||||
if has_course_moderator_role() or doc.member == frappe.session.user:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_lms_certificate(source_name, target_doc=None):
|
||||
doc = get_mapped_doc(
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"description",
|
||||
"section_break_6",
|
||||
"students",
|
||||
"courses"
|
||||
"courses",
|
||||
"custom_component"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -61,11 +62,18 @@
|
||||
"fieldtype": "Date",
|
||||
"label": "Start Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"description": "The HTML code entered here will be displayed on the class details page.",
|
||||
"fieldname": "custom_component",
|
||||
"fieldtype": "Code",
|
||||
"label": "Custom Component",
|
||||
"options": "HTML"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-11-21 10:55:50.067225",
|
||||
"modified": "2022-11-25 10:37:24.250557",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Class",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"list_columns": [],
|
||||
"login_required": 1,
|
||||
"max_attachment_size": 0,
|
||||
"modified": "2022-11-23 14:57:47.700695",
|
||||
"modified": "2022-11-25 17:05:30.851109",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "evaluation",
|
||||
@@ -29,7 +29,7 @@
|
||||
"published": 1,
|
||||
"route": "evaluation",
|
||||
"show_attachments": 0,
|
||||
"show_list": 1,
|
||||
"show_list": 0,
|
||||
"show_sidebar": 0,
|
||||
"title": "Evaluation",
|
||||
"web_form_fields": [
|
||||
@@ -146,4 +146,4 @@
|
||||
"show_in_filter": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from lms.lms.utils import has_course_moderator_role
|
||||
|
||||
|
||||
def get_context(context):
|
||||
|
||||
if not has_course_moderator_role():
|
||||
message = "Only Moderators have access to this page."
|
||||
if frappe.session.user == "Guest":
|
||||
message = "Please login to access this page."
|
||||
|
||||
raise frappe.PermissionError(_(message))
|
||||
pass
|
||||
|
||||
@@ -36,6 +36,6 @@ lms.patches.v0_0.set_dashboard #11-10-2022
|
||||
lms.patches.v0_0.set_courses_page_as_home
|
||||
lms.patches.v0_0.set_member_in_progress #09-11-2022
|
||||
lms.patches.v0_0.convert_progress_to_float
|
||||
lms.patches.v0_0.add_pages_to_nav #11-11-2022
|
||||
lms.patches.v0_0.add_pages_to_nav #25-11-2022
|
||||
lms.patches.v0_0.change_role_names
|
||||
lms.patches.v0_0.quiz_submission_result
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
<div class="form-group">
|
||||
<label> {{ _("Result") }} </label>
|
||||
<div class="control-input flex align-center form-control">
|
||||
<select class="input-with-feedback form-control pl-0" id="result" data-type="{{ assignment.status }}">
|
||||
<select class="input-with-feedback form-control pl-0" id="result"
|
||||
{% if not is_moderator %} disabled {% endif %} data-type="{{ assignment.status }}">
|
||||
<option selected> {{ _("Not Graded") }} </option>
|
||||
<option value="Pass"> {{ _("Pass") }} </option>
|
||||
<option value="Fail"> {{ _("Fail") }} </option>
|
||||
@@ -61,7 +62,8 @@
|
||||
|
||||
<div class="form-group col-md-6">
|
||||
<label>{{ _("Comments") }}</label>
|
||||
<textarea class="form-control" id="comments">{% if assignment.comments %}{{ assignment.comments }}{% endif %}</textarea>
|
||||
<textarea class="form-control" id="comments" {% if not is_moderator %} disabled readonly {% endif %}
|
||||
>{% if assignment.comments %}{{ assignment.comments }}{% endif %}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,16 +7,29 @@ def get_context(context):
|
||||
context.no_cache = 1
|
||||
assignment = frappe.form_dict["assignment"]
|
||||
|
||||
if not has_course_moderator_role():
|
||||
message = "Only Moderators have access to this page."
|
||||
context.assignment = frappe.db.get_value(
|
||||
"Lesson Assignment",
|
||||
assignment,
|
||||
[
|
||||
"assignment",
|
||||
"comments",
|
||||
"status",
|
||||
"name",
|
||||
"member",
|
||||
"member_name",
|
||||
"course",
|
||||
"lesson",
|
||||
],
|
||||
as_dict=True,
|
||||
)
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
|
||||
if (
|
||||
not has_course_moderator_role()
|
||||
and not frappe.session.user == context.assignment.member
|
||||
):
|
||||
message = "You don't have the permissions to access this page."
|
||||
if frappe.session.user == "Guest":
|
||||
message = "Please login to access this page."
|
||||
|
||||
raise frappe.PermissionError(_(message))
|
||||
|
||||
context.assignment = frappe.db.get_value(
|
||||
"Lesson Assignment",
|
||||
assignment,
|
||||
["assignment", "comments", "status", "name", "member_name", "course", "lesson"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if class_info.custom_component %}
|
||||
{{ class_info.custom_component }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -94,7 +97,8 @@
|
||||
{% for course in published_courses %}
|
||||
{% set checked = course.name in class_courses %}
|
||||
<label class="class-course" data-course="{{ course.name }}">
|
||||
<input type="checkbox" {% if checked %} checked {% endif %}>
|
||||
<input type="checkbox" {% if checked %} checked {% endif %}
|
||||
{% if not is_moderator %} disabled {% endif %}>
|
||||
{{ course.title }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
@@ -105,10 +109,12 @@
|
||||
|
||||
{% macro StudentsSection(class_info, class_students) %}
|
||||
<div class="medium">
|
||||
{% if is_moderator %}
|
||||
{{ AddStudents() }}
|
||||
{% endif %}
|
||||
|
||||
{% if class_students | length %}
|
||||
<table class="table mt-10">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th style="width: 70%">
|
||||
{{ _("Student") }}
|
||||
@@ -116,7 +122,9 @@
|
||||
<th style="width: 20%">
|
||||
{{ _("Last Active") }}
|
||||
</th>
|
||||
{% if is_moderator %}
|
||||
<th style="width: 10%"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for student in class_students %}
|
||||
{% set last_active = frappe.db.get_value("User", student.student, "last_active") %}
|
||||
@@ -129,11 +137,13 @@
|
||||
<td>
|
||||
{{ frappe.utils.format_datetime(last_active, "medium") }}
|
||||
</td>
|
||||
{% if is_moderator %}
|
||||
<td>
|
||||
<svg class="icon icon-md pull-right remove-student" data-student="{{ student.student }}">
|
||||
<use href="#icon-delete"></use>
|
||||
</svg>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -147,7 +157,7 @@
|
||||
|
||||
|
||||
{% macro AddStudents() %}
|
||||
<div>
|
||||
<div class="mb-10">
|
||||
<div class="mb-2">
|
||||
{{ _("Add Student") }}
|
||||
</div>
|
||||
@@ -158,7 +168,9 @@
|
||||
spellcheck="false">
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm" id="submit-student"> {{ _("Add") }} </button>
|
||||
<button class="btn btn-primary btn-sm" id="submit-student">
|
||||
{{ _("Add") }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -5,20 +5,12 @@ from frappe import _
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
|
||||
if not has_course_moderator_role():
|
||||
message = "Only Moderators have access to this page."
|
||||
if frappe.session.user == "Guest":
|
||||
message = "Please login to access this page."
|
||||
|
||||
raise frappe.PermissionError(_(message))
|
||||
|
||||
class_name = frappe.form_dict["classname"]
|
||||
|
||||
context.class_info = frappe.db.get_value(
|
||||
"LMS Class",
|
||||
class_name,
|
||||
["name", "title", "start_date", "end_date", "description"],
|
||||
["name", "title", "start_date", "end_date", "description", "custom_component"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
@@ -33,3 +25,5 @@ def get_context(context):
|
||||
context.class_students = frappe.get_all(
|
||||
"Class Student", {"parent": class_name}, ["student", "student_name", "username"]
|
||||
)
|
||||
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
{% block content %}
|
||||
<div class="common-page-style">
|
||||
<div class="container">
|
||||
{% if has_course_moderator_role() %}
|
||||
<a class="btn btn-default btn-sm pull-right" href="/class/new">
|
||||
{{ _("Create Class") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="course-home-headings"> {{ _("All Classes") }} </div>
|
||||
{% if classes %}
|
||||
{{ ClassCards(classes) }}
|
||||
@@ -63,4 +65,4 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
import frappe
|
||||
from lms.lms.utils import has_course_moderator_role
|
||||
from frappe import _
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
|
||||
if not has_course_moderator_role():
|
||||
message = "Only Moderators have access to this page."
|
||||
if frappe.session.user == "Guest":
|
||||
message = "Please login to access this page."
|
||||
|
||||
raise frappe.PermissionError(_(message))
|
||||
|
||||
context.classes = frappe.get_all(
|
||||
"LMS Class", fields=["name", "title", "start_date", "end_date"]
|
||||
)
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
<span>
|
||||
{{ frappe.utils.format_datetime(student.last_active, "medium") }}
|
||||
</span>
|
||||
{% if is_moderator %}
|
||||
<a class="btn btn-secondary btn-sm ml-3" href="/evaluation/new?member={{student.name}}&date={{frappe.utils.getdate()}}">
|
||||
{{ _("Evaluate") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="course-home-headings">
|
||||
{{ student.full_name }}
|
||||
@@ -55,7 +57,7 @@
|
||||
<div class="ml-3"> {{ frappe.utils.cint(course.membership.progress) }}% </div>
|
||||
</div>
|
||||
|
||||
{% if course.quizzes | length or course.assignments | length %}
|
||||
{% if course.quizzes | length or course.assignments | length or course.evaluations | length %}
|
||||
<div class="my-5">
|
||||
<table class="table">
|
||||
<tr>
|
||||
@@ -73,90 +75,10 @@
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
{% for quiz in course.quizzes %}
|
||||
{% set filters = { "member": student.name, "course": course.course } %}
|
||||
{% set has_submitted = frappe.db.exists("LMS Quiz Submission", filters) %}
|
||||
{% set submission = frappe.db.get_value("LMS Quiz Submission", filters, ["score", "creation"], as_dict=True) %}
|
||||
{% set total_questions = frappe.db.count("LMS Quiz Question", {"parent": quiz.name}) %}
|
||||
{{ Quiz(course, student) }}
|
||||
{{ Assignment(course, student, is_moderator) }}
|
||||
{{ Evaluation(course, student, is_moderator) }}
|
||||
|
||||
<tr>
|
||||
<td class="vertically-center">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-quiz"></use>
|
||||
</svg>
|
||||
{{ _("Quiz") }}
|
||||
</td>
|
||||
<td>{{ quiz.title }}</td>
|
||||
{% if has_submitted %}
|
||||
<td>{{ submission.score }}/{{ total_questions }}</td>
|
||||
<td>{{ frappe.utils.format_date(submission.creation, "medium") }}</td>
|
||||
{% else %}
|
||||
<td>-</td>
|
||||
<td>
|
||||
<div class="indicator-pill red">
|
||||
{{ _("Not Attempted") }}
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% for assignment in course.assignments %}
|
||||
{% set filters = { "member": student.name, "course": course.course, "lesson": assignment.name } %}
|
||||
{% set has_submitted = frappe.db.exists("Lesson Assignment", filters) %}
|
||||
{% set submission = frappe.db.get_value("Lesson Assignment", filters, ["assignment", "creation", "status"], as_dict=True) %}
|
||||
{% set status = submission.status %}
|
||||
{% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %}
|
||||
|
||||
<tr {% if has_submitted %} class="clickable-row" data-href="/assignments/{{ has_submitted }}" {% endif %}>
|
||||
<td class="{% if has_submitted %} subheading {% endif %} vertically-center">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-file"></use>
|
||||
</svg>
|
||||
{{ _("Assignment") }}
|
||||
</td>
|
||||
|
||||
<td>{{ assignment.title }}</td>
|
||||
|
||||
{% if has_submitted %}
|
||||
<td>
|
||||
<div class="indicator-pill {{ color }}">
|
||||
{{ status }}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>{{ frappe.utils.format_date(submission.creation, "medium") }}</td>
|
||||
|
||||
{% else %}
|
||||
<td>-</td>
|
||||
|
||||
<td>
|
||||
<div class="indicator-pill red">
|
||||
{{ _("Not Attempted") }}
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% for evaluation in course.evaluations %}
|
||||
{% set color = "green" if evaluation.status == "Pass" else "red" %}
|
||||
<tr class="clickable-row" data-href="/evaluation/{{evaluation.name}}">
|
||||
<td class="subheading vertically-center">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-quality"></use>
|
||||
</svg>
|
||||
{{ _("Evaluation") }}
|
||||
</td>
|
||||
<td> - </td>
|
||||
<td>
|
||||
<div class="indicator-pill {{ color }}">
|
||||
{{ evaluation.status }}
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ frappe.utils.format_date(evaluation.creation, "medium") }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
@@ -168,3 +90,100 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro Quiz(course, student) %}
|
||||
{% for quiz in course.quizzes %}
|
||||
{% set filters = { "member": student.name, "course": course.course } %}
|
||||
{% set has_submitted = frappe.db.exists("LMS Quiz Submission", filters) %}
|
||||
{% set submission = frappe.db.get_value("LMS Quiz Submission", filters, ["score", "creation"], as_dict=True) %}
|
||||
{% set total_questions = frappe.db.count("LMS Quiz Question", {"parent": quiz.name}) %}
|
||||
|
||||
<tr>
|
||||
<td class="vertically-center">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-quiz"></use>
|
||||
</svg>
|
||||
{{ _("Quiz") }}
|
||||
</td>
|
||||
<td>{{ quiz.title }}</td>
|
||||
{% if has_submitted %}
|
||||
<td>{{ submission.score }}/{{ total_questions }}</td>
|
||||
<td>{{ frappe.utils.format_date(submission.creation, "medium") }}</td>
|
||||
{% else %}
|
||||
<td>-</td>
|
||||
<td>
|
||||
<div class="indicator-pill red">
|
||||
{{ _("Not Attempted") }}
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro Assignment(course, student, is_moderator) %}
|
||||
{% for assignment in course.assignments %}
|
||||
{% set filters = { "member": student.name, "course": course.course, "lesson": assignment.name } %}
|
||||
{% set has_submitted = frappe.db.exists("Lesson Assignment", filters) %}
|
||||
{% set submission = frappe.db.get_value("Lesson Assignment", filters, ["assignment", "creation", "status"], as_dict=True) %}
|
||||
{% set status = submission.status %}
|
||||
{% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %}
|
||||
{% set can_see_details = has_submitted and (is_moderator or frappe.session.user == student.name) %}
|
||||
|
||||
<tr {% if can_see_details %} class="clickable-row" data-href="/assignments/{{ has_submitted }}" {% endif %}>
|
||||
<td class="{% if can_see_details %} subheading {% endif %} vertically-center">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-file"></use>
|
||||
</svg>
|
||||
{{ _("Assignment") }}
|
||||
</td>
|
||||
|
||||
<td>{{ assignment.title }}</td>
|
||||
|
||||
{% if has_submitted %}
|
||||
<td>
|
||||
<div class="indicator-pill {{ color }}">
|
||||
{{ status }}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>{{ frappe.utils.format_date(submission.creation, "medium") }}</td>
|
||||
|
||||
{% else %}
|
||||
<td>-</td>
|
||||
|
||||
<td>
|
||||
<div class="indicator-pill red">
|
||||
{{ _("Not Attempted") }}
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro Evaluation(course, student, is_moderator) %}
|
||||
{% for evaluation in course.evaluations %}
|
||||
{% set color = "green" if evaluation.status == "Pass" else "red" %}
|
||||
{% set can_see_details = is_moderator or frappe.session.user == student.name %}
|
||||
|
||||
<tr {% if can_see_details %} class="clickable-row" data-href="/evaluation/{{evaluation.name}}" {% endif %}>
|
||||
<td class="{% if can_see_details %} subheading {% endif %} vertically-center">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-quality"></use>
|
||||
</svg>
|
||||
{{ _("Evaluation") }}
|
||||
</td>
|
||||
<td> - </td>
|
||||
<td>
|
||||
<div class="indicator-pill {{ color }}">
|
||||
{{ evaluation.status }}
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ frappe.utils.format_date(evaluation.creation, "medium") }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -6,15 +6,9 @@ from frappe import _
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
|
||||
if not has_course_moderator_role():
|
||||
message = "Only Moderators have access to this page."
|
||||
if frappe.session.user == "Guest":
|
||||
message = "Please login to access this page."
|
||||
|
||||
raise frappe.PermissionError(_(message))
|
||||
|
||||
student = frappe.form_dict["username"]
|
||||
classname = frappe.form_dict["classname"]
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
|
||||
context.student = frappe.db.get_value(
|
||||
"User",
|
||||
|
||||
0
lms/www/quiz_result/__init__.py
Normal file
0
lms/www/quiz_result/__init__.py
Normal file
Reference in New Issue
Block a user