diff --git a/styles.css b/styles.css index 6254924..aa3f332 100755 --- a/styles.css +++ b/styles.css @@ -6,6 +6,8 @@ /* prose (changelog, release notes) is not markup: words in it must not add utilities */ @source not "./docs"; @source not "./*.md"; +/* its own output: a removed utility would otherwise keep its theme variable alive, so rebuilds drift */ +@source not "./whiteneuron/static/base/css/styles.css"; /* All daisyUI themes + unfold color mapping (generated by scripts/gen-themes.mjs) */ @import "./daisy-themes.css"; diff --git a/whiteneuron/base/middleware.py b/whiteneuron/base/middleware.py index f975c2a..7061f74 100755 --- a/whiteneuron/base/middleware.py +++ b/whiteneuron/base/middleware.py @@ -8,7 +8,7 @@ import json import re from django.core.cache import cache -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template.loader import render_to_string class RateLimitMiddleware: @@ -316,7 +316,6 @@ def get_client_ip(request): from django.db import IntegrityError, connection -from django.utils.http import url_has_allowed_host_and_scheme from django.utils import timezone from .models import UserActivity, AnonymousActivity, VisitProfile class UserActivityMiddleware: @@ -603,8 +602,9 @@ def _sanitize_post(self, data) -> dict: from .thread_local import thread_local -from django.contrib.auth import login -from .models import User +from .utils import get_guest_user, log_in_guest, safe_next_url +import logging +logger = logging.getLogger(__name__) class ThreadLocalMiddleware: def __init__(self, get_response): @@ -640,20 +640,16 @@ def __call__(self, request): ): try: # Kiểm tra xem guest user có tồn tại, đang active và có quyền staff không - guest_user = User.objects.filter(username='guest', is_active=True, is_staff=True).first() + guest_user = get_guest_user() if guest_user: # Tự động đăng nhập guest user - login(request, guest_user, backend='django.contrib.auth.backends.ModelBackend') - # Nếu có tham số next thì redirect luôn tới đó - next_url = request.GET.get('next') - if next_url and url_has_allowed_host_and_scheme( - next_url, allowed_hosts={request.get_host()}, require_https=request.is_secure() - ): - return redirect(next_url) - else: - pass - except Exception as e: - pass + log_in_guest(request, guest_user) + # Nếu có tham số next thì redirect luôn tới đó (URL, không phải tên route) + next_url = safe_next_url(request, request.GET.get('next')) + if next_url: + return HttpResponseRedirect(next_url) + except Exception: + logger.exception("Auto guest login failed") response = self.get_response(request) return response diff --git a/whiteneuron/base/templatetags/wn_guest.py b/whiteneuron/base/templatetags/wn_guest.py new file mode 100644 index 0000000..968d6a5 --- /dev/null +++ b/whiteneuron/base/templatetags/wn_guest.py @@ -0,0 +1,11 @@ +from django import template + +from ..utils import get_guest_user + +register = template.Library() + + +@register.simple_tag +def guest_login_available(): + """Whether "Log in as guest" can work: GuestLoginView needs an active staff ``guest`` account.""" + return get_guest_user() is not None diff --git a/whiteneuron/base/tests_regressions.py b/whiteneuron/base/tests_regressions.py index c142582..96f0009 100644 --- a/whiteneuron/base/tests_regressions.py +++ b/whiteneuron/base/tests_regressions.py @@ -461,3 +461,254 @@ def test_missing_template_returns_empty_content(self): def test_unset_setting_returns_empty_content(self): response = self._get() # used to return None (500) self.assertEqual((response.status_code, response.content), (200, b"")) + + +@package_test_settings() +class GuestLoginButtonTests(TestCase): + FORM = 'id="guest-login-form"' + + def setUp(self): + self.ACTION = f'action="{reverse("guest_login")}"' + # AutoGuestLoginMiddleware (if enabled) would log the guest in instead of showing the form + self.client.cookies["skip_auto_guest"] = "1" + + def _login_page(self, **params): + page = self.client.get(reverse("admin:login"), params) + self.assertEqual(page.status_code, 200) + return page + + def _guest_form(self, page): + html = page.content.decode() + start = html.index(self.FORM) + return html[start:html.index("", start)] + + def test_shown_as_styled_button_with_guest_user(self): + User.objects.create(username="guest", is_staff=True) + form = self._guest_form(self._login_page(next="/admin/")) + self.assertIn('name="next" value="/admin/"', form) + # the raw - - \ No newline at end of file +{% guest_login_available as show_guest_login %} +{% if show_guest_login %} +
+ {% csrf_token %} + {% if next %}{% endif %} + {% component "unfold/components/button.html" with submit=1 variant="secondary" class="w-full" %} + {% translate "Log in as guest" %} + {% endcomponent %} +
+{% endif %}