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

Destroy User Account view added.

Rafał Pitoń 11 лет назад
Родитель
Сommit
552fa5ec2c

+ 7 - 2
misago/acl/exceptions.py

@@ -2,8 +2,13 @@
 ACL Exceptions thrown by Misago actions
 """
 
-class ACLError403(Exception):
+class ACLErrror(Exception):
     pass
 
-class ACLError404(Exception):
+
+class ACLError403(ACLErrror):
+    pass
+
+
+class ACLError404(ACLErrror):
     pass

+ 22 - 18
misago/acl/permissions/destroyusers.py

@@ -6,18 +6,19 @@ from misago.forms import YesNoSwitch
 from misago.acl.exceptions import ACLError403, ACLError404
 
 def make_form(request, role, form):
-    form.base_fields['can_destroy_user_older_than'] = forms.IntegerField(label=_("Maximum Age of destroyed account (in days)"),
-                                                                         help_text=_("Enter zero to disable this check."),
-                                                                         initial=0, min_value=0, required=False)
-    form.base_fields['can_destroy_user_with_more_posts_than'] = forms.IntegerField(label=_("Maximum number of posts on destroyed account"),
-                                                                                   help_text=_("Enter zero to disable this check."),
-                                                                                   initial=0, min_value=0, required=False)
+    if role.special != 'guest':
+        form.base_fields['can_destroy_user_older_than'] = forms.IntegerField(label=_("Maximum Age of destroyed account (in days)"),
+                                                                             help_text=_("Enter zero to disable this check."),
+                                                                             initial=0, min_value=0, required=False)
+        form.base_fields['can_destroy_user_with_more_posts_than'] = forms.IntegerField(label=_("Maximum number of posts on destroyed account"),
+                                                                                       help_text=_("Enter zero to disable this check."),
+                                                                                       initial=0, min_value=0, required=False)
 
-    form.fieldsets.append((
-                           _("Destroying User Accounts"),
-                           ('can_destroy_user_older_than',
-                            'can_destroy_user_with_more_posts_than')
-                          ))
+        form.fieldsets.append((
+                               _("Destroying User Accounts"),
+                               ('can_destroy_user_older_than',
+                                'can_destroy_user_with_more_posts_than')
+                              ))
 
 
 class DestroyUserACL(BaseACL):
@@ -26,6 +27,9 @@ class DestroyUserACL(BaseACL):
                 or self.acl['can_destroy_user_with_more_posts_than']):
             raise ACLError403(_("You can't destroy user accounts."))
 
+        if user.is_god() or user.is_team:
+            raise ACLError403(_("This user account is protected and cannot be destroyed."))
+
         if self.acl['can_destroy_user_older_than']:
             user_age = timezone.now() - user.join_date
             if user_age.days > self.acl['can_destroy_user_older_than']:
@@ -44,17 +48,17 @@ class DestroyUserACL(BaseACL):
 
 
 def build(acl, roles):
-    acl.destroy_user = DestroyUserACL()
-    acl.destroy_user.acl['can_destroy_user_older_than'] = 0
-    acl.destroy_user.acl['can_destroy_user_with_more_posts_than'] = 0
+    acl.destroyusers = DestroyUserACL()
+    acl.destroyusers.acl['can_destroy_user_older_than'] = 0
+    acl.destroyusers.acl['can_destroy_user_with_more_posts_than'] = 0
 
     for role in roles:
         try:
             if (role['can_destroy_user_older_than']
-                    and role['can_destroy_user_older_than'] > acl.destroy_user.acl['can_destroy_user_older_than']):
-                acl.special.acl['can_destroy_user_older_than'] = role['can_destroy_user_older_than']
+                    and role['can_destroy_user_older_than'] > acl.destroyusers.acl['can_destroy_user_older_than']):
+                acl.destroyusers.acl['can_destroy_user_older_than'] = role['can_destroy_user_older_than']
             if (role['can_destroy_user_with_more_posts_than']
-                    and role['can_destroy_user_with_more_posts_than'] > acl.destroy_user.acl['can_destroy_user_with_more_posts_than']):
-                acl.special.acl['can_destroy_user_with_more_posts_than'] = role['can_destroy_user_with_more_posts_than']
+                    and role['can_destroy_user_with_more_posts_than'] > acl.destroyusers.acl['can_destroy_user_with_more_posts_than']):
+                acl.destroyusers.acl['can_destroy_user_with_more_posts_than'] = role['can_destroy_user_with_more_posts_than']
         except KeyError:
             pass

+ 41 - 0
misago/apps/destroyuser.py

@@ -0,0 +1,41 @@
+from django.shortcuts import redirect
+from django.utils.translation import ugettext as _
+from misago import messages
+from misago.acl.exceptions import ACLError403
+from misago.apps.errors import error403, error404
+from misago.decorators import block_guest, check_csrf
+from misago.models import Forum, User
+
+@block_guest
+@check_csrf
+def destroy_user(request, user, username):
+    try:
+        user = User.objects.get(pk=user)
+    except User.DoesNotExist:
+        return error404(request)
+
+    if user.pk == request.user.pk:
+        return error403(request, _("You can't destroy your own account."))
+
+    try:
+        request.acl.destroyusers.allow_destroy_user(user)
+    except ACLError403 as e:
+        return error403(request, unicode(e))
+
+    forums_to_sync = []
+
+    for thread in user.thread_set.iterator():
+        if not thread.forum_id in forums_to_sync:
+            forums_to_sync.append(thread.forum_id)
+        thread.delete()
+
+    if forums_to_sync:
+        for forum in Forum.objects.filter(id__in=forums_to_sync).iterator():
+            forum.sync()
+            forum.save()
+
+    user.post_set.update(deleted=True)
+    user.delete()
+
+    messages.success(request, _('User Account "%(username)s" has been destroyed.') % {'username': user.username})
+    return redirect('users')

+ 2 - 2
misago/middleware/csrf.py

@@ -4,7 +4,7 @@ class CSRFProtection(object):
     def __init__(self, csrf_token):
         self.csrf_id = '_csrf_token'
         self.csrf_token = csrf_token
-        
+
     def request_secure(self, request):
         return request.method == 'POST' and request.POST.get(self.csrf_id) == self.csrf_token
 
@@ -19,5 +19,5 @@ class CSRFMiddleware(object):
         else:
             csrf_token = random_string(16);
             request.session['csrf_token'] = csrf_token
-        
+
         request.csrf = CSRFProtection(csrf_token)

+ 1 - 0
misago/urls.py

@@ -27,6 +27,7 @@ urlpatterns = patterns('misago.apps',
 urlpatterns += patterns('',
     (r'^', include('misago.apps.signin.urls')),
     (r'^users/', include('misago.apps.profiles.urls')),
+    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/destroy/', 'misago.apps.destroyuser.destroy_user', name="destroy_user"),
     (r'^usercp/', include('misago.apps.usercp.urls')),
     (r'^activate/', include('misago.apps.activation.urls')),
     (r'^watched-threads/', include('misago.apps.watchedthreads.urls')),

+ 1 - 0
templates/cranefly/profiles/posts.html

@@ -65,5 +65,6 @@
 {%- endmacro %}
 
 {% block javascripts %}
+{{ super() }}
 {{ draw_graph() }}
 {% endblock %}

+ 19 - 1
templates/cranefly/profiles/profile.html

@@ -66,6 +66,14 @@
               <a href="{{ url('private_thread_start_with', username=profile.username_slug, user=profile.pk) }}" class="btn btn-icon tooltip-top" title="{% trans user=profile.username %}Start private thread with {{ user }}{% endtrans %}"><i class="icon-envelope"></i></a>
             </li>
             {% endif %}
+            <li class="pull-right">
+              <form class="form-inline form-destroy-user" action="{{ url('destroy_user', username=profile.username_slug, user=profile.pk) }}" method="post">
+                <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+                <button type="submit" class="btn btn-icon tooltip-top" title="{% trans user=profile.username %}Destroy {{ user }}'s user account, deleting it, its threads and soft-deleting it's replies in other threads.{% endtrans %}">
+                  <i class="icon-remove"></i>
+                </button>
+              </form>
+            </li>
             {% endif %}
           </ul>
         </div>
@@ -112,4 +120,14 @@
         .attr("fill", "#DDD");
 
     </script>
-{% endmacro %}
+{% endmacro %}
+
+{% block javascripts %}
+{{ super() }}
+    <script type="text/javascript">
+      $('.form-destroy-user').submit(function() {
+        var decision = confirm("{% trans %}Are you sure you want to destroy this member's account? This action is not reversible!{% endtrans %}");
+        return decision;
+      });
+    </script>
+{% endblock %}

+ 1 - 0
templates/cranefly/profiles/threads.html

@@ -53,6 +53,7 @@
 {%- endmacro %}
 
 {% block javascripts %}
+{{ super() }}
 {{ draw_graph() }}
 {% endblock %}