diff --git a/exams/forms.py b/exams/forms.py index 525c7dab..c231b484 100644 --- a/exams/forms.py +++ b/exams/forms.py @@ -13,9 +13,9 @@ class Meta: class ParticipationPointsForm(forms.Form): exam = forms.ModelChoiceField(PracticeExam.objects.filter(is_test=True)) - pks = forms.CharField( + sids = forms.CharField( widget=forms.Textarea, - help_text="ID's to create stuff for, paste one per line", + help_text="Student ID's to create stuff for, paste one per line", validators=[ RegexValidator(r"[0-9\n]+"), ], diff --git a/exams/tests.py b/exams/tests.py index 759d0eb2..ca6963dc 100644 --- a/exams/tests.py +++ b/exams/tests.py @@ -215,7 +215,7 @@ def test_mocks(self): self.login("dead") self.assertGetDenied("mocks", follow=True) - def test_participation_points(self): + def test_participation_points_with_one_semester(self): test_waltz = PracticeExam.objects.get(family="Waltz", is_test=True) quiz_waltz = PracticeExam.objects.get(family="Waltz", is_test=False) # first check that plebians can't login @@ -233,13 +233,13 @@ def test_participation_points(self): self.assertGetOK("participation-points") # invalid post self.assertHas( - self.assertPostOK("participation-points", data={"pks": "9001"}), + self.assertPostOK("participation-points", data={"sids": "9001"}), "This field is required", ) self.assertEqual(MockCompleted.objects.all().count(), 0) self.assertHas( self.assertPostOK( - "participation-points", data={"exam": quiz_waltz.pk, "pks": "9001"} + "participation-points", data={"exam": quiz_waltz.pk, "sids": "9001"} ), "Select a valid choice", ) @@ -247,7 +247,7 @@ def test_participation_points(self): resp1 = self.assertPostOK( "participation-points", - data={"exam": test_waltz.pk, "pks": "\n".join(pks[:4])}, + data={"exam": test_waltz.pk, "sids": "\n".join(pks[:4])}, ) self.assertHas(resp1, "Created 4 completion database entries") self.assertNotHas(resp1, "with existing entries") @@ -255,8 +255,29 @@ def test_participation_points(self): resp2 = self.assertPostOK( "participation-points", - data={"exam": test_waltz.pk, "pks": "\n".join(pks[2:7])}, + data={"exam": test_waltz.pk, "sids": "\n".join(pks[2:7])}, ) self.assertHas(resp2, "Created 3 completion database entries") self.assertHas(resp2, "There were 2 students with existing entries") self.assertEqual(MockCompleted.objects.all().count(), 7) + + def test_participation_points_multi_semester(self): + test_waltz = PracticeExam.objects.get(family="Waltz", is_test=True) + admin = UserFactory.create(is_staff=True, is_superuser=True) + self.login(admin) + cathy = UserFactory.create(username="cathy") + cathy_student_old = StudentFactory.create( + user=cathy, semester=ExamTest.semester_old + ) + cathy_student_new = StudentFactory.create( + user=cathy, semester=ExamTest.semester + ) + + resp = self.assertPostOK( + "participation-points", + data={"exam": test_waltz.pk, "sids": str(cathy_student_old.pk)}, + ) + self.assertHas(resp, "Created 1 completion database entries") + self.assertEqual(MockCompleted.objects.all().count(), 1) + mc = MockCompleted.objects.get() + self.assertEqual(mc.student.pk, cathy_student_new.pk) diff --git a/exams/views.py b/exams/views.py index a9fc97fe..933f726e 100644 --- a/exams/views.py +++ b/exams/views.py @@ -11,6 +11,7 @@ from exams.calculator import expr_compute from otisweb.decorators import admin_required from otisweb.utils import AuthHttpRequest +from roster.models import Student from roster.utils import get_student_by_pk, infer_student from .forms import ExamAttemptForm, ParticipationPointsForm @@ -151,11 +152,15 @@ def participation_points(request: AuthHttpRequest) -> HttpResponse: if request.method == "POST": form = ParticipationPointsForm(request.POST) if form.is_valid(): - pks = [ + sids = [ int(line) - for line in form.cleaned_data["pks"].splitlines() + for line in form.cleaned_data["sids"].splitlines() if line.strip().isdigit() ] + # Look for students whose ID's match those in SID's and active + pks = Student.objects.filter( + semester__active=True, user__student__pk__in=sids + ).values_list("pk", flat=True) existing_completes = MockCompleted.objects.filter( exam=form.cleaned_data["exam"] )