diff options
-rw-r--r-- | mediagoblin/db/migrations.py | 20 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 46 | ||||
-rw-r--r-- | mediagoblin/db/util.py | 19 | ||||
-rw-r--r-- | mediagoblin/moderation/forms.py | 36 | ||||
-rw-r--r-- | mediagoblin/moderation/tools.py | 134 | ||||
-rw-r--r-- | mediagoblin/moderation/views.py | 85 | ||||
-rw-r--r-- | mediagoblin/static/css/base.css | 17 | ||||
-rw-r--r-- | mediagoblin/static/images/icon_clipboard_alert.png | bin | 0 -> 647 bytes | |||
-rw-r--r-- | mediagoblin/templates/mediagoblin/moderation/report.html | 145 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/moderation/report_panel.html | 112 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/moderation/user.html | 62 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/moderation/user_panel.html | 12 | ||||
-rw-r--r-- | mediagoblin/tools/response.py | 7 |
13 files changed, 490 insertions, 205 deletions
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 3e6791c4..247298ac 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -299,8 +299,6 @@ class ReportBase_v0(declarative_base()): report_content = Column(UnicodeText) reported_user_id = Column(Integer, ForeignKey(User.id), nullable=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) - resolved = Column(DateTime) - result = Column(UnicodeText) discriminator = Column('type', Unicode(50)) __mapper_args__ = {'polymorphic_on': discriminator} @@ -317,13 +315,20 @@ class MediaReport_v0(ReportBase_v0): __tablename__ = 'core__reports_on_media' __mapper_args__ = {'polymorphic_identity': 'media_report'} - id = Column( - 'id', - Integer, - ForeignKey('core__reports.id'), - primary_key=True) + id = Column('id',Integer, ForeignKey('core__reports.id'), primary_key=True) media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) +class ArchivedReport_v0(ReportBase_v0): + __tablename__ = 'core__reports_archived' + __mapper_args__ = {'polymorphic_identity': 'archived_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id')) + + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id)) + comment_id = Column(Integer, ForeignKey(MediaComment.id)) + resolver_id = Column(Integer, ForeignKey(User.id), nullable=False) + resolved_time = Column(DateTime) + result = Column(UnicodeText) class UserBan_v0(declarative_base()): __tablename__ = 'core__user_bans' @@ -356,6 +361,7 @@ def create_moderation_tables(db): ReportBase_v0.__table__.create(db.bind) CommentReport_v0.__table__.create(db.bind) MediaReport_v0.__table__.create(db.bind) + ArchivedReport_v0.__table__.create(db.bind) UserBan_v0.__table__.create(db.bind) Privilege_v0.__table__.create(db.bind) PrivilegeUserAssociation_v0.__table__.create(db.bind) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 01078db8..c85d546f 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -515,11 +515,18 @@ class ReportBase(Base): cascade="all, delete-orphan"), primaryjoin="User.id==ReportBase.reported_user_id") created = Column(DateTime, nullable=False, default=datetime.datetime.now()) - resolved = Column(DateTime) - result = Column(UnicodeText) discriminator = Column('type', Unicode(50)) __mapper_args__ = {'polymorphic_on': discriminator} + def is_comment_report(self): + return self.discriminator=='comment_report' + + def is_media_entry_report(self): + return self.discriminator=='media_report' + + def is_archived_report(self): + return self.discriminator=='archived_report' + class CommentReport(ReportBase): """ @@ -548,10 +555,40 @@ class MediaReport(ReportBase): media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) media_entry = relationship( MediaEntry, - backref=backref("reports_filed_on", + backref=backref("reports_filed_onmod/reports/1/", lazy="dynamic", cascade="all, delete-orphan")) +class ArchivedReport(ReportBase): + """ + A table to keep track of reports that have been resolved + """ + __tablename__ = 'core__reports_archived' + __mapper_args__ = {'polymorphic_identity': 'archived_report'} + id = Column('id',Integer, ForeignKey('core__reports.id'), + primary_key=True) + + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id)) + media_entry = relationship( + MediaEntry, + backref=backref("past_reports_filed_on", + lazy="dynamic")) + comment_id = Column(Integer, ForeignKey(MediaComment.id)) + comment = relationship( + MediaComment, backref=backref("past_reports_filed_on", + lazy="dynamic")) + + resolver_id = Column(Integer, ForeignKey(User.id), nullable=False) + resolver = relationship( + User, + backref=backref("reports_resolved_by", + lazy="dynamic", + cascade="all, delete-orphan"), + primaryjoin="User.id==ArchivedReport.resolver_id") + + resolved = Column(DateTime) + result = Column(UnicodeText) + class UserBan(Base): """ Holds the information on a specific user's ban-state. As long as one of @@ -641,7 +678,8 @@ privilege_foundations = [[u'admin'], [u'moderator'], [u'uploader'],[u'reporter'] MODELS = [ User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData, ReportBase, - CommentReport, MediaReport, UserBan, Privilege, PrivilegeUserAssociation] + CommentReport, MediaReport, UserBan, Privilege, PrivilegeUserAssociation, + ArchivedReport] # Foundations are the default rows that are created immediately after the tables are initialized. Each entry to # this dictionary should be in the format of diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 6ffec44d..1aa0a63c 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -15,7 +15,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from mediagoblin.db.base import Session -from mediagoblin.db.models import MediaEntry, Tag, MediaTag, Collection +from mediagoblin.db.models import (MediaEntry, Tag, MediaTag, Collection, \ + User, Privilege, FOUNDATIONS) ########################## @@ -67,6 +68,22 @@ def check_collection_slug_used(creator_id, slug, ignore_c_id): does_exist = Session.query(Collection.id).filter(filt).first() is not None return does_exist +def user_privileges_to_dictionary(user_id): + """ + This function accepts a users id and returns a dictionary of True or False + values for each privilege the user does or does not have. This allows for + easier referencing of a user's privileges inside templates. + """ + privilege_dictionary = {} + user = User.query.get(user_id) + users_privileges = [p_item.privilege_name for p_item in user.all_privileges] + for privilege_name in FOUNDATIONS[Privilege]: + privilege_name = privilege_name[0] + if privilege_name in users_privileges: + privilege_dictionary[privilege_name]=True + else: + privilege_dictionary[privilege_name]=False + return privilege_dictionary if __name__ == '__main__': from mediagoblin.db.open import setup_connection_and_db_from_config 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) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 343648d8..0378350e 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -618,6 +618,23 @@ table.admin_panel th, table.admin_side_panel th { font-weight: bold; padding-bottom: 4px; text-align: left; + color: #fff; +} + +table td.user_with_privilege { + font-weight: bold; + color: #86D4B1; +} + +table td.user_without_privilege { + font-weight: bold; + color: #D486B1; +} + +.return_to_panel { + text-align:right; + float: right; + font-size:1.2em } /* Delete panel */ diff --git a/mediagoblin/static/images/icon_clipboard_alert.png b/mediagoblin/static/images/icon_clipboard_alert.png Binary files differnew file mode 100644 index 00000000..952c588d --- /dev/null +++ b/mediagoblin/static/images/icon_clipboard_alert.png diff --git a/mediagoblin/templates/mediagoblin/moderation/report.html b/mediagoblin/templates/mediagoblin/moderation/report.html index 6938569d..44067771 100644 --- a/mediagoblin/templates/mediagoblin/moderation/report.html +++ b/mediagoblin/templates/mediagoblin/moderation/report.html @@ -22,9 +22,16 @@ {% if not report %} Sorry, no such report found. {% else %} - <h2> Report #{{ report.id }}</h2> - {% if comment %} - Reported comment: + <a href="{{ request.urlgen('mediagoblin.moderation.reports') }}" + class="return_to_panel button_action" + title="Return to Reports Panel"> + {% trans %}Return to Reports Panel{% endtrans %}</a> + <h2>{% trans %}Report{% endtrans %} #{{ report.id }}</h2> + {% if report.is_comment_report() or + (report.is_archived_report() and report.comment) %} + + {% trans %}Reported comment{% endtrans %}: + {% set comment = report.comment %} {% set reported_user = comment.get_author %} <div id="comment-{{ comment.id }}" class="comment_wrapper"> @@ -35,7 +42,8 @@ class="comment_authorlink"> {{- reported_user.username -}} </a> - <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment', + <a href="{{ request.urlgen( + 'mediagoblin.user_pages.media_home.view_comment', comment=comment.id, user=comment.get_media_entry.get_uploader.username, media=comment.get_media_entry.slug_or_id) }}#comment" @@ -52,23 +60,43 @@ {% endautoescape %} </div> </div> - {% elif media_entry %} + {% elif report.is_media_entry_report() or + (report.is_archived_report() and report.media_entry) %} + + {% set media_entry = report.media_entry %} <div class="media_thumbnail"> - <a href="request.urlgen('mediagoblin.user_pages.media_home'), - user=media_entry.get_uploader.username, - media=media_entry.slug_or_id)"><img src="{{ media_entry.thumb_url}}"/></a> - <a href="request.urlgen('mediagoblin.user_pages.media_home'), + <a href="{{ request.urlgen('mediagoblin.user_pages.media_home', + user=media_entry.get_uploader.username, + media=media_entry.slug_or_id) }}"> + <img src="{{ media_entry.thumb_url}}"/></a> + <a href="{{ request.urlgen('mediagoblin.user_pages.media_home', user=media_entry.get_uploader.username, - media=media_entry.slug_or_id)" class=thumb_entry_title>{{ media_entry.title }}</a> + media=media_entry.slug_or_id) }}" class=thumb_entry_title> + {{ media_entry.title }}</a> </div> <div class=clear></div> + <p>❖ Reported media by <a href=""> + {{ report.reported_user.username }}</a></p> + <div class=clear></div> + {% else %} + <h2>{% trans user_url="request.urlgen( + 'mediagoblin.moderation.users_detail', + user=report.reporter.username)", + user_name=report.reported_user.username %} + CONTENT BY + <a href="{{ user_url }}"> + {{ user_name }}</a> + HAS BEEN DELETED{% endtrans %} + </h2> {% endif %} Reason for report: <div id="report-{{ report.id }}" class="report_wrapper"> <div class="report_author"> - <img src="{{ request.staticdirect('/images/icon_clipboard.png') }}" - alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. Distributed by the GNOME project http://www.gnome.org" /> + <img src="{{ request.staticdirect( + '/images/icon_clipboard_alert.png') }}" + alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. + Distributed by the GNOME project http://www.gnome.org" /> <a href="{{ request.urlgen('mediagoblin.moderation.users_detail', user=report.reporter.username) }}" class="report_authorlink"> @@ -88,7 +116,7 @@ {{ report.report_content }} </div> </div> - {% if not report.resolved %} + {% if not report.is_archived_report() %} <input type=button value=Resolve id=open_resolution_form /> <form action="" method="POST" id=resolution_form> {{ wtforms_util.render_divs(form) }} @@ -98,39 +126,72 @@ <script> - $(document).ready(function() { - $('form#resolution_form').hide() - $('#user_banned_until').val("YYYY-MM-DD") - $('#open_resolution_form').click(function() { - $('form#resolution_form').toggle(); - $('#user_banned_until').hide(); - $('label[for=user_banned_until]').hide(); - }); - $('#action_to_resolve').change(function() { - if ($('ul#action_to_resolve li input:checked').val() == "userban") { - $('#user_banned_until').show(); - $('label[for=user_banned_until]').show(); - } else { - $('#user_banned_until').hide(); - $('label[for=user_banned_until]').hide(); - } - }); - $("#user_banned_until").focus(function() { - $(this).val(""); - $(this).unbind('focus'); - }); - $("#submit_this_report").click(function(){ - if ($("#user_banned_until").val() == 'YYYY-MM-DD'){ - $("#user_banned_until").val(""); - } - }); +$(document).ready(function() { + hidden_input_names = { + 'takeaway':['take_away_privileges'], + 'userban':['user_banned_until','why_user_was_banned'], + 'sendmessage':['message_to_user'] +} + + $('form#resolution_form').hide() + $('#user_banned_until').val("YYYY-MM-DD") + $('#open_resolution_form').click(function() { + $('form#resolution_form').toggle(); + $.each(hidden_input_names, function(key, list){ + $.each(list, function(index, name){ + $('label[for='+name+']').hide(); + $('#'+name).hide(); + }); + }); + }); + $('#action_to_resolve').change(function() { + $('ul#action_to_resolve li input:checked').each(function() { + $.each(hidden_input_names[$(this).val()], function(index, name){ + $('label[for='+name+']').show(); + $('#'+name).show(); + }); + }); + $('ul#action_to_resolve li input:not(:checked)').each(function() { + $.each(hidden_input_names[$(this).val()], function(index, name){ + $('label[for='+name+']').hide(); + $('#'+name).hide(); + }); + }); +/* $.each(hidden_input_names, function(key,name){ + if ($.inArray(key, $('ul#action_to_resolve li input:checked').val())){ + $.each(hidden_input_names[key], function(index,name){ + $('#'+name).show(); + $('label[for='+name+']').show(); + }); + } else { + $.each(hidden_input_names[key], function(index,name){ + $('#'+name).hide(); + $('label[for='+name+']').hide(); + }); + } + });*/ + }); + $("#user_banned_until").focus(function() { + $(this).val(""); + $(this).unbind('focus'); + }); + $("#submit_this_report").click(function(){ + if ($("#user_banned_until").val() == 'YYYY-MM-DD'){ + $("#user_banned_until").val(""); + } + }); }); </script> {% else %} - <h2>Status:</h2> - RESOLVED on {{ report.resolved.strftime("%I:%M%p %Y-%m-%d") }} + <h2><img src="{{ request.staticdirect('/images/icon_clipboard.png') }}" + alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. + Distributed by the GNOME project http://www.gnome.org" /> + {% trans %}Status{% endtrans %}: + </h2> + <b>{% trans %}RESOLVED{% endtrans %}</b> + {{ report.resolved.strftime("%I:%M%p %Y-%m-%d") }} {% autoescape False %} - <p>{{ report.result }}</p> + <p>{{ report.result }}</p> {% endautoescape %} {% endif %} {% endif %} diff --git a/mediagoblin/templates/mediagoblin/moderation/report_panel.html b/mediagoblin/templates/mediagoblin/moderation/report_panel.html index 126b247c..f3840e29 100644 --- a/mediagoblin/templates/mediagoblin/moderation/report_panel.html +++ b/mediagoblin/templates/mediagoblin/moderation/report_panel.html @@ -26,42 +26,57 @@ <h1>{% trans %}Report panel{% endtrans %}</h1> <p> - {% trans %}Here you can look up users in order to take punitive actions on them.{% endtrans %} + {% trans %} + Here you can look up open reports that have been filed by users. + {% endtrans %} </p> -<h2>{% trans %}Reports Filed{% endtrans %}</h2> +<h2>{% trans %}Active Reports Filed{% endtrans %}</h2> {% if report_list.count() %} <table class="admin_panel processing"> <tr> - <th>ID</th> - <th>Report Type</th> - <th>Offender</th> - <th>When Reported</th> - <th>Reported By</th> - <th>Reason</th> - <th>Reported Comment or Media Entry</th> + <th></th> + <th>{% trans %}Offender{% endtrans %}</th> + <th>{% trans %}When Reported{% endtrans %}</th> + <th>{% trans %}Reported By{% endtrans %}</th> + <th>{% trans %}Reason{% endtrans %}</th> </tr> {% for report in report_list %} <tr> - - <td><a href="{{ request.urlgen('mediagoblin.moderation.reports_detail', - report_id=report.id) }}">{{ report.id }}</a></td> {% if report.discriminator == "comment_report" %} - <td>Comment Report</td> - <td>{{ report.comment.get_author.username }}</td> - <td>{{ report.created.strftime("%F %R") }}</td> - <td>{{ report.reporter.username }}</td> - <td>{{ report.report_content }}</td> - <td><a href="{{ report.comment.get_media_entry.url_for_self(request.urlgen) }}">{{ report.comment.get_media_entry.title }}</a></td> + <td> + <img + src="{{ request.staticdirect('/images/icon_clipboard_alert.png') }}" + alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. + Distributed by the GNOME project http://www.gnome.org" /> + <a href="{{ request.urlgen( + 'mediagoblin.moderation.reports_detail', + report_id=report.id) }}"> + {% trans report_id=report.id %} + Comment Report #{{ report_id }} + {% endtrans %} + </a> + </td> {% elif report.discriminator == "media_report" %} - <td>Media Report</td> - <td>{{ report.media_entry.get_uploader.username }}</td> - <td>{{ report.created.strftime("%F %R") }}</td> - <td>{{ report.reporter.username }}</td> - <td>{{ report.report_content[0:20] }}...</td> - <td><a href="{{ report.media_entry.url_for_self(request.urlgen) }}">{{ report.media_entry.title }}</a></td> + <td> + <img + src="{{ request.staticdirect('/images/icon_clipboard_alert.png') }}" + alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. + Distributed by the GNOME project http://www.gnome.org" /> + <a href="{{ request.urlgen( + 'mediagoblin.moderation.reports_detail', + report_id=report.id) }}"> + {% trans report_id=report.id %} + Media Report #{{ report_id }} + {% endtrans %} + </a> + </td> {% endif %} + <td>{{ report.reported_user.username }}</td> + <td>{{ report.created.strftime("%F %R") }}</td> + <td>{{ report.reporter.username }}</td> + <td>{{ report.report_content[0:20] }}...</td> </tr> {% endfor %} </table> @@ -72,32 +87,33 @@ {% if closed_report_list.count() %} <table class="media_panel processing"> <tr> - <th>ID</th> - <th>Resolved</th> - <th>Offender</th> - <th>Action Taken</th> - <th>Reported By</th> - <th>Reason</th> - <th>Reported Comment or Media Entry</th> + <th></th> + <th>{% trans %}Resolved{% endtrans %}</th> + <th>{% trans %}Offender{% endtrans %}</th> + <th>{% trans %}Action Taken{% endtrans %}</th> + <th>{% trans %}Reported By{% endtrans %}</th> + <th>{% trans %}Reason{% endtrans %}</th> </tr> {% for report in closed_report_list %} - <td><a href="{{ request.urlgen('mediagoblin.moderation.reports_detail', - report_id=report.id) }}">{{ report.id }}</a></td> - {% if report.discriminator == "comment_report" %} - <td>{{ report.resolved.strftime("%F %R") }}</td> - <td>{{ report.comment.get_author.username }}</td> - <td>{{ report.created.strftime("%F %R") }}</td> - <td>{{ report.reporter.username }}</td> - <td>{{ report.report_content }}</td> - <td><a href="{{ report.comment.get_media_entry.url_for_self(request.urlgen) }}">{{ report.comment.get_media_entry.title }}</a></td> - {% elif report.discriminator == "media_report" %} - <td>{{ report.resolved.strftime("%F %R") }}</td> - <td>{{ report.media_entry.get_uploader.username }}</td> - <td>{{ report.created.strftime("%F %R") }}</td> - <td>{{ report.reporter.username }}</td> - <td>{{ report.report_content[0:20] }}...</td> - <td><a href="{{ report.media_entry.url_for_self(request.urlgen) }}">{{ report.media_entry.title }}</a></td> - {% endif %} + <tr> + <td> + <img + src="{{ request.staticdirect('/images/icon_clipboard.png') }}" + alt="Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. + Distributed by the GNOME project http://www.gnome.org" /> + <a href="{{ request.urlgen('mediagoblin.moderation.reports_detail', + report_id=report.id) }}"> + {% trans report_id=report.id %} + Closed Report #{{ report_id }} + {% endtrans %} + </a> + </td> + <td>{{ report.resolved.strftime("%F %R") }}</td> + <td>{{ report.reported_user.username }}</td> + <td>{{ report.created.strftime("%F %R") }}</td> + <td>{{ report.reporter.username }}</td> + <td>{{ report.report_content }}</td> + </tr> {% endfor %} </table> {% else %} diff --git a/mediagoblin/templates/mediagoblin/moderation/user.html b/mediagoblin/templates/mediagoblin/moderation/user.html index f868aa8a..3fb65063 100644 --- a/mediagoblin/templates/mediagoblin/moderation/user.html +++ b/mediagoblin/templates/mediagoblin/moderation/user.html @@ -41,13 +41,15 @@ <p> {% trans -%} - Someone has registered an account with this username, but it still has to be activated. + Someone has registered an account with this username, but it still has + to be activated. {%- endtrans %} </p> - + <p> {% trans login_url=request.urlgen('mediagoblin.auth.login') -%} - If you are that person but you've lost your verification email, you can <a href="{{ login_url }}">log in</a> and resend it. + If you are that person but you've lost your verification email, you can + <a href="{{ login_url }}">log in</a> and resend it. {%- endtrans %} </p> </div> @@ -56,6 +58,11 @@ {% else %} <h1> {%- trans username=user.username %}{{ username }}'s profile{% endtrans -%} + {% if user_banned and user_banned.expiration_date %} + — BANNED until {{ user_banned.expiration_date }} + {% elif user_banned %} + — Banned Indefinitely + {% endif %} </h1> {% if not user.url and not user.bio %} @@ -121,35 +128,42 @@ <a class="right_align">{{ user.username }}'s report history</a> <span class=clear></span> <h2>{{ user.username }}'s Privileges</h2> - <table class="admin_panel"> + <form action="{{ request.urlgen('mediagoblin.moderation.give_or_take_away_privilege', + user=user.username) }}" + method=post > + <table class="admin_side_panel"> <tr> <th>{% trans %}Privilege{% endtrans %}</th> <th>{% trans %}User Has Privilege{% endtrans %}</th> </tr> {% for privilege in privileges %} <tr> - <form action="{{ request.urlgen('mediagoblin.moderation.give_or_take_away_privilege', - user=user.username) }}" - method=post > <td>{{ privilege.privilege_name }}</td> - <td> - {% if privilege in user.all_privileges %}Yes</td> - {% if (not privilege.is_admin_or_moderator() or request.user.is_admin) and not (user.is_admin and not request.user.is_admin) %} - <td><input type=submit value="{% trans %}Take Away{% endtrans %}" /> - <input type=hidden name=giving_privilege /> - {% endif %} - {% else %}No</td> - {% if (not privilege.is_admin_or_moderator() or request.user.is_admin) and not (user.is_admin and not request.user.is_admin) %} - <td><input type=submit value="{% trans %}Give Privilege{% endtrans %}" > - <input type=hidden name=giving_privilege value=True /> - {% endif %} - {% endif %} - <input type=hidden name=privilege_name value="{{ privilege.privilege_name }}" /> - </td> - {{ csrf_token }} - </form> - </tr> + {% if privilege in user.all_privileges %} + <td class="user_with_privilege"> + Yes{% else %} + <td class="user_without_privilege"> + No{% endif %} + </td> + {% if requesting_user_privileges.admin%} + <td>{% if privilege in user.all_privileges %} + <input type=submit id="{{ privilege.privilege_name }}" class=submit_button value ="-" />{% else %} + <input type=submit id="{{ privilege.privilege_name }}" class=submit_button value ="+" />{% endif %} + </td> + {% endif %} + + </tr> {% endfor %} </table> + {{ csrf_token }} + <input type=hidden name=privilege_name id=hidden_privilege_name /> + </form> {% endif %} + <script> +$(document).ready(function(){ + $('.submit_button').click(function(){ + $('#hidden_privilege_name').val($(this).attr('id')); + }); +}); + </script> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/moderation/user_panel.html b/mediagoblin/templates/mediagoblin/moderation/user_panel.html index 49877074..6762a844 100644 --- a/mediagoblin/templates/mediagoblin/moderation/user_panel.html +++ b/mediagoblin/templates/mediagoblin/moderation/user_panel.html @@ -26,7 +26,9 @@ <h1>{% trans %}User panel{% endtrans %}</h1> <p> - {% trans %}Here you can look up users in order to take punitive actions on them.{% endtrans %} + {% trans %} + Here you can look up users in order to take punitive actions on them. + {% endtrans %} </p> <h2>{% trans %}Active Users{% endtrans %}</h2> @@ -42,8 +44,12 @@ {% for user in user_list %} <tr> <td>{{ user.id }}</td> - <td><a href="{{ request.urlgen('mediagoblin.moderation.users_detail', - user= user.username) }}">{{ user.username }}</a></td> + <td> + <a href="{{ request.urlgen('mediagoblin.moderation.users_detail', + user= user.username) }}"> + {{ user.username }} + </a> + </td> <td>{{ user.created.strftime("%F %R") }}</td> <td>{{ user.posted_comments.count() }}</td> </tr> diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py index ecea307e..85558300 100644 --- a/mediagoblin/tools/response.py +++ b/mediagoblin/tools/response.py @@ -19,7 +19,8 @@ from werkzeug.wrappers import Response as wz_Response from mediagoblin.tools.template import render_template from mediagoblin.tools.translate import (lazy_pass_to_ugettext as _, pass_to_ugettext) -from mediagoblin.db.models import UserBan +from mediagoblin.db.models import UserBan, User +from datetime import datetime class Response(wz_Response): """Set default response mimetype to HTML, otherwise we get text/plain""" @@ -68,6 +69,10 @@ def render_user_banned(request): and the reason why they have been banned" """ user_ban = UserBan.query.get(request.user.id) + if datetime.now()>user_ban.expiration_date: + user_ban.delete() + redirect(request, + 'mediagoblin.index') return render_to_response(request, 'mediagoblin/banned.html', {'reason':user_ban.reason, |