feat: student progress

This commit is contained in:
Jannat Patel
2022-11-16 18:43:10 +05:30
parent ae2c15fe8c
commit a4ec058a81
11 changed files with 211 additions and 50 deletions

View File

@@ -159,7 +159,8 @@ website_route_rules = [
{"from_route": "/users", "to_route": "profiles/profile"}, {"from_route": "/users", "to_route": "profiles/profile"},
{"from_route": "/jobs/<job>", "to_route": "jobs/job"}, {"from_route": "/jobs/<job>", "to_route": "jobs/job"},
{"from_route": "/classes/<classname>/students/<username>", {"from_route": "/classes/<classname>/students/<username>",
"to_route": "/classes/progress"} "to_route": "/classes/progress"},
{"from_route": "/assignments/<assignment>", "to_route": "assignments/assignment"}
] ]
website_redirects = [ website_redirects = [

View File

@@ -9,9 +9,11 @@
"assignment", "assignment",
"lesson", "lesson",
"course", "course",
"status",
"column_break_3", "column_break_3",
"member", "member",
"member_name" "member_name",
"comments"
], ],
"fields": [ "fields": [
{ {
@@ -59,12 +61,24 @@
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Course", "label": "Course",
"read_only": 1 "read_only": 1
},
{
"default": "Not Graded",
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Pass\nFail\nNot Graded"
},
{
"fieldname": "comments",
"fieldtype": "Small Text",
"label": "Comments"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"make_attachments_public": 1, "make_attachments_public": 1,
"modified": "2022-10-31 13:18:09.609729", "modified": "2022-11-16 12:11:59.472025",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Lesson Assignment", "name": "Lesson Assignment",
@@ -85,6 +99,19 @@
], ],
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"states": [], "states": [
{
"color": "Green",
"title": "Pass"
},
{
"color": "Orange",
"title": "Not Graded"
},
{
"color": "Red",
"title": "Fail"
}
],
"title_field": "lesson" "title_field": "lesson"
} }

View File

@@ -12,7 +12,7 @@ class LessonAssignment(Document):
def validate_duplicates(self): def validate_duplicates(self):
if frappe.db.exists( if frappe.db.exists(
"Lesson Assignment", {"lesson": self.lesson, "member": self.member} "Lesson Assignment", {"lesson": self.lesson, "member": self.member, "name": ["!=", self.name]}
): ):
lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title") lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title")
frappe.throw( frappe.throw(

View File

@@ -152,7 +152,7 @@ def assignment_renderer(detail):
file_type = detail.split("-")[1] file_type = detail.split("-")[1]
accept = supported_types[file_type] if file_type else "" accept = supported_types[file_type] if file_type else ""
return frappe.render_template( return frappe.render_template(
"templates/assignment.html", {"question": question, "accept": accept} "templates/assignment.html", {"question": question, "accept": accept, "file_type": file_type}
) )

View File

@@ -1841,10 +1841,8 @@ select {
.progress-course-header { .progress-course-header {
display: flex; display: flex;
justify-content: space-between;
background-color: var(--gray-100); background-color: var(--gray-100);
padding: 0.5rem; padding: 0.5rem;
border-radius: var(--border-radius-sm);
} }
.section-heading { .section-heading {
@@ -1852,3 +1850,9 @@ select {
color: var(--gray-900); color: var(--gray-900);
font-weight: 500; font-weight: 500;
} }
.table th {
color: var(--gray-900);
font-weight: 500;
border-bottom: 1px solid var(--gray-300);
}

View File

@@ -1,12 +1,15 @@
<div class="form-group"> <div class="form-group">
<div class=""> <div class="">
<h3> {{ _("Assignment") }} </h3> <h3> {{ _("Assignment") }} </h3>
<div class="my-3"> {{ _(question) }} </div> <div class="my-3"> {{ _(question) }} </div>
<input class="btn btn-default btn-sm border attach-file" type="file" accept="{{ accept }}" /> <div class="alert alert-info small">
<div class="btn btn-secondary ml-2 submit-work">{{ _("Submit") }}</div> {{ _("Only files of type {0} will be accepted").format(file_type) }}
<div class="preview-work hide"> </div>
<a target="_blank"></a> <input class="btn btn-default btn-sm border attach-file" type="file" accept="{{ accept }}" />
<div class="btn btn-secondary btn-sm ml-2 clear-work">{{ _("Change") }}</div> <div class="btn btn-secondary ml-2 submit-work">{{ _("Submit") }}</div>
</div> <div class="preview-work hide">
</div> <a target="_blank"></a>
<div class="btn btn-secondary btn-sm ml-2 clear-work">{{ _("Change") }}</div>
</div>
</div>
</div> </div>

View File

@@ -0,0 +1,36 @@
{% extends "templates/base.html" %}
{% block title %}
{{ _("Assignments") }}
{% endblock %}
{% block content %}
<div class="common-page-style">
<div class="container">
<div class="common-card-style column-card">
<div class="btn btn-primary btn-sm pull-right" id="save-assignment"> {{ _("Save") }} </div>
<div class="course-home-headings"> {{ _("Assignments") }} </div>
<div class="row medium">
<div class="col">
<div>
<a href="{{ assignment.assignment }}" target="_blank">
{{ _("Click to open assignment") }}
</a>
</div>
<div>
<select class="btn btn-default ml-2" id="file-type" data-type="{{ assignment.status }}">
<option selected> {{ _("Result") }} </option>
<option value="Image"> {{ _("Pass") }} </option>
<option value="Document"> {{ _("Fail") }} </option>
</select>
</div>
</div>
<div class="col">
<div contenteditable="true" data-placeholder="{{ _('Comments') }}"
style="height: 100px;" >{% if assignment.comments %}{{ assignment.comments }}{% endif %}</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,16 @@
import frappe
from lms.lms.utils import has_course_moderator_role
from frappe import _
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."
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"], as_dict=True)

View File

@@ -1,6 +1,7 @@
import frappe import frappe
from lms.lms.utils import has_course_moderator_role from lms.lms.utils import has_course_moderator_role
from frappe import _ from frappe import _
from lms.lms.utils import has_course_moderator_role
def get_context(context): def get_context(context):

View File

@@ -36,40 +36,106 @@
<div class="medium"> <div class="medium">
<div class="progress-course-header"> <div class="progress-course-header">
<div class="section-heading"> {{ course.title }} </div> <div class="section-heading"> {{ course.title }} </div>
<div> {{ frappe.utils.cint(course.membership.progress) }}% </div> <div class="ml-3"> {{ frappe.utils.cint(course.membership.progress) }}% </div>
</div> </div>
{% if course.quizzes | length or course.assignments | length %}
{% for quiz in course.quizzes %}
{% set filters = { "member": student.name, "course": course.course } %}
{% set submitted = frappe.db.exists("LMS Quiz Submission", filters) %}
{% set score = frappe.db.get_value("LMS Quiz Submission", filters, ["score"]) %}
<div class="my-5"> <div class="my-5">
<div class="subheading"> {{ _("Quiz") }}: </div> <table class="table">
<div class="d-flex"> <tr>
<div> <th style="width: 40%;">
{{ quiz.title }} {{ _("Activity") }}
</div> </th>
{% if submitted %} <th style="width: 20%;">
<div class="ml-5"> {{ _("Type") }}
{{ score }} </th>
</div> <th style="width: 20%;">
{% else %} {{ _("Score/Status") }}
<div class="indicator-pill red ml-5"> </th>
Not Attempted <th style="width: 20%;">
</div> {{ _("Last Attempt Date") }}
{% endif %} </th>
</div> </tr>
</div> {% for quiz in course.quizzes %}
{% endfor %} {% set filters = { "member": student.name, "course": course.course } %}
{% for quiz in class_courses.assignments %} {% set has_submitted = frappe.db.exists("LMS Quiz Submission", filters) %}
<div> {% set submission = frappe.db.get_value("LMS Quiz Submission", filters, ["score", "creation"], as_dict=True) %}
{{ assignments.assignment }}
<tr class="">
<td>
{{ quiz.title }}
</td>
<td>
{{ _("Quiz") }}
</td>
{% if has_submitted %}
<td>
{{ submission.score }}
</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>
<td>
{{ assignment.title }}
</td>
<td>
{{ _("Assignment") }}
</td>
{% if has_submitted %}
<td>
{% if status == "Not Graded" %}
<a class="btn btn-secondary btn-sm" href="/assignments/{{ has_submitted }}"> {{ _("Grade") }} </a>
{% else %}
<div class="indicator-pill {{ color }}">
{{ status }}
</div>
{% endif %}
</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 %}
</table>
</div> </div>
{% endfor %} {% else %}
<div class="text-muted medium my-5">
{{ _("There are no activities in this course.") }}
</div>
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -1,9 +1,17 @@
import frappe import frappe
from lms.lms.utils import has_course_moderator_role
from frappe import _
def get_context(context): def get_context(context):
context.no_cache = 1 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"] student = frappe.form_dict["username"]
classname = frappe.form_dict["classname"] classname = frappe.form_dict["classname"]
@@ -20,7 +28,6 @@ def get_context(context):
"course": course.course "course": course.course
}, ["progress"], as_dict=True) }, ["progress"], as_dict=True)
course.quizzes = frappe.get_all("LMS Quiz", {"course": course.course}, ["name", "title"]) course.quizzes = frappe.get_all("LMS Quiz", {"course": course.course}, ["name", "title"])
course.assignments = frappe.get_all("Lesson Assignment", {"course": course.course}, ["name", "assignment"]) course.assignments = frappe.get_all("Course Lesson", {"course": course.course, "question": ["is", "set"]}, ["name", "title"])
print(class_courses)
context.class_courses = class_courses context.class_courses = class_courses