From: tilly-Q Date: Sat, 27 Jul 2013 20:44:40 +0000 (-0400) Subject: This commit had some important milestones in it. The major update is that now I X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=3aa3871b909500ae9198d63814dd79fd28921f93;p=mediagoblin.git 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 --- 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 . 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 . + +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"
%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 + \ + "
"+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"
%s banned user %s until %s." % ( + request.user.username, + user.username, + form.user_banned_until.data) + else: + form.resolution_content.data += \ + u"
%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"
%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"
%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"
%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"
%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"
%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 + \ - "
"+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"
%s banned user %s until %s." % ( - request.user.username, - user.username, - form.user_banned_until.data) - else: - form.resolution_content.data += \ - u"
%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 new file mode 100644 index 00000000..952c588d Binary files /dev/null and b/mediagoblin/static/images/icon_clipboard_alert.png differ 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 %} -

Report #{{ report.id }}

- {% if comment %} - Reported comment: + + {% trans %}Return to Reports Panel{% endtrans %} +

{% trans %}Report{% endtrans %} #{{ report.id }}

+ {% 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 %}
@@ -35,7 +42,8 @@ class="comment_authorlink"> {{- reported_user.username -}} -
- {% elif media_entry %} + {% elif report.is_media_entry_report() or + (report.is_archived_report() and report.media_entry) %} + + {% set media_entry = report.media_entry %}
- - + + {{ media_entry.title }} + media=media_entry.slug_or_id) }}" class=thumb_entry_title> + {{ media_entry.title }}
+

❖ Reported media by + {{ report.reported_user.username }}

+
+ {% else %} +

{% trans user_url="request.urlgen( + 'mediagoblin.moderation.users_detail', + user=report.reporter.username)", + user_name=report.reported_user.username %} + CONTENT BY + + {{ user_name }} + HAS BEEN DELETED{% endtrans %} +

{% endif %} Reason for report: - {% if not report.resolved %} + {% if not report.is_archived_report() %}
{{ wtforms_util.render_divs(form) }} @@ -98,39 +126,72 @@ {% else %} -

Status:

- RESOLVED on {{ report.resolved.strftime("%I:%M%p %Y-%m-%d") }} +

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 %}: +

+ {% trans %}RESOLVED{% endtrans %} + {{ report.resolved.strftime("%I:%M%p %Y-%m-%d") }} {% autoescape False %} -

{{ report.result }}

+

{{ report.result }}

{% 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 @@

{% trans %}Report panel{% endtrans %}

- {% 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 %}

-

{% trans %}Reports Filed{% endtrans %}

+

{% trans %}Active Reports Filed{% endtrans %}

{% if report_list.count() %} - - - - - - - + + + + + {% for report in report_list %} - - {% if report.discriminator == "comment_report" %} - - - - - - + {% elif report.discriminator == "media_report" %} - - - - - - + {% endif %} + + + + {% endfor %}
IDReport TypeOffenderWhen ReportedReported ByReasonReported Comment or Media Entry{% trans %}Offender{% endtrans %}{% trans %}When Reported{% endtrans %}{% trans %}Reported By{% endtrans %}{% trans %}Reason{% endtrans %}
{{ report.id }}Comment Report{{ report.comment.get_author.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content }}{{ report.comment.get_media_entry.title }} + Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license.
+                   Distributed by the GNOME project http://www.gnome.org + + {% trans report_id=report.id %} + Comment Report #{{ report_id }} + {% endtrans %} + + Media Report{{ report.media_entry.get_uploader.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content[0:20] }}...{{ report.media_entry.title }} + Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license.
+                   Distributed by the GNOME project http://www.gnome.org + + {% trans report_id=report.id %} + Media Report #{{ report_id }} + {% endtrans %} + + {{ report.reported_user.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content[0:20] }}...
@@ -72,32 +87,33 @@ {% if closed_report_list.count() %} - - - - - - - + + + + + + {% for report in closed_report_list %} - - {% if report.discriminator == "comment_report" %} - - - - - - - {% elif report.discriminator == "media_report" %} - - - - - - - {% endif %} + + + + + + + + {% endfor %}
IDResolvedOffenderAction TakenReported ByReasonReported Comment or Media Entry{% trans %}Resolved{% endtrans %}{% trans %}Offender{% endtrans %}{% trans %}Action Taken{% endtrans %}{% trans %}Reported By{% endtrans %}{% trans %}Reason{% endtrans %}
{{ report.id }}{{ report.resolved.strftime("%F %R") }}{{ report.comment.get_author.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content }}{{ report.comment.get_media_entry.title }}{{ report.resolved.strftime("%F %R") }}{{ report.media_entry.get_uploader.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content[0:20] }}...{{ report.media_entry.title }}
+ Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license.
+                 Distributed by the GNOME project http://www.gnome.org + + {% trans report_id=report.id %} + Closed Report #{{ report_id }} + {% endtrans %} + + {{ report.resolved.strftime("%F %R") }}{{ report.reported_user.username }}{{ report.created.strftime("%F %R") }}{{ report.reporter.username }}{{ report.report_content }}
{% 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 @@

{% 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 %}

- +

{% trans login_url=request.urlgen('mediagoblin.auth.login') -%} - If you are that person but you've lost your verification email, you can log in and resend it. + If you are that person but you've lost your verification email, you can + log in and resend it. {%- endtrans %}

@@ -56,6 +58,11 @@ {% else %}

{%- 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 %}

{% if not user.url and not user.bio %} @@ -121,35 +128,42 @@ {{ user.username }}'s report history

{{ user.username }}'s Privileges

- + +
{% for privilege in privileges %} - - - {% if (not privilege.is_admin_or_moderator() or request.user.is_admin) and not (user.is_admin and not request.user.is_admin) %} - - {% if (not privilege.is_admin_or_moderator() or request.user.is_admin) and not (user.is_admin and not request.user.is_admin) %} - - {{ csrf_token }} - - + {% if privilege in user.all_privileges %} + + {% if requesting_user_privileges.admin%} + + {% endif %} + + {% endfor %}
{% trans %}Privilege{% endtrans %} {% trans %}User Has Privilege{% endtrans %}
{{ privilege.privilege_name }} - {% if privilege in user.all_privileges %}Yes - - {% endif %} - {% else %}No - - {% endif %} - {% endif %} - -
+ Yes{% else %} + + No{% endif %} + {% if privilege in user.all_privileges %} + {% else %} + {% endif %} +
+ {{ csrf_token }} + + {% endif %} + {% 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 @@

{% trans %}User panel{% endtrans %}

- {% 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 %}

{% trans %}Active Users{% endtrans %}

@@ -42,8 +44,12 @@ {% for user in user_list %} {{ user.id }} - {{ user.username }} + + + {{ user.username }} + + {{ user.created.strftime("%F %R") }} {{ user.posted_comments.count() }} 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,