Browse Source

Refactored ChangeUsernameForm, WIP banning

Rafał Pitoń 11 years ago
parent
commit
57917e6774

+ 6 - 2
misago/templates/misago/modusers/mod_options.html

@@ -33,18 +33,22 @@
         {% trans "Edit and ban signature" %}
       </a>
     </li>
+    {% if profile.acl_.can_ban_username %}
     <li>
-      <a href="#">
+      <a href="{% url 'misago:ban_user_name' user_slug=profile.slug user_id=profile.pk %}">
         <span class="fa fa-lock"></span>
         {% trans "Ban username" %}
       </a>
     </li>
+    {% endif %}
+    {% if profile.acl_.can_ban_email %}
     <li>
-      <a href="#">
+      <a href="{% url 'misago:ban_user_email' user_slug=profile.slug user_id=profile.pk %}">
         <span class="fa fa-lock"></span>
         {% trans "Ban e-mail address" %}
       </a>
     </li>
+    {% endif %}
     {% if profile.acl_.can_delete %}
     <li class="divider"></li>
     <li>

+ 32 - 0
misago/users/forms/rename.py

@@ -0,0 +1,32 @@
+from django.utils.translation import ugettext_lazy as _
+from misago.core import forms
+from misago.users.validators import validate_username
+
+
+class ChangeUsernameForm(forms.Form):
+    new_username = forms.CharField(label=_("New username"), max_length=200,
+                                   required=False)
+
+    def __init__(self, *args, **kwargs):
+        self.user = kwargs.pop('user', None)
+        super(ChangeUsernameForm, self).__init__(*args, **kwargs)
+
+    def clean(self):
+        data = super(ChangeUsernameForm, self).clean()
+        new_username = data.get('new_username')
+
+        if not new_username:
+            raise forms.ValidationError(_("Enter new username."))
+
+        if new_username == self.user.username:
+            message = _("New username is same as current one.")
+            raise forms.ValidationError(message)
+
+        validate_username(new_username, exclude=self.user)
+
+        return data
+
+    def change_username(self, changed_by):
+        self.user.set_username(self.cleaned_data['new_username'],
+                          changed_by=changed_by)
+        self.user.save(update_fields=['username', 'slug'])

+ 1 - 26
misago/users/forms/usercp.py

@@ -5,8 +5,7 @@ from misago.conf import settings
 from misago.core import forms, timezones
 
 from misago.users.models import AUTO_SUBSCRIBE_CHOICES
-from misago.users.validators import (validate_email, validate_password,
-                                     validate_username)
+from misago.users.validators import validate_email, validate_password
 
 
 class ChangeForumOptionsBaseForm(forms.ModelForm):
@@ -66,30 +65,6 @@ class EditSignatureForm(forms.ModelForm):
         return data
 
 
-class ChangeUsernameForm(forms.Form):
-    new_username = forms.CharField(label=_("New username"), max_length=200,
-                                   required=False)
-
-    def __init__(self, *args, **kwargs):
-        self.user = kwargs.pop('user', None)
-        super(ChangeUsernameForm, self).__init__(*args, **kwargs)
-
-    def clean(self):
-        data = super(ChangeUsernameForm, self).clean()
-        new_username = data.get('new_username')
-
-        if not new_username:
-            raise forms.ValidationError(_("Enter new username."))
-
-        if new_username == self.user.username:
-            message = _("New username is same as current one.")
-            raise forms.ValidationError(message)
-
-        validate_username(new_username, exclude=self.user)
-
-        return data
-
-
 class ChangeEmailPasswordForm(forms.Form):
     current_password = forms.CharField(
         label=_("Current password"),

+ 7 - 0
misago/users/forms/usermod.py

@@ -0,0 +1,7 @@
+from misago.users.forms.admin import BanUsersForm
+
+
+class BanForm(BanUsersForm):
+    def __init__(self *args, **kwargs):
+        self.user = kwargs.pop('user')
+        super(BanForm, self).__init__(*args, **kwargs)

+ 38 - 5
misago/users/permissions/moderation.py

@@ -14,8 +14,14 @@ Admin Permissions Form
 class PermissionsForm(forms.Form):
     legend = _("Users moderation")
 
-    can_rename_users = forms.YesNoSwitch(
-        label=_("Can rename users"))
+    can_rename_users = forms.YesNoSwitch(label=_("Can rename users"))
+    can_ban_usernames = forms.YesNoSwitch(label=_("Can ban usernames"))
+    can_ban_emails = forms.YesNoSwitch(label=_("Can ban e-mails"))
+    max_ban_length = forms.IntegerField(
+        label=_("Max length, in days, of imposed ban"),
+        help_text=_("Enter zero to let moderators impose permanent bans."),
+        min_value=0,
+        initial=0)
 
 
 def change_permissions_form(role):
@@ -31,12 +37,18 @@ ACL Builder
 def build_acl(acl, roles, key_name):
     new_acl = {
         'can_rename_users': 0,
+        'can_ban_usernames': 0,
+        'can_ban_emails': 0,
+        'max_ban_length': 2,
     }
     new_acl.update(acl)
 
     return algebra.sum_acls(
             new_acl, roles=roles, key=key_name,
-            can_rename_users=algebra.greater
+            can_rename_users=algebra.greater,
+            can_ban_usernames=algebra.greater,
+            can_ban_emails=algebra.greater,
+            max_ban_length=algebra.greater_or_zero
             )
 
 
@@ -46,8 +58,13 @@ ACL's for targets
 @require_target_type(get_user_model())
 def add_acl_to_target(user, acl, target):
     target.acl_['can_rename'] = can_rename_user(user, target)
-    if target.acl_['can_rename']:
-        target.acl_['can_moderate'] = True
+    target.acl_['can_ban_username'] = can_ban_username(user, target)
+    target.acl_['can_ban_email'] = can_ban_email(user, target)
+
+    for permission in ('can_rename', 'can_ban_username', 'can_ban_email'):
+        if target.acl_[permission]:
+            target.acl_['can_moderate'] = True
+            break
 
 
 """
@@ -59,3 +76,19 @@ def allow_rename_user(user, target):
     if not user.is_superuser and (target.is_staff or target.is_superuser):
         raise PermissionDenied(_("You can't rename administrators."))
 can_rename_user = return_boolean(allow_rename_user)
+
+
+def allow_ban_username(user, target):
+    if not user.acl['can_ban_usernames']:
+        raise PermissionDenied(_("You can't ban usernames."))
+    if target.is_staff or target.is_superuser:
+        raise PermissionDenied(_("You can't ban administrators."))
+can_ban_username = return_boolean(allow_ban_username)
+
+
+def allow_ban_email(user, target):
+    if not user.acl['can_ban_emails']:
+        raise PermissionDenied(_("You can't ban e-mails."))
+    if target.is_staff or target.is_superuser:
+        raise PermissionDenied(_("You can't ban administrators."))
+can_ban_email = return_boolean(allow_ban_email)

+ 17 - 10
misago/users/tests/test_usercp_views.py

@@ -4,6 +4,7 @@ from django.contrib.auth import get_user_model
 from django.core import mail
 from django.core.urlresolvers import reverse
 
+from misago.acl.testutils import override_acl
 from misago.admin.testutils import AdminTestCase
 from misago.conf import settings
 from misago.core import threadstore
@@ -189,16 +190,22 @@ class EditSignatureTests(AdminTestCase):
 
     def test_signature_no_permission(self):
         """edit signature view with no ACL returns 404"""
+        override_acl(self.test_admin, {
+            'misago.users.permissions.account': {
+                'can_have_signature': 0,
+            }
+        })
+
         response = self.client.get(self.view_link)
         self.assertEqual(response.status_code, 404)
 
     def test_signature_banned(self):
         """GET to usercp change options view returns 200"""
-        role = self.test_admin.roles.all()[0]
-        permissions = role.permissions
-        account_permissions = permissions['misago.users.permissions.account']
-        account_permissions['can_have_signature'] = 1
-        role.permissions = permissions
+        override_acl(self.test_admin, {
+            'misago.users.permissions.account': {
+                'can_have_signature': 1,
+            }
+        })
 
         self.test_admin.is_signature_banned = True
         self.test_admin.signature_ban_user_message = 'Your siggy is banned.'
@@ -210,11 +217,11 @@ class EditSignatureTests(AdminTestCase):
 
     def test_signature_change(self):
         """GET to usercp change options view returns 200"""
-        role = self.test_admin.roles.all()[0]
-        permissions = role.permissions
-        account_permissions = permissions['misago.users.permissions.account']
-        account_permissions['can_have_signature'] = 1
-        role.permissions = permissions
+        override_acl(self.test_admin, {
+            'misago.users.permissions.account': {
+                'can_have_signature': 1,
+            }
+        })
 
         self.test_admin.is_signature_banned = False
         self.test_admin.save()

+ 2 - 0
misago/users/urls.py

@@ -65,6 +65,8 @@ urlpatterns += patterns('',
 urlpatterns += patterns('',
     url(r'^mod-user/(?P<user_slug>[a-zA-Z0-9]+)-(?P<user_id>\d+)/', include(patterns('misago.users.views.moderation',
         url(r'^rename/$', 'rename', name='rename_user'),
+        url(r'^ban-username/$', 'ban_username', name='ban_user_name'),
+        url(r'^ban-email/$', 'ban_email', name='ban_user_email'),
         url(r'^delete/$', 'delete', name='delete_user'),
     ))),
 )

+ 49 - 3
misago/users/views/moderation.py

@@ -1,6 +1,6 @@
 from django.contrib import messages
 from django.contrib.auth import get_user_model
-from django.db import transaction
+from django.db import IntegrityError, transaction
 from django.shortcuts import redirect, render
 from django.utils.translation import ugettext as _
 
@@ -8,9 +8,11 @@ from misago.acl import add_acl
 from misago.core.decorators import require_POST
 from misago.core.shortcuts import get_object_or_404, validate_slug
 
-from misago.users.forms.usercp import ChangeUsernameForm
+from misago.users.forms.rename import ChangeUsernameForm
 from misago.users.decorators import deny_guests
-from misago.users.permissions.moderation import allow_rename_user
+from misago.users.permissions.moderation import (allow_rename_user,
+                                                 allow_ban_username,
+                                                 allow_ban_email)
 from misago.users.permissions.delete import allow_delete_user
 from misago.users.sites import user_profile
 
@@ -42,6 +44,50 @@ def rename(request, user):
         old_username = user.username
         form = ChangeUsernameForm(request.POST, user=user)
         if form.is_valid():
+            try:
+                form.change_username(changed_by=request.user)
+                message = _("%(old_username)s's username has been changed.")
+                message = message % {'old_username': old_username}
+                messages.success(request, message)
+
+                return redirect(user_profile.get_default_link(),
+                                **{'user_slug': user.slug, 'user_id': user.pk})
+            except IntegrityError:
+                message = _("Error changing username. Please try again.")
+                messages.error(request, message)
+
+    return render(request, 'misago/modusers/rename.html',
+                  {'profile': user, 'form': form})
+
+
+@user_moderation_view(allow_ban_username)
+def ban_username(request, user):
+    form = ChangeUsernameForm(user=user)
+    if request.method == 'POST':
+        old_username = user.username
+        form = ChangeUsernameForm(request.POST, user=user)
+        if form.is_valid():
+            user.set_username(form.cleaned_data['new_username'],
+                              changed_by=request.user)
+            user.save(update_fields=['username', 'slug'])
+
+            message = _("%(old_username)s's username has been changed.")
+            messages.success(request, message % {'old_username': old_username})
+
+            return redirect(user_profile.get_default_link(),
+                            **{'user_slug': user.slug, 'user_id': user.pk})
+
+    return render(request, 'misago/modusers/rename.html',
+                  {'profile': user, 'form': form})
+
+
+@user_moderation_view(allow_ban_email)
+def ban_email(request, user):
+    form = ChangeUsernameForm(user=user)
+    if request.method == 'POST':
+        old_username = user.username
+        form = ChangeUsernameForm(request.POST, user=user)
+        if form.is_valid():
             user.set_username(form.cleaned_data['new_username'],
                               changed_by=request.user)
             user.save(update_fields=['username', 'slug'])

+ 9 - 6
misago/users/views/usercp.py

@@ -16,9 +16,9 @@ from misago.markup import Editor
 
 from misago.users import avatars
 from misago.users.decorators import deny_guests
+from misago.users.forms.rename import ChangeUsernameForm
 from misago.users.forms.usercp import (ChangeForumOptionsForm,
                                        EditSignatureForm,
-                                       ChangeUsernameForm,
                                        ChangeEmailPasswordForm)
 from misago.users.signatures import set_user_signature
 from misago.users.sites import usercp
@@ -251,13 +251,16 @@ def change_username(request):
     if request.method == 'POST' and namechanges.left:
         form = ChangeUsernameForm(request.POST, user=request.user)
         if form.is_valid():
-            request.user.set_username(form.cleaned_data['new_username'])
-            request.user.save(update_fields=['username', 'slug'])
+            try:
+                form.change_username(changed_by=request.user)
 
-            message = _("Your username has been changed.")
-            messages.success(request, message)
+                message = _("Your username has been changed.")
+                messages.success(request, message)
 
-            return redirect('misago:usercp_change_username')
+                return redirect('misago:usercp_change_username')
+            except IntegrityError:
+                message = _("Error changing username. Please try again.")
+                messages.error(request, message)
 
     return render(request, 'misago/usercp/change_username.html', {
             'form': form,