From 1a2d31e1c59427c28211030ea09cd4964b4bd8d8 Mon Sep 17 00:00:00 2001
From: adityacp
Date: Tue, 16 Feb 2021 15:21:24 +0530
Subject: Change test data files, views, models, template
- Fix upload marks for a quiz column missing error
- Add upload marks task to celery
- Minor fixes to avoid errors in regrade and custom_filters
---
yaksh/fixtures/marks_correct.csv | 5 +-
yaksh/fixtures/marks_header_missing.csv | 2 +-
yaksh/fixtures/marks_header_modified.csv | 2 +-
yaksh/fixtures/marks_invalid_data.csv | 2 +-
yaksh/fixtures/marks_invalid_question_id.csv | 2 +-
yaksh/fixtures/marks_invalid_user.csv | 2 +-
yaksh/fixtures/marks_not_attempted_question.csv | 2 +-
yaksh/fixtures/marks_single_question.csv | 2 +-
yaksh/models.py | 21 ++---
yaksh/tasks.py | 116 +++++++++++++++++++++++-
yaksh/templates/yaksh/grade_user.html | 3 +
yaksh/templates/yaksh/monitor.html | 48 ++++++----
yaksh/templatetags/custom_filters.py | 15 +--
yaksh/test_views.py | 7 +-
yaksh/views.py | 116 +++++++-----------------
15 files changed, 208 insertions(+), 137 deletions(-)
diff --git a/yaksh/fixtures/marks_correct.csv b/yaksh/fixtures/marks_correct.csv
index 9134da5..d739644 100644
--- a/yaksh/fixtures/marks_correct.csv
+++ b/yaksh/fixtures/marks_correct.csv
@@ -1,4 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,1,good work,1,nice
-student2,1,good work,0,bad
-
+student2,1,good work,0,bad
\ No newline at end of file
diff --git a/yaksh/fixtures/marks_header_missing.csv b/yaksh/fixtures/marks_header_missing.csv
index 8c3a747..81b0c77 100644
--- a/yaksh/fixtures/marks_header_missing.csv
+++ b/yaksh/fixtures/marks_header_missing.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks
+user__username,Q-1212-Dummy1-1.0-marks
student1,0.9
student2,1
diff --git a/yaksh/fixtures/marks_header_modified.csv b/yaksh/fixtures/marks_header_modified.csv
index 08ba31d..f6d6859 100644
--- a/yaksh/fixtures/marks_header_modified.csv
+++ b/yaksh/fixtures/marks_header_modified.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummmy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-1212-Dummmy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,0.75,fine work,1,not nice
student2,1,good work,0,not okay
diff --git a/yaksh/fixtures/marks_invalid_data.csv b/yaksh/fixtures/marks_invalid_data.csv
index 44fb2bb..b4af15b 100644
--- a/yaksh/fixtures/marks_invalid_data.csv
+++ b/yaksh/fixtures/marks_invalid_data.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,NA,good work,1,nice
student2,1,good work,0,bad
diff --git a/yaksh/fixtures/marks_invalid_question_id.csv b/yaksh/fixtures/marks_invalid_question_id.csv
index eb1d921..629a673 100644
--- a/yaksh/fixtures/marks_invalid_question_id.csv
+++ b/yaksh/fixtures/marks_invalid_question_id.csv
@@ -1,3 +1,3 @@
-username,Q-12112-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-12112-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,1,good work,1,nice
student2,1,good work,0,bad
diff --git a/yaksh/fixtures/marks_invalid_user.csv b/yaksh/fixtures/marks_invalid_user.csv
index bd31071..5d5c200 100644
--- a/yaksh/fixtures/marks_invalid_user.csv
+++ b/yaksh/fixtures/marks_invalid_user.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,1,good work,1,nice
student452,1,good work,0,bad
diff --git a/yaksh/fixtures/marks_not_attempted_question.csv b/yaksh/fixtures/marks_not_attempted_question.csv
index 3c3e2e7..ecce363 100644
--- a/yaksh/fixtures/marks_not_attempted_question.csv
+++ b/yaksh/fixtures/marks_not_attempted_question.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
+user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments
student1,1,good work,1,nice
student2,0.3,very good,1,good
diff --git a/yaksh/fixtures/marks_single_question.csv b/yaksh/fixtures/marks_single_question.csv
index 9677730..00b74fe 100644
--- a/yaksh/fixtures/marks_single_question.csv
+++ b/yaksh/fixtures/marks_single_question.csv
@@ -1,3 +1,3 @@
-username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments
+user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments
student1,0.5,okay work
student2,1,good work
diff --git a/yaksh/models.py b/yaksh/models.py
index 11ddf8a..77b3684 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -2267,7 +2267,7 @@ class AnswerPaper(models.Model):
ans_data = None
if not df.empty:
ans_data = df.groupby("question_id").tail(1)
- for que_summary, que_id in question_ids:
+ for que_summary, que_id, que_comments in question_ids:
if ans_data is not None:
ans = ans_data['question_id'].to_list()
marks = ans_data['marks'].to_list()
@@ -2278,6 +2278,7 @@ class AnswerPaper(models.Model):
que_data[que_summary] = 0
else:
que_data[que_summary] = 0
+ que_data[que_comments] = "NA"
return que_data
def current_question(self):
@@ -2576,25 +2577,17 @@ class AnswerPaper(models.Model):
self.user, self.question_paper.quiz.description,
question_id
)
- return False, msg + 'Question not in the answer paper.'
+ return False, f'{msg} Question not in the answer paper.'
user_answer = self.answers.filter(question=question).last()
- if not user_answer:
- return False, msg + 'Did not answer.'
+ if not user_answer or not user_answer.answer:
+ return False, f'{msg} Did not answer.'
if question.type in ['mcc', 'arrange']:
try:
answer = literal_eval(user_answer.answer)
if type(answer) is not list:
- return (False,
- msg + '{0} answer not a list.'.format(
- question.type
- )
- )
+ return (False, f'{msg} {question.type} answer not a list.')
except Exception:
- return (False,
- msg + '{0} answer submission error'.format(
- question.type
- )
- )
+ return (False, f'{msg} {question.type} answer submission error')
else:
answer = user_answer.answer
json_data = question.consolidate_answer_data(answer) \
diff --git a/yaksh/tasks.py b/yaksh/tasks.py
index 1c4658b..5068c64 100644
--- a/yaksh/tasks.py
+++ b/yaksh/tasks.py
@@ -1,6 +1,8 @@
# Python Imports
from __future__ import absolute_import, unicode_literals
from textwrap import dedent
+import csv
+import json
# Django and celery imports
from celery import shared_task
@@ -8,7 +10,10 @@ from django.urls import reverse
from django.shortcuts import get_object_or_404
# Local imports
-from .models import Course, QuestionPaper, Quiz, AnswerPaper, CourseStatus
+from .models import (
+ Course, QuestionPaper, Quiz, AnswerPaper, CourseStatus, User, Question,
+ Answer
+)
from notifications_plugin.models import NotificationMessage, Notification
@@ -80,3 +85,112 @@ def regrade_papers(data):
notification = Notification.objects.add_single_notification(
user_id, nm.id
)
+
+
+@shared_task
+def update_user_marks(data):
+ request_user = data.get("user_id")
+ course_id = data.get("course_id")
+ questionpaper_id = data.get("questionpaper_id")
+ csv_data = data.get("csv_data")
+ question_paper = QuestionPaper.objects.get(id=questionpaper_id)
+ def _get_header_info(reader):
+ question_ids = []
+ fields = reader.fieldnames
+ for field in fields:
+ if field.startswith('Q') and field.count('-') > 0:
+ qid = int(field.split('-')[1])
+ if qid not in question_ids:
+ question_ids.append(qid)
+ return question_ids
+ try:
+ reader = csv.DictReader(csv_data)
+ question_ids = _get_header_info(reader)
+ _read_marks_csv(
+ reader, request_user, course_id, question_paper, question_ids
+ )
+ except TypeError:
+ url = reverse(
+ "yaksh:monitor", args=[question_paper.quiz_id, course_id]
+ )
+ message = dedent("""
+ Unable to update quiz marks. Please re-upload correct CSV file
+ Click here to view
+ """.format(url)
+ )
+ nm = NotificationMessage.objects.add_single_message(
+ request_user, "{0} marks update status".format(
+ question_paper.quiz.description
+ ), message, "warning"
+ )
+ notification = Notification.objects.add_single_notification(
+ request_user, nm.id
+ )
+
+
+def _read_marks_csv(
+ reader, request_user, course_id, question_paper, question_ids):
+ update_status = []
+ for row in reader:
+ username = row['user__username']
+ user = User.objects.filter(username=username).first()
+ if user:
+ answerpapers = question_paper.answerpaper_set.filter(
+ course_id=course_id, user_id=user.id)
+ else:
+ update_status.append(f'{username} user not found!')
+ continue
+ answerpaper = answerpapers.last()
+ if not answerpaper:
+ update_status.append(f'{username} has no answerpaper!')
+ continue
+ answers = answerpaper.answers.all()
+ questions = answerpaper.questions.values_list('id', flat=True)
+ for qid in question_ids:
+ question = Question.objects.filter(id=qid).first()
+ if not question:
+ update_status.append(f'{qid} is an invalid question id!')
+ continue
+ if qid in questions:
+ answer = answers.filter(question_id=qid).last()
+ if not answer:
+ answer = Answer(question_id=qid, marks=0, correct=False,
+ answer='', error=json.dumps([]))
+ answer.save()
+ answerpaper.answers.add(answer)
+ key1 = 'Q-{0}-{1}-{2}-marks'.format(qid, question.summary,
+ question.points)
+ key2 = 'Q-{0}-{1}-comments'.format(qid, question.summary)
+ if key1 in reader.fieldnames:
+ try:
+ answer.set_marks(float(row[key1]))
+ except ValueError:
+ update_status.append(f'{row[key1]} invalid marks!')
+ if key2 in reader.fieldnames:
+ answer.set_comment(row[key2])
+ answer.save()
+ answerpaper.update_marks(state='completed')
+ answerpaper.save()
+ update_status.append(
+ 'Updated successfully for user: {0}, question: {1}'.format(
+ username, question.summary)
+ )
+ url = reverse(
+ "yaksh:grade_user",
+ args=[question_paper.quiz_id, course_id]
+ )
+ message = dedent("""
+ Quiz mark update is complete.
+ Click here to view
+
{1}
+ """.format(url, "\n".join(update_status))
+ )
+ summary = "{0} marks update status".format(
+ question_paper.quiz.description
+ )
+ nm = NotificationMessage.objects.add_single_message(
+ request_user, summary, message, "info"
+ )
+ notification = Notification.objects.add_single_notification(
+ request_user, nm.id
+ )
diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html
index 4e1db2b..32cf09c 100644
--- a/yaksh/templates/yaksh/grade_user.html
+++ b/yaksh/templates/yaksh/grade_user.html
@@ -559,6 +559,9 @@ function searchNames() {
{% endif %}
+
+ Comment:
+
diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html
index c7755e7..6fd3cb1 100644
--- a/yaksh/templates/yaksh/monitor.html
+++ b/yaksh/templates/yaksh/monitor.html
@@ -52,7 +52,8 @@ $(document).ready(function()
{% if quiz %}
{% if papers %}
-
- - Download the CSV file from the button above
- - Edit and upload the same
-
-