diff options
-rw-r--r-- | yaksh/fixtures/marks_header_missing.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_header_modified.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_invalid_data.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_invalid_question_id.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_invalid_user.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_not_attempted_question.csv | 3 | ||||
-rw-r--r-- | yaksh/fixtures/marks_single_question.csv | 3 | ||||
-rw-r--r-- | yaksh/test_views.py | 186 | ||||
-rw-r--r-- | yaksh/views.py | 72 |
9 files changed, 245 insertions, 34 deletions
diff --git a/yaksh/fixtures/marks_header_missing.csv b/yaksh/fixtures/marks_header_missing.csv new file mode 100644 index 0000000..8c3a747 --- /dev/null +++ b/yaksh/fixtures/marks_header_missing.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..08ba31d --- /dev/null +++ b/yaksh/fixtures/marks_header_modified.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..44fb2bb --- /dev/null +++ b/yaksh/fixtures/marks_invalid_data.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..eb1d921 --- /dev/null +++ b/yaksh/fixtures/marks_invalid_question_id.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..bd31071 --- /dev/null +++ b/yaksh/fixtures/marks_invalid_user.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..3c3e2e7 --- /dev/null +++ b/yaksh/fixtures/marks_not_attempted_question.csv @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..9677730 --- /dev/null +++ b/yaksh/fixtures/marks_single_question.csv @@ -0,0 +1,3 @@ +username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments +student1,0.5,okay work +student2,1,good work diff --git a/yaksh/test_views.py b/yaksh/test_views.py index e87686c..ea3858e 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -2672,14 +2672,23 @@ class TestUploadMarks(TestCase): question=self.question2, answer="answer2", correct=False, error=json.dumps([]), marks=0 ) + self.answer12 = Answer( + question=self.question1, answer="answer12", + correct=False, error=json.dumps([]), marks=0 + ) self.answer1.save() + self.answer12.save() self.answer2.save() self.ans_paper1.answers.add(self.answer1) self.ans_paper1.answers.add(self.answer2) + self.ans_paper2.answers.add(self.answer12) self.ans_paper1.questions_answered.add(self.question1) self.ans_paper1.questions_answered.add(self.question2) + self.ans_paper2.questions_answered.add(self.question1) self.ans_paper1.questions.add(self.question1) self.ans_paper1.questions.add(self.question2) + self.ans_paper2.questions.add(self.question1) + self.ans_paper2.questions.add(self.question2) def tearDown(self): self.client.logout() @@ -2696,6 +2705,181 @@ class TestUploadMarks(TestCase): self.question2.delete() self.mod_group.delete() + def test_upload_users_marks_not_attempted_question(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_not_attempted_question.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + ans_paper = AnswerPaper.objects.get(user=self.student2, + question_paper=self.question_paper, + course=self.course) + self.assertEqual(ans_paper.marks_obtained, 1.3) + answer = Answer.objects.get(answer='answer12') + self.assertEqual(answer.comment.strip(), 'very good') + + def test_upload_users_marks_invalid_question_id(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_invalid_question_id.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + + def test_upload_users_marks_invalid_user(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_invalid_user.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + + def test_upload_users_marks_invalid_data(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_invalid_data.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + + def test_upload_users_marks_headers_missing(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_header_missing.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + ans_paper = AnswerPaper.objects.get(user=self.student1, + question_paper=self.question_paper, + course=self.course) + self.assertEqual(ans_paper.marks_obtained, 0.9) + + def test_upload_users_marks_headers_modified(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_header_modified.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + answer = Answer.objects.get(answer='answer1') + self.assertEqual(answer.comment.strip(), 'fine work') + self.assertNotEqual(answer.marks, 0.75) + answer = Answer.objects.get(answer='answer2') + self.assertEqual(answer.comment.strip(), 'not nice') + + def test_upload_users_marks_csv_single_question(self): + # Given + self.client.login( + username=self.teacher.username, + password='teacher' + ) + csv_file_path = os.path.join(FIXTURES_DIR_PATH, + "marks_single_question.csv") + csv_file = open(csv_file_path, 'rb') + upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) + + # When + response = self.client.post( + reverse('yaksh:upload_marks', + kwargs={'course_id': self.course.id, + 'questionpaper_id': self.question_paper.id}), + data={'csv_file': upload_file}) + csv_file.close() + + # Then + self.assertEqual(response.status_code, 302) + ans_paper = AnswerPaper.objects.get(user=self.student1, + question_paper=self.question_paper, + course=self.course) + self.assertEqual(ans_paper.marks_obtained, 0.5) + answer = Answer.objects.get(answer='answer1') + self.assertEqual(answer.comment.strip(), 'okay work') + def test_upload_users_with_correct_csv(self): # Given self.client.login( @@ -2705,7 +2889,6 @@ class TestUploadMarks(TestCase): csv_file_path = os.path.join(FIXTURES_DIR_PATH, "marks_correct.csv") csv_file = open(csv_file_path, 'rb') upload_file = SimpleUploadedFile(csv_file_path, csv_file.read()) - previous_total = self.ans_paper1.marks_obtained # When response = self.client.post( @@ -2717,7 +2900,6 @@ class TestUploadMarks(TestCase): # Then self.assertEqual(response.status_code, 302) - self.assertEqual(previous_total, 0) ans_paper = AnswerPaper.objects.get(user=self.student1, question_paper=self.question_paper, course=self.course) diff --git a/yaksh/views.py b/yaksh/views.py index 7a4810c..eb2cc31 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -4073,12 +4073,8 @@ def upload_marks(request, course_id, questionpaper_id): except TypeError: messages.warning(request, "Bad CSV file") return redirect('yaksh:monitor', quiz.id, course_id) - user_ids, question_ids = _get_header_info(reader) - csv_file.seek(0) - reader = csv.DictReader(csv_file.read().decode('utf-8').splitlines(), - dialect=dialect) - _read_marks_csv(reader, course, question_paper, user_ids, question_ids) - messages.warning(request, "Marks uploaded!") + question_ids = _get_header_info(reader) + _read_marks_csv(request, reader, course, question_paper, question_ids) return redirect('yaksh:monitor', quiz.id, course_id) @@ -4090,43 +4086,55 @@ def _get_header_info(reader): qid = int(field.split('-')[1]) if qid not in question_ids: question_ids.append(qid) - for row in reader: - username = row['username'] - user = User.objects.filter(username=username).first() - if not user: - pass - user_ids.append(user.id) - return user_ids, question_ids + return question_ids -def _read_marks_csv(reader, course, question_paper, user_ids, question_ids): - answerpapers = question_paper.answerpaper_set.filter(course=course, - user_id__in=user_ids) +def _read_marks_csv(request, reader, course, question_paper, question_ids): + messages.info(request, 'Marks Uploaded!') for row in reader: username = row['username'] user = User.objects.filter(username=username).first() - if not user: - pass - answerpaper = answerpapers.get(user=user) + if user: + answerpapers = question_paper.answerpaper_set.filter(course=course, + user_id=user.id) + else: + messages.info(request, '{0} user not found!'.format(username)) + continue + answerpaper = answerpapers.last() + if not answerpaper: + messages.info(request, '{0} has no answerpaper!'.format(username)) + continue answers = answerpaper.answers.all() - answered = answerpaper.questions_answered.all().values_list('id', - flat=True) + questions = answerpaper.questions.all().values_list('id', flat=True) for qid in question_ids: question = Question.objects.filter(id=qid).first() if not question: - pass - if qid in answered: + messages.info(request, + '{0} is an invalid question id!'.format(qid)) + continue + if qid in questions: answer = answers.filter(question_id=qid).last() if not answer: - pass - answer.set_marks( - float(row['Q-{0}-{1}-{2}-marks'.format( - qid, question.summary, question.points)]) - ) - answer.set_comment( - row['Q-{0}-{1}-comments'.format( - qid, question.summary, question.points)] - ) + answer = Answer(question_id=qid, marks=0, correct=False, + answer='Created During Marks Update!', + 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, + question.points) + if key1 in reader.fieldnames: + try: + answer.set_marks(float(row[key1])) + except ValueError: + messages.info(request, + '{0} invalid marks!'.format(row[key1])) + if key2 in reader.fieldnames: + answer.set_comment(row[key2]) answer.save() answerpaper.update_marks(state='completed') answerpaper.save() + messages.info(request, + 'Updated successfully for user: {0}, question: {1}'.format( + username, question.summary)) |