From 3541007ad28d4b5ed14c194e0ec6d52e26ed3bdd Mon Sep 17 00:00:00 2001 From: ApprenticeofEnder Date: Thu, 29 Apr 2021 22:33:27 -0400 Subject: [PATCH 1/2] Add attempt counter and uniqueness validation/testing --- .../migrations/0004_submission_attempts.py | 18 +++++++ .../migrations/0005_auto_20210430_0158.py | 17 +++++++ codechallenges/models.py | 7 +++ codechallenges/tests.py | 50 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 codechallenges/migrations/0004_submission_attempts.py create mode 100644 codechallenges/migrations/0005_auto_20210430_0158.py diff --git a/codechallenges/migrations/0004_submission_attempts.py b/codechallenges/migrations/0004_submission_attempts.py new file mode 100644 index 0000000..280a76f --- /dev/null +++ b/codechallenges/migrations/0004_submission_attempts.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.4 on 2021-04-30 01:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("codechallenges", "0003_submission_answer"), + ] + + operations = [ + migrations.AddField( + model_name="submission", + name="attempts", + field=models.IntegerField(default=0), + ), + ] diff --git a/codechallenges/migrations/0005_auto_20210430_0158.py b/codechallenges/migrations/0005_auto_20210430_0158.py new file mode 100644 index 0000000..f16ec36 --- /dev/null +++ b/codechallenges/migrations/0005_auto_20210430_0158.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.4 on 2021-04-30 01:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("codechallenges", "0004_submission_attempts"), + ] + + operations = [ + migrations.AlterUniqueTogether( + name="submission", + unique_together={("email", "question")}, + ), + ] diff --git a/codechallenges/models.py b/codechallenges/models.py index ec2c88c..2633a7d 100644 --- a/codechallenges/models.py +++ b/codechallenges/models.py @@ -38,3 +38,10 @@ class Submission(models.Model): question = models.ForeignKey( Question, on_delete=models.CASCADE, blank=True, null=True ) + attempts = models.IntegerField(default=0) + + class Meta: + unique_together = ( + "email", + "question", + ) diff --git a/codechallenges/tests.py b/codechallenges/tests.py index 7ce503c..761cf72 100644 --- a/codechallenges/tests.py +++ b/codechallenges/tests.py @@ -1,3 +1,53 @@ from django.test import TestCase +from codechallenges.models import Question, Submission +import datetime # Create your tests here. + + +class SubmissionTestCase(TestCase): + def test_unique_together(self): + question1 = Question.objects.create( + title="Yeet", + body="Blaghjdklahgjfkl", + format="t", + answer="Yote", + release_date=datetime.date.today(), + expiration_date=datetime.date(2022, 4, 29), + ) + + # Verify question 1 is created + self.assertNotEquals(question1, None) + + submission1 = Submission.objects.create( + email="test123@gmail.com", + answer="Yote", + correct=True, + question=question1, + attempts=5, + ) + + # Verify submission 1 is created + self.assertNotEquals(submission1, None) + + # This should pass because it's not a dupe! + submission2 = Submission.objects.create( + email="test124@gmail.com", + answer="Y0te", + correct=False, + question=question1, + attempts=5, + ) + + # Verify submission 3 is created + self.assertNotEquals(submission2, None) + + # This should fail due to duplicate checking + with self.assertRaises(Exception): + submission3 = Submission.objects.create( + email="test123@gmail.com", + answer="Yate", + correct=False, + question=question1, + attempts=5, + ) From 0e79a060281f99d71b3fa31805d6c506e9fb0d45 Mon Sep 17 00:00:00 2001 From: ApprenticeofEnder Date: Fri, 30 Apr 2021 15:06:49 -0400 Subject: [PATCH 2/2] Update views and tests to allow multiple submission attempts --- codechallenges/admin.py | 9 +++- .../migrations/0004_question_difficulty.py | 23 +++++++++ .../migrations/0006_merge_20210430_0347.py | 13 +++++ codechallenges/models.py | 10 ++++ codechallenges/serializers.py | 2 +- codechallenges/tests.py | 47 +++++++++++++++++++ codechallenges/views.py | 21 +++++++++ 7 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 codechallenges/migrations/0004_question_difficulty.py create mode 100644 codechallenges/migrations/0006_merge_20210430_0347.py diff --git a/codechallenges/admin.py b/codechallenges/admin.py index 1821a8d..a29f86e 100644 --- a/codechallenges/admin.py +++ b/codechallenges/admin.py @@ -6,7 +6,14 @@ @admin.register(Question) class CustomerQuestion(admin.ModelAdmin): - list_display = ("title", "body", "answer", "release_date", "expiration_date") + list_display = ( + "title", + "body", + "answer", + "release_date", + "expiration_date", + "difficulty", + ) @admin.register(Submission) diff --git a/codechallenges/migrations/0004_question_difficulty.py b/codechallenges/migrations/0004_question_difficulty.py new file mode 100644 index 0000000..ddffb28 --- /dev/null +++ b/codechallenges/migrations/0004_question_difficulty.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.4 on 2021-04-30 01:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("codechallenges", "0003_submission_answer"), + ] + + operations = [ + migrations.AddField( + model_name="question", + name="difficulty", + field=models.CharField( + blank=True, + choices=[("e", "easy"), ("m", "medium"), ("h", "hard")], + max_length=1, + null=True, + ), + ), + ] diff --git a/codechallenges/migrations/0006_merge_20210430_0347.py b/codechallenges/migrations/0006_merge_20210430_0347.py new file mode 100644 index 0000000..2694fb6 --- /dev/null +++ b/codechallenges/migrations/0006_merge_20210430_0347.py @@ -0,0 +1,13 @@ +# Generated by Django 3.1.4 on 2021-04-30 03:47 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("codechallenges", "0004_question_difficulty"), + ("codechallenges", "0005_auto_20210430_0158"), + ] + + operations = [] diff --git a/codechallenges/models.py b/codechallenges/models.py index 2633a7d..8763803 100644 --- a/codechallenges/models.py +++ b/codechallenges/models.py @@ -23,6 +23,16 @@ class Question(models.Model): answer = models.CharField(max_length=150) release_date = models.DateField() expiration_date = models.DateField() + difficulty = models.CharField( + choices=( + ("e", "easy"), + ("m", "medium"), + ("h", "hard"), + ), + max_length=1, + null=True, + blank=True, + ) event = models.ForeignKey( CodeChallengeEvent, on_delete=models.CASCADE, blank=True, null=True ) diff --git a/codechallenges/serializers.py b/codechallenges/serializers.py index bd03970..9c1c0ca 100644 --- a/codechallenges/serializers.py +++ b/codechallenges/serializers.py @@ -24,4 +24,4 @@ class Meta: class SubmissionSerializer(serializers.ModelSerializer): class Meta: model = Submission - fields = ("email", "correct", "answer", "question") + fields = ("email", "correct", "answer", "question", "attempts") diff --git a/codechallenges/tests.py b/codechallenges/tests.py index 761cf72..b810977 100644 --- a/codechallenges/tests.py +++ b/codechallenges/tests.py @@ -1,11 +1,58 @@ from django.test import TestCase +from rest_framework.test import APIRequestFactory from codechallenges.models import Question, Submission +from .views import SubmissionList import datetime # Create your tests here. class SubmissionTestCase(TestCase): + def test_submission(self): + question1 = Question.objects.create( + title="Yeet", + body="Blaghjdklahgjfkl", + format="t", + answer="Yote", + release_date=datetime.date.today(), + expiration_date=datetime.date(2022, 4, 29), + ) + factory = APIRequestFactory() + + # Makes and verifies successful request (first attempt) + attempt1 = factory.post( + "/api/codechallenges/submissions/", + { + "email": "robertbabaev@cmail.carleton.ca", + "question": 1, + "answer": "Yate", + }, + format="json", + ) + response = SubmissionList(attempt1) + self.assertEquals(response.status_code, 201) + + # Verifies submission creation + submissions = list(Submission.objects.all()) + self.assertEquals(submissions[0].attempts, 1) + + # Makes and verifies successful request (second attempt) + attempt2 = factory.post( + "/api/codechallenges/submissions/", + { + "email": "robertbabaev@cmail.carleton.ca", + "question": 1, + "answer": "Yote", + }, + format="json", + ) + response = SubmissionList(attempt2) + self.assertEquals(response.status_code, 200) + + # Verifies submission update + submissions = list(Submission.objects.all()) + self.assertEquals(submissions[0].attempts, 2) + def test_unique_together(self): question1 = Question.objects.create( title="Yeet", diff --git a/codechallenges/views.py b/codechallenges/views.py index daf19dc..622a478 100644 --- a/codechallenges/views.py +++ b/codechallenges/views.py @@ -20,6 +20,27 @@ def SubmissionList(request): except Question.DoesNotExist: return HttpResponse(status=500) + # Need to check if submission exists before creating one + try: + submission = Submission.objects.get( + question=data["question"], email=data["email"] + ) + submission.attempts += 1 + + if question.answer == data["answer"]: + submission.correct = True + else: + submission.correct = False + + submission.answer = data["answer"] + submission.save() + + serializer = SubmissionSerializer(submission) + + return JsonResponse(serializer.data, status=200) + except Submission.DoesNotExist: + data["attempts"] = 1 + if question.answer == data["answer"]: data["correct"] = True else: