diff options
author | tilly-Q <nattilypigeonfowl@gmail.com> | 2013-07-27 16:44:40 -0400 |
---|---|---|
committer | tilly-Q <nattilypigeonfowl@gmail.com> | 2013-07-27 16:44:40 -0400 |
commit | 3aa3871b909500ae9198d63814dd79fd28921f93 (patch) | |
tree | 02fbde1fcc3c395f19dbb6e5004c6866ee28fb12 /mediagoblin/moderation | |
parent | 6bba33d7e6fbb0cedc39f9a11f816fe5bd372ae7 (diff) | |
download | mediagoblin-3aa3871b909500ae9198d63814dd79fd28921f93.tar.lz mediagoblin-3aa3871b909500ae9198d63814dd79fd28921f93.tar.xz mediagoblin-3aa3871b909500ae9198d63814dd79fd28921f93.zip |
This commit had some important milestones in it. The major update is that now I
have mostly completed the moderator punishment and resolution of reports. Along
with this, I have also added one last table to the database: one that holds ar-
-chived (or resolved) reports. This is some of the primary functionality of my
whole update, so this is a big step! The other changes I made this update are
primarily organizational. I refactored some of my code into functions and I cl-
eaned up many of my templates.
--\ mediagoblin/db/models.py
--| Created the new ArchivedReport table
--| Removed columns from BaseReport table that are only necessary for Archived
| reports
--\ mediagoblin/db/migrations.py
--| Created the new ArchivedReport table
--| Removed columns from BaseReport table that are only necessary for Archived
| reports
--\ mediagoblin/db/util.py
--| Created the user_privileges_to_dictionary function. This is useful for
| accessing a user's permissions from within a template.
--\ mediagoblin/moderation/forms.py
--| Expanded the disciplinary actions a moderator can take
--| Allowed the moderator to choose more than one disciplinary action at a time
| (It's now managed with a list of checkboxes rather than radio buttons)
----| Pulled a MultiCheckBox class from a wtforms tutorial
--| Added various other form inputs for details of the moderator's disciplinary
| actions
--| Tried to ensure that every string is unicode and translated
--\ mediagoblin/moderation/tools.py
--| Created this file for holding useful moderation tools
--| Moved the penalizing code from views to the function take_punitive_actions
--| Added many more types of punitive actions
--| Added the archiving of old reports
--\ mediagoblin/moderation/views.py
--| Used the privileges_to_dictionary function for the Users Detail view to
| allow for different actions available to a moderator and an admin.
--| Added in functionality for ArchivedReports to the reports_detail and
| reports_panel views
--| Moved the punishments of repots_detail to tools.py (as mentioned above)
--\ mediagoblin/static/css/base.css
--| Added new styling for the User Detail page
--\ mediagoblin/static/images/icon_clipboard_alert.png
--| Added this image to represent unresolved reports
--\ mediagoblin/templates/mediagoblin/moderation/report.html
--| Added 'Return to Reports Panel' button
--| Fixed the spacing to be less that 80 columns wide
--| Added in display for Archived Reports
--\ mediagoblin/templates/mediagoblin/moderation/reports_panel.html
--| Changed the placement and columns of the tables
--| Fixed the spacing to be less that 80 columns wide
--| Added in display for Archived Reports
--\ mediagoblin/templates/mediagoblin/moderation/user.html
--| Fixed the spacing to be less that 80 columns wide
--| Took away the moderator's ability to add and remove privileges at will.
| Only the admin has this power now.
--\ mediagoblin/templates/mediagoblin/moderation/users_panel.html
--| Fixed the spacing to be less that 80 columns wide
--\ mediagoblin/tools/response.py
--| Added in code to remove a UserBan from a User if that user logs in after
| the expiration date
Diffstat (limited to 'mediagoblin/moderation')
-rw-r--r-- | mediagoblin/moderation/forms.py | 36 | ||||
-rw-r--r-- | mediagoblin/moderation/tools.py | 134 | ||||
-rw-r--r-- | mediagoblin/moderation/views.py | 85 |
3 files changed, 180 insertions, 75 deletions
diff --git a/mediagoblin/moderation/forms.py b/mediagoblin/moderation/forms.py index 0a91b9b4..718cd8fa 100644 --- a/mediagoblin/moderation/forms.py +++ b/mediagoblin/moderation/forms.py @@ -17,24 +17,44 @@ import wtforms from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ -ACTION_CHOICES = [(_(u'takeaway'),_('Take away privilege')), - (_(u'userban'),_('Ban the user')), - (_(u'closereport'),_('Close the report without taking an action'))] +ACTION_CHOICES = [(_(u'takeaway'),_(u'Take away privilege')), + (_(u'userban'),_(u'Ban the user')), + (_(u'sendmessage'),(u'Send the user a message')), + (_(u'delete'),_(u'Delete the content'))] + +class MultiCheckboxField(wtforms.SelectMultipleField): + """ + A multiple-select, except displays a list of checkboxes. + + Iterating the field will produce subfields, allowing custom rendering of + the enclosed checkbox fields. + + code from http://wtforms.simplecodes.com/docs/1.0.4/specific_problems.html + """ + widget = wtforms.widgets.ListWidget(prefix_label=False) + option_widget = wtforms.widgets.CheckboxInput() + class PrivilegeAddRemoveForm(wtforms.Form): - giving_privilege = wtforms.HiddenField('',[wtforms.validators.required()]) privilege_name = wtforms.HiddenField('',[wtforms.validators.required()]) class ReportResolutionForm(wtforms.Form): - action_to_resolve = wtforms.RadioField( - _('What action will you take to resolve this report'), - validators=[wtforms.validators.required()], + action_to_resolve = MultiCheckboxField( + _(u'What action will you take to resolve the report?'), + validators=[wtforms.validators.optional()], choices=ACTION_CHOICES) targeted_user = wtforms.HiddenField('', validators=[wtforms.validators.required()]) + take_away_privileges = wtforms.SelectMultipleField( + _(u'What privileges will you take away?'), + validators=[wtforms.validators.optional()]) user_banned_until = wtforms.DateField( - _('User will be banned until:'), + _(u'User will be banned until:'), format='%Y-%m-%d', validators=[wtforms.validators.optional()]) + why_user_was_banned = wtforms.TextAreaField( + validators=[wtforms.validators.optional()]) + message_to_user = wtforms.TextAreaField( + validators=[wtforms.validators.optional()]) resolution_content = wtforms.TextAreaField() diff --git a/mediagoblin/moderation/tools.py b/mediagoblin/moderation/tools.py new file mode 100644 index 00000000..9a3b1c2e --- /dev/null +++ b/mediagoblin/moderation/tools.py @@ -0,0 +1,134 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from mediagoblin import mg_globals +from mediagoblin.db.models import User, Privilege, ArchivedReport, UserBan +from mediagoblin.db.base import Session +from mediagoblin.tools.mail import send_email +from mediagoblin.tools.response import redirect +from datetime import datetime +from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ +import sys, traceback + +def take_punitive_actions(request, form, report, user): + message_body ='' + try: + + # The bulk of this action is running through all of the different + # punitive actions that a moderator could take. + if u'takeaway' in form.action_to_resolve.data: + for privilege_name in form.take_away_privileges.data: + privilege = Privilege.one({u'privilege_name':privilege_name}) + form.resolution_content.data += \ + u"<br>%s took away %s\'s %s privileges" % ( + request.user.username, + user.username, + privilege.privilege_name) + user.all_privileges.remove(privilege) + + # If the moderator elects to ban the user, a new instance of user_ban + # will be created. + if u'userban' in form.action_to_resolve.data: + reason = form.resolution_content.data + \ + "<br>"+request.user.username + user_ban = UserBan( + user_id=form.targeted_user.data, + expiration_date=form.user_banned_until.data, + reason= form.why_user_was_banned.data + ) + Session.add(user_ban) + + if form.user_banned_until.data is not None: + form.resolution_content.data += \ + u"<br>%s banned user %s until %s." % ( + request.user.username, + user.username, + form.user_banned_until.data) + else: + form.resolution_content.data += \ + u"<br>%s banned user %s indefinitely." % ( + request.user.username, + user.username) + + # If the moderator elects to send a warning message. An email will be + # sent to the email address given at sign up + if u'sendmessage' in form.action_to_resolve.data: + message_body = form.message_to_user.data + form.resolution_content.data += \ + u"<br>%s sent a warning email to the offender." % ( + request.user.username) + + archive = ArchivedReport( + reporter_id=report.reporter_id, + report_content=report.report_content, + reported_user_id=report.reported_user_id, + created=report.created, + resolved=datetime.now(), + resolver_id=request.user.id + ) + + if u'delete' in form.action_to_resolve.data and \ + report.is_comment_report(): + deleted_comment = report.comment + Session.delete(deleted_comment) + form.resolution_content.data += \ + u"<br>%s deleted the comment" % ( + request.user.username) + elif u'delete' in form.action_to_resolve.data and \ + report.is_media_entry_report(): + deleted_media = report.media_entry + Session.delete(deleted_media) + form.resolution_content.data += \ + u"<br>%s deleted the media entry" % ( + request.user.username) + + # If the moderator didn't delete the content we then attach the + # content to the archived report. We also have to actively delete the + # old report, since it won't be deleted by cascading. + elif report.is_comment_report(): + archive.comment_id = report.comment_id + Session.delete(report) + elif report.is_media_entry_report(): + archive.media_entry_id = report.media_entry.id + Session.delete(report) + + + archive.result=form.resolution_content.data +# Session.add(archive) + Session.commit() + if message_body: + send_email( + mg_globals.app_config['email_sender_address'], + [user.email], + _('Warning from')+ '- {moderator} '.format( + moderator=request.user.username), + message_body) + + return redirect( + request, + 'mediagoblin.moderation.users_detail', + user=user.username) + except: +#TODO make a more effective and specific try except statement. To account for +# incorrect value addition my moderators + print sys.exc_info()[0] + print sys.exc_info()[1] + traceback.print_tb(sys.exc_info()[2]) + Session.rollback() + return redirect( + request, + 'mediagoblin.moderation.reports_detail', + report_id=report.id) diff --git a/mediagoblin/moderation/views.py b/mediagoblin/moderation/views.py index 6f6318bc..67928927 100644 --- a/mediagoblin/moderation/views.py +++ b/mediagoblin/moderation/views.py @@ -18,11 +18,13 @@ from werkzeug.exceptions import Forbidden from mediagoblin.db.models import (MediaEntry, User, MediaComment, \ CommentReport, ReportBase, Privilege, \ - UserBan) + UserBan, ArchivedReport) +from mediagoblin.db.util import user_privileges_to_dictionary from mediagoblin.decorators import (require_admin_or_moderator_login, \ active_user_from_url) from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.moderation import forms as moderation_forms +from mediagoblin.moderation.tools import take_punitive_actions from datetime import datetime @require_admin_or_moderator_login @@ -67,17 +69,22 @@ def moderation_users_detail(request): ''' user = User.query.filter_by(username=request.matchdict['user']).first() active_reports = user.reports_filed_on.filter( - ReportBase.resolved==None).limit(5) + ReportBase.discriminator!='archived_report').limit(5) closed_reports = user.reports_filed_on.filter( - ReportBase.resolved!=None).all() + ReportBase.discriminator=='archived_report').all() privileges = Privilege.query + user_banned = UserBan.query.get(user.id) + user_privileges = user_privileges_to_dictionary(user.id) + requesting_user_privileges = user_privileges_to_dictionary(request.user.id) return render_to_response( request, 'mediagoblin/moderation/user.html', {'user':user, - 'privileges':privileges, - 'reports':active_reports}) + 'privileges': privileges, + 'requesting_user_privileges':requesting_user_privileges, + 'reports':active_reports, + 'user_banned':user_banned}) @require_admin_or_moderator_login def moderation_reports_panel(request): @@ -86,10 +93,10 @@ def moderation_reports_panel(request): media entries for this instance. ''' report_list = ReportBase.query.filter( - ReportBase.resolved==None).order_by( + ReportBase.discriminator!="archived_report").order_by( ReportBase.created.desc()).limit(10) closed_report_list = ReportBase.query.filter( - ReportBase.resolved!=None).order_by( + ReportBase.discriminator=="archived_report").order_by( ReportBase.created.desc()).limit(10) # Render to response @@ -109,66 +116,12 @@ def moderation_reports_detail(request): form = moderation_forms.ReportResolutionForm(request.form) report = ReportBase.query.get(request.matchdict['report_id']) + form.take_away_privileges.choices = [(s.privilege_name,s.privilege_name.title()) for s in report.reported_user.all_privileges] + if request.method == "POST" and form.validate(): user = User.query.get(form.targeted_user.data) - if form.action_to_resolve.data == u'takeaway': - if report.discriminator == u'comment_report': - privilege = Privilege.one({'privilege_name':u'commenter'}) - form.resolution_content.data += \ - u"<br>%s took away %s\'s commenting privileges" % ( - request.user.username, - user.username) - else: - privilege = Privilege.one({'privilege_name':u'uploader'}) - form.resolution_content.data += \ - u"<br>%s took away %s\'s media uploading privileges" % ( - request.user.username, - user.username) - user.all_privileges.remove(privilege) - user.save() - report.result = form.resolution_content.data - report.resolved = datetime.now() - report.save() - - elif form.action_to_resolve.data == u'userban': - reason = form.resolution_content.data + \ - "<br>"+request.user.username - user_ban = UserBan( - user_id=form.targeted_user.data, - expiration_date=form.user_banned_until.data, - reason= form.resolution_content.data) - user_ban.save() - if not form.user_banned_until == "": - form.resolution_content.data += \ - u"<br>%s banned user %s until %s." % ( - request.user.username, - user.username, - form.user_banned_until.data) - else: - form.resolution_content.data += \ - u"<br>%s banned user %s indefinitely." % ( - request.user.username, - user.username, - form.user_banned_until.data) - - report.result = form.resolution_content.data - report.resolved = datetime.now() - report.save() - - else: - pass - - return redirect( - request, - 'mediagoblin.moderation.users_detail', - user=user.username) + return take_punitive_actions(request, form, report, user) - if report.discriminator == 'comment_report': - comment = MediaComment.query.get(report.comment_id) - media_entry = None - elif report.discriminator == 'media_report': - media_entry = MediaEntry.query.get(report.media_entry_id) - comment = None form.targeted_user.data = report.reported_user_id @@ -176,8 +129,6 @@ def moderation_reports_detail(request): request, 'mediagoblin/moderation/report.html', {'report':report, - 'media_entry':media_entry, - 'comment':comment, 'form':form}) @require_admin_or_moderator_login @@ -189,7 +140,7 @@ def give_or_take_away_privilege(request, url_user): form = moderation_forms.PrivilegeAddRemoveForm(request.form) if request.method == "POST" and form.validate(): privilege = Privilege.one({'privilege_name':form.privilege_name.data}) - if privilege in url_user.all_privileges is True: + if privilege in url_user.all_privileges: url_user.all_privileges.remove(privilege) else: url_user.all_privileges.append(privilege) |