From fa278282b6870730a55790544a68692c47486f0b Mon Sep 17 00:00:00 2001 From: dawnwages Date: Sat, 27 Jan 2024 14:27:01 -0500 Subject: [PATCH 01/29] fix media issue --- indymeet/settings/storages.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indymeet/settings/storages.py b/indymeet/settings/storages.py index eab2552b..7db08a80 100644 --- a/indymeet/settings/storages.py +++ b/indymeet/settings/storages.py @@ -6,7 +6,7 @@ class AzureMediaStorage(AzureStorage): account_name = settings.AZURE_ACCOUNT_NAME - account_key = settings.AZURE_ACCOUNT_KEY + account_key = settings.AZURE_STORAGE_KEY azure_container = settings.AZURE_MEDIA_CONTAINER expiration_secs = None overwrite_files = True @@ -14,7 +14,7 @@ class AzureMediaStorage(AzureStorage): class AzureStaticStorage(AzureStorage): account_name = settings.AZURE_ACCOUNT_NAME - account_key = settings.AZURE_ACCOUNT_KEY + account_key = settings.AZURE_STORAGE_KEY azure_container = settings.AZURE_STATIC_CONTAINER expiration_secs = None overwrite_files = True From a01fa1ca08d26824c5b8d8470d67d5b0f5e98c5b Mon Sep 17 00:00:00 2001 From: dawnwages Date: Sat, 27 Jan 2024 14:42:54 -0500 Subject: [PATCH 02/29] fix media issue, change name from Azure storage Key to Azure account key --- indymeet/settings/storages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indymeet/settings/storages.py b/indymeet/settings/storages.py index 7db08a80..06ed908f 100644 --- a/indymeet/settings/storages.py +++ b/indymeet/settings/storages.py @@ -6,7 +6,7 @@ class AzureMediaStorage(AzureStorage): account_name = settings.AZURE_ACCOUNT_NAME - account_key = settings.AZURE_STORAGE_KEY + account_key = settings.AZURE_ACCOUNT_KEY azure_container = settings.AZURE_MEDIA_CONTAINER expiration_secs = None overwrite_files = True From ac8f5def7dca06699edba0b3abbdd9005bff3b97 Mon Sep 17 00:00:00 2001 From: dawnwages Date: Sat, 27 Jan 2024 14:46:56 -0500 Subject: [PATCH 03/29] fix media issue, change name from Azure storage Key to Azure account key --- indymeet/settings/storages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indymeet/settings/storages.py b/indymeet/settings/storages.py index 06ed908f..eab2552b 100644 --- a/indymeet/settings/storages.py +++ b/indymeet/settings/storages.py @@ -14,7 +14,7 @@ class AzureMediaStorage(AzureStorage): class AzureStaticStorage(AzureStorage): account_name = settings.AZURE_ACCOUNT_NAME - account_key = settings.AZURE_STORAGE_KEY + account_key = settings.AZURE_ACCOUNT_KEY azure_container = settings.AZURE_STATIC_CONTAINER expiration_secs = None overwrite_files = True From e847975aed42c617971bec1db07cbb7f421bd35a Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 16:52:58 -0500 Subject: [PATCH 04/29] Improvements (#252) * add template for NPM BIN PATH for tailwindcss support * add template for NPM BIN PATH for tailwindcss support * local settings for tailwindcss --- README.md | 8 +++----- indymeet/settings/.local.template.py | 14 ++++++++++++++ indymeet/settings/production.py | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 indymeet/settings/.local.template.py diff --git a/README.md b/README.md index c667b6ea..c741d37b 100644 --- a/README.md +++ b/README.md @@ -163,15 +163,13 @@ This is an example of how to list things you need to use the software and how to 7. Install tailwind. You also need npm installed. ```sh python manage.py tailwind install + python manage.py tailwind start # to create style.css ``` -8. Run server locally +8. Run collectstatic and start server locally ```sh + python manage.py collectstatic python manage.py runserver ``` -9. Run tailwind in another terminal locally - ```sh - python manage.py tailwind start - ``` Alternatively, if you're not using Windows you can run the following instead of steps 8 and 9: diff --git a/indymeet/settings/.local.template.py b/indymeet/settings/.local.template.py new file mode 100644 index 00000000..334f8b68 --- /dev/null +++ b/indymeet/settings/.local.template.py @@ -0,0 +1,14 @@ +# ---------------------------------------------- +# For local issues +# ---------------------------------------------- +import os + +print("----------------------------------") +print("----------------------------------") +print("LOCAL") +print("----------------------------------") +print("----------------------------------") + +# uncomment for tailwind NPM executable in your system +# NPM_BIN_PATH = os.environ.get("NPM_BIN_PATH", "False") +# NPM_BIN_PATH = r"C:\Program Files\nodejs\npm.cmd" diff --git a/indymeet/settings/production.py b/indymeet/settings/production.py index 83af6695..13e7b42d 100644 --- a/indymeet/settings/production.py +++ b/indymeet/settings/production.py @@ -23,6 +23,7 @@ "djangonaut-space.azurewebsites.net", "djangonaut.space", "staging-djangonaut-space.azurewebsites.net", + "localhost", ] CSRF_TRUSTED_ORIGINS = [ "https://djangonaut.space", From 1cb3c87838069652658fbdb76c852a538985f8ca Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 17:36:13 -0500 Subject: [PATCH 05/29] Improvements (#253) * add template for NPM BIN PATH for tailwindcss support * add template for NPM BIN PATH for tailwindcss support * local settings for tailwindcss * update contact info on README * update package.json for oryx build --- README.md | 2 +- package.json | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c741d37b..099f51b3 100644 --- a/README.md +++ b/README.md @@ -340,7 +340,7 @@ Distributed under the MIT License. See `LICENSE.txt` for more information. ## Contact -- Dawn Wages - [@dawnwagessays](https://twitter.com/dawnwagessays) - [@fly00gemini8712@mastodon.online](https://mastodon.online/@fly00gemini8712) +- Dawn Wages - [@dawnwagessays](https://twitter.com/bajoranengineer) - [@bajoranengineer@mastodon.online](https://mastodon.online/@bajoranengineer) - [Djangonaut Space Organizers](mailto:contact@djangonaut.space) diff --git a/package.json b/package.json index d226d9b4..eed08d70 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,16 @@ +/* -------- +dummy package.json for Oryx automatic build +*/ + { - "name": "djangonaut-space", - "version": "1.0.0", + "name": "theme", + "version": "3.6.0", + "description": "", "engines": { - "node": "17.6.0" + "node": "20.11.0" }, "scripts": { "test": "" } } + From 9562251e6c74e37d690ec73b6347681b4f68262d Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 17:38:28 -0500 Subject: [PATCH 06/29] Improvements (#254) * add template for NPM BIN PATH for tailwindcss support * add template for NPM BIN PATH for tailwindcss support * local settings for tailwindcss * update contact info on README * update package.json for oryx build * error with comment From fc7e5612f07f81f3f1ddc1178b51ef2a84d560af Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 17:41:13 -0500 Subject: [PATCH 07/29] Improvements (#255) * add template for NPM BIN PATH for tailwindcss support * add template for NPM BIN PATH for tailwindcss support * local settings for tailwindcss * update contact info on README * update package.json for oryx build * error with comment From b61c8e4a01d7b20ba3c80387196de1953e0b27b8 Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 17:41:56 -0500 Subject: [PATCH 08/29] Update package.json --- package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package.json b/package.json index eed08d70..fa609890 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,3 @@ -/* -------- -dummy package.json for Oryx automatic build -*/ - { "name": "theme", "version": "3.6.0", From 6dcd3e82ce380b195eda826bbe27f104618819a7 Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 18:07:11 -0500 Subject: [PATCH 09/29] Improvements (#256) * upgrade app service build version and node version in gh actions workflows --- .github/workflows/develop_djangonaut_space.yml | 4 ++-- .github/workflows/main_djangonaut-space.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/develop_djangonaut_space.yml b/.github/workflows/develop_djangonaut_space.yml index 50df1931..49f9a4e1 100644 --- a/.github/workflows/develop_djangonaut_space.yml +++ b/.github/workflows/develop_djangonaut_space.yml @@ -23,7 +23,7 @@ env: AZURE_WEBAPP_NAME: staging-djangonaut-space # set this to the name of your Azure Web App AZURE_WEBAPP_PACKAGE_PATH: '.' PYTHON_VERSION: '3.9' # set this to the Python version to use - NODE_VERSION: '17.6.0' + NODE_VERSION: '20.11.0' on: push: @@ -88,7 +88,7 @@ jobs: # Optional: Add step to run tests here (PyTest, Django test suites, etc.) - name: Building web app - uses: azure/appservice-build@v2 + uses: azure/appservice-build@v3 - name: Deploy web App using GH Action azure/webapps-deploy uses: azure/webapps-deploy@v3 with: diff --git a/.github/workflows/main_djangonaut-space.yml b/.github/workflows/main_djangonaut-space.yml index 729187e0..24d05250 100644 --- a/.github/workflows/main_djangonaut-space.yml +++ b/.github/workflows/main_djangonaut-space.yml @@ -58,7 +58,7 @@ jobs: printenv -0 - name: Building web app - uses: azure/appservice-build@v2 + uses: azure/appservice-build@v3 - name: Deploy web App using GH Action azure/webapps-deploy uses: azure/webapps-deploy@v3 with: From ee8eab4d6eee2677e7c9153ec1b63ffc1988a2c3 Mon Sep 17 00:00:00 2001 From: Dawn Wages Date: Sat, 27 Jan 2024 18:26:56 -0500 Subject: [PATCH 10/29] Improvements (#257) * add template for NPM BIN PATH for tailwindcss support * add template for NPM BIN PATH for tailwindcss support * local settings for tailwindcss * update contact info on README * update package.json for oryx build * error with comment * upgrade app service build version and node version in gh actions workflows * python version 3.11 --- .github/workflows/develop_djangonaut_space.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/develop_djangonaut_space.yml b/.github/workflows/develop_djangonaut_space.yml index 49f9a4e1..f18fedea 100644 --- a/.github/workflows/develop_djangonaut_space.yml +++ b/.github/workflows/develop_djangonaut_space.yml @@ -22,7 +22,7 @@ name: Staging build and deploy Python app to Azure Web App - djangonaut-space env: AZURE_WEBAPP_NAME: staging-djangonaut-space # set this to the name of your Azure Web App AZURE_WEBAPP_PACKAGE_PATH: '.' - PYTHON_VERSION: '3.9' # set this to the Python version to use + PYTHON_VERSION: '3.11' # set this to the Python version to use NODE_VERSION: '20.11.0' on: From 0b96b62f8871f3ddf2d5be4a4013efff5f2dadcc Mon Sep 17 00:00:00 2001 From: dawnwages Date: Mon, 29 Jan 2024 15:56:37 -0500 Subject: [PATCH 11/29] Revert "Improvements (#252)" This reverts commit e847975aed42c617971bec1db07cbb7f421bd35a. --- README.md | 8 +++++--- indymeet/settings/.local.template.py | 14 -------------- indymeet/settings/production.py | 1 - 3 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 indymeet/settings/.local.template.py diff --git a/README.md b/README.md index c741d37b..c667b6ea 100644 --- a/README.md +++ b/README.md @@ -163,13 +163,15 @@ This is an example of how to list things you need to use the software and how to 7. Install tailwind. You also need npm installed. ```sh python manage.py tailwind install - python manage.py tailwind start # to create style.css ``` -8. Run collectstatic and start server locally +8. Run server locally ```sh - python manage.py collectstatic python manage.py runserver ``` +9. Run tailwind in another terminal locally + ```sh + python manage.py tailwind start + ``` Alternatively, if you're not using Windows you can run the following instead of steps 8 and 9: diff --git a/indymeet/settings/.local.template.py b/indymeet/settings/.local.template.py deleted file mode 100644 index 334f8b68..00000000 --- a/indymeet/settings/.local.template.py +++ /dev/null @@ -1,14 +0,0 @@ -# ---------------------------------------------- -# For local issues -# ---------------------------------------------- -import os - -print("----------------------------------") -print("----------------------------------") -print("LOCAL") -print("----------------------------------") -print("----------------------------------") - -# uncomment for tailwind NPM executable in your system -# NPM_BIN_PATH = os.environ.get("NPM_BIN_PATH", "False") -# NPM_BIN_PATH = r"C:\Program Files\nodejs\npm.cmd" diff --git a/indymeet/settings/production.py b/indymeet/settings/production.py index 13e7b42d..83af6695 100644 --- a/indymeet/settings/production.py +++ b/indymeet/settings/production.py @@ -23,7 +23,6 @@ "djangonaut-space.azurewebsites.net", "djangonaut.space", "staging-djangonaut-space.azurewebsites.net", - "localhost", ] CSRF_TRUSTED_ORIGINS = [ "https://djangonaut.space", From d927aaf8ba275b145d505025472de7a820ae9cc1 Mon Sep 17 00:00:00 2001 From: dawnwages Date: Mon, 29 Jan 2024 19:57:05 -0500 Subject: [PATCH 12/29] remove node and python upgrade --- .github/workflows/develop_djangonaut_space.yml | 6 +++--- .github/workflows/main_djangonaut-space.yml | 2 +- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/develop_djangonaut_space.yml b/.github/workflows/develop_djangonaut_space.yml index f18fedea..50df1931 100644 --- a/.github/workflows/develop_djangonaut_space.yml +++ b/.github/workflows/develop_djangonaut_space.yml @@ -22,8 +22,8 @@ name: Staging build and deploy Python app to Azure Web App - djangonaut-space env: AZURE_WEBAPP_NAME: staging-djangonaut-space # set this to the name of your Azure Web App AZURE_WEBAPP_PACKAGE_PATH: '.' - PYTHON_VERSION: '3.11' # set this to the Python version to use - NODE_VERSION: '20.11.0' + PYTHON_VERSION: '3.9' # set this to the Python version to use + NODE_VERSION: '17.6.0' on: push: @@ -88,7 +88,7 @@ jobs: # Optional: Add step to run tests here (PyTest, Django test suites, etc.) - name: Building web app - uses: azure/appservice-build@v3 + uses: azure/appservice-build@v2 - name: Deploy web App using GH Action azure/webapps-deploy uses: azure/webapps-deploy@v3 with: diff --git a/.github/workflows/main_djangonaut-space.yml b/.github/workflows/main_djangonaut-space.yml index 24d05250..729187e0 100644 --- a/.github/workflows/main_djangonaut-space.yml +++ b/.github/workflows/main_djangonaut-space.yml @@ -58,7 +58,7 @@ jobs: printenv -0 - name: Building web app - uses: azure/appservice-build@v3 + uses: azure/appservice-build@v2 - name: Deploy web App using GH Action azure/webapps-deploy uses: azure/webapps-deploy@v3 with: diff --git a/package.json b/package.json index fa609890..e3623a29 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "3.6.0", "description": "", "engines": { - "node": "20.11.0" + "node": "17.6.0" }, "scripts": { "test": "" From 971353ce8eeb948022ead28810ea7e4f866c684a Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:28:08 +0100 Subject: [PATCH 13/29] Fixed accounts signup form. (#267) --- accounts/tests/test_signup_view.py | 48 +++++++++++++++++++++ home/templates/forms/sign_up.html | 2 +- indymeet/settings/base.py | 1 + indymeet/templates/registration/signup.html | 2 +- indymeet/urls.py | 2 +- requirements/requirements-test.txt | 22 ++-------- requirements/requirements.in | 1 + requirements/requirements.txt | 13 ++---- 8 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 accounts/tests/test_signup_view.py diff --git a/accounts/tests/test_signup_view.py b/accounts/tests/test_signup_view.py new file mode 100644 index 00000000..91e08922 --- /dev/null +++ b/accounts/tests/test_signup_view.py @@ -0,0 +1,48 @@ +from unittest.mock import patch + +from django.core import mail +from django.test import Client, TestCase +from django.urls import reverse + + +class SignUpViewTests(TestCase): + def setUp(self): + self.client = Client() + self.url = reverse("signup") + + def test_signup_template_renders(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Registration") + + @patch("captcha.fields.ReCaptchaField.validate", return_value=True) + def test_signup_template_post_success(self, mock_captcha): + response = self.client.post( + self.url, + data={ + "username": "janedoe", + "email": "jane@whoareyou.com", + "first_name": "Jane", + "last_name": "Doe", + "password1": "secretpassword123", + "password2": "secretpassword123", + "email_consent": True, + "accepted_coc": True, + "g-recaptcha-response": "dummy-response", + }, + follow=True, + ) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Registration") + self.assertContains( + response, + "Your registration was successful. Please check your email provided for a confirmation link.", + ) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual( + mail.outbox[0].subject, "Djangonaut Space Registration Confirmation" + ) + self.assertIn( + "To confirm your email address on djangonaut.space please visit the link:", + mail.outbox[0].body, + ) diff --git a/home/templates/forms/sign_up.html b/home/templates/forms/sign_up.html index c0b46812..130e3c6a 100644 --- a/home/templates/forms/sign_up.html +++ b/home/templates/forms/sign_up.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load i18n wagtailcore_tags static %} +{% load i18n wagtailcore_tags bootstrap3 static %} diff --git a/indymeet/settings/base.py b/indymeet/settings/base.py index 2234c0eb..a2a7134a 100644 --- a/indymeet/settings/base.py +++ b/indymeet/settings/base.py @@ -62,6 +62,7 @@ # other "tailwind", "theme", + "bootstrap3", ] MIDDLEWARE = [ diff --git a/indymeet/templates/registration/signup.html b/indymeet/templates/registration/signup.html index ed9e9772..490e2a0d 100644 --- a/indymeet/templates/registration/signup.html +++ b/indymeet/templates/registration/signup.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load i18n wagtailcore_tags static %} +{% load i18n wagtailcore_tags bootstrap3 static %} diff --git a/indymeet/urls.py b/indymeet/urls.py index b3641cb0..ee7bef8f 100644 --- a/indymeet/urls.py +++ b/indymeet/urls.py @@ -17,7 +17,7 @@ path("admin/", include(wagtailadmin_urls)), path("documents/", include(wagtaildocs_urls)), path("search/", search_views.search, name="search"), - path("accounts/", include("accounts.urls")), + path("accounts/", include("accounts.urls"), name="accounts"), path("", include("home.urls")), path("", include("puput.urls")), ] diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index f6fd9584..efa9891e 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # pip-compile --output-file=requirements/requirements-test.txt --strip-extras requirements/requirements-test.in @@ -54,6 +54,7 @@ django==4.1.13 # via # -r requirements/requirements.txt # django-anymail + # django-bootstrap3 # django-colorful # django-debug-toolbar # django-el-pagination @@ -71,6 +72,8 @@ django==4.1.13 # wagtail django-anymail==9.0 # via -r requirements/requirements.txt +django-bootstrap3==23.6 + # via -r requirements/requirements.txt django-colorful==1.3 # via # -r requirements/requirements.txt @@ -126,11 +129,6 @@ et-xmlfile==1.1.0 # via # -r requirements/requirements.txt # openpyxl -exceptiongroup==1.2.0 - # via - # -r requirements/requirements.txt - # anyio - # pytest filetype==1.2.0 # via # -r requirements/requirements.txt @@ -148,10 +146,6 @@ idna==3.6 # -r requirements/requirements.txt # anyio # requests -importlib-metadata==7.0.1 - # via - # -r requirements/requirements.txt - # markdown iniconfig==2.0.0 # via pytest isodate==0.6.1 @@ -257,13 +251,9 @@ telepath==0.3.1 # wagtail text-unidecode==1.3 # via python-slugify -tomli==2.0.1 - # via pytest typing-extensions==4.6.3 # via # -r requirements/requirements.txt - # anyio - # asgiref # azure-core # azure-storage-blob # pyee @@ -291,7 +281,3 @@ willow==1.6.3 # via # -r requirements/requirements.txt # wagtail -zipp==3.17.0 - # via - # -r requirements/requirements.txt - # importlib-metadata diff --git a/requirements/requirements.in b/requirements/requirements.in index c2a558ca..af6275ac 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -14,3 +14,4 @@ django-extensions django-debug-toolbar typing-extensions django-tailwind +django-bootstrap3 \ No newline at end of file diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 93818350..01538780 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # pip-compile --output-file=requirements/requirements.txt --strip-extras requirements/requirements.in @@ -32,6 +32,7 @@ django==4.1.13 # via # -r requirements/requirements.in # django-anymail + # django-bootstrap3 # django-colorful # django-debug-toolbar # django-el-pagination @@ -49,6 +50,8 @@ django==4.1.13 # wagtail django-anymail==9.0 # via -r requirements/requirements.in +django-bootstrap3==23.6 + # via -r requirements/requirements.in django-colorful==1.3 # via puput django-debug-toolbar==4.2.0 @@ -83,8 +86,6 @@ draftjs-exporter==2.1.7 # via wagtail et-xmlfile==1.1.0 # via openpyxl -exceptiongroup==1.2.0 - # via anyio filetype==1.2.0 # via willow html5lib==1.1 @@ -93,8 +94,6 @@ idna==3.6 # via # anyio # requests -importlib-metadata==7.0.1 - # via markdown isodate==0.6.1 # via azure-storage-blob l18n==2021.3 @@ -146,8 +145,6 @@ telepath==0.3.1 typing-extensions==4.6.3 # via # -r requirements/requirements.in - # anyio - # asgiref # azure-core # azure-storage-blob urllib3==1.26.18 @@ -169,5 +166,3 @@ whitenoise==6.3.0 # via -r requirements/requirements.in willow==1.6.3 # via wagtail -zipp==3.17.0 - # via importlib-metadata From aec55cb63686cfbca3202c67d54f035f8d6ff179 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Wed, 14 Feb 2024 22:15:24 +0100 Subject: [PATCH 14/29] Add Sentry setup. (#268) --- indymeet/settings/production.py | 13 +++++++++++++ requirements/requirements-dev.txt | 22 ++++++++++++++++++---- requirements/requirements-test.txt | 29 ++++++++++++++++++++++++++++- requirements/requirements.in | 3 ++- requirements/requirements.txt | 20 ++++++++++++++++++-- 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/indymeet/settings/production.py b/indymeet/settings/production.py index 83af6695..7600d5b8 100644 --- a/indymeet/settings/production.py +++ b/indymeet/settings/production.py @@ -1,4 +1,5 @@ from __future__ import annotations +import sentry_sdk from .base import * @@ -54,6 +55,18 @@ STATIC_URL = f"https://{AZURE_CUSTOM_DOMAIN}/{AZURE_STATIC_CONTAINER}/" MEDIA_URL = f"https://{AZURE_CUSTOM_DOMAIN}/{AZURE_MEDIA_CONTAINER}/" + SENTRY_DNS = os.environ.get( + "SENTRY_DNS", + "https://302dde9a33fabc5af106ccf19ae23680@o4506747118157824.ingest.sentry.io/4506747129626624" # Staging + ) + sentry_sdk.init( + dsn=SENTRY_DNS, + # Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring. + traces_sample_rate=0.1, + # Set profiles_sample_rate to 1.0 to profile 100% of sampled transactions. + profiles_sample_rate=0.1, + ) + try: from .local import * except ImportError: diff --git a/requirements/requirements-dev.txt b/requirements/requirements-dev.txt index 522c5457..ad634472 100644 --- a/requirements/requirements-dev.txt +++ b/requirements/requirements-dev.txt @@ -46,6 +46,7 @@ certifi==2023.11.17 # -r requirements/requirements-test.txt # -r requirements/requirements.txt # requests + # sentry-sdk cffi==1.16.0 # via # -r requirements/requirements-test.txt @@ -60,6 +61,11 @@ charset-normalizer==3.3.2 # requests click==8.1.7 # via pip-tools +colorama==0.4.6 + # via + # build + # click + # pytest cryptography==41.0.7 # via # -r requirements/requirements-test.txt @@ -77,6 +83,7 @@ django==4.1.13 # -r requirements/requirements-test.txt # -r requirements/requirements.txt # django-anymail + # django-bootstrap3 # django-browser-reload # django-colorful # django-debug-toolbar @@ -97,6 +104,10 @@ django-anymail==9.0 # via # -r requirements/requirements-test.txt # -r requirements/requirements.txt +django-bootstrap3==23.6 + # via + # -r requirements/requirements-test.txt + # -r requirements/requirements.txt django-browser-reload==1.12.1 # via django-tailwind django-colorful==1.3 @@ -179,7 +190,6 @@ et-xmlfile==1.1.0 # openpyxl exceptiongroup==1.2.0 # via - # -r requirements/requirements-test.txt # -r requirements/requirements.txt # anyio # pytest @@ -211,7 +221,6 @@ idna==3.6 # requests importlib-metadata==7.0.1 # via - # -r requirements/requirements-test.txt # -r requirements/requirements.txt # build # markdown @@ -332,6 +341,8 @@ requests==2.31.0 # django-anymail # pytest-base-url # wagtail +sentry-sdk==1.40.4 + # via -r requirements/requirements.txt six==1.16.0 # via # -r requirements/requirements-test.txt @@ -369,7 +380,6 @@ text-unidecode==1.3 # python-slugify tomli==2.0.1 # via - # -r requirements/requirements-test.txt # build # pip-tools # pyproject-hooks @@ -383,11 +393,16 @@ typing-extensions==4.6.3 # azure-core # azure-storage-blob # pyee +tzdata==2024.1 + # via + # -r requirements/requirements.txt + # django urllib3==1.26.18 # via # -r requirements/requirements-test.txt # -r requirements/requirements.txt # requests + # sentry-sdk virtualenv==20.25.0 # via pre-commit wagtail==4.1.9 @@ -420,7 +435,6 @@ willow==1.6.3 # wagtail zipp==3.17.0 # via - # -r requirements/requirements-test.txt # -r requirements/requirements.txt # importlib-metadata diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index efa9891e..8273c896 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile --output-file=requirements/requirements-test.txt --strip-extras requirements/requirements-test.in @@ -34,6 +34,7 @@ certifi==2023.11.17 # via # -r requirements/requirements.txt # requests + # sentry-sdk cffi==1.16.0 # via # -r requirements/requirements.txt @@ -42,6 +43,8 @@ charset-normalizer==3.3.2 # via # -r requirements/requirements.txt # requests +colorama==0.4.6 + # via pytest cryptography==41.0.7 # via # -r requirements/requirements.txt @@ -129,6 +132,11 @@ et-xmlfile==1.1.0 # via # -r requirements/requirements.txt # openpyxl +exceptiongroup==1.2.0 + # via + # -r requirements/requirements.txt + # anyio + # pytest filetype==1.2.0 # via # -r requirements/requirements.txt @@ -146,6 +154,10 @@ idna==3.6 # -r requirements/requirements.txt # anyio # requests +importlib-metadata==7.0.1 + # via + # -r requirements/requirements.txt + # markdown iniconfig==2.0.0 # via pytest isodate==0.6.1 @@ -223,6 +235,8 @@ requests==2.31.0 # django-anymail # pytest-base-url # wagtail +sentry-sdk==1.40.4 + # via -r requirements/requirements.txt six==1.16.0 # via # -r requirements/requirements.txt @@ -251,16 +265,25 @@ telepath==0.3.1 # wagtail text-unidecode==1.3 # via python-slugify +tomli==2.0.1 + # via pytest typing-extensions==4.6.3 # via # -r requirements/requirements.txt + # anyio + # asgiref # azure-core # azure-storage-blob # pyee +tzdata==2024.1 + # via + # -r requirements/requirements.txt + # django urllib3==1.26.18 # via # -r requirements/requirements.txt # requests + # sentry-sdk wagtail==4.1.9 # via # -r requirements/requirements.txt @@ -281,3 +304,7 @@ willow==1.6.3 # via # -r requirements/requirements.txt # wagtail +zipp==3.17.0 + # via + # -r requirements/requirements.txt + # importlib-metadata diff --git a/requirements/requirements.in b/requirements/requirements.in index af6275ac..fe6de893 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -14,4 +14,5 @@ django-extensions django-debug-toolbar typing-extensions django-tailwind -django-bootstrap3 \ No newline at end of file +django-bootstrap3 +sentry-sdk[django] \ No newline at end of file diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 01538780..eefa6663 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile --output-file=requirements/requirements.txt --strip-extras requirements/requirements.in @@ -19,7 +19,9 @@ beautifulsoup4==4.11.2 bleach==4.1.0 # via wagtail-markdown certifi==2023.11.17 - # via requests + # via + # requests + # sentry-sdk cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 @@ -47,6 +49,7 @@ django==4.1.13 # django-treebeard # djangorestframework # puput + # sentry-sdk # wagtail django-anymail==9.0 # via -r requirements/requirements.in @@ -86,6 +89,8 @@ draftjs-exporter==2.1.7 # via wagtail et-xmlfile==1.1.0 # via openpyxl +exceptiongroup==1.2.0 + # via anyio filetype==1.2.0 # via willow html5lib==1.1 @@ -94,6 +99,8 @@ idna==3.6 # via # anyio # requests +importlib-metadata==7.0.1 + # via markdown isodate==0.6.1 # via azure-storage-blob l18n==2021.3 @@ -124,6 +131,8 @@ requests==2.31.0 # azure-core # django-anymail # wagtail +sentry-sdk==1.40.4 + # via -r requirements/requirements.in six==1.16.0 # via # -r requirements/requirements.in @@ -145,12 +154,17 @@ telepath==0.3.1 typing-extensions==4.6.3 # via # -r requirements/requirements.in + # anyio + # asgiref # azure-core # azure-storage-blob +tzdata==2024.1 + # via django urllib3==1.26.18 # via # -r requirements/requirements.in # requests + # sentry-sdk wagtail==4.1.9 # via # -r requirements/requirements.in @@ -166,3 +180,5 @@ whitenoise==6.3.0 # via -r requirements/requirements.in willow==1.6.3 # via wagtail +zipp==3.17.0 + # via importlib-metadata From cc73a8440a7c64c2e35dbb3bf383d0d92dd7e3e7 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:45:17 +0100 Subject: [PATCH 15/29] Account page updates - tests, styling, email template. (#269) --- accounts/forms.py | 16 +- ...8_userprofile_receiving_program_updates.py | 18 +++ accounts/models.py | 1 + accounts/tests/test_activate_view.py | 59 +++++++ accounts/tests/test_profile_view.py | 38 +++++ accounts/tests/test_signup_view.py | 13 +- accounts/tests/test_unsubscribe_view.py | 45 ++++++ accounts/views.py | 31 ++-- indymeet/static/css/registration.css | 29 ++-- indymeet/templates/emails/base.html | 148 ++++++++++++++++++ .../templates/emails/email_confirmation.html | 5 + .../templates/emails/email_confirmation.txt | 9 ++ indymeet/templates/includes/nav.html | 2 +- .../templates/registration/logged_out.html | 20 +-- indymeet/templates/registration/login.html | 83 +++++----- indymeet/templates/registration/profile.html | 120 ++++++-------- indymeet/templates/registration/signup.html | 64 ++++---- .../templates/registration/unsubscribed.html | 2 +- 18 files changed, 513 insertions(+), 190 deletions(-) create mode 100644 accounts/migrations/0008_userprofile_receiving_program_updates.py create mode 100644 accounts/tests/test_activate_view.py create mode 100644 accounts/tests/test_profile_view.py create mode 100644 accounts/tests/test_unsubscribe_view.py create mode 100644 indymeet/templates/emails/base.html create mode 100644 indymeet/templates/emails/email_confirmation.html create mode 100644 indymeet/templates/emails/email_confirmation.txt diff --git a/accounts/forms.py b/accounts/forms.py index c09395bf..f5e4f6b8 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -19,13 +19,20 @@ class CustomUserCreationForm(UserCreationForm): receive_newsletter = forms.BooleanField( required=False, help_text="Optional: Please check this to opt-in for receiving " - "general updates about community and events. You can " - "opt-out on your profile page at anytime.", + "a newsletter containing general updates about Djangonaut Space. " + "This newsletter does not yet exist. You can opt-out on your profile " + "page at anytime.", ) receive_event_updates = forms.BooleanField( required=False, help_text="Optional: Please check this to opt-in for receiving " - "emails to events you register to. You can opt-out on " + "emails about upcoming community events. You can opt-out on " + "your profile page at anytime.", + ) + receive_program_updates = forms.BooleanField( + required=False, + help_text="Optional: Please check this to opt-in for receiving " + "emails about upcoming program sessions. You can opt-out on " "your profile page at anytime.", ) accepted_coc = forms.BooleanField( @@ -48,8 +55,9 @@ class Meta: "password2", "email_consent", "accepted_coc", - "receive_newsletter", + "receive_program_updates", "receive_event_updates", + "receive_newsletter", ) def __init__(self, *args, **kwargs): diff --git a/accounts/migrations/0008_userprofile_receiving_program_updates.py b/accounts/migrations/0008_userprofile_receiving_program_updates.py new file mode 100644 index 00000000..4cbe23f0 --- /dev/null +++ b/accounts/migrations/0008_userprofile_receiving_program_updates.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.13 on 2024-02-15 19:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0007_alter_userprofile_user"), + ] + + operations = [ + migrations.AddField( + model_name="userprofile", + name="receiving_program_updates", + field=models.BooleanField(default=False), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index 9cecb5f7..317c998f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -61,6 +61,7 @@ class UserProfile(models.Model): email_confirmed = models.BooleanField(default=False) receiving_newsletter = models.BooleanField(default=False) receiving_event_updates = models.BooleanField(default=False) + receiving_program_updates = models.BooleanField(default=False) def __str__(self): return self.user.username diff --git a/accounts/tests/test_activate_view.py b/accounts/tests/test_activate_view.py new file mode 100644 index 00000000..550c6d20 --- /dev/null +++ b/accounts/tests/test_activate_view.py @@ -0,0 +1,59 @@ +from django.test import Client, TestCase +from django.urls import reverse +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode + +from accounts.models import CustomUser +from accounts.tokens import account_activation_token + + +class ActivateViewTests(TestCase): + def setUp(self): + self.client = Client() + + @classmethod + def setUpTestData(cls): + cls.user = CustomUser.objects.create_user( + username="test", email="example@example.com", password="" + ) + + def test_user_does_not_exist(self): + activate_url = reverse( + "activate_account", + kwargs={ + "uidb64": urlsafe_base64_encode(force_bytes("500")), + "token": account_activation_token.make_token(self.user), + }, + ) + response = self.client.get(activate_url, follow=True) + self.assertRedirects(response, reverse("signup")) + self.assertContains(response, "Your confirmation link is invalid.") + self.user.profile.refresh_from_db() + self.assertFalse(self.user.profile.email_confirmed) + + def test_invalid_token(self): + activate_url = reverse( + "activate_account", + kwargs={ + "uidb64": urlsafe_base64_encode(force_bytes(self.user.pk)), + "token": "INVALID_TOKEN", + }, + ) + response = self.client.get(activate_url, follow=True) + self.assertRedirects(response, reverse("signup")) + self.assertContains(response, "Your confirmation link is invalid.") + self.user.profile.refresh_from_db() + self.assertFalse(self.user.profile.email_confirmed) + + def test_activate_email(self): + activate_url = reverse( + "activate_account", + kwargs={ + "uidb64": urlsafe_base64_encode(force_bytes(self.user.pk)), + "token": account_activation_token.make_token(self.user), + }, + ) + response = self.client.get(activate_url) + self.assertRedirects(response, reverse("profile")) + self.user.profile.refresh_from_db() + self.assertTrue(self.user.profile.email_confirmed) diff --git a/accounts/tests/test_profile_view.py b/accounts/tests/test_profile_view.py new file mode 100644 index 00000000..4c4e51bc --- /dev/null +++ b/accounts/tests/test_profile_view.py @@ -0,0 +1,38 @@ +from django.test import Client, TestCase +from django.urls import reverse + +from accounts.models import CustomUser + + +class ProfileViewTests(TestCase): + def setUp(self): + self.client = Client() + + @classmethod + def setUpTestData(cls): + cls.user = CustomUser.objects.create_user( + username="test", + email="example@example.com", + password="", + first_name="Jane", + last_name="Doe", + ) + cls.user.refresh_from_db() + cls.user.profile.receiving_newsletter = True + cls.user.profile.receiving_program_updates = True + cls.user.profile.receiving_event_updates = True + cls.user.profile.save() + cls.profile_url = reverse("profile") + + def test_redirect_when_unauthenticated(self): + response = self.client.get(self.profile_url, follow=True) + self.assertRedirects(response, f"{reverse('login')}?next={self.profile_url}") + + def test_profile(self): + self.client.force_login(self.user) + response = self.client.get(self.profile_url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Welcome, Jane") + self.assertContains(response, "Profile Info") + self.assertContains(response, "test") + self.assertContains(response, "Jane Doe") diff --git a/accounts/tests/test_signup_view.py b/accounts/tests/test_signup_view.py index 91e08922..cedced0f 100644 --- a/accounts/tests/test_signup_view.py +++ b/accounts/tests/test_signup_view.py @@ -4,6 +4,8 @@ from django.test import Client, TestCase from django.urls import reverse +from accounts.models import CustomUser + class SignUpViewTests(TestCase): def setUp(self): @@ -28,6 +30,9 @@ def test_signup_template_post_success(self, mock_captcha): "password2": "secretpassword123", "email_consent": True, "accepted_coc": True, + "receive_newsletter": True, + "receive_program_updates": True, + "receive_event_updates": True, "g-recaptcha-response": "dummy-response", }, follow=True, @@ -43,6 +48,12 @@ def test_signup_template_post_success(self, mock_captcha): mail.outbox[0].subject, "Djangonaut Space Registration Confirmation" ) self.assertIn( - "To confirm your email address on djangonaut.space please visit the link:", + "Thank you for signing up to Djangonaut Space! Click the link to verify your email:", mail.outbox[0].body, ) + created_user = CustomUser.objects.get(username="janedoe") + self.assertTrue(created_user.is_active) + self.assertTrue(created_user.profile.accepted_coc) + self.assertTrue(created_user.profile.receiving_newsletter) + self.assertTrue(created_user.profile.receiving_program_updates) + self.assertTrue(created_user.profile.receiving_event_updates) diff --git a/accounts/tests/test_unsubscribe_view.py b/accounts/tests/test_unsubscribe_view.py new file mode 100644 index 00000000..6209fdee --- /dev/null +++ b/accounts/tests/test_unsubscribe_view.py @@ -0,0 +1,45 @@ +from django.test import Client, TestCase +from django.urls import reverse + +from accounts.models import CustomUser + + +class UnsubscribeViewTests(TestCase): + def setUp(self): + self.client = Client() + + @classmethod + def setUpTestData(cls): + cls.user = CustomUser.objects.create_user( + username="test", email="example@example.com", password="" + ) + cls.user.refresh_from_db() + cls.user.profile.receiving_newsletter = True + cls.user.profile.receiving_program_updates = True + cls.user.profile.receiving_event_updates = True + cls.user.profile.save() + cls.unsubscribe_url = reverse( + "unsubscribe", kwargs={"user_id": cls.user.id, "token": "dummytoken"} + ) + + def test_user_does_not_exist(self): + response = self.client.get( + reverse("unsubscribe", kwargs={"user_id": 500, "token": "dummytoken"}) + ) + self.assertEqual(response.status_code, 404) + + def test_redirect_when_unauthenticated(self): + response = self.client.get(self.unsubscribe_url) + self.assertRedirects( + response, f"{reverse('login')}?next={self.unsubscribe_url}" + ) + + def test_unsubscribe(self): + self.client.force_login(self.user) + response = self.client.get(self.unsubscribe_url) + self.assertEqual(response.status_code, 200) + profile = self.user.profile + profile.refresh_from_db() + self.assertFalse(profile.receiving_newsletter) + self.assertFalse(profile.receiving_program_updates) + self.assertFalse(profile.receiving_event_updates) diff --git a/accounts/views.py b/accounts/views.py index 468d6830..e54d761f 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -11,6 +11,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import redirect from django.shortcuts import render +from django.template.loader import render_to_string from django.urls import reverse from django.utils.encoding import force_bytes from django.utils.encoding import force_str @@ -66,6 +67,9 @@ def form_valid(self, form): user = self.object user.profile.accepted_coc = form.cleaned_data["accepted_coc"] user.profile.receiving_newsletter = form.cleaned_data["receive_newsletter"] + user.profile.receiving_program_updates = form.cleaned_data[ + "receive_program_updates" + ] user.profile.receiving_event_updates = form.cleaned_data[ "receive_event_updates" ] @@ -73,6 +77,7 @@ def form_valid(self, form): update_fields=[ "accepted_coc", "receiving_newsletter", + "receiving_program_updates", "receiving_event_updates", ] ) @@ -83,15 +88,18 @@ def form_valid(self, form): "token": account_activation_token.make_token(user), }, ) - message = ( - "To confirm your email address on djangonaut.space please visit the link: " - + self.request.build_absolute_uri(invite_link) - ) + unsubscribe_link = user.profile.create_unsubscribe_link() + email_dict = { + "cta_link": self.request.build_absolute_uri(invite_link), + "name": user.get_full_name(), + "unsubscribe_link": unsubscribe_link, + } send_mail( "Djangonaut Space Registration Confirmation", - message, + render_to_string("emails/email_confirmation.txt", email_dict), settings.DEFAULT_FROM_EMAIL, [user.email], + html_message=render_to_string("emails/email_confirmation.html", email_dict), fail_silently=False, ) return super().form_valid(form) @@ -115,17 +123,12 @@ def unsubscribe(request, user_id, token): ) or user.profile.check_token(token): # unsubscribe them profile = user.profile - if request.GET.get("events", None): - email_type = "events" - profile.receiving_event_updates = False - else: - email_type = "newsletters" - profile.receiving_newsletter = False + profile.receiving_event_updates = False + profile.receiving_program_updates = False + profile.receiving_newsletter = False profile.save() - return render( - request, "registration/unsubscribed.html", {"email_type": email_type} - ) + return render(request, "registration/unsubscribed.html") # Otherwise redirect to login page next_url = reverse( diff --git a/indymeet/static/css/registration.css b/indymeet/static/css/registration.css index bd9bc695..24a7190a 100644 --- a/indymeet/static/css/registration.css +++ b/indymeet/static/css/registration.css @@ -1,27 +1,18 @@ /* --------------------------------------------------------------------- REGISTRATION - LOGIN LOG OUT ----------------------------------------------------------------------*/ -.registration-form { - width: 20rem; - margin: auto; +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; } -.registration-logo { - width: 100%; +.control-label { + font-weight: 700; + margin-bottom: 5px; } -.profile-img { - width: 100%; -} - -table { - border:1px solid black; - padding: 10px; - } -th, td{ - border:1px solid black; - padding: .5rem; -} -td:first-child { - width: 20%; +.form-group { + margin-bottom: 5px; } diff --git a/indymeet/templates/emails/base.html b/indymeet/templates/emails/base.html new file mode 100644 index 00000000..31d817d7 --- /dev/null +++ b/indymeet/templates/emails/base.html @@ -0,0 +1,148 @@ + + + + + + Simple Transactional Email + + + + + + + + + + + + \ No newline at end of file diff --git a/indymeet/templates/emails/email_confirmation.html b/indymeet/templates/emails/email_confirmation.html new file mode 100644 index 00000000..db97fa83 --- /dev/null +++ b/indymeet/templates/emails/email_confirmation.html @@ -0,0 +1,5 @@ +{% extends "emails/base.html" %} +{% block preheader %}Djangonaut Space - Verify your email{% endblock preheader %} +{% block before_cta %}Thank you for signing up to Djangonaut Space! Click the button to verify your email.{% endblock before_cta %} +{% block cta_button_text %}Verify Email{% endblock cta_button_text %} +{% block after_cta %}{% endblock after_cta %} \ No newline at end of file diff --git a/indymeet/templates/emails/email_confirmation.txt b/indymeet/templates/emails/email_confirmation.txt new file mode 100644 index 00000000..de8a8f32 --- /dev/null +++ b/indymeet/templates/emails/email_confirmation.txt @@ -0,0 +1,9 @@ +Hi {{ name }}, + +Thank you for signing up to Djangonaut Space! Click the link to verify your email: {{ cta_link }}. + +Thank you, + +Djangonaut Space Organizers + +Don't like these emails? Unsubscribe: {{ unsubscribe_link }} diff --git a/indymeet/templates/includes/nav.html b/indymeet/templates/includes/nav.html index 07c63f08..0c7e69b5 100644 --- a/indymeet/templates/includes/nav.html +++ b/indymeet/templates/includes/nav.html @@ -14,7 +14,7 @@
  • - + {% trans "Join us!" %}
  • diff --git a/indymeet/templates/registration/logged_out.html b/indymeet/templates/registration/logged_out.html index ac875da2..d941fba9 100644 --- a/indymeet/templates/registration/logged_out.html +++ b/indymeet/templates/registration/logged_out.html @@ -1,20 +1,22 @@ {% extends "base.html" %} -{% load i18n wagtailcore_tags static %} - +{% load i18n wagtailcore_tags bootstrap3 static %} +{% block title %}{% translate "Logged out | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Logged out | Djangonaut Space" %}{% endblock %} {% block extra_css %} - - {% endblock extra_css %} {% block content %} -
    -

    You've been logged out.

    - - - +
    +
    +
    +
    +

    {% translate "You've been logged out." %}

    +
    +
    +
    {% endblock content %} diff --git a/indymeet/templates/registration/login.html b/indymeet/templates/registration/login.html index ce21b9c3..31baaa92 100644 --- a/indymeet/templates/registration/login.html +++ b/indymeet/templates/registration/login.html @@ -1,52 +1,53 @@ {% extends "base.html" %} -{% load i18n wagtailcore_tags static %} - +{% load i18n wagtailcore_tags bootstrap3 static %} +{% block title %}{% translate "Login | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Login | Djangonaut Space" %}{% endblock %} {% block extra_css %} - - {% endblock extra_css %} {% block content %} -
    -{% if form.errors %} -

    Your username and password didn't match. Please try again.

    -{% endif %} - -{% if next %} - {% if user.is_authenticated %} -

    Your account doesn't have access to this page. To proceed, - please login with an account that has access.

    - {% else %} -

    Please login to see this page.

    - {% endif %} -{% endif %} - -
    -{% csrf_token %} - - - - - - - - - - - - -
    {{ form.username.label_tag }}{{ form.username }}
    {{ form.password.label_tag }}{{ form.password }}
    - - - -
    - -{# Assumes you set up the password_reset view in your URLconf #} -

    Lost password?

    - +
    +
    + {% if next %} +
    +
    + {% if user.is_authenticated %} +

    {% translate "Your account doesn't have access to this page. To proceed, please login with an account that has access." %}

    + {% else %} +

    {% translate "Please login to see this page." %}

    + {% endif %} +
    +
    + {% endif %} + {% if form.errors and not form.non_field_errors %} +
    + {% for key, error in form.errors.items %} +

    {{ key }}:{{ error }}

    + {% endfor %} +
    + {% endif %} + +
    +
    +
    + {% csrf_token %} + + {% bootstrap_form form layout="horizontal" %} + + +
    +
    +
    +
    +

    {% translate "Forgotten your password?" %}{% translate "Reset password." %}

    +
    +
    +
    +
    +
    {% endblock content %} diff --git a/indymeet/templates/registration/profile.html b/indymeet/templates/registration/profile.html index 9ae896ee..03076235 100644 --- a/indymeet/templates/registration/profile.html +++ b/indymeet/templates/registration/profile.html @@ -1,90 +1,74 @@ {% extends "base.html" %} -{% load i18n wagtailcore_tags static %} - +{% load i18n wagtailcore_tags bootstrap3 static %} +{% block title %}{% translate "Profile | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Profile | Djangonaut Space" %}{% endblock %} {% block extra_css %} - - {% endblock extra_css %} {% block content %} -
    -
    -

    ACCOUNT PAGE

    -
    -
    -
    - -
    -
    -
    +
    +
    +

    {% translate "Welcome," %} {{ user.first_name }} 👋

    +
    +
    +

    {% translate "We're so happy to have you here!" %}

    +
    +
    +
    +
    +

    {% translate "Profile Info" %}

    +
    +
    +
    +
    - Account Details - - - - - - - - - - - - - - - + + + - - - + + + - - - + + + - - - + + + - -
    Name:{{ user }}
    Bio{{ user.profile.bio }}
    Pronouns{{ user.profile.pronouns }}
    Session Participations{% for session in user.sessions.all %} - {{ session }}{% if forloop.last %}{% else %}, {% endif %} - {% endfor %}
    {% translate "Name" %}{{ user.get_full_name }}
    Interested in Recruitment?{{ user.profile.recruitment_interest }}
    {% translate "Username" %}{{ user.username }}
    Recieving Newsletter?{{ user.profile.receiving_newsletter }}
    {% translate "Receiving Program updates?" %} + {% if user.profile.receiving_program_updates %} + {% translate "Yes" %} + {% else %} + {% translate "No" %} + {% endif %} +
    Reviewed CoC{{ user.profile.accepted_coc }}
    {% translate "Receiving event updates?" %} + {% if user.profile.receiving_event_updates %} + {% translate "Yes" %} + {% else %} + {% translate "No" %} + {% endif %} +
    -
    -
    -
    -
    - - Socials - - {% for link in user.profile.links.all %} - - - + + + - {% endfor %}
    {{ link.name }}{{ link.url }}
    {% translate "Receiving Newsletter?" %} + {% if user.profile.receiving_newsletter %} + {% translate "Yes" %} + {% else %} + {% translate "No" %} + {% endif %} +
    +
    -
    -
    -

    UPCOMING REGISTERED EVENTS

    - {% with user.rsvp_events.upcoming as future_events %} - {% include 'home/includes/events_upcoming.html' %} - {% endwith %} -
    {% endblock content %} diff --git a/indymeet/templates/registration/signup.html b/indymeet/templates/registration/signup.html index 490e2a0d..189a1a46 100644 --- a/indymeet/templates/registration/signup.html +++ b/indymeet/templates/registration/signup.html @@ -1,43 +1,43 @@ {% extends "base.html" %} {% load i18n wagtailcore_tags bootstrap3 static %} - +{% block title %}{% translate "Registration | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Registration | Djangonaut Space" %}{% endblock %} {% block extra_css %} - - {% endblock extra_css %} {% block content %} -
    - - -
    -

    Registration

    -
    - {% if form.errors and not form.non_field_errors %} -
    - {% for key, error in form.errors.items %} -

    {{ key }}:{{ error }}

    - {% endfor %} -
    - {% endif %} - -
    -
    -
    - {% csrf_token %} - - {% bootstrap_form form layout="horizontal" %} - - -
    -
    -
    -
    - - - +
    +
    +

    {% translate "Registration" %}

    +
    +
    +

    {% translate "Sign up to keep up with all things Djangonaut Space!" %}

    +
    +
    + {% if form.errors and not form.non_field_errors %} +
    + {% for key, error in form.errors.items %} +

    {{ key }}:{{ error }}

    + {% endfor %} +
    + {% endif %} + +
    +
    +
    + {% csrf_token %} + + {% bootstrap_form form layout="horizontal" %} + + +
    +
    +
    +
    +
    +
    {% endblock content %} diff --git a/indymeet/templates/registration/unsubscribed.html b/indymeet/templates/registration/unsubscribed.html index bd842334..19cfc1d8 100644 --- a/indymeet/templates/registration/unsubscribed.html +++ b/indymeet/templates/registration/unsubscribed.html @@ -15,6 +15,6 @@ -

    You've been successfully unsubscribed from {{ email_type }}.

    +

    You've been successfully unsubscribed from our emails.

    {% endblock content %} From 5484f8e93d96ee5cbf64b35b256c90db7215e8fa Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Fri, 16 Feb 2024 07:28:37 -0600 Subject: [PATCH 16/29] Create MIT LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8f007a35 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Djangonaut Space + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From cf43a84be557511029475b143fb2d3f71f39a366 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Fri, 16 Feb 2024 21:55:57 +0100 Subject: [PATCH 17/29] Account form updates. (#278) --- .../registration/password_reset_complete.html | 29 ++++--- .../registration/password_reset_confirm.html | 80 ++++++++++--------- .../registration/password_reset_done.html | 29 ++++--- .../registration/password_reset_form.html | 53 +++++++----- 4 files changed, 114 insertions(+), 77 deletions(-) diff --git a/indymeet/templates/registration/password_reset_complete.html b/indymeet/templates/registration/password_reset_complete.html index fbe6ab38..a4feb1ec 100644 --- a/indymeet/templates/registration/password_reset_complete.html +++ b/indymeet/templates/registration/password_reset_complete.html @@ -1,14 +1,23 @@ -{% extends "content_base.html" %} -{% load i18n %} +{% extends "base.html" %} +{% load i18n wagtailcore_tags static %} -{% block page_title %} -{% translate 'Password reset' %} -{% endblock %} +{% block title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} -{% block main_content %} -

    {% translate "Your password has been set. You may go ahead and log in now." %}

    +{% block extra_css %} + +{% endblock extra_css %} -

    {% translate 'Log in' %}

    - -{% endblock %} +{% block content %} +
    +
    +
    +
    +

    {% translate "Your password has been set. You may go ahead and log in now." %}

    +

    {% translate 'Log in' %}

    +
    +
    +
    +
    +{% endblock content %} diff --git a/indymeet/templates/registration/password_reset_confirm.html b/indymeet/templates/registration/password_reset_confirm.html index 24d68082..8c6a6092 100644 --- a/indymeet/templates/registration/password_reset_confirm.html +++ b/indymeet/templates/registration/password_reset_confirm.html @@ -1,40 +1,42 @@ -{% extends "content_base.html" %} -{% load i18n static %} -{% load django_bootstrap5 %} - -{% block extrastyle %}{{ block.super }}{% endblock %} -{% block page_title %} -{% translate 'Password reset confirmation' %} -{% endblock %} - -{% block main_content %} - -{% if validlink %} - -

    {% translate "Please enter your new password twice so we can verify you typed it in correctly." %}

    - -
    -
    {% csrf_token %} -
    - -
    - {{ form.new_password1.errors }} - - {% bootstrap_field form.new_password1 %} +{% extends "base.html" %} +{% load i18n wagtailcore_tags bootstrap3 static %} + +{% block title %}{% translate "Password reset confirmation | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Password reset confirmation | Djangonaut Space" %}{% endblock %} + + +{% block extra_css %} + +{% endblock extra_css %} + +{% block content %} +
    +
    +

    {% translate "Reset password" %}

    + {% if validlink %} + {% if form.errors and not form.non_field_errors %} +
    + {% for key, error in form.errors.items %} +

    {{ key }}:{{ error }}

    + {% endfor %} +
    + {% endif %} + +
    +
    + + {% csrf_token %} + + {% bootstrap_form form layout="horizontal" %} + + + +
    +
    -
    - {{ form.new_password2.errors }} - - {% bootstrap_field form.new_password2 %} -
    - -
    - -
    -{% else %} - -

    {% translate "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

    - -{% endif %} - -{% endblock %} + {% else %} +

    {% translate "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

    + {% endif %} + +
    +{% endblock content %} diff --git a/indymeet/templates/registration/password_reset_done.html b/indymeet/templates/registration/password_reset_done.html index cef5c51d..23cc8aea 100644 --- a/indymeet/templates/registration/password_reset_done.html +++ b/indymeet/templates/registration/password_reset_done.html @@ -1,14 +1,23 @@ -{% extends "content_base.html" %} -{% load i18n %} +{% extends "base.html" %} +{% load i18n wagtailcore_tags static %} -{% block page_title %} -{% translate 'Password reset' %} -{% endblock %} +{% block title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} -{% block main_content %} -

    {% translate 'We’ve emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.' %}

    +{% block extra_css %} + +{% endblock extra_css %} -

    {% translate 'If you don’t receive an email, please make sure you’ve entered the address you registered with, and check your spam folder.' %}

    - -{% endblock %} +{% block content %} +
    +
    +
    +
    +

    {% translate "We’ve emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}

    +

    {% translate "If you don’t receive an email, please make sure you’ve entered the address you registered with, and check your spam folder." %}

    +
    +
    +
    +
    +{% endblock content %} diff --git a/indymeet/templates/registration/password_reset_form.html b/indymeet/templates/registration/password_reset_form.html index 472f91c8..b871f10c 100644 --- a/indymeet/templates/registration/password_reset_form.html +++ b/indymeet/templates/registration/password_reset_form.html @@ -1,24 +1,41 @@ -{% extends "content_base.html" %} -{% load i18n static %} -{% load django_bootstrap5 %} +{% extends "base.html" %} +{% load i18n wagtailcore_tags bootstrap3 static %} -{% block page_title %} -{% translate 'Password Reset' %} -{% endblock %} +{% block title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} +{% block meta_title %}{% translate "Password reset | Djangonaut Space" %}{% endblock %} -{% block main_content %} -

    {% translate 'Forgotten your password? Enter your email address below, and we’ll email instructions for setting a new one.' %}

    +{% block extra_css %} + +{% endblock extra_css %} -
    {% csrf_token %} -
    -
    - {{ form.email.errors }} +{% block content %} +
    +
    +

    {% translate "Reset password" %}

    +
    +
    +

    {% translate "Forgotten your password? Enter your email address below, and we’ll email instructions for setting a new one." %}

    +
    +
    + {% if form.errors and not form.non_field_errors %} +
    + {% for key, error in form.errors.items %} +

    {{ key }}:{{ error }}

    + {% endfor %} +
    + {% endif %} - {% bootstrap_field form.email %} +
    +
    + + {% csrf_token %} + {% bootstrap_form form layout="horizontal" %} + + +
    +
    +
    - -
    - - -{% endblock %} +
    +{% endblock content %} From 99f205d0055687872b6425a1d0737d117e189470 Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Fri, 16 Feb 2024 15:39:08 -0600 Subject: [PATCH 18/29] Run the migrate command after builds, but before deployment. (#277) --- scripts/postbuild.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index 3f2d81d3..dd61fd3b 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -1,3 +1,4 @@ python manage.py tailwind install python manage.py tailwind build python manage.py collectstatic --noinput +python manage.py migrate From 050054a95de9780d85450215402533a0281f05ed Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 07:39:45 -0600 Subject: [PATCH 19/29] Log all errors and above to the console Sentry should be helping with this, but I'm still running into application errors that don't make their way to Sentry. --- indymeet/settings/base.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/indymeet/settings/base.py b/indymeet/settings/base.py index a2a7134a..44d3b976 100644 --- a/indymeet/settings/base.py +++ b/indymeet/settings/base.py @@ -225,3 +225,21 @@ if os.environ.get("ENABLE_TOOLBAR"): INSTALLED_APPS += ["debug_toolbar"] MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] + + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "root": {"level": "WARNING", "handlers": ["console"]}, + "formatters": {"simple": {"format": "%(levelname)s %(message)s"}}, + "handlers": { + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "simple", + }, + }, + "loggers": { + "django.request": {"handlers": [], "level": "ERROR"}, + }, +} From 69548d733c9abf9acfbcfb8b4c935f8d5a554976 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 07:42:13 -0600 Subject: [PATCH 20/29] Remove migrate from postbuild script. This would require us to have the database connection settings in our github repository and that doesn't sit well with me currently. Let's keep looking. --- scripts/postbuild.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index dd61fd3b..3f2d81d3 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -1,4 +1,3 @@ python manage.py tailwind install python manage.py tailwind build python manage.py collectstatic --noinput -python manage.py migrate From b641b3d36dae8782cd7997a598d05481edd45168 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 09:45:39 -0600 Subject: [PATCH 21/29] Attempt to install supervisor during the build Supervisor would allow us to programatically run background tasks more easily. --- scripts/postbuild.sh | 3 +++ scripts/startup.sh | 3 +++ supervisord.conf | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 scripts/startup.sh create mode 100644 supervisord.conf diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index 3f2d81d3..5398c95f 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -1,3 +1,6 @@ python manage.py tailwind install python manage.py tailwind build python manage.py collectstatic --noinput +# Install supervisor +apt-get update -y +apt-get install -y supervisor diff --git a/scripts/startup.sh b/scripts/startup.sh new file mode 100644 index 00000000..4bbf8097 --- /dev/null +++ b/scripts/startup.sh @@ -0,0 +1,3 @@ +#!/bin/sh +supervisord -c supervisord.conf +/opt/startup/startup.sh diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 00000000..6aaad3e1 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,2 @@ +[program:foo] +command=/bin/cat From ca24ff337bf12cce529f5d264970bf63c8b76a19 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 09:46:17 -0600 Subject: [PATCH 22/29] I want to know if this file ends up in the app service or not. --- scripts/postbuild.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index 5398c95f..e65434fa 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -4,3 +4,5 @@ python manage.py collectstatic --noinput # Install supervisor apt-get update -y apt-get install -y supervisor +# Test what happens when we try to create a sample file +touch test.txt From e6b147c510175f9c03a000fd84310a92b878e9f2 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 10:06:39 -0600 Subject: [PATCH 23/29] Revise supervisor install to install on server Oryx's post build command won't install the dependencies within the image. The next place I know we can install them is from within the startup command. --- scripts/postbuild.sh | 5 ----- scripts/startup.sh | 10 ++++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index e65434fa..3f2d81d3 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -1,8 +1,3 @@ python manage.py tailwind install python manage.py tailwind build python manage.py collectstatic --noinput -# Install supervisor -apt-get update -y -apt-get install -y supervisor -# Test what happens when we try to create a sample file -touch test.txt diff --git a/scripts/startup.sh b/scripts/startup.sh index 4bbf8097..9573a006 100644 --- a/scripts/startup.sh +++ b/scripts/startup.sh @@ -1,3 +1,13 @@ #!/bin/sh +# This file is configured to be used within the environment variables +# in the App Service under Configuration > General Settings > Startup Command + +# Install supervisor +apt-get update -y +apt-get install -y supervisor +# Start supervisord supervisord -c supervisord.conf + +# This is the existing file that's generated by Oryx and how Azure +# wants to start up our App Service. It ends in a gunicorn command /opt/startup/startup.sh From 18ddd03a203829c7a5ccdd598f4dcc2499482599 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 10:36:57 -0600 Subject: [PATCH 24/29] Add a supervisord section to supervisord.conf It was failing to start up causing the whole server to not load. --- scripts/startup.sh | 4 ++-- supervisord.conf | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/startup.sh b/scripts/startup.sh index 9573a006..f1e4a459 100644 --- a/scripts/startup.sh +++ b/scripts/startup.sh @@ -3,8 +3,8 @@ # in the App Service under Configuration > General Settings > Startup Command # Install supervisor -apt-get update -y -apt-get install -y supervisor +apt update -y +apt install -y supervisor # Start supervisord supervisord -c supervisord.conf diff --git a/supervisord.conf b/supervisord.conf index 6aaad3e1..02d956dc 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -1,2 +1,5 @@ +[supervisord] +nodaemon=false + [program:foo] command=/bin/cat From 53651705eb6b7437512baf39d00bafc21db2fb3c Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 11:05:45 -0600 Subject: [PATCH 25/29] Attempt to install supervisor via pip Installing things via the startup command causing conflicts from the apt lockfile. --- requirements/requirements.in | 3 ++- requirements/requirements.txt | 7 +++++-- scripts/startup.sh | 3 --- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/requirements/requirements.in b/requirements/requirements.in index fe6de893..01643372 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -15,4 +15,5 @@ django-debug-toolbar typing-extensions django-tailwind django-bootstrap3 -sentry-sdk[django] \ No newline at end of file +sentry-sdk[django] +supervisor diff --git a/requirements/requirements.txt b/requirements/requirements.txt index eefa6663..fc527667 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -149,6 +149,8 @@ sqlparse==0.4.4 # via # django # django-debug-toolbar +supervisor==4.2.5 + # via -r requirements/requirements.in telepath==0.3.1 # via wagtail typing-extensions==4.6.3 @@ -158,8 +160,6 @@ typing-extensions==4.6.3 # asgiref # azure-core # azure-storage-blob -tzdata==2024.1 - # via django urllib3==1.26.18 # via # -r requirements/requirements.in @@ -182,3 +182,6 @@ willow==1.6.3 # via wagtail zipp==3.17.0 # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/scripts/startup.sh b/scripts/startup.sh index f1e4a459..27ef31ff 100644 --- a/scripts/startup.sh +++ b/scripts/startup.sh @@ -2,9 +2,6 @@ # This file is configured to be used within the environment variables # in the App Service under Configuration > General Settings > Startup Command -# Install supervisor -apt update -y -apt install -y supervisor # Start supervisord supervisord -c supervisord.conf From 80896f1f387595e68608c216c9cc6f55372cb1a8 Mon Sep 17 00:00:00 2001 From: tschilling Date: Sat, 17 Feb 2024 11:36:40 -0600 Subject: [PATCH 26/29] We still need to run gunicorn at the end of startup.sh --- scripts/startup.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/startup.sh b/scripts/startup.sh index 27ef31ff..e45feb55 100644 --- a/scripts/startup.sh +++ b/scripts/startup.sh @@ -5,6 +5,5 @@ # Start supervisord supervisord -c supervisord.conf -# This is the existing file that's generated by Oryx and how Azure -# wants to start up our App Service. It ends in a gunicorn command -/opt/startup/startup.sh +# This is generally how the startup script gets generated by Oryx +GUNICORN_CMD_ARGS="--timeout 600 --access-logfile '-' --error-logfile '-' -c /opt/startup/gunicorn.conf.py" gunicorn indymeet.wsgi From 578cb3d48380bcce71481aa64f17786c35e43745 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Sun, 18 Feb 2024 12:02:24 +0100 Subject: [PATCH 27/29] Add Factory boy for tests. (#289) * Add factory_boy dependency. * Add factories for tests. --- accounts/factories.py | 23 ++++++++++++++++++++ accounts/tests/test_activate_view.py | 6 ++---- accounts/tests/test_profile_view.py | 16 +++----------- accounts/tests/test_unsubscribe_view.py | 14 ++++++------- home/factories.py | 28 +++++++++++++++++++++++++ home/tests/test_event_views.py | 14 +++---------- home/tests/test_models.py | 9 ++------ home/tests/test_session_views.py | 17 +++------------ requirements/requirements-test.in | 1 + requirements/requirements-test.txt | 8 ++++++- 10 files changed, 78 insertions(+), 58 deletions(-) create mode 100644 accounts/factories.py create mode 100644 home/factories.py diff --git a/accounts/factories.py b/accounts/factories.py new file mode 100644 index 00000000..c99a67ea --- /dev/null +++ b/accounts/factories.py @@ -0,0 +1,23 @@ +import factory +from django.db.models.signals import post_save +from accounts.models import CustomUser, UserProfile + + +@factory.django.mute_signals(post_save) +class ProfileFactory(factory.django.DjangoModelFactory): + class Meta: + model = UserProfile + + user = factory.SubFactory("accounts.factories.UserFactory", profile=None) + + +@factory.django.mute_signals(post_save) +class UserFactory(factory.django.DjangoModelFactory): + class Meta: + model = CustomUser + + username = factory.Sequence(lambda n: "user_%d" % n) + first_name = "Jane" + last_name = "Doe" + email = "example@example.com" + profile = factory.RelatedFactory(ProfileFactory, factory_related_name="user") diff --git a/accounts/tests/test_activate_view.py b/accounts/tests/test_activate_view.py index 550c6d20..5b39b2bc 100644 --- a/accounts/tests/test_activate_view.py +++ b/accounts/tests/test_activate_view.py @@ -3,7 +3,7 @@ from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode -from accounts.models import CustomUser +from accounts.factories import UserFactory from accounts.tokens import account_activation_token @@ -13,9 +13,7 @@ def setUp(self): @classmethod def setUpTestData(cls): - cls.user = CustomUser.objects.create_user( - username="test", email="example@example.com", password="" - ) + cls.user = UserFactory.create() def test_user_does_not_exist(self): activate_url = reverse( diff --git a/accounts/tests/test_profile_view.py b/accounts/tests/test_profile_view.py index 4c4e51bc..6ab9e75d 100644 --- a/accounts/tests/test_profile_view.py +++ b/accounts/tests/test_profile_view.py @@ -1,7 +1,7 @@ from django.test import Client, TestCase from django.urls import reverse -from accounts.models import CustomUser +from accounts.factories import ProfileFactory class ProfileViewTests(TestCase): @@ -10,18 +10,8 @@ def setUp(self): @classmethod def setUpTestData(cls): - cls.user = CustomUser.objects.create_user( - username="test", - email="example@example.com", - password="", - first_name="Jane", - last_name="Doe", - ) - cls.user.refresh_from_db() - cls.user.profile.receiving_newsletter = True - cls.user.profile.receiving_program_updates = True - cls.user.profile.receiving_event_updates = True - cls.user.profile.save() + profile = ProfileFactory.create(user__username="test") + cls.user = profile.user cls.profile_url = reverse("profile") def test_redirect_when_unauthenticated(self): diff --git a/accounts/tests/test_unsubscribe_view.py b/accounts/tests/test_unsubscribe_view.py index 6209fdee..93903a4a 100644 --- a/accounts/tests/test_unsubscribe_view.py +++ b/accounts/tests/test_unsubscribe_view.py @@ -1,7 +1,7 @@ from django.test import Client, TestCase from django.urls import reverse -from accounts.models import CustomUser +from accounts.factories import ProfileFactory class UnsubscribeViewTests(TestCase): @@ -10,14 +10,12 @@ def setUp(self): @classmethod def setUpTestData(cls): - cls.user = CustomUser.objects.create_user( - username="test", email="example@example.com", password="" + profile = ProfileFactory.create( + receiving_newsletter=True, + receiving_program_updates=True, + receiving_event_updates=True, ) - cls.user.refresh_from_db() - cls.user.profile.receiving_newsletter = True - cls.user.profile.receiving_program_updates = True - cls.user.profile.receiving_event_updates = True - cls.user.profile.save() + cls.user = profile.user cls.unsubscribe_url = reverse( "unsubscribe", kwargs={"user_id": cls.user.id, "token": "dummytoken"} ) diff --git a/home/factories.py b/home/factories.py new file mode 100644 index 00000000..7d906cc2 --- /dev/null +++ b/home/factories.py @@ -0,0 +1,28 @@ +import factory +from home.models import Event, Session + + +class EventFactory(factory.django.DjangoModelFactory): + class Meta: + model = Event + + title = factory.Sequence(lambda n: "Event %d" % n) + slug = factory.Sequence(lambda n: "event-%d" % n) + start_time = factory.Faker("datetime") + end_time = factory.Faker("datetime") + location = "https://zoom.link" + status = Event.SCHEDULED + + +class SessionFactory(factory.django.DjangoModelFactory): + class Meta: + model = Session + + start_date = factory.Faker("date") + end_date = factory.Faker("date") + title = factory.Sequence(lambda n: "Session %d" % n) + slug = factory.Sequence(lambda n: "session-%d" % n) + invitation_date = factory.Faker("date") + application_start_date = factory.Faker("date") + application_end_date = factory.Faker("date") + application_url = factory.Sequence(lambda n: "https://apply.session%d.com" % n) diff --git a/home/tests/test_event_views.py b/home/tests/test_event_views.py index 8e58c11f..7f7ed63a 100644 --- a/home/tests/test_event_views.py +++ b/home/tests/test_event_views.py @@ -6,7 +6,7 @@ from django.utils import timezone from freezegun import freeze_time -from home.models import Event +from home.factories import EventFactory @freeze_time("2012-01-14") @@ -16,24 +16,16 @@ def setUp(self): @staticmethod def create_upcoming_event(): - return Event.objects.create( - title="Testathon 5.0", - slug="testathon-5", + return EventFactory.create( start_time=datetime(2023, 2, 1, 10, 0, tzinfo=dt_timezone.utc), end_time=datetime(2023, 2, 1, 11, 0, tzinfo=dt_timezone.utc), - location="https://zoom.link", - status=Event.SCHEDULED, ) @staticmethod def create_past_event(): - return Event.objects.create( - title="Coffee Chat", - slug="coffee-chat", + return EventFactory.create( start_time=datetime(2010, 2, 1, 10, 0, tzinfo=dt_timezone.utc), end_time=datetime(2010, 2, 1, 11, 0, tzinfo=dt_timezone.utc), - location="zoom", - status=Event.SCHEDULED, ) def test_list_no_events(self): diff --git a/home/tests/test_models.py b/home/tests/test_models.py index 904472c4..caa4d0a8 100644 --- a/home/tests/test_models.py +++ b/home/tests/test_models.py @@ -3,18 +3,13 @@ from django.test import TestCase from freezegun import freeze_time -from home.models import Session +from home.factories import SessionFactory class SessionTests(TestCase): @classmethod def setUpTestData(cls): - cls.session = Session.objects.create( - start_date=datetime(2024, 1, 15).date(), - end_date=datetime(2024, 3, 11).date(), - title="2024 Session 1", - slug="2024-session-1", - invitation_date=datetime(2023, 12, 1).date(), + cls.session = SessionFactory.create( application_start_date=datetime(2023, 10, 16).date(), application_end_date=datetime(2023, 11, 15).date(), ) diff --git a/home/tests/test_session_views.py b/home/tests/test_session_views.py index 53bd05f7..ccbab1e6 100644 --- a/home/tests/test_session_views.py +++ b/home/tests/test_session_views.py @@ -4,7 +4,7 @@ from django.urls import reverse from freezegun import freeze_time -from home.models import Session +from home.factories import SessionFactory @freeze_time("2023-11-16") @@ -16,25 +16,14 @@ def setUp(self): @classmethod def setUpTestData(cls): super().setUpTestData() - cls.session_application_open = Session.objects.create( - start_date=datetime(2024, 1, 15).date(), - end_date=datetime(2024, 3, 11).date(), - title="2024 Session 1", - slug="2024-session-1", - invitation_date=datetime(2023, 12, 1).date(), + cls.session_application_open = SessionFactory.create( application_start_date=datetime(2023, 10, 16).date(), application_end_date=datetime(2023, 11, 15).date(), - application_url="https://apply.session1.com", ) - cls.session_application_closed = Session.objects.create( - start_date=datetime(2023, 7, 1).date(), - end_date=datetime(2024, 10, 1).date(), - title="2023 Pilot", - slug="2023-pilot", + cls.session_application_closed = SessionFactory.create( invitation_date=datetime(2023, 6, 30).date(), application_start_date=datetime(2023, 6, 1).date(), application_end_date=datetime(2023, 6, 20).date(), - application_url="https://apply.pilot.com", ) def test_session_list(self): diff --git a/requirements/requirements-test.in b/requirements/requirements-test.in index a19363c2..79bfe4f4 100644 --- a/requirements/requirements-test.in +++ b/requirements/requirements-test.in @@ -5,3 +5,4 @@ pytest pytest-django pytest-mock pytest-playwright +factory_boy diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index 8273c896..23b09f47 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -137,6 +137,10 @@ exceptiongroup==1.2.0 # -r requirements/requirements.txt # anyio # pytest +factory-boy==3.3.0 + # via -r requirements/requirements-test.in +faker==23.2.1 + # via factory-boy filetype==1.2.0 # via # -r requirements/requirements.txt @@ -217,7 +221,9 @@ pytest-mock==3.12.0 pytest-playwright==0.4.3 # via -r requirements/requirements-test.in python-dateutil==2.8.2 - # via freezegun + # via + # faker + # freezegun python-dotenv==0.21.1 # via -r requirements/requirements.txt python-slugify==8.0.1 From 8ceb4a69c25e1b3833c093e50f9e53bb17abdc41 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Sun, 18 Feb 2024 12:09:59 +0100 Subject: [PATCH 28/29] Add sign up for email notifications as an option in the session list. (#290) --- home/templates/home/prerelease/session_list.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/home/templates/home/prerelease/session_list.html b/home/templates/home/prerelease/session_list.html index df5b624f..4440a0db 100644 --- a/home/templates/home/prerelease/session_list.html +++ b/home/templates/home/prerelease/session_list.html @@ -17,8 +17,8 @@

    Sessions

    These sessions are limited to those who are accepted from an application process. If a session is accepting applications, you'll see an Apply - button. If not, you can express interest in joining - here. + button. You can also sign up and opt-in + to receiving email notifications for future sessions.

    From 5fa8db35a7a33acd5c5e6349c03f52b827c461ad Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Sun, 18 Feb 2024 15:47:36 +0100 Subject: [PATCH 29/29] Render non-field errors and other small tweaks. (#292) --- indymeet/settings/production.py | 5 +---- indymeet/templates/emails/base.html | 3 ++- indymeet/templates/emails/email_confirmation.html | 2 +- indymeet/templates/includes/no_field_errors.html | 5 +++++ indymeet/templates/registration/login.html | 8 +------- .../templates/registration/password_reset_confirm.html | 8 +------- indymeet/templates/registration/password_reset_form.html | 8 +------- indymeet/templates/registration/signup.html | 8 +------- 8 files changed, 13 insertions(+), 34 deletions(-) create mode 100644 indymeet/templates/includes/no_field_errors.html diff --git a/indymeet/settings/production.py b/indymeet/settings/production.py index 7600d5b8..336974f4 100644 --- a/indymeet/settings/production.py +++ b/indymeet/settings/production.py @@ -55,10 +55,7 @@ STATIC_URL = f"https://{AZURE_CUSTOM_DOMAIN}/{AZURE_STATIC_CONTAINER}/" MEDIA_URL = f"https://{AZURE_CUSTOM_DOMAIN}/{AZURE_MEDIA_CONTAINER}/" - SENTRY_DNS = os.environ.get( - "SENTRY_DNS", - "https://302dde9a33fabc5af106ccf19ae23680@o4506747118157824.ingest.sentry.io/4506747129626624" # Staging - ) + SENTRY_DNS = os.environ.get("SENTRY_DNS") sentry_sdk.init( dsn=SENTRY_DNS, # Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring. diff --git a/indymeet/templates/emails/base.html b/indymeet/templates/emails/base.html index 31d817d7..2217ea0d 100644 --- a/indymeet/templates/emails/base.html +++ b/indymeet/templates/emails/base.html @@ -1,9 +1,10 @@ + - Simple Transactional Email + Djangonaut Space