def cadmin_top(course_id): """ Present top level course admin page """ course = Courses2.get_course(course_id) if not course: abort(404) user_id = session['user_id'] is_sysadmin = check_perm(user_id, -1, 'sysadmin') topics = Courses2.get_topics_list(course_id) exams = [ Exams.get_exam_struct(exam_id, course_id) for exam_id in Courses.get_exams(course_id, prev_years=False) ] exams.sort(key=lambda y: y['start_epoch'], reverse=True) groups = Courses.get_groups(course_id) choosegroups = [ group for group in Groups.all_groups() if group.id not in groups ] return render_template("courseadmin_top.html", course=course, topics=topics, exams=exams, choosegroups=choosegroups, groups=groups, is_sysadmin=is_sysadmin)
def cadmin_export_csv(course_id, exam_id, group_id): """ Send the group results as a CSV file """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam['cid']) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for('cadmin_top', course_id=course_id)) group = Groups.Group(g_id=group_id) output = Spreadsheets.exam_results_as_spreadsheet(course_id, group, exam_id) response = make_response(output) response.headers.add( 'Content-Type', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8" ) response.headers.add( 'Content-Disposition', 'attachment; filename="OASIS_%s_%s_Results.xlsx"' % (course.title, exam.title)) return response
def cadmin_export_csv(course_id, exam_id, group_id): """ Send the group results as a CSV file """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam["cid"]) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for("cadmin_top", course_id=course_id)) group = Groups.Group(g_id=group_id) output = Spreadsheets.exam_results_as_spreadsheet(course_id, group, exam_id) response = make_response(output) response.headers.add( "Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8" ) response.headers.add( "Content-Disposition", 'attachment; filename="OASIS_%s_%s_Results.xlsx"' % (course["title"], exam["title"]) ) return response
def cadmin_edit_exam(course_id, exam_id): """ Provide a form to edit an assessment """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam['cid']) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for('cadmin_top', course_id=course_id)) exam['start_date'] = int(date_from_py2js(exam['start'])) exam['end_date'] = int(date_from_py2js(exam['end'])) exam['start_hour'] = int(exam['start'].hour) exam['end_hour'] = int(exam['end'].hour) exam['start_minute'] = int(exam['start'].minute) exam['end_minute'] = int(exam['end'].minute) return render_template( "exam_edit.html", course=course, exam=exam )
def setup_usersummary(view_id): """ Show an account summary for the given user account. """ user_id = session['user_id'] if not check_perm(user_id, -1, "useradmin"): flash("You do not have User Administration access.") return redirect(url_for('setup_top')) is_sysadmin = check_perm(user_id, -1, 'sysadmin') user = Users2.get_user(view_id) examids = Exams.get_exams_done(view_id) exams = [] for examid in examids: exam = Exams.get_exam_struct(examid) started = General.human_date(exam['start']) exam['started'] = started exam['viewable'] = satisfy_perms(user_id, exam['cid'], ("viewmarks", )) exams.append(exam) exams.sort(key=lambda x: x['start_epoch'], reverse=True) course_ids = Users2.get_courses(view_id) courses = [] for course_id in course_ids: courses.append(Courses2.get_course(course_id)) user_is_admin = check_perm(view_id, 0, 'sysadmin') return render_template('setup_usersummary.html', user=user, exams=exams, courses=courses, is_sysadmin=is_sysadmin, user_is_admin=user_is_admin)
def cadmin_top(course_id): """ Present top level course admin page """ course = Courses2.get_course(course_id) if not course: abort(404) user_id = session['user_id'] is_sysadmin = check_perm(user_id, -1, 'sysadmin') topics = Courses2.get_topics_list(course_id) exams = [Exams.get_exam_struct(exam_id, course_id) for exam_id in Courses.get_exams(course_id, prev_years=False)] exams.sort(key=lambda y: y['start_epoch'], reverse=True) groups = Courses.get_groups(course_id) choosegroups = [group for group in Groups.all_groups() if group.id not in groups] return render_template( "courseadmin_top.html", course=course, topics=topics, exams=exams, choosegroups=choosegroups, groups=groups, is_sysadmin=is_sysadmin )
def api_exam_qtemplates(course_id, exam_id): """ Return a JSON list of all the qtemplates used for the given exam. """ user_id = session['user_id'] if not satisfy_perms(user_id, course_id, ("examcreate", )): abort(401) if exam_id == 0: # New assessment may be being created return jsonify(result=[ [ { 'qtid': 0 }, ], ]) exam = Exams.get_exam_struct(exam_id) ecid = exam['cid'] if not ecid == course_id: # They may be trying to bypass permission check abort(401) qtemplates = [] try: qtemplates = Exams.get_qts_list(exam_id) except KeyError: abort(401) return jsonify(result=qtemplates)
def get_exam_list_sorted(user_id, prev_years=False): """ Return a list of exams for the given user. """ courses = Courses.get_all() exams = [] for cid in courses: try: exams += [Exams.get_exam_struct(e, user_id) for e in Courses.get_exams(cid, prev_years=prev_years)] except KeyError, err: L.error("Failed fetching exam list for user %s: %s" % (user_id, err))
def cadmin_exam_viewmarked(course_id, exam_id, student_uid): """ Show a student's marked assessment results """ course = Courses2.get_course(course_id) try: exam = Exams.get_exam_struct(exam_id, course_id) except KeyError: exam = {} abort(404) results, examtotal = Assess.render_own_marked_exam(student_uid, exam_id) if examtotal is False: status = 0 else: status = 1 marktime = Exams.get_mark_time(exam_id, student_uid) firstview = Exams.get_student_start_time(exam_id, student_uid) submittime = Exams.get_submit_time(exam_id, student_uid) try: datemarked = General.human_date(marktime) except AttributeError: datemarked = None try: datefirstview = General.human_date(firstview) except AttributeError: datefirstview = None try: datesubmit = General.human_date(submittime) except AttributeError: datesubmit = None user = Users2.get_user(student_uid) if submittime and firstview: taken = submittime-firstview takenmins = (taken.seconds/60) else: takenmins = None return render_template( "cadmin_markedresult.html", course=course, exam=exam, results=results, examtotal=examtotal, datesubmit=datesubmit, datemarked=datemarked, datefirstview=datefirstview, taken=takenmins, user=user, status=status )
def get_exam_list_sorted(user_id, prev_years=False): """ Return a list of exams for the given user. """ courses = Courses.get_all() exams = [] for cid in courses: try: exams += [ Exams.get_exam_struct(e, user_id) for e in Courses.get_exams(cid, prev_years=prev_years) ] except KeyError, err: L.error("Failed fetching exam list for user %s: %s" % (user_id, err))
def cadmin_exam_results(course_id, exam_id): """ View the results of an assessment """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam['cid']) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for('cadmin_top', course_id=course_id)) exam['start_date'] = int(date_from_py2js(exam['start'])) exam['end_date'] = int(date_from_py2js(exam['end'])) exam['start_hour'] = int(exam['start'].hour) exam['end_hour'] = int(exam['end'].hour) exam['start_minute'] = int(exam['start'].minute) exam['end_minute'] = int(exam['end'].minute) groups = [Groups.Group(g_id=g_id) for g_id in Groups.active_by_course(course_id)] results = {} uids = set([]) totals = {} for group in groups: results[group.id] = Exams.get_marks(group, exam_id) for user_id in results[group.id]: uids.add(user_id) if user_id not in totals: totals[user_id] = 0.0 for qt, val in results[group.id][user_id].iteritems(): totals[user_id] += val['score'] questions = Exams.get_qts_list(exam_id) users = {} for uid in uids: users[uid] = Users2.get_user(uid) return render_template( "cadmin_examresults.html", course=course, exam=exam, results=results, groups=groups, users=users, questions=questions, when=datetime.now().strftime("%H:%m, %a %d %b %Y"), totals=totals )
def cadmin_exam_viewmarked(course_id, exam_id, student_uid): """ Show a student's marked assessment results """ course = Courses2.get_course(course_id) try: exam = Exams.get_exam_struct(exam_id, course_id) except KeyError: exam = {} abort(404) results, examtotal = Assess.render_own_marked_exam(student_uid, exam_id) if examtotal is False: status = 0 else: status = 1 marktime = Exams.get_mark_time(exam_id, student_uid) firstview = Exams.get_student_start_time(exam_id, student_uid) submittime = Exams.get_submit_time(exam_id, student_uid) try: datemarked = General.human_date(marktime) except AttributeError: datemarked = None try: datefirstview = General.human_date(firstview) except AttributeError: datefirstview = None try: datesubmit = General.human_date(submittime) except AttributeError: datesubmit = None user = Users2.get_user(student_uid) if submittime and firstview: taken = submittime - firstview takenmins = (taken.seconds / 60) else: takenmins = None return render_template("cadmin_markedresult.html", course=course, exam=exam, results=results, examtotal=examtotal, datesubmit=datesubmit, datemarked=datemarked, datefirstview=datefirstview, taken=takenmins, user=user, status=status)
def cadmin_exam_unsubmit(course_id, exam_id, student_uid): """ "unsubmit" the student's assessment and reset their timer so they can log back on and have another attempt. """ course = Courses2.get_course(course_id) try: exam = Exams.get_exam_struct(exam_id, course.id) except KeyError: exam = {} abort(404) Exams.unsubmit(exam_id, student_uid) user = Users2.get_user(student_uid) flash("""Assessment for %s unsubmitted and timer reset.""" % user["uname"]) return redirect(url_for("cadmin_exam_viewmarked", course_id=course.id, exam_id=exam["id"], student_uid=student_uid))
def cadmin_exam_results(course_id, exam_id): """ View the results of an assessment """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam['cid']) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for('cadmin_top', course_id=course_id)) exam['start_date'] = int(date_from_py2js(exam['start'])) exam['end_date'] = int(date_from_py2js(exam['end'])) exam['start_hour'] = int(exam['start'].hour) exam['end_hour'] = int(exam['end'].hour) exam['start_minute'] = int(exam['start'].minute) exam['end_minute'] = int(exam['end'].minute) groups = [ Groups.Group(g_id=g_id) for g_id in Groups.active_by_course(course_id) ] results = {} uids = set([]) totals = {} for group in groups: results[group.id] = Exams.get_marks(group, exam_id) for user_id in results[group.id]: uids.add(user_id) if user_id not in totals: totals[user_id] = 0.0 for qt, val in results[group.id][user_id].iteritems(): totals[user_id] += val['score'] questions = Exams.get_qts_list(exam_id) users = {} for uid in uids: users[uid] = Users2.get_user(uid) return render_template("cadmin_examresults.html", course=course, exam=exam, results=results, groups=groups, users=users, questions=questions, when=datetime.now().strftime("%H:%m, %a %d %b %Y"), totals=totals)
def cadmin_prev_assessments(course_id): """ Show a list of older assessments.""" course = Courses2.get_course(course_id) if not course: abort(404) exams = [ Exams.get_exam_struct(exam_id, course_id) for exam_id in DB.get_course_exam_all(course_id, prev_years=True) ] years = [exam["start"].year for exam in exams] years = list(set(years)) years.sort(reverse=True) exams.sort(key=lambda y: y["start_epoch"]) return render_template("courseadmin_previousassessments.html", course=course, exams=exams, years=years)
def cadmin_edit_exam_submit(course_id, exam_id): """ Provide a form to edit an assessment """ user_id = session["user_id"] course = Courses2.get_course(course_id) if not course: abort(404) if "exam_cancel" in request.form: flash("Assessment editing cancelled.") return redirect(url_for("cadmin_top", course_id=course_id)) exam_id = CourseAdmin.exam_edit_submit(request, user_id, course_id, exam_id) exam = Exams.get_exam_struct(exam_id, course_id) flash("Assessment saved.") return render_template("exam_edit_submit.html", course=course, exam=exam)
def cadmin_edit_exam_submit(course_id, exam_id): """ Provide a form to edit an assessment """ user_id = session['user_id'] course = Courses2.get_course(course_id) if not course: abort(404) if "exam_cancel" in request.form: flash("Assessment editing cancelled.") return redirect(url_for('cadmin_top', course_id=course_id)) exam_id = CourseAdmin.exam_edit_submit(request, user_id, course_id, exam_id) exam = Exams.get_exam_struct(exam_id, course_id) flash("Assessment saved.") return render_template("exam_edit_submit.html", course=course, exam=exam)
def cadmin_exam_unsubmit(course_id, exam_id, student_uid): """ "unsubmit" the student's assessment and reset their timer so they can log back on and have another attempt. """ try: exam = Exams.get_exam_struct(exam_id, course_id) except KeyError: exam = {} abort(404) Exams.unsubmit(exam_id, student_uid) user = Users2.get_user(student_uid) flash("""Assessment for %s unsubmitted and timer reset.""" % user['uname']) return redirect( url_for("cadmin_exam_viewmarked", course_id=course_id, exam_id=exam['id'], student_uid=student_uid))
def cadmin_prev_assessments(course_id): """ Show a list of older assessments.""" course = Courses2.get_course(course_id) if not course: abort(404) exams = [ Exams.get_exam_struct(exam_id, course_id) for exam_id in DB.get_course_exam_all(course_id, prev_years=True) ] years = [exam['start'].year for exam in exams] years = list(set(years)) years.sort(reverse=True) exams.sort(key=lambda y: y['start_epoch']) return render_template("courseadmin_previousassessments.html", course=course, exams=exams, years=years)
def api_exam_qtemplates(course_id, exam_id): """ Return a JSON list of all the qtemplates used for the given exam. """ user_id = session['user_id'] if not satisfy_perms(user_id, course_id, ("examcreate",)): abort(401) if exam_id == 0: # New assessment may be being created return jsonify(result=[[{'qtid': 0}, ], ]) exam = Exams.get_exam_struct(exam_id) ecid = exam['cid'] if not ecid == course_id: # They may be trying to bypass permission check abort(401) qtemplates = [] try: qtemplates = Exams.get_qts_list(exam_id) except KeyError: abort(401) return jsonify(result=qtemplates)
def cadmin_edit_exam(course_id, exam_id): """ Provide a form to edit an assessment """ course = Courses2.get_course(course_id) if not course: abort(404) exam = Exams.get_exam_struct(exam_id, course_id) if not exam: abort(404) if not int(exam['cid']) == int(course_id): flash("Assessment %s does not belong to this course." % int(exam_id)) return redirect(url_for('cadmin_top', course_id=course_id)) exam['start_date'] = int(date_from_py2js(exam['start'])) exam['end_date'] = int(date_from_py2js(exam['end'])) exam['start_hour'] = int(exam['start'].hour) exam['end_hour'] = int(exam['end'].hour) exam['start_minute'] = int(exam['start'].minute) exam['end_minute'] = int(exam['end'].minute) return render_template("exam_edit.html", course=course, exam=exam)
def setup_usersummary(view_id): """ Show an account summary for the given user account. """ user_id = session['user_id'] if not check_perm(user_id, -1, "useradmin"): flash("You do not have User Administration access.") return redirect(url_for('setup_top')) is_sysadmin = check_perm(user_id, -1, 'sysadmin') user = Users2.get_user(view_id) examids = Exams.get_exams_done(view_id) exams = [] for examid in examids: exam = Exams.get_exam_struct(examid) started = General.human_date(exam['start']) exam['started'] = started exam['viewable'] = satisfy_perms(user_id, exam['cid'], ("viewmarks", )) exams.append(exam) exams.sort(key=lambda x: x['start_epoch'], reverse=True) course_ids = Users2.get_courses(view_id) courses = [] for course_id in course_ids: courses.append(Courses.get_course(course_id)) user_is_admin = check_perm(view_id, 0, 'sysadmin') return render_template( 'setup_usersummary.html', user=user, exams=exams, courses=courses, is_sysadmin=is_sysadmin, user_is_admin=user_is_admin )
def exam_results_as_spreadsheet(course_id, group, exam_id): """ Export the assessment results as a XLSX spreadsheet """ course = Courses2.get_course(course_id) exam = Exams.get_exam_struct(exam_id, course_id) uids = set([]) totals = {} results = Exams.get_marks(group, exam_id) for user_id in results: uids.add(user_id) if user_id not in totals: totals[user_id] = 0.0 for qt, val in results[user_id].iteritems(): totals[user_id] += val['score'] questions = Exams.get_qts_list(exam_id) users = {} for uid in uids: users[uid] = Users2.get_user(uid) wb = Workbook() ws = wb.get_active_sheet() ws.title = "Results" ws.cell(row=1, column=0).value = course['name'] ws.cell(row=1, column=1).value = course['title'] ws.cell(row=2, column=0).value = "Assessment:" ws.cell(row=2, column=1).value = exam['title'] ws.cell(row=3, column=0).value = "Group:" ws.cell(row=3, column=1).value = group.name col = 5 qcount = 1 for _ in questions: ws.cell(row=4, column=col).value = "Q%s" % qcount qcount += 1 col += 1 ws.cell(row=4, column=col).value = "Total" row = 5 sortusers = users.keys() sortusers.sort(key=lambda us: users[us]['familyname']) for user_id in sortusers: result = results[user_id] ws.cell(row=row, column=0).value = users[user_id]['uname'] ws.cell(row=row, column=1).value = users[user_id]['student_id'] ws.cell(row=row, column=2).value = users[user_id]['familyname'] ws.cell(row=row, column=3).value = users[user_id]['givenname'] ws.cell(row=row, column=4).value = users[user_id]['email'] col = 5 for pos in questions: for qt in pos: if qt['id'] in result: ws.cell(row=row, column=col).value = result[qt['id']]['score'] col += 1 ws.cell(row=row, column=col).value = totals[user_id] row += 1 return save_virtual_workbook(wb)
def exam_results_as_spreadsheet(course_id, group, exam_id): """ Export the assessment results as a XLSX spreadsheet """ course = Courses2.get_course(course_id) exam = Exams.get_exam_struct(exam_id, course_id) uids = set([]) totals = {} results = Exams.get_marks(group, exam_id) for user_id in results: uids.add(user_id) if user_id not in totals: totals[user_id] = 0.0 for qt, val in results[user_id].iteritems(): totals[user_id] += val['score'] questions = Exams.get_qts_list(exam_id) users = {} for uid in uids: users[uid] = Users2.get_user(uid) wb = Workbook() ws = wb.get_active_sheet() ws.title = "Results" ws.cell(row=1, column=0).value = course['name'] ws.cell(row=1, column=1).value = course['title'] ws.cell(row=2, column=0).value = "Assessment:" ws.cell(row=2, column=1).value = exam['title'] ws.cell(row=3, column=0).value = "Group:" ws.cell(row=3, column=1).value = group.name col = 5 qcount = 1 for _ in questions: ws.cell(row=4, column=col).value = "Q%s" % qcount qcount += 1 col += 1 ws.cell(row=4, column=col).value = "Total" row = 5 sortusers = users.keys() sortusers.sort(key=lambda us: users[us]['familyname']) for user_id in sortusers: result = results[user_id] ws.cell(row=row, column=0).value = users[user_id]['uname'] ws.cell(row=row, column=1).value = users[user_id]['student_id'] ws.cell(row=row, column=2).value = users[user_id]['familyname'] ws.cell(row=row, column=3).value = users[user_id]['givenname'] ws.cell(row=row, column=4).value = users[user_id]['email'] col = 5 for pos in questions: for qt in pos: if qt['id'] in result: ws.cell(row=row, column=col).value = result[qt['id']]['score'] col += 1 ws.cell(row=row, column=col).value = totals[user_id] row += 1 return save_virtual_workbook(wb)