Browse Source

WIP ban users form users list, dropped activate individual user

Rafał Pitoń 11 years ago
parent
commit
6f699a2caf

+ 3 - 2
misago/admin/views/generic/base.py

@@ -16,7 +16,7 @@ class AdminView(View):
         """
         return context
 
-    def render(self, request, context=None):
+    def render(self, request, context=None, template=None):
         context = context or {}
 
         context['root_link'] = self.root_link
@@ -24,4 +24,5 @@ class AdminView(View):
 
         context = self.process_context(request, context)
 
-        return render(request, self.final_template(), context)
+        template = template or self.final_template()
+        return render(request, template, context)

+ 76 - 0
misago/templates/misago/admin/users/ban_users.html

@@ -0,0 +1,76 @@
+{% extends "misago/admin/generic/form.html" %}
+{% load i18n misago_avatars misago_capture misago_forms %}
+
+
+{% block title %}
+{% trans "Ban users" %} | {{ active_link.name }} | {{ block.super }}
+{% endblock title %}
+
+
+{% block page-target %}
+{% trans "Ban users" %}
+{% endblock page-target %}
+
+
+{% block form-header %}
+<h1>
+  {% trans "Ban selected users:" %}
+</h1>
+<p>
+  {% for user in users %}
+  <img src="{{ user|avatar:24 }}" class="img-rounded tooltip-top" alt="{{ user.username }}" width="24" height="24" title="{{ user.username }}">
+  {% endfor %}
+</p>
+{% endblock %}
+
+
+{% block form-extra %}
+class="form-horizontal"
+{% endblock form-extra%}
+
+
+{% block form-body %}
+<input type="hidden" name="action" value="ban">
+{% for user in users %}
+<input type="hidden" name="selected_items" value="{{ user.pk }}">
+{% endfor %}
+<div class="form-body">
+  {% with label_class="col-md-3" field_class="col-md-9" %}
+  <fieldset>
+    <legend>{% trans "Ban settings" %}</legend>
+
+    {% form_row form.valid_until label_class field_class %}
+
+  </fieldset>
+  <fieldset>
+    <legend>{% trans "Messages" %}</legend>
+
+    {% form_row form.user_message label_class field_class %}
+    {% form_row form.staff_message label_class field_class %}
+
+  </fieldset>
+  {% endwith %}
+</div>
+{% endblock form-body %}
+
+
+{% block form-footer %}
+<button class="btn btn-primary" name="finalize">{% trans "Set bans" %}</button>
+{% endblock %}
+
+
+{% block form-footer-class %}
+col-md-offset-3
+{% endblock form-footer-class %}
+
+
+{% block javascripts %}
+<script type="text/javascript">
+  $(function() {
+    $('#id_valid_until').datetimepicker({
+      language: $('html').attr('lang'),
+      pickTime: false
+    });
+  });
+</script>
+{% endblock %}

+ 1 - 21
misago/templates/misago/admin/users/list.html

@@ -25,9 +25,6 @@
 <th style="width: 1%;">&nbsp;</th>
 {% endfor %}
 <th style="width: 1%;">&nbsp;</th>
-<th style="width: 1%;">&nbsp;</th>
-<th style="width: 1%;">&nbsp;</th>
-<th style="width: 1%;">&nbsp;</th>
 {% endblock table-header %}
 
 
@@ -84,23 +81,6 @@
 </td>
 {% endfor %}
 <td class="row-action">
-  {% if item.requires_activation %}
-  <form action="{% url 'misago:admin:users:accounts:activate' user_id=item.pk %}" method="post">
-    <button class="btn btn-success tooltip-top" title="{% trans "Activate user" %}">
-      {% csrf_token %}
-      <span class="fa fa-check-square-o"></span>
-    </button>
-  </form>
-  {% else %}
-  &nbsp;
-  {% endif %}
-</td>
-<td class="row-action">
-  <a href="{% url 'misago:admin:users:accounts:edit' user_id=item.pk %}" class="btn btn-warning tooltip-top" title="{% trans "Ban user" %}">
-    <span class="fa fa-lock"></span>
-  </a>
-</td>
-<td class="row-action">
   <a href="{% url 'misago:admin:users:accounts:edit' user_id=item.pk %}" class="btn btn-primary tooltip-top" title="{% trans "Edit user" %}">
     <span class="fa fa-pencil"></span>
   </a>
@@ -114,7 +94,7 @@
 
 
 {% block emptylist %}
-<td colspan="{{ 13|add:extra_actions_len }}">
+<td colspan="{{ 11|add:extra_actions_len }}">
   <p>{% trans "No users matching search criteria have been found." %}</p>
 </td>
 {% endblock emptylist %}

+ 1 - 3
misago/users/admin.py

@@ -8,8 +8,7 @@ from misago.users.views.admin.bans import BansList, NewBan, EditBan, DeleteBan
 from misago.users.views.admin.ranks import (RanksList, NewRank, EditRank,
                                             DeleteRank, MoveDownRank,
                                             MoveUpRank, DefaultRank, RankUsers)
-from misago.users.views.admin.users import (UsersList, NewUser, EditUser,
-                                            ActivateUser)
+from misago.users.views.admin.users import UsersList, NewUser, EditUser
 from misago.users.views.admin.warnings import (WarningsList, NewWarning,
                                                EditWarning, MoveDownWarning,
                                                MoveUpWarning, DeleteWarning)
@@ -49,7 +48,6 @@ class MisagoAdminExtension(object):
             url(r'^(?P<page>\d+)/$', UsersList.as_view(), name='index'),
             url(r'^new/$', NewUser.as_view(), name='new'),
             url(r'^edit/(?P<user_id>\d+)/$', EditUser.as_view(), name='edit'),
-            url(r'^activate/(?P<user_id>\d+)/$', ActivateUser.as_view(), name='activate'),
         )
 
         # Ranks

+ 33 - 0
misago/users/forms/admin.py

@@ -250,6 +250,39 @@ def SearchUsersForm(*args, **kwargs):
     return FinalForm(*args, **kwargs)
 
 
+class BanUsersForm(forms.Form):
+    user_message = forms.CharField(
+        label=_("User message"), required=False, max_length=1000,
+        help_text=_("Optional message displayed instead of default one."),
+        widget=forms.Textarea(attrs={'rows': 3}),
+        error_messages={
+            'max_length': _("Message can't be longer than 1000 characters.")
+        })
+    staff_message = forms.CharField(
+        label=_("Team message"), required=False, max_length=1000,
+        help_text=_("Optional ban message for moderators and administrators."),
+        widget=forms.Textarea(attrs={'rows': 3}),
+        error_messages={
+            'max_length': _("Message can't be longer than 1000 characters.")
+        })
+    valid_until = forms.DateField(
+        label=_("Expiration date"),
+        required=False, input_formats=['%m-%d-%Y'],
+        widget=forms.DateInput(
+            format='%m-%d-%Y', attrs={'data-date-format': 'MM-DD-YYYY'}),
+        help_text=_('Leave this field empty for this ban to never expire.'))
+
+    def clean_banned_value(self):
+        data = self.cleaned_data['banned_value']
+        while '**' in data:
+            data = data.replace('**', '*')
+
+        if data == '*':
+            raise forms.ValidationError(_("Banned value is too vague."))
+
+        return data
+
+
 """
 Ranks
 """

+ 7 - 1
misago/users/models/bans.py

@@ -15,6 +15,9 @@ __all__ = [
 ]
 
 
+BAN_CACHEBUSTER = 'misago_bans'
+
+
 BAN_USERNAME = 0
 BAN_EMAIL = 1
 BAN_IP = 2
@@ -37,6 +40,9 @@ class BansManager(models.Manager):
     def is_email_banned(self, email):
         return self.check_ban(email=email)
 
+    def invalidate_cache(self):
+        cachebuster.invalidate(BAN_CACHEBUSTER)
+
     def find_ban(self, username=None, email=None, ip=None):
         tests = []
 
@@ -117,7 +123,7 @@ class BanCache(models.Model):
 
     @property
     def is_valid(self):
-        version_is_valid = cachebuster.is_valid('misago_bans',
+        version_is_valid = cachebuster.is_valid(BAN_CACHEBUSTER,
                                                 self.bans_version)
         not_expired = not self.valid_until or self.valid_until < date.today()
 

+ 0 - 16
misago/users/tests/test_useradmin_views.py

@@ -130,19 +130,3 @@ class UserAdminViewsTests(AdminTestCase):
 
         User.objects.get_by_username('Bawww')
         User.objects.get_by_email('reg@stered.com')
-
-    def test_activate_view(self):
-        """activate user view activates account"""
-        User = get_user_model()
-        test_user = User.objects.create_user('Bob', 'bob@test.com', 'pass123',
-                                             requires_activation=1)
-
-        test_link = reverse('misago:admin:users:accounts:activate',
-                            kwargs={'user_id': test_user.pk})
-        response = self.client.post(test_link)
-        self.assertEqual(response.status_code, 302)
-
-        self.assertIn("has been activated", mail.outbox[0].subject)
-
-        test_user = User.objects.get(pk=test_user.pk)
-        self.assertEqual(test_user.requires_activation, 0)

+ 3 - 4
misago/users/views/admin/bans.py

@@ -2,7 +2,6 @@ from django.contrib import messages
 from django.utils.translation import ugettext_lazy as _
 
 from misago.admin.views import generic
-from misago.core import cachebuster
 
 from misago.users.models import Ban
 from misago.users.forms.admin import SearchBansForm, BanForm
@@ -17,7 +16,7 @@ class BanAdmin(generic.AdminBaseMixin):
 
     def handle_form(self, form, request, target):
         super(BanAdmin, self).handle_form(form, request, target)
-        cachebuster.invalidate('misago_bans')
+        Ban.objects.invalidate_cache()
 
 
 class BansList(BanAdmin, generic.ListView):
@@ -42,7 +41,7 @@ class BansList(BanAdmin, generic.ListView):
 
     def action_delete(self, request, items):
         items.delete()
-        cachebuster.invalidate('misago_bans')
+        Ban.objects.invalidate_cache()
         messages.success(request, _("Selected bans have been removed."))
 
 
@@ -57,6 +56,6 @@ class EditBan(BanAdmin, generic.ModelFormView):
 class DeleteBan(BanAdmin, generic.ButtonView):
     def button_action(self, request, target):
         target.delete()
-        cachebuster.invalidate('misago_bans')
+        Ban.objects.invalidate_cache()
         message = _('Ban "%s" has been removed.') % unicode(target.name)
         messages.success(request, message)

+ 49 - 35
misago/users/views/admin/users.py

@@ -10,8 +10,9 @@ from misago.core.mail import mail_users
 
 from misago.users.avatars.dynamic import set_avatar as set_dynamic_avatar
 from misago.users.forms.admin import (StaffFlagUserFormFactory, NewUserForm,
-                                      EditUserForm, SearchUsersForm)
-from misago.users.models import ACTIVATION_REQUIRED_NONE, User
+                                      EditUserForm, SearchUsersForm,
+                                      BanUsersForm)
+from misago.users.models import ACTIVATION_REQUIRED_NONE, User, Ban
 from misago.users.signatures import set_user_signature
 
 
@@ -31,16 +32,6 @@ class UserAdmin(generic.AdminBaseMixin):
         return StaffFlagUserFormFactory(
             self.Form, target, add_staff_field=add_staff_field)
 
-    def send_activation_mail(self, request, activated_users):
-        mail_subject = _("Your account on %(forum_title)s "
-                             "forums has been activated")
-        subject_formats = {'forum_title': settings.forum_name}
-        mail_subject = mail_subject % subject_formats
-
-        mail_subject = mail_subject
-        mail_users(request, activated_users, mail_subject,
-                   'misago/emails/activation/by_admin')
-
 
 class UsersList(UserAdmin, generic.ListView):
     items_per_page = 24
@@ -64,7 +55,6 @@ class UsersList(UserAdmin, generic.ListView):
             'action': 'ban',
             'name': _("Ban users"),
             'icon': 'fa fa-lock',
-            'confirmation': _("Are you sure you want to ban those users?")
         },
         {
             'action': 'delete',
@@ -94,11 +84,49 @@ class UsersList(UserAdmin, generic.ListView):
             queryset = User.objects.filter(pk__in=activated_users_pks)
             queryset.update(requires_activation=ACTIVATION_REQUIRED_NONE)
 
-            self.send_activation_mail(request, queryset)
+            mail_subject = _("Your account on %(forum_title)s "
+                                 "forums has been activated")
+            subject_formats = {'forum_title': settings.forum_name}
+            mail_subject = mail_subject % subject_formats
+
+            mail_subject = mail_subject
+            mail_users(request, inactive_users, mail_subject,
+                       'misago/emails/activation/by_admin')
 
             message = _("Selected users accounts have been activated.")
             messages.success(request, message)
 
+    def action_ban(self, request, users):
+        users = users.order_by('username_slug')
+        for user in users:
+            if user.is_superuser:
+                message = _("%(username)s is super admin and can't be banned.")
+                mesage = message % {'username': user.username}
+                raise generic.MassActionError(mesage)
+
+        form = BanUsersForm()
+        if 'finalize' in request.POST:
+            form = BanUsersForm(request.POST)
+            if form.is_valid():
+                for user in users:
+                    Ban.objects.create(
+                        banned_value=user.username,
+                        user_message=form.cleaned_data.get('user_message'),
+                        staff_message=form.cleaned_data.get('staff_message'),
+                        valid_until=form.cleaned_data.get('valid_until')
+                    )
+
+                Ban.objects.invalidate_cache()
+                message = _("Selected users have been banned.")
+                messages.success(request, message)
+                return None
+
+        return self.render(
+            request, template='misago/admin/users/ban_users.html', context={
+                'users': users,
+                'form': form,
+            })
+
 
 class NewUser(UserAdmin, generic.ModelFormView):
     Form = NewUserForm
@@ -152,35 +180,21 @@ class EditUser(UserAdmin, generic.ModelFormView):
 
         if form.cleaned_data.get('email'):
             target.set_email(form.cleaned_data['email'])
-            start_admin_session(request, target)
+            if target.pk == request.user.pk:
+                start_admin_session(request, target)
 
         if form.cleaned_data.get('is_avatar_banned'):
             set_dynamic_avatar(target)
 
-        if form.cleaned_data.get('staff_level'):
-            form.instance.staff_level = form.cleaned_data['staff_level']
+        if 'staff_level' in form.cleaned_data:
+            target.staff_level = form.cleaned_data['staff_level']
 
         if form.cleaned_data.get('roles'):
-            form.instance.roles.add(*form.cleaned_data['roles'])
+            target.roles.add(*form.cleaned_data['roles'])
 
         set_user_signature(target, form.cleaned_data.get('signature'))
 
-        form.instance.update_acl_key()
-        form.instance.save()
+        target.update_acl_key()
+        target.save()
 
         messages.success(request, self.message_submit % target.username)
-
-
-class ActivateUser(UserAdmin, generic.ButtonView):
-    def button_action(self, request, target):
-        if target.requires_activation:
-            target.requires_activation=ACTIVATION_REQUIRED_NONE
-            target.save(update_fields=['requires_activation'])
-
-            self.send_activation_mail(request, [target])
-
-            message = _("%(username)s's account has been activated.")
-            messages.success(request, message % {'username': target.username})
-        else:
-            message = _("%(username)s's account is already active.")
-            messages.info(request, message % {'username': target.username})