This commit had some important milestones in it. The major update is that now I
authortilly-Q <nattilypigeonfowl@gmail.com>
Sat, 27 Jul 2013 20:44:40 +0000 (16:44 -0400)
committertilly-Q <nattilypigeonfowl@gmail.com>
Sat, 27 Jul 2013 20:44:40 +0000 (16:44 -0400)
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

13 files changed:
mediagoblin/db/migrations.py
mediagoblin/db/models.py
mediagoblin/db/util.py
mediagoblin/moderation/forms.py
mediagoblin/moderation/tools.py [new file with mode: 0644]
mediagoblin/moderation/views.py
mediagoblin/static/css/base.css
mediagoblin/static/images/icon_clipboard_alert.png [new file with mode: 0644]
mediagoblin/templates/mediagoblin/moderation/report.html
mediagoblin/templates/mediagoblin/moderation/report_panel.html
mediagoblin/templates/mediagoblin/moderation/user.html
mediagoblin/templates/mediagoblin/moderation/user_panel.html
mediagoblin/tools/response.py

index 3e6791c4cb20d6ee7deb221797dab1135daef0dd..247298ace2db022aed3fcd37ad2e8cfb252906e2 100644 (file)
@@ -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)
index 01078db802a4ac9075778ed97d87a337f091c31c..c85d546f778005f0889031c18cb9a5e6afd4a5c4 100644 (file)
@@ -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 
index 6ffec44da18e58665119c4fb4ba05ab87fbda666..1aa0a63ca837c2cb0cbf715da7858f5b22559b9c 100644 (file)
@@ -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
index 0a91b9b484db6e870b9ab5b3fa8d7c8b6cc6dc8b..718cd8fa661002161e88741d6041e5ac0f77af15 100644 (file)
 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 (file)
index 0000000..9a3b1c2
--- /dev/null
@@ -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)
index 6f6318bcdce4105dc30b291814bd134d05ad21fc..67928927b58772a6985c1637f2ef171e9b54dfed 100644 (file)
@@ -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)
index 343648d8d7f5586d6214a33a7b473281f9de241e..0378350efaf1a902a40d37277c74a54bb2e58548 100644 (file)
@@ -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 (file)
index 0000000..952c588
Binary files /dev/null and b/mediagoblin/static/images/icon_clipboard_alert.png differ
index 6938569d7c9e04158293498d18eb5da705ea0928..4406777170d741626a2e3fb1301fc9f8b3717916 100644 (file)
 {% 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"
         {% 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">
       {{ 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) }}
 
 
   <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 %}
index 126b247c41ec4e54d0b06218cf7c37665e734aac..f3840e292d5e82963024764482d0b44dc6f74b82 100644 (file)
 <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>
 {% 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 %}
index f868aa8a1ca338df26a0910710dff651dd573559..3fb650638fec3df52279365a04e9413137e64a46 100644 (file)
 
     <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>
   {% else %}
     <h1>
       {%- trans username=user.username %}{{ username }}'s profile{% endtrans -%}
+    {% if user_banned and user_banned.expiration_date %}
+      &mdash; BANNED until {{ user_banned.expiration_date }}
+    {% elif user_banned %}
+      &mdash; Banned Indefinitely
+    {% endif %}
     </h1>
 
     {% if not user.url and not user.bio %}
     <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 %}
index 498770742fc8b488e08f25511290136ab372eb1a..6762a84404bda0d6f8d622c184bbba67aa34c1d2 100644 (file)
@@ -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>
     {% 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>
index ecea307e8c3e9dd9de776a09fd84fe5bd610de40..85558300dabb929252ffa29355b77f283f00f2b4 100644 (file)
@@ -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,