Repository: ephios-dev/ephios

Issue:
Password Reset Button for Managers
As a manager,  
I want to be able to click a button on user list or in the user form to quickly send a password reset link to the user  
so that I don't need to go the long route and copy-paste the email into the password reset form.



Discussion:

Resolving patch:
diff --git a/ephios/core/urls.py b/ephios/core/urls.py
--- a/ephios/core/urls.py
+++ b/ephios/core/urls.py
@@ -12,6 +12,7 @@
     UserProfileCreateView,
     UserProfileDeleteView,
     UserProfileListView,
+    UserProfilePasswordResetView,
     UserProfileSettingsView,
     UserProfileUpdateView,
 )
@@ -175,6 +176,11 @@
         UserProfileDeleteView.as_view(),
         name="userprofile_delete",
     ),
+    path(
+        "users/<int:pk>/password_reset",
+        UserProfilePasswordResetView.as_view(),
+        name="userprofile_password_reset",
+    ),
     path(
         "users/create/",
         UserProfileCreateView.as_view(),
diff --git a/ephios/core/views/accounts.py b/ephios/core/views/accounts.py
--- a/ephios/core/views/accounts.py
+++ b/ephios/core/views/accounts.py
@@ -1,4 +1,5 @@
 from django.contrib import messages
+from django.contrib.auth.forms import PasswordResetForm
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.contrib.auth.models import Group
 from django.contrib.messages.views import SuccessMessageMixin
@@ -154,6 +155,45 @@ def get_success_url(self):
         return reverse("core:userprofile_list")
 
 
+class UserProfilePasswordResetView(CustomPermissionRequiredMixin, SingleObjectMixin, TemplateView):
+    model = UserProfile
+    permission_required = "core.change_userprofile"
+    template_name = "core/userprofile_confirm_password_reset.html"
+
+    def setup(self, request, *args, **kwargs):
+        super().setup(request, *args, **kwargs)
+        self.object = self.get_object()
+
+    def post(self, request, *args, **kwargs):
+        if request.POST.get("confirm"):
+            form = PasswordResetForm(
+                {
+                    "email": self.object.email,
+                }
+            )
+            if form.is_valid():
+                form.save(request=request)
+                messages.info(
+                    request,
+                    _(
+                        "The user's password has been reset. An email was sent to {email}.".format(
+                            email=self.object.email
+                        )
+                    ),
+                )
+            else:
+                messages.error(
+                    request,
+                    _(
+                        "No valid email address ({email}). The password has not been reset.".format(
+                            email=self.object.email
+                        )
+                    ),
+                )
+            return redirect(reverse("core:userprofile_list"))
+        return self.render_to_response({"userprofile": self.object})
+
+
 class UserProfileSettingsView(LoginRequiredMixin, SuccessMessageMixin, UserPreferenceFormView):
     template_name = "core/userprofile_settings.html"
     success_message = _("Settings succesfully saved.")


Test patch:
diff --git a/tests/core/test_views_userprofile.py b/tests/core/test_views_userprofile.py
--- a/tests/core/test_views_userprofile.py
+++ b/tests/core/test_views_userprofile.py
@@ -114,6 +114,16 @@ def test_userprofile_delete(self, django_app, groups, volunteer, manager):
         with pytest.raises(UserProfile.DoesNotExist):
             UserProfile.objects.get(email=userprofile.email).exists()
 
+    def test_userprofile_password_reset(self, django_app, groups, volunteer, manager):
+        userprofile = volunteer
+        response = django_app.get(
+            reverse("core:userprofile_password_reset", kwargs={"pk": userprofile.id}),
+            user=manager,
+        )
+        assert response.status_code == 200
+        response.form.submit()
+        assert response.status_code == 200
+
     def test_userprofile_edit_by_hr_allowed(self, django_app, volunteer, hr_group, groups):
         managers, planners, volunteers = groups
         form = django_app.get(