From eece277934cdd58196830883f6ff8276a063780b Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Fri, 20 Jun 2014 12:52:43 -0300 Subject: allow bulk deletion of content by user upon blocking --- askbot/doc/source/changelog.rst | 1 + askbot/forms.py | 14 ++++++++++ askbot/media/style/style.css | 3 +++ askbot/media/style/style.less | 4 +++ askbot/models/__init__.py | 33 ++++++++++++++++++++++++ askbot/templates/user_profile/user_moderate.html | 12 ++++++--- askbot/views/users.py | 13 ++++++++-- 7 files changed, 75 insertions(+), 5 deletions(-) diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index 67928fbc..a71e5641 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -3,6 +3,7 @@ Changes in Askbot Development master branch (only on github) ------------------------------------------ +* Allow bulk deletion of user content simultaneously with blocking * Allow custom destination url under the logo * Option to allow asking without registration (Egil Moeller) * Implemented Mozilla Persona authentication diff --git a/askbot/forms.py b/askbot/forms.py index e3c6c253..0d9cde1d 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -640,6 +640,7 @@ class ChangeUserStatusForm(forms.Form): """ user_status = forms.ChoiceField(label=_('Change status to')) + delete_content = forms.CharField(widget=forms.HiddenInput, initial='false') def __init__(self, *arg, **kwarg): @@ -676,6 +677,15 @@ class ChangeUserStatusForm(forms.Form): self.moderator = moderator self.subject = subject + def clean_delete_content(self): + delete = self.cleaned_data.get('delete_content', False) + if delete == 'true': + delete = True + else: + delete = False + self.cleaned_data['delete_content'] = delete + return self.cleaned_data['delete_content'] + def clean(self): #if moderator is looking at own profile - do not #let change status @@ -717,6 +727,10 @@ class ChangeUserStatusForm(forms.Form): ) % {'username': self.subject.username} raise forms.ValidationError(msg) + if user_status not in ('s', 'b'):#not blocked or suspended + if self.cleaned_data['delete_content'] == True: + self.cleaned_data['delete_content'] = False + return self.cleaned_data diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css index d86b8fc7..33df2b0a 100644 --- a/askbot/media/style/style.css +++ b/askbot/media/style/style.css @@ -3019,6 +3019,9 @@ a:hover.medal { padding: 0; margin-top: -3px; } +.user-profile-page table.form-as-table { + margin: 5px 0 12px; +} .user-profile-page .submit-row { margin-bottom: 0; } diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less index 09b2810f..f4ac2dfd 100644 --- a/askbot/media/style/style.less +++ b/askbot/media/style/style.less @@ -3172,6 +3172,10 @@ a:hover.medal { margin-top: -3px; } + table.form-as-table { + margin: 5px 0 12px; + } + .submit-row { margin-bottom: 0; } diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index 93c8d599..c1327bb5 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -1560,6 +1560,35 @@ def user_delete_question( ) +def user_delete_all_content_authored_by_user(self, author, timestamp=None): + """Deletes all questions, answers and comments made by the user""" + count = 0 + + #delete answers + answers = Post.objects.get_answers().filter(author=author) + timestamp = timestamp or datetime.datetime.now() + count += answers.update(deleted_at=timestamp, deleted_by=self, deleted=True) + + #delete questions + questions = Post.objects.get_questions().filter(author=author) + count += questions.update(deleted_at=timestamp, deleted_by=self, deleted=True) + + #delete threads + thread_ids = questions.values_list('thread_id', flat=True) + #load second time b/c threads above are not quite real + threads = Thread.objects.filter(id__in=thread_ids) + threads.update(deleted=True) + for thread in threads: + thread.invalidate_cached_data() + + #delete comments + comments = Post.objects.get_comments().filter(author=author) + count += comments.count() + comments.delete() + + return count + + @auto_now_timestamp def user_close_question( self, @@ -2992,6 +3021,10 @@ User.add_to_class('get_unused_votes_today', user_get_unused_votes_today) User.add_to_class('delete_comment', user_delete_comment) User.add_to_class('delete_question', user_delete_question) User.add_to_class('delete_answer', user_delete_answer) +User.add_to_class( + 'delete_all_content_authored_by_user', + user_delete_all_content_authored_by_user +) User.add_to_class('restore_post', user_restore_post) User.add_to_class('close_question', user_close_question) User.add_to_class('reopen_question', user_reopen_question) diff --git a/askbot/templates/user_profile/user_moderate.html b/askbot/templates/user_profile/user_moderate.html index 75c6d6fe..1e33f4d7 100644 --- a/askbot/templates/user_profile/user_moderate.html +++ b/askbot/templates/user_profile/user_moderate.html @@ -8,16 +8,18 @@

{% trans username=view_user.username|escape, status=view_user.get_status_display() %}{{username}}'s current status is "{{status}}"{% endtrans %}

{% if user_status_changed %} -

{% trans %}User status changed{% endtrans %}

+

{{ user_status_changed_message }}

{% endif %}
{% csrf_token %} {{ change_user_status_form.as_table() }}
-

+

+

+ +

-
{% endif %}

@@ -89,5 +91,9 @@ $('#id_user_status_info').hide('slow'); } }) + $('input[name="hard_block"]').click(function() { + $('input[name="delete_content"]').val('true'); + $('select[name="user_status"]').val('b'); + }); {% endblock %} diff --git a/askbot/views/users.py b/askbot/views/users.py index 91f210d9..32203998 100644 --- a/askbot/views/users.py +++ b/askbot/views/users.py @@ -27,7 +27,9 @@ from django.shortcuts import render from django.http import HttpResponse, HttpResponseForbidden from django.http import HttpResponseRedirect, Http404 from django.utils.translation import get_language +from django.utils.translation import string_concat from django.utils.translation import ugettext as _ +from django.utils.translation import ungettext from django.utils import simplejson from django.utils.html import strip_tags as strip_all_tags from django.views.decorators import csrf @@ -214,13 +216,14 @@ def user_moderate(request, subject, context): user_rep_changed = False user_status_changed = False + user_status_changed_message = _('User status changed') message_sent = False email_error_message = None user_rep_form = forms.ChangeUserReputationForm() send_message_form = forms.SendMessageForm() if request.method == 'POST': - if 'change_status' in request.POST: + if 'change_status' in request.POST or 'hard_block' in request.POST: user_status_form = forms.ChangeUserStatusForm( request.POST, moderator = moderator, @@ -228,6 +231,11 @@ def user_moderate(request, subject, context): ) if user_status_form.is_valid(): subject.set_status( user_status_form.cleaned_data['user_status'] ) + if user_status_form.cleaned_data['delete_content'] == True: + num_deleted = request.user.delete_all_content_authored_by_user(subject) + if num_deleted: + num_deleted_message = ungettext('%d post deleted', '%d posts deleted', num_deleted) % num_deleted + user_status_changed_message = string_concat(user_status_changed_message, ', ', num_deleted_message) user_status_changed = True elif 'send_message' in request.POST: send_message_form = forms.SendMessageForm(request.POST) @@ -291,7 +299,8 @@ def user_moderate(request, subject, context): 'message_sent': message_sent, 'email_error_message': email_error_message, 'user_rep_changed': user_rep_changed, - 'user_status_changed': user_status_changed + 'user_status_changed': user_status_changed, + 'user_status_changed_message': user_status_changed_message } context.update(data) return render(request, 'user_profile/user_moderate.html', context) -- cgit v1.2.3-1-g7c22