From 1f554e7505f5a6aa1b796b2e31e1541188af56da Mon Sep 17 00:00:00 2001 From: prathamesh Date: Thu, 26 Oct 2017 14:35:08 +0530 Subject: CSV download for quiz enhanced CSV download for a quiz now shows question wise grades. Also, for a given attempt all the users from the course are entered in the CSV. If the user has not attempted then a dash '-' is put under the grades. Also, handles random questions, if a question paper has questions selected from pool of questions then all the questions are entered in the CSV. 'NA' is put under the question grade if that question has not come in the question/answer paper for that given user. --- yaksh/views.py | 115 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 38 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index b4cb844..8bd65bb 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -991,7 +991,12 @@ def monitor(request, quiz_id=None): papers = [] q_paper = None latest_attempts = [] + attempt_numbers = [] else: + if q_paper: + attempt_numbers = AnswerPaper.objects.get_attempt_numbers(q_paper.last().id) + else: + attempt_numbers = [] latest_attempts = [] papers = AnswerPaper.objects.filter(question_paper=q_paper).order_by( 'user__profile__roll_number' @@ -1007,11 +1012,15 @@ def monitor(request, quiz_id=None): attempt_number=last_attempt['last_attempt_num'] ) ) + csv_fields = ['name', 'username', 'roll_number', 'institute', + 'department', 'questions', 'total', 'out_of', 'percentage', 'status'] context = { "papers": papers, "quiz": quiz, "msg": "Quiz Results", - "latest_attempts": latest_attempts + "latest_attempts": latest_attempts, + "csv_fields": csv_fields, + "attempt_numbers": attempt_numbers } return my_render_to_response('yaksh/monitor.html', context, context_instance=ci) @@ -1264,49 +1273,79 @@ def user_data(request, user_id, questionpaper_id=None): context_instance=RequestContext(request)) +def _expand_questions(questions, field_list): + i = field_list.index('questions') + field_list.remove('questions') + for question in questions: + field_list.insert(i, '{0}-{1}'.format(question.summary, question.points)) + return field_list + + @login_required @email_verified -def download_csv(request, questionpaper_id): - user = request.user - if not is_moderator(user): +def download_quiz_csv(request, course_id, quiz_id): + current_user = request.user + if not is_moderator(current_user): raise Http404('You are not allowed to view this page!') - quiz = Quiz.objects.get(questionpaper=questionpaper_id) + course = get_object_or_404(Course, id=course_id) + quiz = get_object_or_404(Quiz, id=quiz_id) + if not course.is_creator(current_user) and not course.is_teacher(current_user): + raise Http404('The quiz does not belong to your course') + users = course.get_enrolled().order_by('first_name') + if not users: + return monitor(request, quiz_id) + csv_fields = [] + attempt_number = None + question_paper = quiz.questionpaper_set.last() + last_attempt_number =AnswerPaper.objects.get_attempt_numbers(question_paper.id).last() + if request.method == 'POST': + csv_fields = request.POST.getlist('csv_fields') + attempt_number = request.POST.get('attempt_number', last_attempt_number) + if not csv_fields: + csv_fields = ['name', 'username', 'roll_number', 'institute', + 'department', 'questions', 'total', 'out_of', 'percentage', 'status'] + if not attempt_number: + attempt_number = last_attempt_number + + questions = question_paper.get_question_bank() + answerpapers = AnswerPaper.objects.filter(question_paper=question_paper, + attempt_number=attempt_number) + if not answerpapers: + return monitor(request, quiz_id) - if not quiz.course.is_creator(user) and not quiz.course.is_teacher(user): - raise Http404('The question paper does not belong to your course') - papers = AnswerPaper.objects.get_latest_attempts(questionpaper_id) - if not papers: - return monitor(request, questionpaper_id) response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="{0}.csv"'.format( - (quiz.description).replace('.', '')) + response['Content-Disposition'] = 'attachment; filename="{0}-{1}-attempt{2}.csv"'.format( + course.name.replace('.', ''), quiz.description.replace('.', ''), + attempt_number) writer = csv.writer(response) - header = [ - 'name', - 'username', - 'roll_number', - 'institute', - 'marks_obtained', - 'total_marks', - 'percentage', - 'questions', - 'questions_answered', - 'status' - ] - writer.writerow(header) - for paper in papers: - row = [ - '{0} {1}'.format(paper.user.first_name, paper.user.last_name), - paper.user.username, - paper.user.profile.roll_number, - paper.user.profile.institute, - paper.marks_obtained, - paper.question_paper.total_marks, - paper.percent, - paper.questions.all(), - paper.questions_answered.all(), - paper.status - ] + if 'questions' in csv_fields: + csv_fields = _expand_questions(questions, csv_fields) + writer.writerow(csv_fields) + + csv_fields_values = {'name': 'user.get_full_name().title()', + 'roll_number': 'user.profile.roll_number', + 'institute': 'user.profile.institute', + 'department': 'user.profile.department', + 'username': 'user.username', 'total': 'answerpaper.marks_obtained', + 'out_of': 'question_paper.total_marks', + 'percentage': 'answerpaper.percent', 'status': 'answerpaper.status'} + questions_scores = {} + for question in questions: + questions_scores['{0}-{1}'.format(question.summary, question.points)] \ + = 'answerpaper.get_per_question_score({0})'.format(question.id) + csv_fields_values.update(questions_scores) + + for user in users: + row = [] + answerpaper = None + papers = answerpapers.filter(user=user) + if papers: + answerpaper = papers.first() + for field in csv_fields: + try: + row.append(eval(csv_fields_values[field])) + except AttributeError: + row.append('-') writer.writerow(row) return response -- cgit From b7864df91a82d6d56d4eb76d39aae2954302669a Mon Sep 17 00:00:00 2001 From: prathamesh Date: Fri, 27 Oct 2017 03:43:19 +0530 Subject: Excluded teachers and creator form the enrolled users list Changed the HTML select id attribute to name, necessary to track in POST request --- yaksh/views.py | 1 + 1 file changed, 1 insertion(+) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index 8bd65bb..0293ae7 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1335,6 +1335,7 @@ def download_quiz_csv(request, course_id, quiz_id): = 'answerpaper.get_per_question_score({0})'.format(question.id) csv_fields_values.update(questions_scores) + users = users.exclude(id=course.creator.id).exclude(id__in=course.teachers.all()) for user in users: row = [] answerpaper = None -- cgit From 3ab5cf0783159aab349ef69db7500a42ad2e719c Mon Sep 17 00:00:00 2001 From: prathamesh Date: Fri, 27 Oct 2017 12:49:45 +0530 Subject: Edit Profile Bug Fix edit_profile view had a decorator has_profile. So, has_profile will redirect to edit_profile if no profile. But then if I submit my profile form then the has_profile will again redirect to edit_profile, instead of updating my profile. So this cycle will continue endlessly for a user with no profile, and will never be able to create/update his profile! Will face this when user is created via csv upload, django admin or oauth login without pipeline. Also, profile instance is passed to the profile form via get query, which will fail if no profile. Added a views test for the above. Fixed. Additionally that can be thought of later: The has_profile decorator is used for few views only, so one can access views if they know the url, even if they do not have a profile. email edit option for users --- yaksh/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index b4cb844..c50ba33 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1406,7 +1406,6 @@ def view_profile(request): @login_required -@has_profile @email_verified def edit_profile(request): """ edit profile details facility for moderator and students """ @@ -1418,7 +1417,10 @@ def edit_profile(request): else: template = 'user.html' context = {'template': template} - profile = Profile.objects.get(user_id=user.id) + try: + profile = Profile.objects.get(user_id=user.id) + except Profile.DoesNotExist: + profile = None if request.method == 'POST': form = ProfileForm(request.POST, user=user, instance=profile) -- cgit From ae78048a1f978a6a570faeb10ecb77229460eae1 Mon Sep 17 00:00:00 2001 From: Akshen Date: Tue, 31 Oct 2017 11:15:41 +0530 Subject: Fix Course Ordering in Courses Page Latest Course will be shown on Top in Courses Page --- yaksh/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index b4cb844..47d8c9f 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -792,8 +792,10 @@ def courses(request): ci = RequestContext(request) if not is_moderator(user): raise Http404('You are not allowed to view this page') - courses = Course.objects.filter(creator=user, is_trial=False) - allotted_courses = Course.objects.filter(teachers=user, is_trial=False) + courses = Course.objects.filter( + creator=user, is_trial=False).order_by('-id') + allotted_courses = Course.objects.filter( + teachers=user, is_trial=False).order_by('-id') context = {'courses': courses, "allotted_courses": allotted_courses} return my_render_to_response('yaksh/courses.html', context, context_instance=ci) -- cgit From 9aeaf153851c7821336ab542b4fd8f4e621a8d65 Mon Sep 17 00:00:00 2001 From: Akshen Date: Sat, 4 Nov 2017 13:35:36 +0530 Subject: Show Active Course on top of Courses Page --- yaksh/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index 47d8c9f..0d6acfe 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -793,9 +793,9 @@ def courses(request): if not is_moderator(user): raise Http404('You are not allowed to view this page') courses = Course.objects.filter( - creator=user, is_trial=False).order_by('-id') + creator=user, is_trial=False).order_by('-active') allotted_courses = Course.objects.filter( - teachers=user, is_trial=False).order_by('-id') + teachers=user, is_trial=False).order_by('-active') context = {'courses': courses, "allotted_courses": allotted_courses} return my_render_to_response('yaksh/courses.html', context, context_instance=ci) -- cgit From 52afb684b1bd59cc1d5f2f1a6963b877a5604b37 Mon Sep 17 00:00:00 2001 From: Akshen Date: Mon, 6 Nov 2017 15:45:21 +0530 Subject: Show Latest Active Course on top of Courses Page --- yaksh/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index 0d6acfe..e2412bb 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -793,9 +793,9 @@ def courses(request): if not is_moderator(user): raise Http404('You are not allowed to view this page') courses = Course.objects.filter( - creator=user, is_trial=False).order_by('-active') + creator=user, is_trial=False).order_by('-active', '-id') allotted_courses = Course.objects.filter( - teachers=user, is_trial=False).order_by('-active') + teachers=user, is_trial=False).order_by('-active', '-id') context = {'courses': courses, "allotted_courses": allotted_courses} return my_render_to_response('yaksh/courses.html', context, context_instance=ci) -- cgit From 4c1ddc15f3b9a15bee49ac2f6640c8ed311f7151 Mon Sep 17 00:00:00 2001 From: prathamesh Date: Tue, 7 Nov 2017 13:05:05 +0530 Subject: Made changes as per suggestions --- yaksh/views.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'yaksh/views.py') diff --git a/yaksh/views.py b/yaksh/views.py index 0293ae7..3c57b83 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -80,6 +80,10 @@ def add_to_group(users): user.groups.add(group) +CSV_FIELDS = ['name', 'username', 'roll_number', 'institute', 'department', + 'questions', 'marks_obtained', 'out_of', 'percentage', 'status'] + + @email_verified def index(request, next_url=None): """The start page. @@ -1012,8 +1016,7 @@ def monitor(request, quiz_id=None): attempt_number=last_attempt['last_attempt_num'] ) ) - csv_fields = ['name', 'username', 'roll_number', 'institute', - 'department', 'questions', 'total', 'out_of', 'percentage', 'status'] + csv_fields = CSV_FIELDS context = { "papers": papers, "quiz": quiz, @@ -1302,8 +1305,7 @@ def download_quiz_csv(request, course_id, quiz_id): csv_fields = request.POST.getlist('csv_fields') attempt_number = request.POST.get('attempt_number', last_attempt_number) if not csv_fields: - csv_fields = ['name', 'username', 'roll_number', 'institute', - 'department', 'questions', 'total', 'out_of', 'percentage', 'status'] + csv_fields = CSV_FIELDS if not attempt_number: attempt_number = last_attempt_number @@ -1326,7 +1328,8 @@ def download_quiz_csv(request, course_id, quiz_id): 'roll_number': 'user.profile.roll_number', 'institute': 'user.profile.institute', 'department': 'user.profile.department', - 'username': 'user.username', 'total': 'answerpaper.marks_obtained', + 'username': 'user.username', + 'marks_obtained': 'answerpaper.marks_obtained', 'out_of': 'question_paper.total_marks', 'percentage': 'answerpaper.percent', 'status': 'answerpaper.status'} questions_scores = {} -- cgit