def fill_form(self, form, fill_complete): form[question_id(self.course.general_contribution, self.top_course_questionnaire, self.top_text_question)] = "some text" form[question_id(self.course.general_contribution, self.top_course_questionnaire, self.top_grade_question)] = 3 form[question_id(self.course.general_contribution, self.top_course_questionnaire, self.top_likert_question)] = 1 form[question_id(self.course.general_contribution, self.bottom_course_questionnaire, self.bottom_text_question)] = "some bottom text" form[question_id(self.course.general_contribution, self.bottom_course_questionnaire, self.bottom_grade_question)] = 4 form[question_id(self.course.general_contribution, self.bottom_course_questionnaire, self.bottom_likert_question)] = 2 form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_text_question)] = "some other text" form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_likert_question)] = 4 form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_text_question)] = "some more text" if fill_complete: form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_likert_question)] = 2
def test_incomplete_form(self): """ Submits a student vote, verifies that an error message is displayed if not all rating questions have been answered and that all given answers stay selected/filled. """ page = self.app.get(self.url, user=self.voting_user1.username, status=200) form = page.forms["student-vote-form"] self.fill_form(form, fill_complete=False) response = form.submit() self.assertEqual(response.status_code, 200) self.assertIn("vote for all rating questions", response) form = page.forms["student-vote-form"] self.assertEqual(form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_text_question)].value, "some text") self.assertEqual(form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_likert_question)].value, "1") self.assertEqual(form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_grade_question)].value, "3") self.assertEqual(form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_text_question)].value, "some bottom text") self.assertEqual(form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_likert_question)].value, "2") self.assertEqual(form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_grade_question)].value, "4") self.assertEqual(form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_text_question)].value, "some other text") self.assertEqual(form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_likert_question)].value, "4") self.assertEqual(form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_text_question)].value, "some more text")
def test_incomplete_form(self): """ Submits a student vote, verifies that an error message is displayed if not all rating questions have been answered and that all given answers stay selected/filled. """ page = self.app.get(self.url, user=self.voting_user1.username, status=200) form = page.forms["student-vote-form"] self.fill_form(form, fill_complete=False) response = form.submit() self.assertEqual(response.status_code, 200) self.assertIn("vote for all rating questions", response) form = page.forms["student-vote-form"] self.assertEqual(form[question_id(self.course.general_contribution, self.top_general_questionnaire, self.top_text_question)].value, "some text") self.assertEqual(form[question_id(self.course.general_contribution, self.top_general_questionnaire, self.top_likert_question)].value, "1") self.assertEqual(form[question_id(self.course.general_contribution, self.top_general_questionnaire, self.top_grade_question)].value, "3") self.assertEqual(form[question_id(self.course.general_contribution, self.bottom_general_questionnaire, self.bottom_text_question)].value, "some bottom text") self.assertEqual(form[question_id(self.course.general_contribution, self.bottom_general_questionnaire, self.bottom_likert_question)].value, "2") self.assertEqual(form[question_id(self.course.general_contribution, self.bottom_general_questionnaire, self.bottom_grade_question)].value, "4") self.assertEqual(form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_text_question)].value, "some other text") self.assertEqual(form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_likert_question)].value, "4") self.assertEqual(form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_text_question)].value, "some more text")
def let_user_vote_for_evaluation(app, user, evaluation): url = '/student/vote/{}'.format(evaluation.id) page = app.get(url, user=user, status=200) form = page.forms["student-vote-form"] for contribution in evaluation.contributions.all().prefetch_related("questionnaires", "questionnaires__questions"): for questionnaire in contribution.questionnaires.all(): for question in questionnaire.questions.all(): if question.is_text_question: form[question_id(contribution, questionnaire, question)] = "Lorem ispum" elif question.is_rating_question: form[question_id(contribution, questionnaire, question)] = 1 form.submit()
def let_user_vote_for_course(self, user, course): url = '/student/vote/{}'.format(course.id) page = self.app.get(url, user=user, status=200) form = page.forms["student-vote-form"] for contribution in course.contributions.all().prefetch_related("questionnaires", "questionnaires__question_set"): for questionnaire in contribution.questionnaires.all(): for question in questionnaire.question_set.all(): if question.type == "T": form[question_id(contribution, questionnaire, question)] = "Lorem ispum" elif question.type in ["L", "G", "P", "N"]: form[question_id(contribution, questionnaire, question)] = 1 form.submit()
def let_user_vote_for_course(app, user, course): url = '/student/vote/{}'.format(course.id) page = app.get(url, user=user, status=200) form = page.forms["student-vote-form"] for contribution in course.contributions.all().prefetch_related( "questionnaires", "questionnaires__questions"): for questionnaire in contribution.questionnaires.all(): for question in questionnaire.questions.all(): if question.type == "T": form[question_id(contribution, questionnaire, question)] = "Lorem ispum" elif question.type in ["L", "G", "P", "N"]: form[question_id(contribution, questionnaire, question)] = 1 form.submit()
def fill_form(self, form, fill_complete): form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_text_question)] = "some text" form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_grade_question)] = 3 form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_likert_question)] = 1 form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_text_question)] = "some bottom text" form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_grade_question)] = 4 form[question_id(self.evaluation.general_contribution, self.bottom_general_questionnaire, self.bottom_likert_question)] = 2 form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_text_question)] = "some other text" form[question_id(self.contribution1, self.contributor_questionnaire, self.contributor_likert_question)] = 4 form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_text_question)] = "some more text" if fill_complete: form[question_id(self.contribution2, self.contributor_questionnaire, self.contributor_likert_question)] = 2
def __init__(self, *args, contribution, questionnaire, **kwargs): super().__init__(*args, **kwargs) self.questionnaire = questionnaire for question in self.questionnaire.questions.all(): # generic arguments for all kinds of fields field_args = dict(label=question.text) if question.is_text_question: field = forms.CharField(required=False, widget=forms.Textarea(), **field_args) elif question.is_rating_question: choices = CHOICES[question.type] field = forms.TypedChoiceField(widget=forms.RadioSelect(attrs={'choices': choices}), choices=zip(choices.values, choices.names), coerce=int, **field_args) elif question.is_heading_question: field = HeadingField(label=question.text) identifier = question_id(contribution, questionnaire, question) self.fields[identifier] = field
def __init__(self, *args, contribution, questionnaire, **kwargs): super().__init__(*args, **kwargs) self.questionnaire = questionnaire for question in self.questionnaire.questions.all(): # generic arguments for all kinds of fields field_args = dict(label=question.text) if question.is_text_question: field = forms.CharField(required=False, widget=forms.Textarea(), **field_args) elif question.is_rating_question: choices = CHOICES[question.type] field = forms.TypedChoiceField( widget=forms.RadioSelect(attrs={'choices': choices}), choices=zip(choices.values, choices.names), coerce=int, **field_args) elif question.is_heading_question: field = HeadingField(label=question.text) identifier = question_id(contribution, questionnaire, question) self.fields[identifier] = field
def test_xmin_of_all_answers_is_updated(self): page = self.app.get(self.url, user=self.voting_user1) form = page.forms["student-vote-form"] self.fill_form(form) form.submit() page = self.app.get(self.url, user=self.voting_user2) form = page.forms["student-vote-form"] self.fill_form(form) form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_grade_question)] = 2 form.submit() self.assertEqual( set(Answer.__subclasses__()), {RatingAnswerCounter, TextAnswer}, "This test requires an update if a new answer type is added. Also, when adding a new answer type, " "the new table should probably also be vacuumed and clustered -- see and update " "https://github.com/e-valuation/EvaP/wiki/Installation#database-vacuuming-and-clustering" ) query = RatingAnswerCounter.objects.raw("SELECT id, xmin FROM evaluation_ratinganswercounter") rating_answer_xmins = [row.xmin for row in query] self.assertTrue(all(xmin == rating_answer_xmins[0] for xmin in rating_answer_xmins)) query = TextAnswer.objects.raw("SELECT id, xmin FROM evaluation_textanswer") text_answer_xmins = [row.xmin for row in query] self.assertTrue(all(xmin == text_answer_xmins[0] for xmin in text_answer_xmins))
def test_xmin_of_all_answers_is_updated(self): page = self.app.get(self.url, user=self.voting_user1) form = page.forms["student-vote-form"] self.fill_form(form) form.submit() page = self.app.get(self.url, user=self.voting_user2) form = page.forms["student-vote-form"] self.fill_form(form) form[question_id(self.evaluation.general_contribution, self.top_general_questionnaire, self.top_grade_question)] = 2 form.submit() self.assertEqual( set(Answer.__subclasses__()), {RatingAnswerCounter, TextAnswer}, "This requires an update if a new answer type is added") query = RatingAnswerCounter.objects.raw( "SELECT id, xmin FROM evaluation_ratinganswercounter") rating_answer_xmins = [row.xmin for row in query] self.assertTrue( all(xmin == rating_answer_xmins[0] for xmin in rating_answer_xmins)) query = TextAnswer.objects.raw( "SELECT id, xmin FROM evaluation_textanswer") text_answer_xmins = [row.xmin for row in query] self.assertTrue( all(xmin == text_answer_xmins[0] for xmin in text_answer_xmins))
def vote(request, evaluation_id): evaluation = get_object_or_404(Evaluation, id=evaluation_id) if not evaluation.can_user_vote(request.user): raise PermissionDenied form_groups, rendered_page = get_valid_form_groups_or_render_vote_page( request, evaluation, preview=False) if rendered_page is not None: return rendered_page # all forms are valid, begin vote operation with transaction.atomic(): # add user to evaluation.voters # not using evaluation.voters.add(request.user) since that fails silently when done twice. evaluation.voters.through.objects.create( userprofile_id=request.user.pk, evaluation_id=evaluation.pk) for contribution, form_group in form_groups.items(): for questionnaire_form in form_group: questionnaire = questionnaire_form.questionnaire for question in questionnaire.questions.all(): if question.is_heading_question: continue identifier = question_id(contribution, questionnaire, question) value = questionnaire_form.cleaned_data.get(identifier) if question.is_text_question: if value: question.answer_class.objects.create( contribution=contribution, question=question, answer=value) else: if value != NO_ANSWER: answer_counter, __ = question.answer_class.objects.get_or_create( contribution=contribution, question=question, answer=value) answer_counter.count += 1 answer_counter.save() if not evaluation.can_publish_text_results: # enable text result publishing if first user confirmed that publishing is okay or second user voted if request.POST.get('text_results_publish_confirmation_top' ) == 'on' or request.POST.get( 'text_results_publish_confirmation_bottom' ) == 'on' or evaluation.voters.count() >= 2: evaluation.can_publish_text_results = True evaluation.save() evaluation.evaluation_evaluated.send( sender=Evaluation, request=request, semester=evaluation.course.semester) messages.success(request, _("Your vote was recorded.")) return HttpResponse(SUCCESS_MAGIC_STRING)
def vote(request, course_id): course = get_object_or_404(Course, id=course_id) if not course.can_user_vote(request.user): raise PermissionDenied form_groups, rendered_page = get_valid_form_groups_or_render_vote_page( request, course, preview=False) if rendered_page is not None: return rendered_page # all forms are valid, begin vote operation with transaction.atomic(): # add user to course.voters # not using course.voters.add(request.user) since it fails silently when done twice. # manually inserting like this gives us the 'created' return value and ensures at the database level that nobody votes twice. __, created = course.voters.through.objects.get_or_create( userprofile_id=request.user.pk, course_id=course.pk) if not created: # vote already got recorded, bail out raise SuspiciousOperation( "A second vote has been received shortly after the first one.") for contribution, form_group in form_groups.items(): for questionnaire_form in form_group: questionnaire = questionnaire_form.questionnaire for question in questionnaire.question_set.all(): identifier = question_id(contribution, questionnaire, question) value = questionnaire_form.cleaned_data.get(identifier) if question.is_text_question: if value: question.answer_class.objects.create( contribution=contribution, question=question, answer=value) elif question.is_heading_question: pass # ignore these else: if value != 6: answer_counter, __ = question.answer_class.objects.get_or_create( contribution=contribution, question=question, answer=value) answer_counter.add_vote() answer_counter.save() course.course_evaluated.send(sender=Course, request=request, semester=course.semester) messages.success(request, _("Your vote was recorded.")) return HttpResponse(SUCCESS_MAGIC_STRING)
def vote(request, evaluation_id): evaluation = get_object_or_404(Evaluation, id=evaluation_id) if not evaluation.can_be_voted_for_by(request.user): raise PermissionDenied form_groups, rendered_page = get_valid_form_groups_or_render_vote_page(request, evaluation, preview=False) if rendered_page is not None: return rendered_page # all forms are valid, begin vote operation with transaction.atomic(): # add user to evaluation.voters # not using evaluation.voters.add(request.user) since that fails silently when done twice. evaluation.voters.through.objects.create(userprofile_id=request.user.pk, evaluation_id=evaluation.pk) for contribution, form_group in form_groups.items(): for questionnaire_form in form_group: questionnaire = questionnaire_form.questionnaire for question in questionnaire.questions.all(): if question.is_heading_question: continue identifier = question_id(contribution, questionnaire, question) value = questionnaire_form.cleaned_data.get(identifier) if question.is_text_question: if value: question.answer_class.objects.create(contribution=contribution, question=question, answer=value) else: if value != NO_ANSWER: answer_counter, __ = question.answer_class.objects.get_or_create(contribution=contribution, question=question, answer=value) answer_counter.count += 1 answer_counter.save() if not evaluation.can_publish_text_results: # enable text result publishing if first user confirmed that publishing is okay or second user voted if request.POST.get('text_results_publish_confirmation_top') == 'on' or request.POST.get('text_results_publish_confirmation_bottom') == 'on' or evaluation.voters.count() >= 2: evaluation.can_publish_text_results = True evaluation.save() evaluation.evaluation_evaluated.send(sender=Evaluation, request=request, semester=evaluation.course.semester) messages.success(request, _("Your vote was recorded.")) return HttpResponse(SUCCESS_MAGIC_STRING)
def __init__(self, *args, contribution, questionnaire, **kwargs): super().__init__(*args, **kwargs) self.questionnaire = questionnaire for question in self.questionnaire.question_set.all(): # generic arguments for all kinds of fields field_args = dict(label=question.text) if question.is_text_question: field = forms.CharField(required=False, widget=forms.Textarea(), **field_args) elif question.is_likert_question: field = forms.TypedChoiceField(widget=forms.RadioSelect(), choices=LIKERT_CHOICES, coerce=int, **field_args) elif question.is_grade_question: field = forms.TypedChoiceField(widget=forms.RadioSelect(), choices=GRADE_CHOICES, coerce=int, **field_args) elif question.is_positive_yes_no_question: field = forms.TypedChoiceField(widget=forms.RadioSelect(), choices=POSITIVE_YES_NO_CHOICES, coerce=int, **field_args) elif question.is_negative_yes_no_question: field = forms.TypedChoiceField(widget=forms.RadioSelect(), choices=NEGATIVE_YES_NO_CHOICES, coerce=int, **field_args) elif question.is_heading_question: field = HeadingField(label=question.text) identifier = question_id(contribution, questionnaire, question) self.fields[identifier] = field
def vote(request, course_id): # retrieve course and make sure that the user is allowed to vote course = get_object_or_404(Course, id=course_id) if not course.can_user_vote(request.user): raise PermissionDenied # prevent a user from voting on themselves. contributions_to_vote_on = course.contributions.exclude( contributor=request.user).all() form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on) if not all( all(form.is_valid() for form in form_group) for form_group in form_groups.values()): errors_exist = any( helper_has_errors(form_group) for form_group in form_groups.values()) course_form_group = form_groups.pop(course.general_contribution) contributor_form_groups = list( (contribution.contributor, contribution.label, form_group, helper_has_errors(form_group)) for contribution, form_group in form_groups.items()) template_data = dict(errors_exist=errors_exist, course_form_group=course_form_group, contributor_form_groups=contributor_form_groups, course=course, participants_warning=course.num_participants <= 5, preview=False) return render(request, "student_vote.html", template_data) # all forms are valid, begin vote operation with transaction.atomic(): # add user to course.voters # not using course.voters.add(request.user) since it fails silently when done twice. # manually inserting like this gives us the 'created' return value and ensures at the database level that nobody votes twice. __, created = course.voters.through.objects.get_or_create( userprofile_id=request.user.pk, course_id=course.pk) if not created: # vote already got recorded, bail out raise SuspiciousOperation( "A second vote has been received shortly after the first one.") for contribution, form_group in form_groups.items(): for questionnaire_form in form_group: questionnaire = questionnaire_form.questionnaire for question in questionnaire.question_set.all(): identifier = question_id(contribution, questionnaire, question) value = questionnaire_form.cleaned_data.get(identifier) if question.is_text_question: if value: question.answer_class.objects.create( contribution=contribution, question=question, answer=value) else: if value != 6: answer_counter, __ = question.answer_class.objects.get_or_create( contribution=contribution, question=question, answer=value) answer_counter.add_vote() answer_counter.save() course.course_evaluated.send(sender=Course, request=request, semester=course.semester) messages.success(request, _("Your vote was recorded.")) return redirect('student:index')