feat: added page to see progress of a batch
This commit is contained in:
@@ -147,6 +147,7 @@ primary_rules = [
|
||||
{"from_route": "/courses/<course>/<batch>/members", "to_route": "batch/members"},
|
||||
{"from_route": "/courses/<course>/<batch>/discuss", "to_route": "batch/discuss"},
|
||||
{"from_route": "/courses/<course>/<batch>/about", "to_route": "batch/about"},
|
||||
{"from_route": "/courses/<course>/<batch>/progress", "to_route": "batch/progress"}
|
||||
]
|
||||
|
||||
# Any frappe default URL is blocked by profile-rules, add it here to unblock it
|
||||
|
||||
52
community/www/batch/progress.html
Normal file
52
community/www/batch/progress.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% from "www/macros/livecode.html" import LiveCodeEditorJS, LiveCodeEditor with context %}
|
||||
{% block title %}{{ course.title }} - Batch Dashboard{% endblock %}
|
||||
|
||||
{% block head_include %}
|
||||
<meta name="description" content="{{course.title}} - Batch Dashboard" />
|
||||
<meta name="keywords" content="{{course.title}} - Batch Dashboard" />
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="{{ livecode_url }}/static/codemirror/lib/codemirror.css">
|
||||
<link rel="stylesheet" href="/assets/css/lms.css">
|
||||
|
||||
<script src="{{ livecode_url }}/static/codemirror/lib/codemirror.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/mode/python/python.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/keymap/sublime.js"></script>
|
||||
|
||||
<script src="{{ livecode_url }}/static/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/addon/comment/comment.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch) }}
|
||||
|
||||
<div class="container">
|
||||
<div class="mentor-dashboard">
|
||||
<h1>Batch Progress</h1>
|
||||
{% for exercise in report.exercises %}
|
||||
<div class="exercise-submissions">
|
||||
<h2>{{exercise.title}}</h2>
|
||||
{% for s in report.get_submissions_of_exercise(exercise.name) %}
|
||||
<div class="submission">
|
||||
<h4><a href="/{{s.owner.username}}">{{s.owner.full_name}}</a></h4>
|
||||
<div class="livecode-editor-small">
|
||||
{{ LiveCodeEditor(name=s.name, code=s.solution, reset_code=s.solution) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
{{ LiveCodeEditorJS() }}
|
||||
{% endblock %}
|
||||
64
community/www/batch/progress.py
Normal file
64
community/www/batch/progress.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import frappe
|
||||
from community.lms.models import Course
|
||||
from collections import defaultdict
|
||||
from . import utils
|
||||
|
||||
def get_context(context):
|
||||
utils.get_common_context(context)
|
||||
|
||||
exercise_name = frappe.form_dict.get("exercise")
|
||||
if exercise_name:
|
||||
exercise = frappe.get_doc("Exercise", exercise_name)
|
||||
else:
|
||||
exercise = None
|
||||
|
||||
context.exercise = exercise
|
||||
context.report = BatchReport(context.course, context.batch)
|
||||
|
||||
class BatchReport:
|
||||
def __init__(self, course, batch):
|
||||
self.submissions = get_submissions(batch)
|
||||
self.exercises = self.get_exercises(course.name)
|
||||
|
||||
self.submissions_by_exercise = defaultdict(list)
|
||||
for s in self.submissions:
|
||||
self.submissions_by_exercise[s.exercise].append(s)
|
||||
|
||||
def get_exercises(self, course_name):
|
||||
return frappe.get_all("Exercise", {"course": course_name}, ["name", "title"])
|
||||
|
||||
def get_submissions_of_exercise(self, exercise_name):
|
||||
return self.submissions_by_exercise[exercise_name]
|
||||
|
||||
def get_submissions(batch):
|
||||
students = batch.get_students()
|
||||
students_map = {s['email']: s for s in students}
|
||||
|
||||
names, values = nparams("s", students_map.keys())
|
||||
|
||||
sql = """
|
||||
select owner, exercise, name, solution, creation, image
|
||||
from (
|
||||
select owner, exercise, name, solution, creation, image,
|
||||
row_number() over (partition by owner, exercise order by creation desc) as ix
|
||||
from `tabExercise Submission`) as t
|
||||
where t.ix=1 and owner IN {}
|
||||
""".format(names)
|
||||
|
||||
data = frappe.db.sql(sql, values=values, as_dict=True)
|
||||
|
||||
for row in data:
|
||||
row['owner'] = students_map[row['owner']]
|
||||
return data
|
||||
|
||||
def nparams(name, values):
|
||||
"""Creates n paramters from a list of values for a db query.
|
||||
|
||||
>>> nparams("name", ["a", "b])
|
||||
("(%(name_1)s, %(name_2)s)", {"name_1": "a", "name_2": "b"})
|
||||
"""
|
||||
keys = [f"{name}_{i}" for i, _ in enumerate(values, start=1)]
|
||||
param_names = [f"%({k})s" for k in keys]
|
||||
param_values = dict(zip(keys, values))
|
||||
joined_names = "(" + ", ".join(param_names) + ")"
|
||||
return joined_names, param_values
|
||||
@@ -7,5 +7,8 @@
|
||||
<a href="/courses/{{course.name}}/{{batch.name}}/members"><i class="fa fa-users fa-lg"></i></a>
|
||||
<a href="/courses/{{course.name}}/{{batch.name}}/discuss"><i class="fa fa-comments fa-lg"></i></a>
|
||||
<a href="/courses/{{course.name}}/{{batch.name}}/about"><i class="fa fa-info-circle fa-lg"></i></a>
|
||||
{% if batch.is_member(frappe.session.user, member_type="Mentor") %}
|
||||
<a href="/courses/{{course.name}}/{{batch.name}}/progress"><i class="fa fa-flag-checkered fa-lg"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
Reference in New Issue
Block a user