From d76b3f99b3f370f817a33019332cc410e8890044 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Mon, 20 Jan 2025 14:19:36 +0300 Subject: [PATCH 01/12] Feature: Added account disabled page Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 19 +++++++++++++++++++ pontoon/base/templates/account_disabled.html | 6 ++++++ pontoon/base/tests/test_middleware.py | 18 ++++++++++++++++++ pontoon/settings/base.py | 11 +++++++++-- pontoon/urls.py | 2 ++ 5 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 pontoon/base/templates/account_disabled.html diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index e731ebfc4..a17ae5fcb 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -149,3 +149,22 @@ def __call__(self, request): cache.set(observed_key, (1, now), self.observation_period) return response + + +class AccountDisabledMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + user = request.user + if user.is_authenticated and not user.is_active: + response = render( + request, + "account_disabled.html", + {"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL}, + status=403, + ) + return response + + response = self.get_response(request) + return response diff --git a/pontoon/base/templates/account_disabled.html b/pontoon/base/templates/account_disabled.html new file mode 100644 index 000000000..ed5f47d68 --- /dev/null +++ b/pontoon/base/templates/account_disabled.html @@ -0,0 +1,6 @@ +{% extends "404.html" %} + +{% block title %}Account Disabled{% endblock %} +{% block description %} +Your account has been disabled. If you believe this is a mistake or need further assistance, please contact us at {{ DEFAULT_FROM_EMAIL }}. +{% endblock %} \ No newline at end of file diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index c40768484..2595fc8c6 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -67,3 +67,21 @@ def test_throttle(client, settings): # Make another request after block duration response = client.get(url, REMOTE_ADDR=ip_address) assert response.status_code == 200 + + +@pytest.mark.django_db +def test_AccountDisabledMiddleware(client, member, settings): + # Ensure the user is authenticated but not active + member.user.is_active = False + member.user.save() + + response = member.client.get("/") + assert response.status_code == 403 + assert "account_disabled.html" in [t.name for t in response.templates] + + # Ensure the user is authenticated and active + member.user.is_active = True + member.user.save() + + response = member.client.get("/") + assert response.status_code == 200 diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index 9779ca16c..0336bd9c5 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -329,6 +329,7 @@ def _default_from_email(): "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "pontoon.base.middleware.AccountDisabledMiddleware", "pontoon.base.middleware.ThrottleIpMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.messages.middleware.MessageMiddleware", @@ -753,7 +754,10 @@ def _default_from_email(): # cache. if os.environ.get("MEMCACHE_SERVERS") is not None: CACHES = { - "default": {"BACKEND": "django_bmemcached.memcached.BMemcached", "OPTIONS": {}} + "default": { + "BACKEND": "django_bmemcached.memcached.BMemcached", + "OPTIONS": {}, + } } else: CACHES = { @@ -1168,7 +1172,10 @@ def account_username(user): ) # Used for Community Builder badge BADGES_PROMOTION_THRESHOLDS = list( - map(int, os.environ.get("BADGES_PROMOTION_THRESHOLDS", "1, 2, 5").split(",")) + map( + int, + os.environ.get("BADGES_PROMOTION_THRESHOLDS", "1, 2, 5").split(","), + ) ) DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/pontoon/urls.py b/pontoon/urls.py index e848b570e..89cc85a20 100644 --- a/pontoon/urls.py +++ b/pontoon/urls.py @@ -17,6 +17,7 @@ class LocaleConverter(StringConverter): page_not_found_view = TemplateView.as_view(template_name="404.html") too_many_requests_view = TemplateView.as_view(template_name="429.html") server_error_view = TemplateView.as_view(template_name="500.html") +account_disabled_view = TemplateView.as_view(template_name="account_disabled.html") urlpatterns = [ # Accounts @@ -34,6 +35,7 @@ class LocaleConverter(StringConverter): path("404/", page_not_found_view), path("429/", too_many_requests_view), path("500/", server_error_view), + path("account_disabled/", account_disabled_view), # Robots.txt path( "robots.txt", From 3ac7caaf65e3abe0cfa7befab795fef5efc5f91d Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Mon, 20 Jan 2025 14:30:19 +0300 Subject: [PATCH 02/12] Fix: Moved AccountDisabledMiddleware at the bottom in base.py\n\nTry to see if the reason its not being activated arrives from its possition in the middlewares\n Signed-off-by: RafaelJohn9 --- pontoon/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index 0336bd9c5..9b495aecc 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -329,13 +329,13 @@ def _default_from_email(): "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", - "pontoon.base.middleware.AccountDisabledMiddleware", "pontoon.base.middleware.ThrottleIpMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", "pontoon.base.middleware.EmailConsentMiddleware", + "pontoon.base.middleware.AccountDisabledMiddleware", ) CONTEXT_PROCESSORS = ( From 3ef5bd3b1cd4de1e9d794f0b7d1fc2bce6bfc0ec Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Mon, 20 Jan 2025 16:07:08 +0300 Subject: [PATCH 03/12] Fix: Updated test file on accountdisabledmiddleware Signed-off-by: RafaelJohn9 --- pontoon/base/tests/test_middleware.py | 1 + pontoon/settings/base.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index 2595fc8c6..e209893b2 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -72,6 +72,7 @@ def test_throttle(client, settings): @pytest.mark.django_db def test_AccountDisabledMiddleware(client, member, settings): # Ensure the user is authenticated but not active + member.user.is_authenticated = True member.user.is_active = False member.user.save() diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index 9b495aecc..0336bd9c5 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -329,13 +329,13 @@ def _default_from_email(): "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "pontoon.base.middleware.AccountDisabledMiddleware", "pontoon.base.middleware.ThrottleIpMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", "pontoon.base.middleware.EmailConsentMiddleware", - "pontoon.base.middleware.AccountDisabledMiddleware", ) CONTEXT_PROCESSORS = ( From 4feaf25f7b381429be7abfb454d6cd5a97efa8b0 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Tue, 21 Jan 2025 00:18:51 +0300 Subject: [PATCH 04/12] Fix: Account disabled page Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 2 +- pontoon/base/tests/test_middleware.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index a17ae5fcb..0a5419867 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -157,7 +157,7 @@ def __init__(self, get_response): def __call__(self, request): user = request.user - if user.is_authenticated and not user.is_active: + if not user.is_authenticated and not user.is_active: response = render( request, "account_disabled.html", diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index e209893b2..141b15ac4 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -72,7 +72,7 @@ def test_throttle(client, settings): @pytest.mark.django_db def test_AccountDisabledMiddleware(client, member, settings): # Ensure the user is authenticated but not active - member.user.is_authenticated = True + member.user.is_authenticated = False member.user.is_active = False member.user.save() @@ -82,6 +82,7 @@ def test_AccountDisabledMiddleware(client, member, settings): # Ensure the user is authenticated and active member.user.is_active = True + member.user.is_authenticated = True member.user.save() response = member.client.get("/") From 84ce15ce74c7d948accb4cafd9cf948e6728692f Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 21:36:18 +0300 Subject: [PATCH 05/12] Fix: test failing workflow Signed-off-by: RafaelJohn9 --- pontoon/base/tests/test_middleware.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index 141b15ac4..726dbc963 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -71,10 +71,8 @@ def test_throttle(client, settings): @pytest.mark.django_db def test_AccountDisabledMiddleware(client, member, settings): - # Ensure the user is authenticated but not active member.user.is_authenticated = False member.user.is_active = False - member.user.save() response = member.client.get("/") assert response.status_code == 403 From 88316bdd58156b05a3853af0d9b1899b6ae8eeaa Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 21:42:44 +0300 Subject: [PATCH 06/12] Update: temp commented the accountdisabled test Signed-off-by: RafaelJohn9 --- pontoon/base/tests/test_middleware.py | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index 726dbc963..40667d980 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -69,19 +69,19 @@ def test_throttle(client, settings): assert response.status_code == 200 -@pytest.mark.django_db -def test_AccountDisabledMiddleware(client, member, settings): - member.user.is_authenticated = False - member.user.is_active = False - - response = member.client.get("/") - assert response.status_code == 403 - assert "account_disabled.html" in [t.name for t in response.templates] - - # Ensure the user is authenticated and active - member.user.is_active = True - member.user.is_authenticated = True - member.user.save() - - response = member.client.get("/") - assert response.status_code == 200 +# @pytest.mark.django_db +# def test_AccountDisabledMiddleware(client, member, settings): +# member.user.is_authenticated = False +# member.user.is_active = False + +# response = member.client.get("/") +# assert response.status_code == 403 +# assert "account_disabled.html" in [t.name for t in response.templates] + +# # Ensure the user is authenticated and active +# member.user.is_active = True +# member.user.is_authenticated = True +# member.user.save() + +# response = member.client.get("/") +# assert response.status_code == 200 From ac0fcc1923770e2993d6acda095dff919dc54dd4 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 21:52:03 +0300 Subject: [PATCH 07/12] Fix: Only checks if user is active Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index 0a5419867..24a939a7e 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -157,7 +157,7 @@ def __init__(self, get_response): def __call__(self, request): user = request.user - if not user.is_authenticated and not user.is_active: + if not user.is_active: response = render( request, "account_disabled.html", From b1536571461f6992c4a4d863bf7ea14e79545212 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 21:57:56 +0300 Subject: [PATCH 08/12] Update: updated the account disabled middleware Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index 24a939a7e..a17ae5fcb 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -157,7 +157,7 @@ def __init__(self, get_response): def __call__(self, request): user = request.user - if not user.is_active: + if user.is_authenticated and not user.is_active: response = render( request, "account_disabled.html", From bddfb0f309e81bc6caf6589cf32ba44eeb5bc169 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 22:03:08 +0300 Subject: [PATCH 09/12] Update: Fix: Account disabled middleware Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index a17ae5fcb..24a939a7e 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -157,7 +157,7 @@ def __init__(self, get_response): def __call__(self, request): user = request.user - if user.is_authenticated and not user.is_active: + if not user.is_active: response = render( request, "account_disabled.html", From 4ce40e63f3f56a876d06d901dbf80a81c437ec93 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Wed, 22 Jan 2025 22:08:18 +0300 Subject: [PATCH 10/12] Update: Changed position of the middleware Signed-off-by: RafaelJohn9 --- pontoon/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index 0336bd9c5..9b495aecc 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -329,13 +329,13 @@ def _default_from_email(): "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", - "pontoon.base.middleware.AccountDisabledMiddleware", "pontoon.base.middleware.ThrottleIpMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", "pontoon.base.middleware.EmailConsentMiddleware", + "pontoon.base.middleware.AccountDisabledMiddleware", ) CONTEXT_PROCESSORS = ( From 919d0fdc3293c11b57b80777c413801bd94f874b Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Thu, 23 Jan 2025 08:41:42 +0300 Subject: [PATCH 11/12] Fix: account disabled middleware Signed-off-by: RafaelJohn9 --- pontoon/base/middleware.py | 38 ++++++++++++++++++++++++++++++-------- pontoon/settings/base.py | 2 +- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pontoon/base/middleware.py b/pontoon/base/middleware.py index 24a939a7e..e157d3fc0 100644 --- a/pontoon/base/middleware.py +++ b/pontoon/base/middleware.py @@ -6,6 +6,8 @@ from raygun4py.middleware.django import Provider from django.conf import settings +from django.contrib.auth.middleware import get_user +from django.contrib.auth.models import User from django.core.cache import cache from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponseForbidden @@ -156,15 +158,35 @@ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): + # Manually fetch user from the session + request.user = get_user(request) user = request.user - if not user.is_active: - response = render( - request, - "account_disabled.html", - {"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL}, - status=403, - ) - return response + # If user is authenticated, check if they are inactive + if user.is_authenticated: + if not user.is_active: + return render( + request, + "account_disabled.html", + {"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL}, + status=403, + ) + else: + # For non-authenticated users, check the session manually + user_id = request.session.get("_auth_user_id") + if user_id: + try: + user = User.objects.get(pk=user_id) + if not user.is_active: + return render( + request, + "account_disabled.html", + {"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL}, + status=403, + ) + except User.DoesNotExist: + pass # If the user ID is invalid, ignore it + + # Continue processing the request response = self.get_response(request) return response diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index 9b495aecc..b87f71307 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -328,6 +328,7 @@ def _default_from_email(): "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", + "pontoon.base.middleware.AccountDisabledMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "pontoon.base.middleware.ThrottleIpMiddleware", "django.middleware.csrf.CsrfViewMiddleware", @@ -335,7 +336,6 @@ def _default_from_email(): "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", "pontoon.base.middleware.EmailConsentMiddleware", - "pontoon.base.middleware.AccountDisabledMiddleware", ) CONTEXT_PROCESSORS = ( From 08710a279ab2f2c52b7f1a1a1035b6778c5f7f95 Mon Sep 17 00:00:00 2001 From: RafaelJohn9 Date: Thu, 23 Jan 2025 08:52:54 +0300 Subject: [PATCH 12/12] Update: Uncommented the account disabled test Signed-off-by: RafaelJohn9 --- pontoon/base/tests/test_middleware.py | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/pontoon/base/tests/test_middleware.py b/pontoon/base/tests/test_middleware.py index 40667d980..eaa00a02a 100644 --- a/pontoon/base/tests/test_middleware.py +++ b/pontoon/base/tests/test_middleware.py @@ -69,19 +69,18 @@ def test_throttle(client, settings): assert response.status_code == 200 -# @pytest.mark.django_db -# def test_AccountDisabledMiddleware(client, member, settings): -# member.user.is_authenticated = False -# member.user.is_active = False - -# response = member.client.get("/") -# assert response.status_code == 403 -# assert "account_disabled.html" in [t.name for t in response.templates] - -# # Ensure the user is authenticated and active -# member.user.is_active = True -# member.user.is_authenticated = True -# member.user.save() - -# response = member.client.get("/") -# assert response.status_code == 200 +@pytest.mark.django_db +def test_AccountDisabledMiddleware(client, member, settings): + member.user.is_active = False + member.user.save() + + response = member.client.get("/") + assert response.status_code == 403 + assert "account_disabled.html" in [t.name for t in response.templates] + + # Ensure the user is authenticated and active + member.user.is_active = True + member.user.save() + + response = member.client.get("/") + assert response.status_code == 200