Просмотр исходного кода

misago.users decorators revamp

deny_ decorators always raise exceptions
new deflect_ decorators redirect to forum index
Rafał Pitoń 10 лет назад
Родитель
Сommit
7f1b83ca5c

+ 34 - 2
docs/developers/decorators.rst

@@ -46,7 +46,7 @@ deny_authenticated
 
 :py:func:`misago.users.decorators.deny_authenticated`
 
-This decorator will block requests made to view if user is authenticated, displaying page with friendly error message in its stead.
+This decorator will block requests made to view if user is authenticated, displaying page with error message or returning JSON/XML in its stead.
 
 
 deny_guests
@@ -54,4 +54,36 @@ deny_guests
 
 :py:func:`misago.users.decorators.deny_guests`
 
-This decorator will block requests made to view if user is not authenticated, displaying page with friendly error message in its stead.
+This decorator will block requests made to view if user is not authenticated, displaying page with error message or returning JSON/XML in its stead.
+
+
+deny_banned_ips
+---------------
+
+:py:func:`misago.users.decorators.deny_banned_ips`
+
+This decorator will block requests made to view if user IP is banned, displaying page with error message or returning JSON/XML in its stead.
+
+
+deflect_authenticated
+---------------------
+
+:py:func:`misago.users.decorators.deflect_authenticated`
+
+This decorator will return redirect to forum index if user is authenticated.
+
+
+deflect_guests
+--------------
+
+:py:func:`misago.users.decorators.deflect_guests`
+
+This decorator will return redirect to forum index if user is not authenticated.
+
+
+deflect_banned_ips
+------------------
+
+:py:func:`misago.users.decorators.deflect_banned_ips`
+
+This decorator will return redirect to forum index if user IP is banned.

+ 5 - 4
misago/core/exceptionhandler.py

@@ -35,10 +35,7 @@ def handle_explicit_first_page_exception(request, exception):
 
 
 def handle_http404_exception(request, exception):
-    if request.is_ajax():
-        return JsonResponse({'detail': 'Not found'}, status=404)
-    else:
-        return errorpages.page_not_found(request)
+    return errorpages.page_not_found(request)
 
 
 def handle_outdated_slug_exception(request, exception):
@@ -92,6 +89,10 @@ def handle_api_exception(exception):
         if isinstance(exception, PermissionDenied):
             try:
                 response.data['detail'] = exception.args[0]
+                try:
+                    response.data.update(exception.args[1])
+                except IndexError:
+                    pass
             except IndexError:
                 pass
         return response

+ 35 - 14
misago/users/decorators.py

@@ -8,11 +8,8 @@ from misago.users.bans import get_request_ip_ban
 def deny_authenticated(f):
     def decorator(request, *args, **kwargs):
         if request.user.is_authenticated():
-            if request.is_ajax():
-                raise PermissionDenied(
-                    _("This action is not available to signed in users."))
-            else:
-                return redirect('misago:index')
+            raise PermissionDenied(
+                _("This action is not available to signed in users."))
         else:
             return f(request, *args, **kwargs)
     return decorator
@@ -21,11 +18,8 @@ def deny_authenticated(f):
 def deny_guests(f):
     def decorator(request, *args, **kwargs):
         if request.user.is_anonymous():
-            if request.is_ajax():
-                raise PermissionDenied(
-                    _("This action is not available to guests."))
-            else:
-                return redirect('misago:index')
+            raise PermissionDenied(
+                _("This action is not available to guests."))
         else:
             return f(request, *args, **kwargs)
     return decorator
@@ -35,10 +29,37 @@ def deny_banned_ips(f):
     def decorator(request, *args, **kwargs):
         ban = get_request_ip_ban(request)
         if ban:
-            if request.is_ajax():
-                raise PermissionDenied(ban.get_serialized_message())
-            else:
-                return redirect('misago:index')
+            raise PermissionDenied(
+                _("Your IP address is banned from performing this action."),
+                {'ban': ban.get_serialized_message()})
+        else:
+            return f(request, *args, **kwargs)
+    return decorator
+
+
+def deflect_authenticated(f):
+    def decorator(request, *args, **kwargs):
+        if request.user.is_authenticated():
+            return redirect('misago:index')
+        else:
+            return f(request, *args, **kwargs)
+    return decorator
+
+
+def deflect_guests(f):
+    def decorator(request, *args, **kwargs):
+        if request.user.is_anonymous():
+            return redirect('misago:index')
+        else:
+            return f(request, *args, **kwargs)
+    return decorator
+
+
+def deflect_banned_ips(f):
+    def decorator(request, *args, **kwargs):
+        ban = get_request_ip_ban(request)
+        if ban:
+            return redirect('misago:index')
         else:
             return f(request, *args, **kwargs)
     return decorator

+ 7 - 2
misago/users/serializers/ban.py

@@ -4,7 +4,7 @@ from rest_framework import serializers
 
 from misago.core.utils import format_plaintext_for_html
 
-from misago.users.models import Ban, BAN_USERNAME, BAN_EMAIL, BAN_IP
+from misago.users.models import Ban, BAN_IP
 
 
 class BanMessageSerializer(serializers.ModelSerializer):
@@ -15,7 +15,12 @@ class BanMessageSerializer(serializers.ModelSerializer):
         fields = ('message', 'expires_on')
 
     def get_message(self, obj):
-        message = obj.user_message or _("You are banned.")
+        if obj.user_message:
+            message = obj.user_message
+        elif obj.check_type == BAN_IP:
+            message = _("Your IP address is banned.")
+        else:
+            message = _("You are banned.")
 
         return {
             'plain': message,

+ 18 - 16
misago/users/tests/test_decorators.py

@@ -3,30 +3,36 @@ from misago.users.testutils import UserTestCase
 
 
 class DenyAuthenticatedTests(UserTestCase):
-    ajax_header = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
-
     def test_success(self):
         """deny_authenticated decorator allowed guest request"""
+        response = self.client.post(reverse('misago:api:login'))
+        self.assertEqual(response.status_code, 400)
+
+    def test_fail(self):
+        """deny_authenticated decorator denied authenticated request"""
+        self.login_user(self.get_authenticated_user())
+
+        response = self.client.post(reverse('misago:api:login'))
+        self.assertEqual(response.status_code, 403)
+
+
+class DeflectAuthenticatedTests(UserTestCase):
+    def test_success(self):
+        """deflect_authenticated decorator allowed guest request"""
         response = self.client.get(reverse('misago:request_password_reset'))
         self.assertEqual(response.status_code, 200)
 
     def test_fail(self):
-        """deny_authenticated decorator blocked authenticated request"""
+        """deflect_authenticated decorator deflected authenticated request"""
         self.login_user(self.get_authenticated_user())
 
         response = self.client.get(reverse('misago:request_password_reset'))
         self.assertEqual(response.status_code, 302)
 
-        response = self.client.get(reverse('misago:request_password_reset'),
-                                           **self.ajax_header)
-        self.assertEqual(response.status_code, 403)
-
-
-class DenyGuestsTests(UserTestCase):
-    ajax_header = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
 
+class DeflectGuestsTests(UserTestCase):
     def test_success(self):
-        """deny_guests decorator allowed authenticated request"""
+        """deflect_guests decorator allowed authenticated request"""
         self.login_user(self.get_authenticated_user())
 
         response = self.client.post(
@@ -34,11 +40,7 @@ class DenyGuestsTests(UserTestCase):
         self.assertEqual(response.status_code, 200)
 
     def test_fail(self):
-        """deny_guests decorator blocked authenticated request"""
+        """deflect_guests decorator deflected authenticated request"""
         response = self.client.post(
             reverse('misago:usercp_change_forum_options'))
         self.assertEqual(response.status_code, 302)
-
-        response = self.client.get(
-            reverse('misago:usercp_change_forum_options'), **self.ajax_header)
-        self.assertEqual(response.status_code, 403)

+ 3 - 3
misago/users/views/forgottenpassword.py

@@ -10,15 +10,15 @@ from misago.core.mail import mail_user
 from misago.core.views import noscript
 
 from misago.users.bans import get_user_ban
-from misago.users.decorators import deny_authenticated, deny_banned_ips
+from misago.users.decorators import deflect_authenticated, deflect_banned_ips
 from misago.users.forms.auth import ResetPasswordForm, SetNewPasswordForm
 from misago.users.tokens import (make_password_reset_token,
                                  is_password_reset_token_valid)
 
 
 def reset_view(f):
-    @deny_authenticated
-    @deny_banned_ips
+    @deflect_authenticated
+    @deflect_banned_ips
     def decorator(*args, **kwargs):
         return f(*args, **kwargs)
     return decorator

+ 11 - 11
misago/users/views/usercp.py

@@ -17,7 +17,7 @@ from misago.markup import Editor
 from misago.notifications import read_user_notifications
 
 from misago.users import avatars
-from misago.users.decorators import deny_guests
+from misago.users.decorators import deflect_guests
 from misago.users.forms.rename import ChangeUsernameForm
 from misago.users.forms.usercp import (ChangeForumOptionsForm,
                                        EditSignatureForm,
@@ -41,7 +41,7 @@ def render(request, template, context=None):
     return django_render(request, template, context)
 
 
-@deny_guests
+@deflect_guests
 def change_forum_options(request):
     return noscript(request, **{
         'title': _("Change options"),
@@ -62,7 +62,7 @@ def change_forum_options(request):
                   {'form': form})
 
 
-@deny_guests
+@deflect_guests
 def change_avatar(request):
     avatar_size = max(settings.MISAGO_AVATARS_SIZES)
 
@@ -106,7 +106,7 @@ def avatar_not_locked(f):
     return decorator
 
 
-@deny_guests
+@deflect_guests
 @avatar_not_locked
 def upload_avatar(request):
     if not settings.allow_custom_avatars:
@@ -122,7 +122,7 @@ def upload_avatar(request):
 
 
 @ajax_only
-@deny_guests
+@deflect_guests
 @require_POST
 @avatar_not_locked
 def upload_avatar_handler(request):
@@ -141,7 +141,7 @@ def upload_avatar_handler(request):
     return JsonResponse({'is_error': 0, 'message': 'Image has been uploaded.'})
 
 
-@deny_guests
+@deflect_guests
 @avatar_not_locked
 def crop_avatar(request, use_tmp_avatar):
     if use_tmp_avatar:
@@ -200,7 +200,7 @@ def crop_avatar(request, use_tmp_avatar):
     })
 
 
-@deny_guests
+@deflect_guests
 @avatar_not_locked
 def avatar_galleries(request):
     if not avatars.gallery.galleries_exist():
@@ -222,7 +222,7 @@ def avatar_galleries(request):
     })
 
 
-@deny_guests
+@deflect_guests
 def edit_signature(request):
     if not request.user.acl['can_have_signature']:
         raise Http404()
@@ -257,7 +257,7 @@ def edit_signature(request):
                   {'form': form, 'editor': editor})
 
 
-@deny_guests
+@deflect_guests
 @transaction.atomic()
 def change_username(request):
     namechanges = UsernameChanges(request.user)
@@ -285,7 +285,7 @@ def change_username(request):
 
 
 @sensitive_post_parameters()
-@deny_guests
+@deflect_guests
 def change_email_password(request):
     form = ChangeEmailPasswordForm()
     if request.method == 'POST':
@@ -335,7 +335,7 @@ def change_email_password(request):
                   {'form': form})
 
 
-@deny_guests
+@deflect_guests
 def confirm_email_password_change(request, token):
     new_credentials = get_new_credentials(request.user, token)
     if not new_credentials: