-
Notifications
You must be signed in to change notification settings - Fork 148
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
Conversation
6545c8d
to
9ea80f3
Compare
d91a83b
to
2f42c54
Compare
2f42c54
to
e2e836e
Compare
c24d5dd
to
178fc31
Compare
0c1711f
to
2f3043b
Compare
dc783bf
to
96e9dc7
Compare
1fa6eb3
to
5a312ec
Compare
2cb0daf
to
cfcf4fd
Compare
cfcf4fd
to
0f5c592
Compare
9b73be5
to
a88760b
Compare
9993ca6
to
c89627a
Compare
@janno42 New proposal: You can add drop-out-questionnaires for each evaluation, just like adding general questionnaires. Simply by having at least one drop-out-questionnaire, the A) Does this seem like a good idea? and B) Do we still need to have the whole "active-drop-out-questionnaire" logic if we implement it like that? |
4933bf8
to
b722b2d
Compare
b722b2d
to
9b1ca48
Compare
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 the "Dropout Questionnaires" list in the contributor evaluation form is empty, the label should not be shown
Co-authored-by: Johannes Wolf <[email protected]>
Co-authored-by: Johannes Wolf <[email protected]>
952a2d1
to
7528c88
Compare
db7f3cc
to
4427ab1
Compare
4427ab1
to
727acca
Compare
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.
I haven't looked at results and staff yet, but here is what I have so far :)
@property | ||
def is_dropout_questionnaire(self): | ||
return self.type == self.Type.DROPOUT | ||
|
||
@property | ||
def is_general_questionnaire(self): | ||
return self.type in (self.Type.TOP, self.Type.BOTTOM) | ||
|
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.
Since these are defined on Questionnaire
, I suppose they could just be called is_dropout
and is_general
?
"password": "pbkdf2_sha256$870000$FI1vp6JGLvZULamq2a9pIL$TLLlUbFnxARDpJFRmuL+gVR9QtFc9fxww/K7pM1PixM=", | ||
"last_login": "2025-02-17T18:41:52.756", |
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.
Can you revert these, or does the CI fail then?
def get_vote_page_form_groups( | ||
request, evaluation: Evaluation, preview: bool, dropout=False | ||
) -> OrderedDict[Contribution, list[QuestionnaireVotingForm]]: |
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.
I think that all methods with a dropout
argument except vote
itself should not have a default value. In fact, vote
calls this function without passing its dropout
value along, and I don't know if it's correct
@@ -255,31 +296,38 @@ def render_vote_page(request, evaluation, preview, for_rendering_in_modal=False) | |||
|
|||
|
|||
@participant_required | |||
def vote(request, evaluation_id): # noqa: PLR0912 | |||
def vote(request: HttpRequest, evaluation_id: int, dropout=False): # noqa: PLR0912 |
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.
def vote(request: HttpRequest, evaluation_id: int, dropout=False): # noqa: PLR0912 | |
def vote(request: HttpRequest, evaluation_id: int, dropout=False) -> HttpResponse: # noqa: PLR0912 |
<input id="{{ choice.id_for_label }}" class="tab-selectable num-selectable btn-check" name="{{ choice.data.name }}" type="radio" value="{{ choice.data.value }}" autocomplete="off"{% if field.initial == choice.data.value %} checked="checked"{% endif %}{% if preview %} disabled{% endif %}/> | ||
<label for="{{ choice.id_for_label }}" class="btn btn-sm btn-light vote-btn vote-btn-{{ color }} d-flex{% if field.errors %} choice-error{% endif %}"> |
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.
I get the removal of active
, but for the other changes I am puzzled - can you explain why you changed these?
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.
field.value
was wrong, the value is stored in initial
<form method="get" action="{% url 'student:drop' evaluation.id %}"> | ||
<confirmation-modal type="submit" confirm-button-class="btn-danger"> |
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.
Please indent :)
<form method="get" action="{% url 'student:drop' evaluation.id %}"> | |
<confirmation-modal type="submit" confirm-button-class="btn-danger"> | |
<form method="get" action="{% url 'student:drop' evaluation.id %}"> | |
<confirmation-modal type="submit" confirm-button-class="btn-danger"> |
for q in Questionnaire.objects.all(): | ||
q.visibility = Questionnaire.Visibility.MANAGERS | ||
q.save() |
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.
for q in Questionnaire.objects.all(): | |
q.visibility = Questionnaire.Visibility.MANAGERS | |
q.save() | |
Questionnaire.objects.update(visibility=Questionnaire.Visibility.MANAGERS) |
self.assertContains(page, "General questionnaires") | ||
self.assertContains(page, "Dropout Questionnaires") |
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.
It's a bit odd that "questionnaires" is capitalized for one option, but not for the other 🤔
selected_questionnaires |= self.cleaned_data.get("general_questionnaires").filter(is_locked=False) | ||
selected_questionnaires |= self.cleaned_data.get("dropout_questionnaires").filter(is_locked=False) | ||
|
||
self.cleaned_data.update( |
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.
I find it a bit odd that we update the form values instead of throwing a ValidationError
when things don't add up. In person, we discussed that we can leave it as is for this PR because it is the same behavior as before, but I think we should revisit this afterwards. What do you think @richardebeling @Kakadus ?
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.
hm. In that case the UI should probably prevent users from deselecting the button directly
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) |
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.
I suppose this test class would be better placed in the student
app
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.
- The dropout button on the student index page should be placed inline before the "Evaluate" button.
- For the questions in the dropout questionnaire(s), no answers should be preselected.
selected_questionnaires |= self.cleaned_data.get("general_questionnaires").filter(is_locked=False) | ||
selected_questionnaires |= self.cleaned_data.get("dropout_questionnaires").filter(is_locked=False) | ||
|
||
self.cleaned_data.update( |
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.
hm. In that case the UI should probably prevent users from deselecting the button directly
class QuestionnaireManager(Manager["Questionnaire"]): | ||
def general_questionnaires(self) -> QuerySet["Questionnaire"]: | ||
return ( | ||
super().get_queryset().exclude(type=Questionnaire.Type.CONTRIBUTOR).exclude(type=Questionnaire.Type.DROPOUT) |
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.
super().get_queryset().exclude(type=Questionnaire.Type.CONTRIBUTOR).exclude(type=Questionnaire.Type.DROPOUT) | |
super().get_queryset().exclude(type__in=(Questionnaire.Type.CONTRIBUTOR, Questionnaire.Type.DROPOUT)) |
@@ -620,6 +639,10 @@ def runtime(self): | |||
def is_in_evaluation_period(self): | |||
return self.vote_start_datetime <= datetime.now() <= self.vote_end_datetime | |||
|
|||
@property | |||
def is_dropout_allowed(self): |
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.
def is_dropout_allowed(self): | |
def is_dropout_allowed(self) -> bool: |
fixes #991
(@janno42) As discussed, we want:
A setting "DROPOUT_QUESTIONNAIRE_ID" to set which questionnaire should be shown when using the drop-out function.Dropout questionnaire Textanswers should not be shown in the textanswer review