-
Notifications
You must be signed in to change notification settings - Fork 147
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
Draft
fekoch
wants to merge
52
commits into
e-valuation:main
Choose a base branch
from
fekoch:991/dropped-courses
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Dropped Courses #2262
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
af389cc
add todos
fekoch 47ba26a
add types
fekoch 8da669d
use icon instead of button
fekoch 8bdb847
drop button
fekoch e8639ae
drop button via extra template
fekoch 90c1ef8
implement modal
fekoch ff52040
allow_drop_out setting on evaluations
fekoch 4783dc5
[wip] dropout questionnaire
fekoch f3e4b68
[wip] query dropout questionnaire
fekoch 55a618c
add DROPOUT Questionnaire type
fekoch 5c196f3
[wip] dropout form
fekoch bdc96c3
[wip] select default dropout
fekoch 230e649
[wip] set_active_dropout
fekoch 25f12b6
remove superfluous space
fekoch c9e44db
fix whitespace in template
fekoch 3593c8a
add test
fekoch 9f17fdf
test set_active_dropout
fekoch fd5e136
change to ajax
fekoch de59f5f
!fixup fix migration
fekoch 291474e
select default for top/bottom questionnaires
fekoch 1d89b89
resolve comment
fekoch 01132e5
rebase migration
fekoch 8334c77
UI test for /drop/id route
fekoch 1fe5b22
manage.py formati
fekoch 8fe2deb
set initial via initial=
fekoch f459319
prevent Dropout questionnaires from being set to a different type
fekoch 3c86f93
merge view logic with vote-view
fekoch 2553ec0
run formatter
fekoch 778c36f
add todos
fekoch e8f6155
add test to make sure if dropout questionnaire is not included
fekoch f72f4a9
remove dropout questionnaires from average calculation
fekoch 40927b8
precommit
fekoch bc082b5
inject dropout questionnaire inside get_vote_page_form_groups
fekoch f26e906
make dropout-questionnaire un-editable by managers after there are an…
fekoch 5174138
don't show used counter for dropout questionnaires
fekoch f3b82da
add is_dropout_questionnaire property
fekoch ac8bfb8
fix missing dropout questionnaires
fekoch 423a9aa
resolve todo
fekoch dbe39a9
make sure if there are dropout-q's, set one as active
fekoch 51b98ae
add dropout count
fekoch 894c70f
remove prefetch thoughts
fekoch 4b9c4e7
can_be_deleted prop for DROPOUT
fekoch 309c13f
add todo
fekoch d060b8b
test for dropout counter and allow_drop_out
fekoch 7154858
handle ajax errors
fekoch f7d0ca1
add explanatory texts
fekoch bd2ae04
prevent HttpRequest typing issue
fekoch 5f5234b
fix too many local variables
fekoch d4f4080
change naming to placate linter
fekoch 0f5c592
add dropout questionnaire to testdata
fekoch 502aa31
add todos
fekoch 977a55d
wip dropout result view
fekoch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
44 changes: 44 additions & 0 deletions
44
evap/evaluation/migrations/0148_evaluation_allow_drop_out_and_more.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Generated by Django 5.1.1 on 2024-10-14 20:03 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("evaluation", "0147_unusable_password_default"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="evaluation", | ||
name="allow_drop_out", | ||
field=models.BooleanField(default=True, verbose_name="allow students to drop out"), | ||
), | ||
migrations.AddField( | ||
model_name="questionnaire", | ||
name="is_active_dropout_questionnaire", | ||
field=models.BooleanField( | ||
blank=True, default=None, null=True, unique=True, verbose_name="questionnaire is selected as active" | ||
), | ||
), | ||
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", | ||
), | ||
), | ||
migrations.AddField( | ||
model_name="evaluation", | ||
name="dropout_count", | ||
field=models.IntegerField(default=0, verbose_name="dropout count"), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,16 @@ | |
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, | ||
Contribution, | ||
Evaluation, | ||
Question, | ||
Questionnaire, | ||
QuestionType, | ||
Semester, | ||
UserProfile, | ||
) | ||
from evap.evaluation.tests.tools import ( | ||
WebTest, | ||
WebTestWith200Check, | ||
|
@@ -14,6 +23,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 +294,93 @@ 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.evaluation = baker.make( | ||
Evaluation, state=Evaluation.State.IN_EVALUATION, participants=[cls.user, cls.user2] | ||
) | ||
|
||
cls.q1 = baker.make( | ||
Question, | ||
type=QuestionType.POSITIVE_LIKERT, | ||
) | ||
cls.evaluation.general_contribution.questionnaires.add(cls.q1.questionnaire) | ||
|
||
cls.q2 = baker.make( | ||
Question, | ||
type=QuestionType.NEGATIVE_YES_NO, | ||
) | ||
cls.contribution = baker.make( | ||
Contribution, | ||
contributor=baker.make(UserProfile, email="[email protected]"), | ||
questionnaires=[cls.q2.questionnaire], | ||
evaluation=cls.evaluation, | ||
) | ||
|
||
def assert_no_answer_set(self, form): | ||
self.assertEqual( | ||
form.fields[answer_field_id(self.evaluation.general_contribution, self.q1.questionnaire, self.q1)][0].value, | ||
str(NO_ANSWER), | ||
f"Rating questions in the general contribution should be set to NO_ANSWER (eg. {NO_ANSWER})", | ||
) | ||
self.assertEqual( | ||
form.fields[answer_field_id(self.contribution, self.q2.questionnaire, self.q2)][0].value, | ||
str(NO_ANSWER), | ||
f"Rating questions in contributor questionnaires should be set to NO_ANSWER (eg. {NO_ANSWER})", | ||
) | ||
|
||
def test_no_dropout_questionnaire_chosen_does_still_work(self): | ||
self.assertFalse(Questionnaire.objects.dropout_questionnaires().exists()) | ||
response = self.app.get(url=reverse("student:drop", args=[self.evaluation.id]), user=self.user, status=200) | ||
|
||
self.assert_no_answer_set(response.forms["student-vote-form"]) | ||
|
||
def test_chosing_dropout_sets_to_no_answer(self): | ||
dropout_questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.DROPOUT) | ||
dropout_question = baker.make(Question, type=QuestionType.TEXT, questionnaire=dropout_questionnaire) | ||
|
||
dropout_questionnaire.set_active_dropout() | ||
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, dropout_questionnaire, dropout_question), | ||
form.fields.keys(), | ||
"The dropout Questionnaire should be shown", | ||
) | ||
self.assert_no_answer_set(form) | ||
|
||
def test_allow_dropout_is_respected(self): | ||
_ = self.app.get(url=reverse("student:vote", args=[self.evaluation.id]), user=self.user, status=200) | ||
_ = self.app.get(url=reverse("student:drop", args=[self.evaluation.id]), user=self.user, status=200) | ||
|
||
no_dropout_evaluation = baker.make( | ||
Evaluation, state=Evaluation.State.IN_EVALUATION, participants=[self.user], allow_drop_out=False | ||
) | ||
|
||
_ = self.app.get(url=reverse("student:vote", args=[no_dropout_evaluation.id]), user=self.user, status=200) | ||
_ = self.app.get(url=reverse("student:drop", args=[no_dropout_evaluation.id]), user=self.user, status=400) | ||
|
||
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() | ||
self.evaluation = Evaluation.objects.get(pk=self.evaluation.pk) | ||
|
||
self.assertEqual(self.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() | ||
self.evaluation = Evaluation.objects.get(pk=self.evaluation.pk) | ||
|
||
self.assertEqual(self.evaluation.dropout_count, 1, "dropout_count should not change on normal vote") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
If you're touching these and it's no trouble, it would probably be nice if you could also add the return type annotation (
-> QuerySet[Questionnaire]
or whatever it should be)(same for the views below that return
HttpResponse
. It's a bit annoying, but for backwards compatibility, no annotation always means "Any", even if the method always returns some specific type. I wonder if mypy issue 4409 will one day be implemented.)