Repository: DDMAL/CantusDB

Issue:
login page--request password
On OldCantus you can initiate a request for a new password--on NewCantus it's just an eternal log-in loop.

Might also be nice to have a way of initiating the request to become a new contributor,  but maybe we want to keep new accounts separate from fixing old ones (so that new users can be vetted first, but old users can get automatic password resets).


Discussion:
you're talking about [this page](https://cantus.uwaterloo.ca/user/password) on OldCantus that NewCantus lacks, yes?

We can add this to our list of things we'd be able to fix if/when we set up an email server, I suppose. Without such a connected email server/service, there's not much we can do about this. Currently, only people who are logged in can change their passwords. If someone loses their password, an administrator (i.e. someone with access to the [admin interface](http://206.12.93.196/admin/)) will be able to assign them a new password, which that user can then use to log in and set their own password - it's not ideal, but at least no one will be permanently and irreversibly locked out of her account.

Resolving patch:
diff --git a/django/cantusdb_project/cantusdb/settings.py b/django/cantusdb_project/cantusdb/settings.py
--- a/django/cantusdb_project/cantusdb/settings.py
+++ b/django/cantusdb_project/cantusdb/settings.py
@@ -163,7 +163,14 @@
 # https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys
 DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
 
-EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
+EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
+EMAIL_HOST = "email-smtp.us-west-2.amazonaws.com"
+EMAIL_PORT = 587
+EMAIL_HOST_USER = os.getenv("AWS_EMAIL_HOST_USER")
+EMAIL_HOST_PASSWORD = os.getenv("AWS_EMAIL_HOST_PASSWORD")
+EMAIL_USE_TLS = True
+
+DEFAULT_FROM_EMAIL = "noreply@cantusdatabase.simssa.ca"
 
 # automatically disable all panels which user can then manually enable
 DEBUG_TOOLBAR_CONFIG = {
diff --git a/django/cantusdb_project/main_app/urls.py b/django/cantusdb_project/main_app/urls.py
--- a/django/cantusdb_project/main_app/urls.py
+++ b/django/cantusdb_project/main_app/urls.py
@@ -1,4 +1,10 @@
-from django.urls import include, path
+from django.urls import include, path, reverse
+from django.contrib.auth.views import (
+    PasswordResetView,
+    PasswordResetDoneView,
+    PasswordResetConfirmView,
+    PasswordResetCompleteView,
+)
 from main_app.views import views
 import debug_toolbar
 from main_app.views.century import (
@@ -95,6 +101,44 @@
         views.change_password,
         name="change-password",
     ),
+    # password reset views
+    path(
+        # here, user can initiate a request to send a password reset email
+        "reset-password/",
+        PasswordResetView.as_view(
+            template_name="registration/reset_password.html",
+            email_template_name="registration/reset_password_email.html",
+            success_url="/reset-password-sent/",
+        ),
+        name="reset_password",
+    ),
+    path(
+        # we display this page once the password reset email has been sent
+        "reset-password-sent/",
+        PasswordResetDoneView.as_view(
+            template_name="registration/reset_password_sent.html",
+        ),
+        name="reset_password_done",
+    ),
+    path(
+        # here, the user can specify their new password
+        "reset/<uidb64>/<token>",
+        PasswordResetConfirmView.as_view(
+            template_name="registration/reset_password_confirm.html",
+            success_url="/reset-password-complete/",
+        ),
+        name="reset_password_confirm",
+    ),
+    path(
+        # we display this page once a user has completed a password reset
+        # depending on whether their attempt was successful, this page either shows
+        # a success message or a non-success message.
+        "reset-password-complete/",
+        PasswordResetCompleteView.as_view(
+            template_name="registration/reset_password_complete.html"
+        ),
+        name="reset_password_complete",
+    ),
     # century
     path("century/<int:pk>", CenturyDetailView.as_view(), name="century-detail"),
     # chant


Test patch: