-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dropped Courses #2262
base: main
Are you sure you want to change the base?
Dropped Courses #2262
Changes from all commits
226fe98
87632ce
22dac82
7772f66
6c7a434
a7ac9da
d572e48
146d44b
452b9b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Generated by Django 5.1.3 on 2025-01-27 18:32 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("evaluation", "0147_unusable_password_default"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="evaluation", | ||
name="dropout_count", | ||
field=models.IntegerField(default=0, verbose_name="dropout count"), | ||
), | ||
migrations.AlterField( | ||
model_name="questionnaire", | ||
name="type", | ||
field=models.IntegerField( | ||
choices=[ | ||
(10, "Top questionnaire"), | ||
(20, "Contributor questionnaire"), | ||
(30, "Bottom questionnaire"), | ||
(40, "Dropout questionnaire"), | ||
], | ||
default=10, | ||
verbose_name="type", | ||
), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
{% load evaluation_filters %} | ||
|
||
<!-- TODO: stimmt dieser template Name ? --> | ||
|
||
<fieldset> | ||
{% for field in evaluation_form %} | ||
{% if field == evaluation_form.general_questionnaires %} | ||
{% if field == evaluation_form.general_questionnaires or field == evaluation_form.dropout_questionnaires %} | ||
<div class="mb-3 d-flex"> | ||
{% include 'bootstrap_form_field_label.html' with field=field class='col-md-3 pe-4' %} | ||
<div class="col-md-7{% if field.errors %} is-invalid{% endif %}"> | ||
Comment on lines
1
to
10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @janno42 Is this a good name for this template? |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
from django.urls import reverse | ||
from model_bakery import baker | ||
|
||
from evap.evaluation.models import Evaluation, Question, QuestionType, Semester, UserProfile | ||
from evap.evaluation.models import NO_ANSWER, Evaluation, Question, Questionnaire, QuestionType, Semester, UserProfile | ||
from evap.evaluation.tests.tools import ( | ||
WebTest, | ||
WebTestWith200Check, | ||
|
@@ -14,6 +14,7 @@ | |
store_ts_test_asset, | ||
) | ||
from evap.staff.tests.utils import WebTestStaffMode | ||
from evap.student.tools import answer_field_id | ||
|
||
|
||
class RenderJsTranslationCatalog(WebTest): | ||
|
@@ -284,3 +285,92 @@ def test_reset_to_new(self) -> None: | |
self.reset_from_x_to_new(s, success_expected=True) | ||
for s in invalid_start_states: | ||
self.reset_from_x_to_new(s, success_expected=False) | ||
|
||
|
||
class TestDropoutQuestionnaire(WebTest): | ||
@classmethod | ||
def setUpTestData(cls) -> None: | ||
cls.user = baker.make(UserProfile, email="[email protected]") | ||
cls.user2 = baker.make(UserProfile, email="[email protected]") | ||
|
||
cls.question = baker.make(Question, type=QuestionType.POSITIVE_YES_NO) | ||
|
||
cls.normal_questionnaire = baker.make( | ||
Questionnaire, | ||
type=Questionnaire.Type.TOP, | ||
questions=[ | ||
baker.make(Question, type=QuestionType.TEXT), | ||
baker.make(Question, type=QuestionType.EASY_DIFFICULT), | ||
], | ||
) | ||
cls.dropout_questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.DROPOUT, questions=[cls.question]) | ||
|
||
cls.evaluation = baker.make( | ||
Evaluation, state=Evaluation.State.IN_EVALUATION, participants=[cls.user, cls.user2] | ||
) | ||
|
||
cls.evaluation.general_contribution.questionnaires.add(cls.dropout_questionnaire, cls.normal_questionnaire) | ||
|
||
def assert_no_answer_set_everywhere(self, form): | ||
for name, fields in form.fields.items(): | ||
if name is not None and name.startswith("question_"): | ||
field = fields[0] | ||
if field.tag == "textarea": | ||
self.assertEqual( | ||
fields[0].value, | ||
"", | ||
f"Answers to Questions in the general contribution should be set to NO_ANSWER (eg. {NO_ANSWER})", | ||
) | ||
else: | ||
self.assertEqual( | ||
fields[0].value, | ||
str(NO_ANSWER), | ||
f"Answers to Questions in the general contribution should be set to NO_ANSWER (eg. {NO_ANSWER})", | ||
) | ||
|
||
def test_choosing_dropout_sets_to_no_answer(self): | ||
response = self.app.get(url=reverse("student:drop", args=[self.evaluation.id]), user=self.user, status=200) | ||
form = response.forms["student-vote-form"] | ||
|
||
self.assertIn( | ||
answer_field_id(self.evaluation.general_contribution, self.dropout_questionnaire, self.question), | ||
form.fields.keys(), | ||
"The dropout Questionnaire should be shown", | ||
) | ||
self.assert_no_answer_set_everywhere(form) | ||
|
||
def test_dropout_possible_iff_dropout_questionnaire_attached(self): | ||
self.assertTrue(self.evaluation.is_dropout_allowed) | ||
self.assertTrue( | ||
self.evaluation.general_contribution.questionnaires.filter(type=Questionnaire.Type.DROPOUT).exists() | ||
) | ||
|
||
normal_questionnaires = self.evaluation.general_contribution.questionnaires.exclude( | ||
type=Questionnaire.Type.DROPOUT | ||
).all() | ||
self.evaluation.general_contribution.questionnaires.set(normal_questionnaires) | ||
|
||
self.assertFalse(self.evaluation.is_dropout_allowed) | ||
self.assertFalse( | ||
self.evaluation.general_contribution.questionnaires.filter(type=Questionnaire.Type.DROPOUT).exists() | ||
) | ||
|
||
def test_dropping_out_increments_dropout_counter(self): | ||
self.assertEqual(self.evaluation.dropout_count, 0, "dropout_count should be initially zero") | ||
|
||
form = self.app.get(url=reverse("student:drop", args=[self.evaluation.id]), user=self.user, status=200).forms[ | ||
"student-vote-form" | ||
] | ||
form.submit() | ||
evaluation = Evaluation.objects.get(pk=self.evaluation.pk) | ||
|
||
self.assertEqual(evaluation.dropout_count, 1, "dropout count should increment with dropout") | ||
|
||
form = self.app.get(url=reverse("student:vote", args=[self.evaluation.id]), user=self.user2, status=200).forms[ | ||
"student-vote-form" | ||
] | ||
form.submit() | ||
evaluation = Evaluation.objects.get(pk=self.evaluation.pk) | ||
|
||
self.assertEqual(evaluation.dropout_count, 1, "dropout_count should not change on normal vote") | ||
self.assertEqual(self.evaluation.dropout_count, 0, "other evaluation should not have been changed") |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -215,7 +215,7 @@ <h3>{{ evaluation.full_name }} ({{ evaluation.course.semester.name }})</h3> | |
{% endif %} | ||
|
||
{% if general_questionnaire_results_bottom %} | ||
<div class="card card-outline-primary"> | ||
<div class="card card-outline-primary mb-3"> | ||
<div class="card-header"> | ||
{% translate 'General' %} | ||
</div> | ||
|
@@ -227,6 +227,23 @@ <h3>{{ evaluation.full_name }} ({{ evaluation.course.semester.name }})</h3> | |
</div> | ||
{% endif %} | ||
|
||
{% if evaluation.is_dropout_allowed or evaluation.dropout_count > 0 or dropout_questionnaire_results %} | ||
<div class="card card-outline-primary mb-3"> | ||
<div class="card-header d-flex flex-row justify-content-between"> | ||
<span>{% translate 'Dropout' %}</span> | ||
|
||
<div class="badge-participants badge-participants-{{ evaluation.dropout_count|participationclass:evaluation.num_voters }} ms-2 ms-lg-3"> | ||
<span class="fas fa-user"></span> {{ evaluation.dropout_count }} | ||
</div> | ||
Comment on lines
+235
to
+237
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this shouldn't use bold text (inherited from |
||
</div> | ||
<div class="card-body"> | ||
{% for questionnaire_result in dropout_questionnaire_results %} | ||
{% include 'results_evaluation_detail_questionnaires.html' %} | ||
{% endfor %} | ||
</div> | ||
</div> | ||
{% endif %} | ||
|
||
{# Leave some space for big tooltips #} | ||
<div class="py-5 py-md-0"></div> | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would probably be better