Repository: e-valuation/EvaP

Issue:
Add due date in evaluation started email
The "Evaluation Started" email for participants should include the due date for the evaluation that just started.
Currently, only all other evaluations that are still due are listed below the new evaluation with their respective due dates.


Discussion:

Resolving patch:
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -1807,9 +1807,13 @@ def send_to_users_in_evaluations(self, evaluations, recipient_groups, use_cc, re
 
         for user, user_evaluations in user_evaluation_map.items():
             subject_params = {}
+            evaluations_with_date = dict()
+            for evaluation in user_evaluations:
+                evaluations_with_date[evaluation] = (evaluation.vote_end_date - date.today()).days
+            evaluations_with_date = sorted(evaluations_with_date.items(), key=lambda tup: tup[0].full_name)
             body_params = {
                 "user": user,
-                "evaluations": user_evaluations,
+                "evaluations": evaluations_with_date,
                 "due_evaluations": user.get_sorted_due_evaluations(),
             }
             self.send_to_user(user, subject_params, body_params, use_cc=use_cc, request=request)
@@ -1934,7 +1938,7 @@ def send_contributor_publish_notifications(cls, evaluations, template=None):
                         evaluations_per_contributor[textanswer.contribution.contributor].add(evaluation)
 
         for contributor, evaluation_set in evaluations_per_contributor.items():
-            body_params = {"user": contributor, "evaluations": list(evaluation_set)}
+            body_params = {"user": contributor, "evaluations": evaluation_set}
             template.send_to_user(contributor, {}, body_params, use_cc=True)
 
     @classmethod


Test patch:
diff --git a/evap/development/fixtures/test_data.json b/evap/development/fixtures/test_data.json
--- a/evap/development/fixtures/test_data.json
+++ b/evap/development/fixtures/test_data.json
@@ -128349,8 +128349,8 @@
   "fields": {
     "name": "Evaluation Started",
     "subject": "[EvaP] Evaluierung hat begonnen / Evaluation started",
-    "plain_content": "{% load evaluation_filters %}(English version below)\r\n\r\n\r\nHallo {{ user.first_name }},\r\n\r\nfür die folgenden Evaluierungen hat die Evaluierungsphase begonnen:\r\n{% for evaluation in evaluations|order_by:\"full_name_de\" %}    - {{ evaluation.full_name_de }}\r\n{% endfor %}\r\nDu kannst dein Feedback auf EvaP{% if not user.needs_login_key %} ({{ page_url }}){% endif %} abgeben, die Dozenten und wir freuen uns über deine Bewertung. Bei Fragen und Rückmeldungen kannst du dich jederzeit an uns wenden ({{ contact_email }}).\r\n{% if user.needs_login_key %}\r\nKlicke hier, um dich anzumelden: {{ login_url }}\r\n{% endif %}\r\n{% if due_evaluations|length > 1%}Diese Evaluierungen warten auf deine Bewertung:\r\n{% for evaluation, due_in_days in due_evaluations %}    - {{ evaluation.full_name_de }} (endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})\r\n{% endfor %}{% endif %}\r\nVielen Dank für deine Mühe und viele Grüße,\r\ndas Evaluierungsteam\r\n\r\n(Dies ist eine automatisch versendete E-Mail.)\r\n\r\n\r\n--\r\n\r\n\r\nDear {{ user.first_name }},\r\n\r\nThe evaluation period for the following evaluations just started:\r\n{% for evaluation in evaluations|order_by:\"full_name_en\" %}    - {{ evaluation.full_name_en }}\r\n{% endfor %}\r\nYou can evaluate them on EvaP{% if not user.needs_login_key %} ({{ page_url }}){% endif %}. The lecturers and we are looking forward to receive your feedback. If you have any questions or feedback, please let us know ({{ contact_email }}).\r\n{% if user.needs_login_key %}\r\nClick here to login: {{ login_url }}\r\n{% endif %}\r\n{% if due_evaluations|length > 1%}These evaluations are waiting for your feedback:\r\n{% for evaluation, due_in_days in due_evaluations %}    - {{ evaluation.full_name_en }} (ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})\r\n{% endfor %}{% endif %}\r\nThank you very much for your efforts and kind regards,\r\nthe Evaluation Team\r\n\r\n(This is an automated message.)",
-    "html_content": "{% load evaluation_filters %}\r\n<i>(English version below)</i><br /><br /><br />\r\n\r\n\r\nHallo {{ user.first_name }},<br /><br />\r\n\r\nfür die folgenden Evaluierungen hat die Evaluierungsphase begonnen:\r\n<ul>{% for evaluation in evaluations|order_by:\"full_name_de\" %}\r\n<li>{{ evaluation.full_name_de }}</li>\r\n{% endfor %}</ul><br />\r\n\r\nDu kannst dein Feedback auf EvaP{% if not user.needs_login_key %} (<a href=\"{{ page_url }}\">{{ page_url }}</a>){% endif %} abgeben, die Dozenten und wir freuen uns über deine Bewertung. Bei Fragen und Rückmeldungen kannst du dich jederzeit an uns wenden (<a href=\"mailto:{{ contact_email }}\">{{ contact_email }}</a>).<br /><br />\r\n\r\n{% if user.needs_login_key %}\r\nKlicke hier, um dich anzumelden: <a href=\"{{ login_url }}\">{{ login_url }}</a><br /><br />\r\n{% endif %}\r\n\r\n{% if due_evaluations|length > 1%}\r\nDiese Evaluierungen warten auf deine Bewertung:\r\n<ul>{% for evaluation, due_in_days in due_evaluations %}\r\n<li>{{ evaluation.full_name_de }} (endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})</li>\r\n{% endfor %}</ul><br />\r\n{% endif %}\r\n\r\nVielen Dank für deine Mühe und viele Grüße,<br />\r\ndas Evaluierungsteam<br /><br />\r\n\r\n<i>(Dies ist eine automatisch versendete E-Mail.)</i><br /><br />\r\n\r\n<hr><br /><br />\r\n\r\nDear {{ user.first_name }},<br /><br />\r\n\r\nThe evaluation period for the following evaluations just started:\r\n<ul>{% for evaluation in evaluations|order_by:\"full_name_en\" %}\r\n<li>{{ evaluation.full_name_en }}</li>\r\n{% endfor %}</ul><br />\r\n\r\nYou can evaluate them on EvaP{% if not user.needs_login_key %} (<a href=\"{{ page_url }}\">{{ page_url }}</a>){% endif %}. The lecturers and we are looking forward to receive your feedback. If you have any questions or feedback, please let us know (<a href=\"mailto:{{ contact_email }}\">{{ contact_email }}</a>).<br /><br />\r\n\r\n{% if user.needs_login_key %}\r\nClick here to login: <a href=\"{{ login_url }}\">{{ login_url }}</a><br /><br />\r\n{% endif %}\r\n{% if due_evaluations|length > 1%}\r\nThese evaluations are waiting for your feedback:\r\n<ul>{% for evaluation, due_in_days in due_evaluations %}\r\n<li>{{ evaluation.full_name_en }} (ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})</li>\r\n{% endfor %}</ul><br />\r\n{% endif %}\r\n\r\nThank you very much for your efforts and kind regards,<br />\r\nthe Evaluation Team<br /><br />\r\n\r\n<i>(This is an automated message.)</i>"
+    "plain_content": "{% load evaluation_filters %}(English version below)\r\n\r\n\r\nHallo {{ user.first_name }},\r\n\r\nfür die folgenden Evaluierungen hat die Evaluierungsphase begonnen:\r\n{% for evaluation, due_in_days in evaluations %}    - {{ evaluation.full_name_de }} (endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})\r\n{% endfor %}\r\nDu kannst dein Feedback auf EvaP{% if not user.needs_login_key %} (https://evap.hpi.de){% endif %} abgeben, die Dozenten und wir freuen uns über deine Bewertung. Bei Fragen und Rückmeldungen kannst du dich jederzeit an uns wenden (evaluierung@hpi.de).\r\n\r\n{% if user.needs_login_key %}Klicke hier, um dich anzumelden: {{ login_url }}\r\n{% endif %}{% if due_evaluations|length > 1%}Diese Evaluierungen warten auf deine Bewertung:\r\n{% for evaluation, due_in_days in due_evaluations %}    - {{ evaluation.full_name_de }} (endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})\r\n{% endfor %}{% endif %}\r\nVielen Dank für deine Mühe und viele Grüße,\r\ndas Evaluierungsteam\r\n\r\n(Dies ist eine automatisch versendete E-Mail.)\r\n\r\n\r\n--\r\n\r\nDear {{ user.first_name }},\r\n\r\nThe evaluation period for the following evaluations just started:\r\n{% for evaluation, due_in_days in evaluations%}    - {{ evaluation.full_name_en }} (ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})\r\n{% endfor %}\r\nYou can evaluate them on EvaP{% if not user.needs_login_key %} (https://evap.hpi.de){% endif %}. The lecturers and we are looking forward to receive your feedback. If you have any questions or feedback, please let us know (evaluierung@hpi.de).\r\n\r\n{% if user.needs_login_key %}Click here to login: {{ login_url }}\r\n{% endif %}{% if due_evaluations|length > 1%}These evaluations are waiting for your feedback:\r\n{% for evaluation, due_in_days in due_evaluations %}    - {{ evaluation.full_name_en }} (ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})\r\n{% endfor %}{% endif %}\r\nThank you very much for your efforts and kind regards,\r\nthe Evaluation Team\r\n\r\n(This is an automated message.)",
+    "html_content": "{% load evaluation_filters %}\r\n<i>(English version below)</i><br /><br /><br />\r\n\r\n\r\nHallo {{ user.first_name }},<br /><br />\r\n\r\nfür die folgenden Evaluierungen hat die Evaluierungsphase begonnen:\r\n<ul>{% for evaluation, due_in_days in evaluations %} \r\n<li>{{ evaluation.full_name_de }}</li>\r\n(endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})\r\n{% endfor %}</ul><br />\r\n\r\nDu kannst dein Feedback auf EvaP{% if not user.needs_login_key %} (<a href=\"{{ page_url }}\">{{ page_url }}</a>){% endif %} abgeben, die Dozenten und wir freuen uns über deine Bewertung. Bei Fragen und Rückmeldungen kannst du dich jederzeit an uns wenden (<a href=\"mailto:{{ contact_email }}\">{{ contact_email }}</a>).<br /><br />\r\n\r\n{% if user.needs_login_key %}\r\nKlicke hier, um dich anzumelden: <a href=\"{{ login_url }}\">{{ login_url }}</a><br /><br />\r\n{% endif %}\r\n\r\n{% if due_evaluations|length > 1%}\r\nDiese Evaluierungen warten auf deine Bewertung:\r\n<ul>{% for evaluation, due_in_days in due_evaluations %}\r\n<li>{{ evaluation.full_name_de }} (endet {% if due_in_days == 0 %}heute{% elif due_in_days == 1 %}morgen{% else %}in {{ due_in_days }} Tagen{% endif %})</li>\r\n{% endfor %}</ul><br />\r\n{% endif %}\r\n\r\nVielen Dank für deine Mühe und viele Grüße,<br />\r\ndas Evaluierungsteam<br /><br />\r\n\r\n<i>(Dies ist eine automatisch versendete E-Mail.)</i><br /><br />\r\n\r\n<hr><br /><br />\r\n\r\nDear {{ user.first_name }},<br /><br />\r\n\r\nThe evaluation period for the following evaluations just started:\r\n<ul>{{% for evaluation, due_in_days in evaluations%}\r\n<li>{{ evaluation.full_name_en }}</li>\r\n(ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})\r\n{% endfor %}</ul><br />\r\n\r\nYou can evaluate them on EvaP{% if not user.needs_login_key %} (<a href=\"{{ page_url }}\">{{ page_url }}</a>){% endif %}. The lecturers and we are looking forward to receive your feedback. If you have any questions or feedback, please let us know (<a href=\"mailto:{{ contact_email }}\">{{ contact_email }}</a>).<br /><br />\r\n\r\n{% if user.needs_login_key %}\r\nClick here to login: <a href=\"{{ login_url }}\">{{ login_url }}</a><br /><br />\r\n{% endif %}\r\n{% if due_evaluations|length > 1%}\r\nThese evaluations are waiting for your feedback:\r\n<ul>{% for evaluation, due_in_days in due_evaluations %}\r\n<li>{{ evaluation.full_name_en }} (ends {% if due_in_days == 0 %}today{% elif due_in_days == 1 %}tomorrow{% else %}in {{ due_in_days }} days{% endif %})</li>\r\n{% endfor %}</ul><br />\r\n{% endif %}\r\n\r\nThank you very much for your efforts and kind regards,<br />\r\nthe Evaluation Team<br /><br />\r\n\r\n<i>(This is an automated message.)</i>"
   }
 },
 {
diff --git a/evap/evaluation/tests/test_models.py b/evap/evaluation/tests/test_models.py
--- a/evap/evaluation/tests/test_models.py
+++ b/evap/evaluation/tests/test_models.py
@@ -927,27 +927,27 @@ def test_send_contributor_publish_notifications():
 
         expected_calls = [
             # these 4 are included since they are contributors for evaluation1 which can publish the average grade
-            call(responsible1, {}, {"user": responsible1, "evaluations": [evaluation1]}, use_cc=True),
-            call(editor1, {}, {"user": editor1, "evaluations": [evaluation1]}, use_cc=True),
-            call(contributor1, {}, {"user": contributor1, "evaluations": [evaluation1]}, use_cc=True),
+            call(responsible1, {}, {"user": responsible1, "evaluations": {evaluation1}}, use_cc=True),
+            call(editor1, {}, {"user": editor1, "evaluations": {evaluation1}}, use_cc=True),
+            call(contributor1, {}, {"user": contributor1, "evaluations": {evaluation1}}, use_cc=True),
             call(
-                contributor_both, {}, {"user": contributor_both, "evaluations": [evaluation1, evaluation2]}, use_cc=True
+                contributor_both, {}, {"user": contributor_both, "evaluations": {evaluation1, evaluation2}}, use_cc=True
             ),
             # contributor2 has textanswers, so they are notified
-            call(contributor2, {}, {"user": contributor2, "evaluations": [evaluation2]}, use_cc=True),
+            call(contributor2, {}, {"user": contributor2, "evaluations": {evaluation2}}, use_cc=True),
         ]
 
         with patch("evap.evaluation.models.EmailTemplate.send_to_user") as send_to_user_mock:
-            EmailTemplate.send_contributor_publish_notifications([evaluation1, evaluation2])
+            EmailTemplate.send_contributor_publish_notifications({evaluation1, evaluation2})
             # Assert that all expected publish notifications are sent to contributors.
             send_to_user_mock.assert_has_calls(expected_calls, any_order=True)
 
         # if general textanswers for an evaluation exist, all responsibles should also be notified
         baker.make(TextAnswer, contribution=evaluation2.general_contribution)
-        expected_calls.append(call(responsible2, {}, {"user": responsible2, "evaluations": [evaluation2]}, use_cc=True))
+        expected_calls.append(call(responsible2, {}, {"user": responsible2, "evaluations": {evaluation2}}, use_cc=True))
 
         with patch("evap.evaluation.models.EmailTemplate.send_to_user") as send_to_user_mock:
-            EmailTemplate.send_contributor_publish_notifications([evaluation1, evaluation2])
+            EmailTemplate.send_contributor_publish_notifications({evaluation1, evaluation2})
             send_to_user_mock.assert_has_calls(expected_calls, any_order=True)