diff --git a/config/settings/base.py b/config/settings/base.py
index bd566f808..8ee1fbdc0 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -3,6 +3,8 @@
from dotenv import load_dotenv
from machina import MACHINA_MAIN_STATIC_DIR, MACHINA_MAIN_TEMPLATE_DIR
+from lacommunaute.utils.enums import Environment
+
load_dotenv()
@@ -17,6 +19,8 @@
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY")
DEBUG = os.getenv("DJANGO_DEBUG", "False") == "True"
+ENVIRONMENT = Environment.PROD
+
PARKING_PAGE = os.getenv("PARKING_PAGE", "False") == "True"
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "communaute.inclusion.beta.gouv.fr,").split(",")
diff --git a/config/settings/dev.py b/config/settings/dev.py
index 1583fb20f..94f751e31 100644
--- a/config/settings/dev.py
+++ b/config/settings/dev.py
@@ -1,6 +1,8 @@
# Enable django-debug-toolbar with Docker.
import socket
+from lacommunaute.utils.enums import Environment
+
from .base import * # pylint: disable=wildcard-import,unused-wildcard-import # noqa: F403 F401
@@ -10,6 +12,7 @@
DEBUG = True
+ENVIRONMENT = Environment.DEV
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "192.168.0.1"]
diff --git a/config/urls.py b/config/urls.py
index ecc1afb97..a2dfc6e38 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -49,9 +49,6 @@
path("tracking/", include(tracking_urlpatterns_factory.urlpatterns)),
]
-if settings.DEBUG is True:
- urlpatterns += [path("", include("django.contrib.auth.urls"))]
-
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += [
diff --git a/lacommunaute/templates/layouts/base.html b/lacommunaute/templates/layouts/base.html
index 716e115ff..7503c77d5 100644
--- a/lacommunaute/templates/layouts/base.html
+++ b/lacommunaute/templates/layouts/base.html
@@ -69,6 +69,7 @@
{% include "partials/header.html" %}
{% endblock %}
{% block sub_header %}{% endblock %}
+ {% if ENVIRONMENT != "PROD" %}
DEV MODE
{% endif %}
{% block messages %}
{% if messages %}
diff --git a/lacommunaute/users/tests/__snapshots__/tests_views.ambr b/lacommunaute/users/tests/__snapshots__/tests_views.ambr
index 385e7a69d..23905b0dc 100644
--- a/lacommunaute/users/tests/__snapshots__/tests_views.ambr
+++ b/lacommunaute/users/tests/__snapshots__/tests_views.ambr
@@ -527,6 +527,9 @@
'''
# ---
-# name: TestSendMagicLink.test_send_magic_link[send_magic_link_payload]
- '{"sender": {"name": "La Communaut\\u00e9", "email": "noreply@inclusion.beta.gouv.fr"}, "to": [{"email": "edith@martin.co"}], "params": {"display_name": "Edith M.", "login_link": "LOGIN_LINK"}, "templateId": 31}'
+# name: TestSendMagicLink.test_send_magic_link[DEV-1][send_magic_link_payload]
+ '{"sender": {"name": "La Communaut\\u00e9", "email": "noreply@inclusion.beta.gouv.fr"}, "to": [{"email": "samuel@jackson.com"}], "params": {"display_name": "Samuel J.", "login_link": "LOGIN_LINK"}, "templateId": 31}'
+# ---
+# name: TestSendMagicLink.test_send_magic_link[PROD-0][send_magic_link_payload]
+ '{"sender": {"name": "La Communaut\\u00e9", "email": "noreply@inclusion.beta.gouv.fr"}, "to": [{"email": "samuel@jackson.com"}], "params": {"display_name": "Samuel J.", "login_link": "LOGIN_LINK"}, "templateId": 31}'
# ---
diff --git a/lacommunaute/users/tests/tests_views.py b/lacommunaute/users/tests/tests_views.py
index da118e772..eadf32948 100644
--- a/lacommunaute/users/tests/tests_views.py
+++ b/lacommunaute/users/tests/tests_views.py
@@ -7,6 +7,10 @@
import respx
from django.conf import settings
from django.contrib.auth.tokens import default_token_generator
+from django.contrib.messages.api import get_messages
+from django.contrib.messages.middleware import MessageMiddleware
+from django.contrib.sessions.middleware import SessionMiddleware
+from django.test import RequestFactory, override_settings
from django.urls import reverse
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
@@ -17,6 +21,7 @@
from lacommunaute.users.factories import UserFactory
from lacommunaute.users.models import User
from lacommunaute.users.views import send_magic_link
+from lacommunaute.utils.enums import Environment
from lacommunaute.utils.testing import parse_response_to_soup
from lacommunaute.utils.urls import clean_next_url
@@ -79,21 +84,31 @@ def validate_magiclink_payload(payload_as_str, uidb64, token, expected):
class TestSendMagicLink:
- def test_send_magic_link(self, db, snapshot, mock_respx_post_to_sib_smtp_url):
- user = UserFactory(first_name="Edith", last_name="Martin", email="edith@martin.co")
- next_url = "/topics/"
- send_magic_link(user, next_url)
-
- token = default_token_generator.make_token(user)
- uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
- url = reverse("users:login_with_link", kwargs={"uidb64": uidb64, "token": token})
- query_params = urlencode({"next": clean_next_url(next_url)})
- login_link = f"{settings.COMMU_PROTOCOL}://{settings.COMMU_FQDN}{url}?{query_params}"
-
- payload_as_str = respx.calls[0].request.content.decode()
- payload = json.loads(payload_as_str)
- assert payload["params"]["login_link"] == login_link
- assert payload_as_str.replace(login_link, "LOGIN_LINK") == snapshot(name="send_magic_link_payload")
+ @pytest.mark.parametrize("env,count_msg", [(Environment.PROD, 0), (Environment.DEV, 1)])
+ def test_send_magic_link(self, db, user, snapshot, mock_respx_post_to_sib_smtp_url, env, count_msg):
+ with override_settings(ENVIRONMENT=env):
+ next_url = "/topics/"
+ request = RequestFactory().get("/")
+ SessionMiddleware(lambda request: None).process_request(request)
+ MessageMiddleware(lambda request: None).process_request(request)
+ send_magic_link(request, user, next_url)
+
+ token = default_token_generator.make_token(user)
+ uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
+ url = reverse("users:login_with_link", kwargs={"uidb64": uidb64, "token": token})
+ query_params = urlencode({"next": clean_next_url(next_url)})
+ login_link = f"{settings.COMMU_PROTOCOL}://{settings.COMMU_FQDN}{url}?{query_params}"
+
+ payload_as_str = respx.calls[0].request.content.decode()
+ payload = json.loads(payload_as_str)
+ assert payload["params"]["login_link"] == login_link
+ assert payload_as_str.replace(login_link, "LOGIN_LINK") == snapshot(name="send_magic_link_payload")
+
+ # we want messages do not appear in the productive environment
+ msgs = get_messages(request)
+ assert len(msgs._queued_messages) == count_msg
+ if msgs._queued_messages:
+ assert str(msgs._queued_messages[0]) == f'{login_link} sent to {user.email}'
class TestLoginView:
@@ -105,6 +120,7 @@ def test_content(self, client, db, next_url, snapshot):
content = parse_response_to_soup(response, selector="main")
assert str(content) == snapshot(name="login_view_content")
+ @override_settings(ENVIRONMENT=Environment.PROD)
@pytest.mark.parametrize("next_url,expected", next_url_tuples)
def test_post(
self,
@@ -152,6 +168,7 @@ def test_user_is_already_authenticated(self, client, db, next_url, expected):
class TestCreateUserView:
+ @override_settings(ENVIRONMENT=Environment.PROD)
@pytest.mark.parametrize("next_url,expected", next_url_tuples)
def test_post_new_email(
self, client, db, next_url, expected, snapshot, mock_token_generator, mock_respx_post_to_sib_smtp_url
@@ -178,6 +195,7 @@ def test_post_new_email(
payload_as_str = respx.calls[0].request.content.decode()
assert validate_magiclink_payload(payload_as_str, uidb64, token, expected)
+ @override_settings(ENVIRONMENT=Environment.PROD)
@pytest.mark.parametrize("next_url,expected", next_url_tuples)
def test_post_existing_email(
self, client, db, user, next_url, expected, snapshot, mock_token_generator, mock_respx_post_to_sib_smtp_url
diff --git a/lacommunaute/users/views.py b/lacommunaute/users/views.py
index 5f0151e1f..a8af72a7c 100644
--- a/lacommunaute/users/views.py
+++ b/lacommunaute/users/views.py
@@ -2,12 +2,14 @@
from urllib.parse import urlencode
from django.conf import settings
+from django.contrib import messages
from django.contrib.auth import login, logout
from django.contrib.auth.tokens import default_token_generator
from django.http import HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils.encoding import force_bytes, force_str
+from django.utils.html import format_html
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.views.generic import FormView
@@ -24,7 +26,7 @@
logger = logging.getLogger(__name__)
-def send_magic_link(user, next_url):
+def send_magic_link(request, user, next_url):
token = default_token_generator.make_token(user)
uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
url = reverse("users:login_with_link", kwargs={"uidb64": uidb64, "token": token})
@@ -38,6 +40,10 @@ def send_magic_link(user, next_url):
template_id=settings.SIB_MAGIC_LINK_TEMPLATE,
)
+ if settings.ENVIRONMENT == "DEV":
+ message = format_html('{0} sent to {1}', login_link, user.email)
+ messages.success(request, message)
+
class LoginView(FormView):
template_name = "registration/login_with_magic_link.html"
@@ -62,7 +68,7 @@ def form_valid(self, form):
query_params = {"email": email, "next": clean_next_url(next_url)}
return HttpResponseRedirect(f"{base_url}?{urlencode(query_params)}")
- send_magic_link(user, next_url)
+ send_magic_link(self.request, user, next_url)
return render(self.request, "registration/login_link_sent.html", {"email": email})
@@ -91,7 +97,7 @@ def form_valid(self, form):
)
ForumProfile.objects.create(user=user)
- send_magic_link(user, next_url)
+ send_magic_link(self.request, user, next_url)
return render(self.request, "registration/login_link_sent.html", {"email": email})
diff --git a/lacommunaute/utils/enums.py b/lacommunaute/utils/enums.py
index a3f452bb8..8fc3a6dea 100644
--- a/lacommunaute/utils/enums.py
+++ b/lacommunaute/utils/enums.py
@@ -4,3 +4,8 @@
class PeriodAggregation(models.TextChoices):
MONTH = "MONTH"
WEEK = "WEEK"
+
+
+class Environment(models.TextChoices):
+ DEV = "DEV"
+ PROD = "PROD"
diff --git a/lacommunaute/utils/settings_context_processors.py b/lacommunaute/utils/settings_context_processors.py
index 9469a4a09..7427c13d4 100644
--- a/lacommunaute/utils/settings_context_processors.py
+++ b/lacommunaute/utils/settings_context_processors.py
@@ -12,4 +12,5 @@ def expose_settings(request):
"BASE_TEMPLATE": base_template,
"MATOMO_SITE_ID": settings.MATOMO_SITE_ID,
"MATOMO_BASE_URL": settings.MATOMO_BASE_URL,
+ "ENVIRONMENT": settings.ENVIRONMENT,
}
diff --git a/lacommunaute/utils/tests/tests_middleware.py b/lacommunaute/utils/tests/tests_middleware.py
index 40573b400..5313ce39a 100644
--- a/lacommunaute/utils/tests/tests_middleware.py
+++ b/lacommunaute/utils/tests/tests_middleware.py
@@ -1,5 +1,8 @@
+import pytest
from django.test import TestCase, override_settings
+from lacommunaute.utils.enums import Environment
+
class ParkingMiddlewareTest(TestCase):
@override_settings(PARKING_PAGE=True)
@@ -13,3 +16,17 @@ def test_no_parking_page_middleware(self):
response = self.client.get("/")
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "pages/home.html")
+
+
+class TestEnvironmentSettingsMiddleware:
+ @pytest.mark.parametrize(
+ "env,expected",
+ [
+ (Environment.PROD, False),
+ (Environment.DEV, True),
+ ],
+ )
+ def test_prod_environment(self, client, db, env, expected):
+ with override_settings(ENVIRONMENT=env):
+ response = client.get("/")
+ assert ('id="debug-mode-banner"' in response.content.decode()) == expected
diff --git a/lacommunaute/utils/tests/tests_urls.py b/lacommunaute/utils/tests/tests_urls.py
index 51e7af78f..b58c984d7 100644
--- a/lacommunaute/utils/tests/tests_urls.py
+++ b/lacommunaute/utils/tests/tests_urls.py
@@ -13,15 +13,8 @@ def _clear_url_caches():
sys.modules.pop("config.urls", None)
-def test_django_urls_dev(settings):
- settings.DEBUG = True
- assert reverse("login") == "/login/"
-
-
def test_django_urls_prod(settings):
settings.DEBUG = False
- with pytest.raises(NoReverseMatch):
- reverse("login")
with pytest.raises(NoReverseMatch):
reverse("djdt:render_panel")