Repository: e-valuation/EvaP

Issue:
Manually send Evaluation Started email for user
Sometimes the email address of a user has to be updated by managers after the email informing about the start of an evaluation was sent and bounced because the address was incorrect. In this situation, managers should be able to send an email informing about the currently running evaluations for this user (and the login code if applicable).

On the user profile page, a button (`btn-light`) saying `Send email with evaluation list` should be added in the top right corner.
This will send the `Evaluation Started` email template to the user, (see `send_to_user` and `send_to_users_in_evaluations` in `evaluation/models.py`) with all currently running evaluations in which the user can still vote (see `get_sorted_due_evaluations`).
To avoid listing all evaluations twice in the email, the parameter `due_evaluations` should be empty.


Discussion:
@janno42 We discussed editing the email template because not all evaluations from `get_sorted_due_evaluations` have recently started. We settled on first implementing it as explained here and seeing what we want to do then :)
For simplicity, the email should list all due evaluations as described above. I don't think we need to update the template or create a new one (manually sending this email is a comfort feature that wouldn't be used for many users so we don't have to fear to include too much information in the email).

Resolving patch:
diff --git a/evap/staff/urls.py b/evap/staff/urls.py
--- a/evap/staff/urls.py
+++ b/evap/staff/urls.py
@@ -73,6 +73,7 @@
     path("user/<int:user_id>/edit", views.user_edit, name="user_edit"),
     path("user/list", views.user_list, name="user_list"),
     path("user/delete", views.user_delete, name="user_delete"),
+    path("user/resend_email", views.user_resend_email, name="user_resend_email"),
     path("user/bulk_update", views.user_bulk_update, name="user_bulk_update"),
     path("user/merge", views.user_merge_selection, name="user_merge_selection"),
     path("user/<int:main_user_id>/merge/<int:other_user_id>", views.user_merge, name="user_merge"),
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -2125,7 +2125,14 @@ def notify_reward_points(grantings, **_kwargs):
         return redirect("staff:user_index")
 
     return render(
-        request, "staff_user_form.html", {"form": form, "evaluations_contributing_to": evaluations_contributing_to}
+        request,
+        "staff_user_form.html",
+        {
+            "form": form,
+            "evaluations_contributing_to": evaluations_contributing_to,
+            "has_due_evaluations": bool(user.get_sorted_due_evaluations()),
+            "user_id": user_id,
+        },
     )
 
 
@@ -2141,6 +2148,23 @@ def user_delete(request):
     return HttpResponse()  # 200 OK
 
 
+@require_POST
+@manager_required
+def user_resend_email(request):
+    user = get_object_from_dict_pk_entry_or_logged_40x(UserProfile, request.POST, "user_id")
+
+    template = EmailTemplate.objects.get(name=EmailTemplate.EVALUATION_STARTED)
+    body_params = {
+        "user": user,
+        "evaluations": user.get_sorted_due_evaluations(),
+        "due_evaluations": {},
+    }
+
+    template.send_to_user(user, {}, body_params, use_cc=False)
+    messages.success(request, _("Successfully resent evaluation started email."))
+    return HttpResponse()  # 200 OK
+
+
 @manager_required
 def user_bulk_update(request):
     form = UserBulkUpdateForm(request.POST or None, request.FILES or None)


Test patch: