From dfd66b789cd6cc9470c2a98bcbda9ee5e0f3ad0f Mon Sep 17 00:00:00 2001 From: tilly-Q Date: Thu, 29 Aug 2013 13:47:50 -0400 Subject: [PATCH] This was a big commit! I included lots of documentation below, but generally I did a few things. I wrote many many many new tests, either in old test files or in the three new test files I made. I also did some code-keeping work, deleting trailing whitespace and deleting vestigial code. Lastly, I fixed the parts of the code which I realized were broken thru the process of running tests. =============================================================================== Deleted trailing whitespace: =============================================================================== --\ mediagoblin/decorators.py --\ mediagoblin/auth/tools.py --\ mediagoblin/db/migrations.py --\ mediagoblin/db/models.py --\ mediagoblin/gmg_commands/users.py --\ mediagoblin/moderation/forms.py --\ mediagoblin/moderation/tools.py --\ mediagoblin/moderation/views.py --\ mediagoblin/templates/mediagoblin/moderation/media_panel.html --\ 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/templates/mediagoblin/user_pages/report.html --\ mediagoblin/templates/mediagoblin/utils/report.html --\ mediagoblin/user_pages/lib.py --\ mediagoblin/user_pages/views.py =============================================================================== Deleted Vestigial Code =============================================================================== --\ mediagoblin/db/util.py --\ mediagoblin/tests/test_notifications.py =============================================================================== Modified the Code: =============================================================================== --\ mediagoblin/moderation/tools.py --| Encapsulated the code around giving/taking away privileges into two | funtions. --\ mediagoblin/moderation/views.py --| Imported and used the give/take away privilege functions --| Replaced 'require_admin_or_moderator_login' with |'user_has_privilege(u"admin")' for adding/taking away privileges, only | admins are allowed to do this. --\ mediagoblin/templates/mediagoblin/banned.html --| Added relevant translation tags --| Added ability to display indefinite banning --\ mediagoblin/templates/mediagoblin/user_pages/media.html --| Made sure the add comments button was only visible for users with the | `commenter` privilege --\ mediagoblin/tests/test_submission.py --| Paroneayea fixed a DetachedInstanceError I was having with the our_user | function --\ mediagoblin/tests/tools.py --| Added a fixture_add_comment_report function for testing. --\ mediagoblin/tools/response.py --| Fixed a minor error where a necessary return statement was missing --| Fit the code within 80 columns --\ mediagoblin/user_pages/views.py --| Added a necessary decorator to ensure that only users with the 'commenter' | privilege can post comments =============================================================================== Wrote new tests for an old test file: =============================================================================== --\ mediagoblin/tests/test_auth.py --| Added a new test to make sure privilege granting on registration happens | correctly --\ mediagoblin/tests/test_modelmethods.py* --| Added a test to ensure the User method has_privilege works properly =============================================================================== Wrote entirely new files full of tests: =============================================================================== --\ mediagoblin/tests/test_moderation.py --\ mediagoblin/tests/test_privileges.py --\ mediagoblin/tests/test_reporting.py =============================================================================== =============================================================================== NOTE: Any files I've marked with a * in this commit report, were actually subm- itted in my last commit. I made that committ to fix an error I was having, so they weren't properly documented in that report. =============================================================================== =============================================================================== --- mediagoblin/auth/tools.py | 4 +- mediagoblin/db/migrations.py | 20 +- mediagoblin/db/models.py | 60 ++--- mediagoblin/db/util.py | 18 -- mediagoblin/decorators.py | 4 +- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/moderation/forms.py | 4 +- mediagoblin/moderation/tools.py | 53 ++++- mediagoblin/moderation/views.py | 29 +-- mediagoblin/templates/mediagoblin/banned.html | 11 +- .../mediagoblin/moderation/media_panel.html | 4 +- .../mediagoblin/moderation/report.html | 18 +- .../mediagoblin/moderation/report_panel.html | 18 +- .../mediagoblin/moderation/user.html | 4 +- .../mediagoblin/moderation/user_panel.html | 4 +- .../mediagoblin/user_pages/media.html | 2 +- .../mediagoblin/user_pages/report.html | 24 +- .../templates/mediagoblin/utils/report.html | 2 +- mediagoblin/tests/test_auth.py | 7 + mediagoblin/tests/test_moderation.py | 194 +++++++++++++++++ mediagoblin/tests/test_notifications.py | 1 - mediagoblin/tests/test_privileges.py | 206 ++++++++++++++++++ mediagoblin/tests/test_reporting.py | 165 ++++++++++++++ mediagoblin/tests/test_submission.py | 30 ++- mediagoblin/tests/tools.py | 34 ++- mediagoblin/tools/response.py | 11 +- mediagoblin/user_pages/lib.py | 10 +- mediagoblin/user_pages/views.py | 11 +- 28 files changed, 793 insertions(+), 157 deletions(-) create mode 100644 mediagoblin/tests/test_moderation.py create mode 100644 mediagoblin/tests/test_privileges.py create mode 100644 mediagoblin/tests/test_reporting.py diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py index f758bca4..76b37e29 100644 --- a/mediagoblin/auth/tools.py +++ b/mediagoblin/auth/tools.py @@ -164,13 +164,13 @@ def register_user(request, register_form): user = auth.create_user(register_form) # give the user the default privileges - default_privileges = [ + default_privileges = [ Privilege.query.filter(Privilege.privilege_name==u'commenter').first(), Privilege.query.filter(Privilege.privilege_name==u'uploader').first(), Privilege.query.filter(Privilege.privilege_name==u'reporter').first()] user.all_privileges += default_privileges user.save() - + # log the user in request.session['user_id'] = unicode(user.id) request.session.save() diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 762d17e6..a97458b6 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -28,7 +28,7 @@ from migrate.changeset.constraint import UniqueConstraint from mediagoblin.db.extratypes import JSONEncoded from mediagoblin.db.migration_tools import RegisterMigration, inspect_table -from mediagoblin.db.models import (MediaEntry, Collection, User, +from mediagoblin.db.models import (MediaEntry, Collection, User, MediaComment, Privilege, ReportBase) MIGRATIONS = {} @@ -425,7 +425,7 @@ class RequestToken_v0(declarative_base()): callback = Column(Unicode, nullable=False, default=u"oob") created = Column(DateTime, nullable=False, default=datetime.datetime.now) updated = Column(DateTime, nullable=False, default=datetime.datetime.now) - + class AccessToken_v0(declarative_base()): """ Model for representing the access tokens @@ -438,7 +438,7 @@ class AccessToken_v0(declarative_base()): request_token = Column(Unicode, ForeignKey(RequestToken_v0.token)) created = Column(DateTime, nullable=False, default=datetime.datetime.now) updated = Column(DateTime, nullable=False, default=datetime.datetime.now) - + class NonceTimestamp_v0(declarative_base()): """ @@ -467,7 +467,7 @@ class ReportBase_v0(declarative_base()): reporter_id = Column(Integer, ForeignKey(User.id), nullable=False) report_content = Column(UnicodeText) reported_user_id = Column(Integer, ForeignKey(User.id), nullable=False) - created = Column(DateTime, nullable=False, default=datetime.datetime.now) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) discriminator = Column('type', Unicode(50)) __mapper_args__ = {'polymorphic_on': discriminator} @@ -512,14 +512,14 @@ class Privilege_v0(declarative_base()): class PrivilegeUserAssociation_v0(declarative_base()): __tablename__ = 'core__privileges_users' group_id = Column( - 'core__privilege_id', - Integer, - ForeignKey(User.id), + 'core__privilege_id', + Integer, + ForeignKey(User.id), primary_key=True) user_id = Column( - 'core__user_id', - Integer, - ForeignKey(Privilege.id), + 'core__user_id', + Integer, + ForeignKey(Privilege.id), primary_key=True) @RegisterMigration(15, MIGRATIONS) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 62c5a5d5..dd2cd3e9 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -669,7 +669,7 @@ class ReportBase(Base): id = Column(Integer, primary_key=True) reporter_id = Column(Integer, ForeignKey(User.id), nullable=False) reporter = relationship( - User, + User, backref=backref("reports_filed_by", lazy="dynamic", cascade="all, delete-orphan"), @@ -677,7 +677,7 @@ class ReportBase(Base): report_content = Column(UnicodeText) reported_user_id = Column(Integer, ForeignKey(User.id), nullable=False) reported_user = relationship( - User, + User, backref=backref("reports_filed_on", lazy="dynamic", cascade="all, delete-orphan"), @@ -722,7 +722,7 @@ class MediaReport(ReportBase): primary_key=True) media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) media_entry = relationship( - MediaEntry, + MediaEntry, backref=backref("reports_filed_onmod/reports/1/", lazy="dynamic", cascade="all, delete-orphan")) @@ -738,7 +738,7 @@ class ArchivedReport(ReportBase): media_entry_id = Column(Integer, ForeignKey(MediaEntry.id)) media_entry = relationship( - MediaEntry, + MediaEntry, backref=backref("past_reports_filed_on", lazy="dynamic")) comment_id = Column(Integer, ForeignKey(MediaComment.id)) @@ -748,7 +748,7 @@ class ArchivedReport(ReportBase): resolver_id = Column(Integer, ForeignKey(User.id), nullable=False) resolver = relationship( - User, + User, backref=backref("reports_resolved_by", lazy="dynamic", cascade="all, delete-orphan"), @@ -759,23 +759,23 @@ class ArchivedReport(ReportBase): class UserBan(Base): """ - Holds the information on a specific user's ban-state. As long as one of - these is attached to a user, they are banned from accessing mediagoblin. - When they try to log in, they are greeted with a page that tells them - the reason why they are banned and when (if ever) the ban will be + Holds the information on a specific user's ban-state. As long as one of + these is attached to a user, they are banned from accessing mediagoblin. + When they try to log in, they are greeted with a page that tells them + the reason why they are banned and when (if ever) the ban will be lifted - :keyword user_id Holds the id of the user this object is - attached to. This is a one-to-one + :keyword user_id Holds the id of the user this object is + attached to. This is a one-to-one relationship. - :keyword expiration_date Holds the date that the ban will be lifted. - If this is null, the ban is permanent + :keyword expiration_date Holds the date that the ban will be lifted. + If this is null, the ban is permanent unless a moderator manually lifts it. :keyword reason Holds the reason why the user was banned. """ __tablename__ = 'core__user_bans' - user_id = Column(Integer, ForeignKey(User.id), nullable=False, + user_id = Column(Integer, ForeignKey(User.id), nullable=False, primary_key=True) expiration_date = Column(DateTime) reason = Column(UnicodeText, nullable=False) @@ -785,21 +785,21 @@ class Privilege(Base): """ The Privilege table holds all of the different privileges a user can hold. If a user 'has' a privilege, the User object is in a relationship with the - privilege object. + privilege object. :keyword privilege_name Holds a unicode object that is the recognizable - name of this privilege. This is the column + name of this privilege. This is the column used for identifying whether or not a user has a necessary privilege or not. - + """ __tablename__ = 'core__privileges' id = Column(Integer, nullable=False, primary_key=True) privilege_name = Column(Unicode, nullable=False, unique=True) all_users = relationship( - User, - backref='all_privileges', + User, + backref='all_privileges', secondary="core__privileges_users") def __init__(self, privilege_name): @@ -818,25 +818,25 @@ class PrivilegeUserAssociation(Base): ''' This table holds the many-to-many relationship between User and Privilege ''' - + __tablename__ = 'core__privileges_users' privilege_id = Column( - 'core__privilege_id', - Integer, - ForeignKey(User.id), + 'core__privilege_id', + Integer, + ForeignKey(User.id), primary_key=True) user_id = Column( - 'core__user_id', - Integer, - ForeignKey(Privilege.id), + 'core__user_id', + Integer, + ForeignKey(Privilege.id), primary_key=True) MODELS = [ User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData, Notification, CommentNotification, ProcessingNotification, Client, - CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan, + CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan, Privilege, PrivilegeUserAssociation, ArchivedReport, RequestToken, AccessToken, NonceTimestamp] @@ -854,10 +854,10 @@ MODELS = [ FOUNDATIONS = {User:user_foundations} """ -privilege_foundations = [{'privilege_name':u'admin'}, - {'privilege_name':u'moderator'}, +privilege_foundations = [{'privilege_name':u'admin'}, + {'privilege_name':u'moderator'}, {'privilege_name':u'uploader'}, - {'privilege_name':u'reporter'}, + {'privilege_name':u'reporter'}, {'privilege_name':u'commenter'}, {'privilege_name':u'active'}] FOUNDATIONS = {Privilege:privilege_foundations} diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 31fc49fb..2488dcac 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -68,24 +68,6 @@ 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] - #TODO update this to account for plugins that may add foundations - for privilege in FOUNDATIONS[Privilege]: - privilege_name = privilege['privilege_name'] - 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/decorators.py b/mediagoblin/decorators.py index a3479164..1a8b124b 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -24,7 +24,7 @@ from mediagoblin import mg_globals as mgg from mediagoblin import messages from mediagoblin.db.models import (MediaEntry, User, MediaComment, UserBan, Privilege) -from mediagoblin.tools.response import (redirect, render_404, +from mediagoblin.tools.response import (redirect, render_404, render_user_banned, json_response) from mediagoblin.tools.translate import pass_to_ugettext as _ @@ -358,7 +358,7 @@ def oauth_required(controller): error = "Missing required parameter." return json_response({"error": error}, status=400) - + request_validator = GMGRequestValidator() resource_endpoint = ResourceEndpoint(request_validator) valid, request = resource_endpoint.validate_protected_resource_request( diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 0002daad..d319cef9 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -55,7 +55,7 @@ def adduser(args): entry.pw_hash = auth.gen_password_hash(args.password) entry.status = u'active' entry.email_verified = True - default_privileges = [ + default_privileges = [ db.Privilege.query.filter( db.Privilege.privilege_name==u'commenter').one(), db.Privilege.query.filter( diff --git a/mediagoblin/moderation/forms.py b/mediagoblin/moderation/forms.py index 718cd8fa..a3202359 100644 --- a/mediagoblin/moderation/forms.py +++ b/mediagoblin/moderation/forms.py @@ -28,7 +28,7 @@ class MultiCheckboxField(wtforms.SelectMultipleField): 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) @@ -40,7 +40,7 @@ class PrivilegeAddRemoveForm(wtforms.Form): class ReportResolutionForm(wtforms.Form): action_to_resolve = MultiCheckboxField( - _(u'What action will you take to resolve the report?'), + _(u'What action will you take to resolve the report?'), validators=[wtforms.validators.optional()], choices=ACTION_CHOICES) targeted_user = wtforms.HiddenField('', diff --git a/mediagoblin/moderation/tools.py b/mediagoblin/moderation/tools.py index b4daca15..d58df3a8 100644 --- a/mediagoblin/moderation/tools.py +++ b/mediagoblin/moderation/tools.py @@ -31,17 +31,15 @@ def take_punitive_actions(request, form, report, user): # 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.query.filter( - Privilege.privilege_name==privilege_name).one() + take_away_privileges(user.username, privilege_name) form.resolution_content.data += \ - u"
%s took away %s\'s %s privileges" % ( + u"
%s took away %s\'s %s privileges." % ( request.user.username, user.username, - privilege.privilege_name) - user.all_privileges.remove(privilege) + privilege_name) # If the moderator elects to ban the user, a new instance of user_ban - # will be created. + # will be created. if u'userban' in form.action_to_resolve.data: reason = form.resolution_content.data + \ "
"+request.user.username @@ -51,7 +49,7 @@ def take_punitive_actions(request, form, report, user): 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." % ( @@ -86,17 +84,17 @@ def take_punitive_actions(request, form, report, user): deleted_comment = report.comment Session.delete(deleted_comment) form.resolution_content.data += \ - u"
%s deleted the comment" % ( + u"
%s deleted the comment." % ( request.user.username) elif u'delete' in form.action_to_resolve.data and \ - report.is_media_entry_report(): + 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) + u"
%s deleted the media entry." % ( + request.user.username) - # If the moderator didn't delete the content we then attach the + # 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(): @@ -133,3 +131,34 @@ def take_punitive_actions(request, form, report, user): request, 'mediagoblin.moderation.reports_detail', report_id=report.id) + +def take_away_privileges(user,*privileges): + if len(privileges) == 1: + privilege = Privilege.query.filter( + Privilege.privilege_name==privileges[0]).first() + user = User.query.filter( + User.username==user).first() + if privilege in user.all_privileges: + user.all_privileges.remove(privilege) + return True + return False + + elif len(privileges) > 1: + return (take_away_privileges(user, privileges[0]) and \ + take_away_privileges(user, *privileges[1:])) + +def give_privileges(user,*privileges): + if len(privileges) == 1: + privilege = Privilege.query.filter( + Privilege.privilege_name==privileges[0]).first() + user = User.query.filter( + User.username==user).first() + if privilege not in user.all_privileges: + user.all_privileges.append(privilege) + return True + return False + + elif len(privileges) > 1: + return (give_privileges(user, privileges[0]) and \ + give_privileges(user, *privileges[1:])) + diff --git a/mediagoblin/moderation/views.py b/mediagoblin/moderation/views.py index d82eca7d..b2223744 100644 --- a/mediagoblin/moderation/views.py +++ b/mediagoblin/moderation/views.py @@ -19,12 +19,12 @@ from werkzeug.exceptions import Forbidden from mediagoblin.db.models import (MediaEntry, User, MediaComment, \ CommentReport, ReportBase, Privilege, \ UserBan, ArchivedReport) -from mediagoblin.db.util import user_privileges_to_dictionary from mediagoblin.decorators import (require_admin_or_moderator_login, \ - active_user_from_url) + active_user_from_url, user_has_privilege) 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 mediagoblin.moderation.tools import (take_punitive_actions, \ + take_away_privileges, give_privileges) from datetime import datetime @require_admin_or_moderator_login @@ -86,7 +86,7 @@ def moderation_users_detail(request): @require_admin_or_moderator_login def moderation_reports_panel(request): ''' - Show the global panel for monitoring reports filed against comments or + Show the global panel for monitoring reports filed against comments or media entries for this instance. ''' report_list = ReportBase.query.filter( @@ -115,7 +115,7 @@ def moderation_reports_detail(request): form.take_away_privileges.choices = [ (s.privilege_name,s.privilege_name.title()) \ - for s in report.reported_user.all_privileges + for s in report.reported_user.all_privileges ] if request.method == "POST" and form.validate() and not ( @@ -134,7 +134,7 @@ def moderation_reports_detail(request): {'report':report, 'form':form}) -@require_admin_or_moderator_login +@user_has_privilege(u'admin') @active_user_from_url def give_or_take_away_privilege(request, url_user): ''' @@ -144,12 +144,13 @@ def give_or_take_away_privilege(request, url_user): if request.method == "POST" and form.validate(): privilege = Privilege.query.filter( Privilege.privilege_name==form.privilege_name.data).one() - if privilege in url_user.all_privileges: - url_user.all_privileges.remove(privilege) - else: - url_user.all_privileges.append(privilege) + if not take_away_privileges( + url_user.username, form.privilege_name.data): + + give_privileges(url_user.username, form.privilege_name.data) url_user.save() - return redirect( - request, - 'mediagoblin.moderation.users_detail', - user=url_user.username) + + return redirect( + request, + 'mediagoblin.moderation.users_detail', + user=url_user.username) diff --git a/mediagoblin/templates/mediagoblin/banned.html b/mediagoblin/templates/mediagoblin/banned.html index 4eda0540..cd54158a 100644 --- a/mediagoblin/templates/mediagoblin/banned.html +++ b/mediagoblin/templates/mediagoblin/banned.html @@ -17,12 +17,19 @@ #} {% extends "mediagoblin/base.html" %} -{% block title %}You are Banned.{% endblock %} +{% block title %}{% trans %}You are Banned.{% endtrans %}{% endblock %} {% block mediagoblin_content %} {% trans %}Image of goblin stressing out{% endtrans %} -

You have been banned until {{ expiration_date }}

+ +

{% trans %}You have been banned{% endtrans %} + {% if expiration_date %} + {% trans %}until{% endtrans %} {{ expiration_date }} + {% else %} + {% trans %}indefinitely{% endtrans %} + {% endif %} +

{{ reason|safe }}

{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/moderation/media_panel.html b/mediagoblin/templates/mediagoblin/moderation/media_panel.html index 1c3c866e..d6e02db8 100644 --- a/mediagoblin/templates/mediagoblin/moderation/media_panel.html +++ b/mediagoblin/templates/mediagoblin/moderation/media_panel.html @@ -28,7 +28,7 @@

{% trans %}Here you can track the state of media being processed on this instance.{% endtrans %}

- +

{% trans %}Media in-processing{% endtrans %}

{% if processing_entries.count() %} @@ -56,7 +56,7 @@ {% else %}

{% trans %}No media in-processing{% endtrans %}

-{% endif %} +{% endif %}

{% trans %}These uploads failed to process:{% endtrans %}

{% if failed_entries.count() %} diff --git a/mediagoblin/templates/mediagoblin/moderation/report.html b/mediagoblin/templates/mediagoblin/moderation/report.html index 04788f05..fafa8b8a 100644 --- a/mediagoblin/templates/mediagoblin/moderation/report.html +++ b/mediagoblin/templates/mediagoblin/moderation/report.html @@ -27,7 +27,7 @@ title="Return to Reports Panel"> {% trans %}Return to Reports Panel{% endtrans %}

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

- {% if report.is_comment_report() or + {% if report.is_comment_report() or (report.is_archived_report() and report.comment) %} {% trans %}Reported comment{% endtrans %}: @@ -60,7 +60,7 @@ {% endautoescape %} - {% elif report.is_media_entry_report() or + {% elif report.is_media_entry_report() or (report.is_archived_report() and report.media_entry) %} {% set media_entry = report.media_entry %} @@ -89,7 +89,7 @@ 'mediagoblin.moderation.users_detail', user=report.reporter.username), user_name=report.reported_user.username %} - CONTENT BY + CONTENT BY {{ user_name }} HAS BEEN DELETED {% endtrans %} @@ -100,8 +100,8 @@ class="report_wrapper">
Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. 
+                  '/images/icon_clipboard_alert.png') }} {% elif not (report.reported_user.has_privilege('admin')) %} -

Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license.
-                  Distributed by the GNOME project http://www.gnome.org + Distributed by the GNOME project http://www.gnome.org" /> {% trans %}Status{% endtrans %}:

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

{{ report.result }}

diff --git a/mediagoblin/templates/mediagoblin/moderation/report_panel.html b/mediagoblin/templates/mediagoblin/moderation/report_panel.html index 2818eb80..fb9d8cd9 100644 --- a/mediagoblin/templates/mediagoblin/moderation/report_panel.html +++ b/mediagoblin/templates/mediagoblin/moderation/report_panel.html @@ -30,7 +30,7 @@ Here you can look up open reports that have been filed by users. {% endtrans %}

- +

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

{% if report_list.count() %} @@ -46,22 +46,22 @@ {% if report.discriminator == "comment_report" %} - 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 }} + Comment Report #{{ report_id }} {% endtrans %} {% elif report.discriminator == "media_report" %} - Under a GNU LGPL v.3 or Creative Commons BY-SA 3.0 license.
                    Distributed by the GNOME project http://www.gnome.org {{ user.username }}'s report history

{{ user.username }}'s Privileges

- {% if request.user.has_privilege('admin') and not user_banned and + {% if request.user.has_privilege('admin') and not user_banned and not user.id == request.user.id %} - {% elif request.user.has_privilege('admin') and not user.id == request.user.id %} diff --git a/mediagoblin/templates/mediagoblin/moderation/user_panel.html b/mediagoblin/templates/mediagoblin/moderation/user_panel.html index 6762a844..54ef7c11 100644 --- a/mediagoblin/templates/mediagoblin/moderation/user_panel.html +++ b/mediagoblin/templates/mediagoblin/moderation/user_panel.html @@ -30,7 +30,7 @@ Here you can look up users in order to take punitive actions on them. {% endtrans %}

- +

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

{% if user_list.count() %} @@ -57,5 +57,5 @@ {% else %}

{% trans %}No users found.{% endtrans %}

-{% endif %} +{% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index e161afc9..b92cf39c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -86,7 +86,7 @@ {% autoescape False %}

{{ media.description_html }}

{% endautoescape %} - {% if comments %} + {% if comments and request.user.has_privilege('commenter') %} {% if app_config['allow_comments'] %}
- @@ -42,7 +42,7 @@ - {%- trans formatted_time=timesince(comment.created) -%} @@ -59,19 +59,19 @@ {% elif media is defined %}

{% trans %}Reporting this Media Entry{% endtrans %}

{%- trans user_url = request.urlgen('mediagoblin.user_pages.user_home', user=media.get_uploader.username), username = media.get_uploader.username %} - ❖ Published by {{ username }} {% endtrans %} {%- endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/report.html b/mediagoblin/templates/mediagoblin/utils/report.html index 4108cd82..2fa4f959 100644 --- a/mediagoblin/templates/mediagoblin/utils/report.html +++ b/mediagoblin/templates/mediagoblin/utils/report.html @@ -18,7 +18,7 @@ {% block report_content -%}

- . + +import pytest + +from mediagoblin.tests.tools import (fixture_add_user, + fixture_add_comment_report, fixture_add_comment) +from mediagoblin.db.models import User, CommentReport, MediaComment, UserBan +from mediagoblin.moderation.tools import take_away_privileges, give_privileges +from mediagoblin.tools import template, mail + +from webtest import AppError + +class TestModerationViews: + @pytest.fixture(autouse=True) + def _setup(self, test_app): + self.test_app = test_app + + fixture_add_user(u'admin', + privileges=[u'admin',u'active']) + fixture_add_user(u'moderator', + privileges=[u'moderator',u'active']) + fixture_add_user(u'regular', + privileges=[u'active',u'commenter']) + self.query_for_users() + + def login(self, username): + self.test_app.post( + '/auth/login/', { + 'username': username, + 'password': 'toast'}) + self.query_for_users() + + def logout(self): + self.test_app.get('/auth/logout/') + self.query_for_users() + + def query_for_users(self): + self.admin_user = User.query.filter(User.username==u'admin').first() + self.mod_user = User.query.filter(User.username==u'moderator').first() + self.user = User.query.filter(User.username==u'regular').first() + + def do_post(self, data, *context_keys, **kwargs): + url = kwargs.pop('url', '/submit/') + do_follow = kwargs.pop('do_follow', False) + template.clear_test_template_context() + response = self.test_app.post(url, data, **kwargs) + if do_follow: + response.follow() + context_data = template.TEMPLATE_TEST_CONTEXT + for key in context_keys: + context_data = context_data[key] + return response, context_data + + def testGiveOrTakeAwayPrivileges(self): + self.login(u'admin') + # First, test an admin taking away a privilege from a user + #---------------------------------------------------------------------- + response, context = self.do_post({'privilege_name':u'commenter'}, + url='/mod/users/{0}/privilege/'.format(self.user.username)) + assert response.status == '302 FOUND' + self.query_for_users() + assert not self.user.has_privilege(u'commenter') + + # Then, test an admin giving a privilege to a user + #---------------------------------------------------------------------- + response, context = self.do_post({'privilege_name':u'commenter'}, + url='/mod/users/{0}/privilege/'.format(self.user.username)) + assert response.status == '302 FOUND' + self.query_for_users() + assert self.user.has_privilege(u'commenter') + + # Then, test a mod trying to take away a privilege from a user + # they are not allowed to do this, so this will raise an error + #---------------------------------------------------------------------- + self.logout() + self.login(u'moderator') + + with pytest.raises(AppError) as excinfo: + response, context = self.do_post({'privilege_name':u'commenter'}, + url='/mod/users/{0}/privilege/'.format(self.user.username)) + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + self.query_for_users() + + assert self.user.has_privilege(u'commenter') + + def testReportResolution(self): + self.login(u'moderator') + + # First, test a moderators taking away a user's privilege in response + # to a reported comment + #---------------------------------------------------------------------- + fixture_add_comment_report(reported_user=self.user) + comment_report = CommentReport.query.filter( + CommentReport.reported_user==self.user).first() + + response = self.test_app.get('/mod/reports/{0}/'.format( + comment_report.id)) + assert response.status == '200 OK' + self.query_for_users() + comment_report = CommentReport.query.filter( + CommentReport.reported_user==self.user).first() + + response, context = self.do_post({'action_to_resolve':[u'takeaway'], + 'take_away_privileges':[u'commenter'], + 'targeted_user':self.user.id}, + url='/mod/reports/{0}/'.format(comment_report.id)) + + assert response.status == '302 FOUND' + fixture_add_comment_report(reported_user=self.user) + comment_report = CommentReport.query.filter( + CommentReport.reported_user==self.user).first() + + assert not self.user.has_privilege(u'commenter') + + # Then, test a moderator sending an email to a user in response to a + # reported comment + #---------------------------------------------------------------------- + self.query_for_users() + + response, context = self.do_post({'action_to_resolve':[u'sendmessage'], + 'message_to_user':'This is your last warning, regular....', + 'targeted_user':self.user.id}, + url='/mod/reports/{0}/'.format(comment_report.id)) + + assert response.status == '302 FOUND' + assert mail.EMAIL_TEST_MBOX_INBOX == [{'to': [u'regular@example.com'], + 'message': 'Content-Type: text/plain; charset="utf-8"\n\ +MIME-Version: 1.0\nContent-Transfer-Encoding: base64\nSubject: Warning from- \ +moderator \nFrom: notice@mediagoblin.example.org\nTo: regular@example.com\n\n\ +VGhpcyBpcyB5b3VyIGxhc3Qgd2FybmluZywgcmVndWxhci4uLi4=\n', + 'from': 'notice@mediagoblin.example.org'}] + + # Then test a moderator banning a user AND a moderator deleting the + # offending comment. This also serves as a test for taking multiple + # actions to resolve a report + #---------------------------------------------------------------------- + self.query_for_users() + fixture_add_comment(author=self.user.id, + comment=u'Comment will be removed') + test_comment = MediaComment.query.filter( + MediaComment.author==self.user.id).first() + fixture_add_comment_report(comment=test_comment, + reported_user=self.user) + comment_report = CommentReport.query.filter( + CommentReport.reported_user==self.user).first() + + response, context = self.do_post( + {'action_to_resolve':[u'userban', u'delete'], + 'targeted_user':self.user.id}, + url='/mod/reports/{0}/'.format(comment_report.id)) + assert response.status == '302 FOUND' + self.query_for_users() + test_user_ban = UserBan.query.filter( + UserBan.user_id == self.user.id).first() + assert test_user_ban is not None + test_comment = MediaComment.query.filter( + MediaComment.author==self.user.id).first() + assert test_comment is None + + # Then, test what happens when a moderator attempts to punish an admin + # from a reported comment on an admin. + #---------------------------------------------------------------------- + fixture_add_comment_report(reported_user=self.admin_user) + comment_report = CommentReport.query.filter( + CommentReport.reported_user==self.admin_user).first() + + response, context = self.do_post({'action_to_resolve':[u'takeaway'], + 'take_away_privileges':[u'active'], + 'targeted_user':self.admin_user.id}, + url='/mod/reports/{0}/'.format(comment_report.id)) + self.query_for_users() + + assert response.status == '200 OK' + assert self.admin_user.has_privilege(u'active') + + def testAllModerationViews(self): + self.login(u'moderator') + self.test_app.get('/mod/reports/') + self.test_app.get('/mod/users/') + self.test_app.get('/mod/media/') diff --git a/mediagoblin/tests/test_notifications.py b/mediagoblin/tests/test_notifications.py index 8420e358..2b414590 100644 --- a/mediagoblin/tests/test_notifications.py +++ b/mediagoblin/tests/test_notifications.py @@ -127,7 +127,6 @@ otherperson@example.com\n\nSGkgb3RoZXJwZXJzb24sCmNocmlzIGNvbW1lbnRlZCBvbiB5b3VyI else: assert mail.EMAIL_TEST_MBOX_INBOX == [] - mail.EMAIL_TEST_MBOX_INBOX = [] # Save the ids temporarily because of DetachedInstanceError notification_id = notification.id diff --git a/mediagoblin/tests/test_privileges.py b/mediagoblin/tests/test_privileges.py new file mode 100644 index 00000000..ced87b7f --- /dev/null +++ b/mediagoblin/tests/test_privileges.py @@ -0,0 +1,206 @@ +# 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 . + +import pytest +from datetime import datetime, timedelta +from webtest import AppError + +from mediagoblin.tests.tools import fixture_add_user, fixture_media_entry + +from mediagoblin.db.models import User, Privilege, UserBan +from mediagoblin.db.base import Session +from mediagoblin.tools import template + +from .resources import GOOD_JPG + +class TestPrivilegeFunctionality: + + @pytest.fixture(autouse=True) + def _setup(self, test_app): + self.test_app = test_app + + fixture_add_user(u'alex', + privileges=[u'admin',u'active']) + fixture_add_user(u'raven', + privileges=[u'moderator',u'active',u'reporter']) + fixture_add_user(u'natalie', + privileges=[u'active']) + self.query_for_users() + + def login(self, username): + self.test_app.post( + '/auth/login/', { + 'username': username, + 'password': 'toast'}) + self.query_for_users() + + def logout(self): + self.test_app.get('/auth/logout/') + self.query_for_users() + + def do_post(self, data, *context_keys, **kwargs): + url = kwargs.pop('url', '/submit/') + do_follow = kwargs.pop('do_follow', False) + template.clear_test_template_context() + response = self.test_app.post(url, data, **kwargs) + if do_follow: + response.follow() + context_data = template.TEMPLATE_TEST_CONTEXT + for key in context_keys: + context_data = context_data[key] + return response, context_data + + def query_for_users(self): + self.admin_user = User.query.filter(User.username==u'alex').first() + self.mod_user = User.query.filter(User.username==u'raven').first() + self.user = User.query.filter(User.username==u'natalie').first() + + def testUserBanned(self): + self.login(u'natalie') + uid = self.user.id + # First, test what happens when a user is banned indefinitely + #---------------------------------------------------------------------- + user_ban = UserBan(user_id=uid, + reason=u'Testing whether user is banned', + expiration_date=None) + user_ban.save() + + response = self.test_app.get('/') + assert response.status == "200 OK" + assert "You are Banned" in response.body + # Then test what happens when that ban has an expiration date which + # hasn't happened yet + #---------------------------------------------------------------------- + user_ban = UserBan.query.get(uid) + user_ban.delete() + user_ban = UserBan(user_id=uid, + reason=u'Testing whether user is banned', + expiration_date= datetime.now() + timedelta(days=20)) + user_ban.save() + + response = self.test_app.get('/') + assert response.status == "200 OK" + assert "You are Banned" in response.body + + # Then test what happens when that ban has an expiration date which + # has already happened + #---------------------------------------------------------------------- + user_ban = UserBan.query.get(uid) + user_ban.delete() + exp_date = datetime.now() - timedelta(days=20) + user_ban = UserBan(user_id=uid, + reason=u'Testing whether user is banned', + expiration_date= exp_date) + user_ban.save() + + response = self.test_app.get('/') + assert response.status == "302 FOUND" + assert not "You are Banned" in response.body + + def testVariousPrivileges(self): + # The various actions that require privileges (ex. reporting, + # commenting, moderating...) are tested in other tests. This method + # will be used to ensure that those actions are impossible for someone + # without the proper privileges. + # For other tests that show what happens when a user has the proper + # privileges, check out: + # tests/test_moderation.py moderator + # tests/test_notifications.py commenter + # tests/test_reporting.py reporter + # tests/test_submission.py uploader + #---------------------------------------------------------------------- + self.login(u'natalie') + + # First test the get and post requests of submission/uploading + #---------------------------------------------------------------------- + with pytest.raises(AppError) as excinfo: + response = self.test_app.get('/submit/') + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + + with pytest.raises(AppError) as excinfo: + response = self.do_post({'upload_files':[('file',GOOD_JPG)], + 'title':u'Normal Upload 1'}, + url='/submit/') + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + # Test that a user cannot comment without the commenter privilege + #---------------------------------------------------------------------- + self.query_for_users() + + media_entry = fixture_media_entry(uploader=self.admin_user.id, + state=u'processed') + + media_entry_id = media_entry.id + media_uri_id = '/u/{0}/m/{1}/'.format(self.admin_user.username, + media_entry.id) + media_uri_slug = '/u/{0}/m/{1}/'.format(self.admin_user.username, + media_entry.slug) + response = self.test_app.get(media_uri_slug) + assert not "Add a comment" in response.body + + self.query_for_users() + with pytest.raises(AppError) as excinfo: + response = self.test_app.post( + media_uri_id + 'comment/add/', + {'comment_content': u'Test comment #42'}) + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + # Test that a user cannot report without the reporter privilege + #---------------------------------------------------------------------- + with pytest.raises(AppError) as excinfo: + response = self.test_app.get(media_uri_slug+"report/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + with pytest.raises(AppError) as excinfo: + response = self.do_post( + {'report_reason':u'Testing Reports #1', + 'reporter_id':u'3'}, + url=(media_uri_slug+"report/")) + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + # Test that a user cannot access the moderation pages w/o moderator + # or admin privileges + #---------------------------------------------------------------------- + with pytest.raises(AppError) as excinfo: + response = self.test_app.get("/mod/users/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + with pytest.raises(AppError) as excinfo: + response = self.test_app.get("/mod/reports/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + with pytest.raises(AppError) as excinfo: + response = self.test_app.get("/mod/media/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + with pytest.raises(AppError) as excinfo: + response = self.test_app.get("/mod/users/1/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + with pytest.raises(AppError) as excinfo: + response = self.test_app.get("/mod/reports/1/") + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) + + self.query_for_users() + + with pytest.raises(AppError) as excinfo: + response, context = self.do_post({'action_to_resolve':[u'takeaway'], + 'take_away_privileges':[u'active'], + 'targeted_user':self.admin_user.id}, + url='/mod/reports/1/') + self.query_for_users() + assert 'Bad response: 403 FORBIDDEN' in str(excinfo) diff --git a/mediagoblin/tests/test_reporting.py b/mediagoblin/tests/test_reporting.py new file mode 100644 index 00000000..1bc7df26 --- /dev/null +++ b/mediagoblin/tests/test_reporting.py @@ -0,0 +1,165 @@ +# 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 . + +import pytest + +from mediagoblin.tools import template +from mediagoblin.tests.tools import (fixture_add_user, fixture_media_entry, + fixture_add_comment, fixture_add_comment_report) +from mediagoblin.db.models import (MediaReport, CommentReport, User, + MediaComment,ArchivedReport) + + +class TestReportFiling: + @pytest.fixture(autouse=True) + def _setup(self, test_app): + self.test_app = test_app + + fixture_add_user(u'allie', + privileges=[u'reporter',u'active']) + fixture_add_user(u'natalie', + privileges=[u'active', u'moderator']) + + def login(self, username): + self.test_app.post( + '/auth/login/', { + 'username': username, + 'password': 'toast'}) + + def logout(self): + self.test_app.get('/auth/logout/') + + def do_post(self, data, *context_keys, **kwargs): + url = kwargs.pop('url', '/submit/') + do_follow = kwargs.pop('do_follow', False) + template.clear_test_template_context() + response = self.test_app.post(url, data, **kwargs) + if do_follow: + response.follow() + context_data = template.TEMPLATE_TEST_CONTEXT + for key in context_keys: + context_data = context_data[key] + return response, context_data + + def query_for_users(self): + return (User.query.filter(User.username==u'allie').first(), + User.query.filter(User.username==u'natalie').first()) + + def testMediaReports(self): + self.login(u'allie') + allie_user, natalie_user = self.query_for_users() + allie_id = allie_user.id + + media_entry = fixture_media_entry(uploader=natalie_user.id, + state=u'processed') + + mid = media_entry.id + media_uri_slug = '/u/{0}/m/{1}/'.format(natalie_user.username, + media_entry.slug) + + response = self.test_app.get(media_uri_slug + "report/") + assert response.status == "200 OK" + + response, context = self.do_post( + {'report_reason':u'Testing Media Report', + 'reporter_id':unicode(allie_id)},url= media_uri_slug + "report/") + + assert response.status == "302 FOUND" + + media_report = MediaReport.query.first() + + allie_user, natalie_user = self.query_for_users() + assert media_report is not None + assert media_report.report_content == u'Testing Media Report' + assert media_report.reporter_id == allie_id + assert media_report.reported_user_id == natalie_user.id + assert media_report.created is not None + assert media_report.discriminator == 'media_report' + + def testCommentReports(self): + self.login(u'allie') + allie_user, natalie_user = self.query_for_users() + allie_id = allie_user.id + + media_entry = fixture_media_entry(uploader=natalie_user.id, + state=u'processed') + mid = media_entry.id + fixture_add_comment(media_entry=mid, + author=natalie_user.id) + comment = MediaComment.query.first() + + comment_uri_slug = '/u/{0}/m/{1}/c/{2}/'.format(natalie_user.username, + media_entry.slug, + comment.id) + + response = self.test_app.get(comment_uri_slug + "report/") + assert response.status == "200 OK" + + response, context = self.do_post({ + 'report_reason':u'Testing Comment Report', + 'reporter_id':unicode(allie_id)},url= comment_uri_slug + "report/") + + assert response.status == "302 FOUND" + + comment_report = CommentReport.query.first() + + allie_user, natalie_user = self.query_for_users() + assert comment_report is not None + assert comment_report.report_content == u'Testing Comment Report' + assert comment_report.reporter_id == allie_id + assert comment_report.reported_user_id == natalie_user.id + assert comment_report.created is not None + assert comment_report.discriminator == 'comment_report' + + def testArchivingReports(self): + self.login(u'natalie') + allie_user, natalie_user = self.query_for_users() + allie_id, natalie_id = allie_user.id, natalie_user.id + + fixture_add_comment(author=allie_user.id, + comment=u'Comment will be removed') + test_comment = MediaComment.query.filter( + MediaComment.author==allie_user.id).first() + fixture_add_comment_report(comment=test_comment, + reported_user=allie_user, + report_content=u'Testing Archived Reports #1', + reporter=natalie_user) + comment_report = CommentReport.query.filter( + CommentReport.reported_user==allie_user).first() + + assert comment_report.report_content == u'Testing Archived Reports #1' + response, context = self.do_post( + {'action_to_resolve':[u'userban', u'delete'], + 'targeted_user':allie_user.id, + 'resolution_content':u'This is a test of archiving reports.'}, + url='/mod/reports/{0}/'.format(comment_report.id)) + + assert response.status == "302 FOUND" + self.query_for_users() + + archived_report = ArchivedReport.query.first() + + assert CommentReport.query.count() == 0 + assert archived_report is not None + assert archived_report.report_content == u'Testing Archived Reports #1' + assert archived_report.reporter_id == natalie_id + assert archived_report.reported_user_id == allie_id + assert archived_report.created is not None + assert archived_report.resolved is not None + assert archived_report.result == u'This is a test of archiving reports\ +.
natalie banned user allie indefinitely.
natalie deleted the comment.' + assert archived_report.discriminator == 'archived_report' + diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index ed088730..d10957d7 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -24,7 +24,7 @@ import pytest from mediagoblin.tests.tools import fixture_add_user from mediagoblin import mg_globals -from mediagoblin.db.models import MediaEntry, User +from mediagoblin.db.models import MediaEntry, User, Privilege from mediagoblin.tools import template from mediagoblin.media_types.image import ImageMediaManager from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites @@ -48,10 +48,20 @@ class TestSubmission: # @as_authenticated_user('chris') fixture_add_user(privileges=[u'active',u'uploader']) - self.test_user = User.query.filter(User.username==u'chris').first() - self.login() + def our_user(self): + """ + Fetch the user we're submitting with. Every .get() or .post() + invalidates the session; this is a hacky workaround. + """ + #### FIXME: Pytest collects this as a test and runs this. + #### ... it shouldn't. At least it passes, but that's + #### totally stupid. + #### Also if we found a way to make this run it should be a + #### property. + return User.query.filter(User.username==u'chris').first() + def login(self): self.test_app.post( '/auth/login/', { @@ -97,10 +107,10 @@ class TestSubmission: def check_normal_upload(self, title, filename): response, context = self.do_post({'title': title}, do_follow=True, **self.upload_data(filename)) - self.check_url(response, '/u/{0}/'.format(self.test_user.username)) + self.check_url(response, '/u/{0}/'.format(self.our_user().username)) assert 'mediagoblin/user_pages/user.html' in context # Make sure the media view is at least reachable, logged in... - url = '/u/{0}/m/{1}/'.format(self.test_user.username, + url = '/u/{0}/m/{1}/'.format(self.our_user().username, title.lower().replace(' ', '-')) self.test_app.get(url) # ... and logged out too. @@ -118,7 +128,7 @@ class TestSubmission: response, context = self.do_post({'title': u'Normal upload 3 (pdf)'}, do_follow=True, **self.upload_data(GOOD_PDF)) - self.check_url(response, '/u/{0}/'.format(self.test_user.username)) + self.check_url(response, '/u/{0}/'.format(self.our_user().username)) assert 'mediagoblin/user_pages/user.html' in context def check_media(self, request, find_data, count=None): @@ -164,7 +174,7 @@ class TestSubmission: # render and post to the edit page. edit_url = request.urlgen( 'mediagoblin.edit.edit_media', - user=self.test_user.username, media_id=media_id) + user=self.our_user().username, media_id=media_id) self.test_app.get(edit_url) self.test_app.post(edit_url, {'title': u'Balanced Goblin', @@ -177,7 +187,7 @@ class TestSubmission: self.check_comments(request, media_id, 0) comment_url = request.urlgen( 'mediagoblin.user_pages.media_post_comment', - user=self.test_user.username, media_id=media_id) + user=self.our_user().username, media_id=media_id) response = self.do_post({'comment_content': 'i love this test'}, url=comment_url, do_follow=True)[0] self.check_comments(request, media_id, 1) @@ -186,7 +196,7 @@ class TestSubmission: # --------------------------------------------------- delete_url = request.urlgen( 'mediagoblin.user_pages.media_confirm_delete', - user=self.test_user.username, media_id=media_id) + user=self.our_user().username, media_id=media_id) # Empty data means don't confirm response = self.do_post({}, do_follow=True, url=delete_url)[0] media = self.check_media(request, {'title': u'Balanced Goblin'}, 1) @@ -251,7 +261,7 @@ class TestSubmission: # they'll be caught as failures during the processing step. response, context = self.do_post({'title': title}, do_follow=True, **self.upload_data(filename)) - self.check_url(response, '/u/{0}/'.format(self.test_user.username)) + self.check_url(response, '/u/{0}/'.format(self.our_user().username)) entry = mg_globals.database.MediaEntry.query.filter_by(title=title).first() assert entry.state == 'failed' assert entry.fail_error == u'mediagoblin.processing:BadMediaFail' diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index feb83b44..1d035494 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -25,7 +25,7 @@ from webtest import TestApp from mediagoblin import mg_globals from mediagoblin.db.models import User, MediaEntry, Collection, MediaComment, \ - CommentSubscription, CommentNotification, Privilege + CommentSubscription, CommentNotification, Privilege, CommentReport from mediagoblin.tools import testing from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.db.base import Session @@ -33,6 +33,8 @@ from mediagoblin.meddleware import BaseMeddleware from mediagoblin.auth import gen_password_hash from mediagoblin.gmg_commands.dbupdate import run_dbupdate +from datetime import datetime + MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__' TEST_SERVER_CONFIG = pkg_resources.resource_filename( @@ -312,3 +314,33 @@ def fixture_add_comment(author=None, media_entry=None, comment=None): return comment +def fixture_add_comment_report(comment=None, reported_user=None, + reporter=None, created=None, report_content=None): + if comment is None: + comment = fixture_add_comment() + + if reported_user is None: + reported_user = fixture_add_user() + + if reporter is None: + reporter = fixture_add_user() + + if created is None: + created=datetime.now() + + if report_content is None: + report_content = \ + 'Auto-generated test report by user {0}'.format( + reporter) + + comment_report = CommentReport(comment=comment, + reported_user = reported_user, + reporter = reporter, + created = created, + report_content=report_content) + + comment_report.save() + + Session.expunge(comment_report) + + return comment_report diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py index a8cf1df9..3884de45 100644 --- a/mediagoblin/tools/response.py +++ b/mediagoblin/tools/response.py @@ -52,7 +52,8 @@ def render_400(request, err_msg=None): _ = pass_to_ugettext title = _("Bad Request") if err_msg is None: - err_msg = _("The request sent to the server is invalid, please double check it") + err_msg = _("The request sent to the server is invalid, \ +please double check it") return render_error(request, 400, title, err_msg) @@ -78,9 +79,11 @@ 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: + if (user_ban.expiration_date is not None and + datetime.now()>user_ban.expiration_date): + user_ban.delete() - redirect(request, + return redirect(request, 'index') return render_to_response(request, 'mediagoblin/banned.html', @@ -141,7 +144,7 @@ def json_response(serializable, _disable_cors=False, *args, **kw): Any extra arguments and keyword arguments are passed to the Response.__init__ method. ''' - + response = wz_Response(json.dumps(serializable), *args, content_type='application/json', **kw) if not _disable_cors: diff --git a/mediagoblin/user_pages/lib.py b/mediagoblin/user_pages/lib.py index 7f03fcd3..f29c1796 100644 --- a/mediagoblin/user_pages/lib.py +++ b/mediagoblin/user_pages/lib.py @@ -19,7 +19,7 @@ from mediagoblin.tools.template import render_template from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin import mg_globals from mediagoblin.db.base import Session -from mediagoblin.db.models import (CollectionItem, MediaReport, CommentReport, +from mediagoblin.db.models import (CollectionItem, MediaReport, CommentReport, MediaComment, MediaEntry) from mediagoblin.user_pages import forms as user_forms @@ -80,14 +80,14 @@ def add_media_to_collection(collection, media, note=None, commit=True): def build_report_object(report_form, media_entry=None, comment=None): """ - This function is used to convert a form object (from a User filing a + This function is used to convert a form object (from a User filing a report) into either a MediaReport or CommentReport object. - :param report_form should be a MediaReportForm or a CommentReportForm + :param report_form should be a MediaReportForm or a CommentReportForm object - :param + :param - :returns either of MediaReport or a CommentReport object that has not been + :returns either of MediaReport or a CommentReport object that has not been saved. In case of an improper form_dict, returns None """ diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 00fcf282..c2d2e66f 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -162,6 +162,7 @@ def media_home(request, media, page, **kwargs): @get_media_entry_by_id @require_active_login +@user_has_privilege(u'commenter') def media_post_comment(request, media): """ recieves POST from a MediaEntry() comment form, saves the comment. @@ -651,13 +652,13 @@ def file_a_report(request, media, comment=None): 'form':form} if request.method == "POST": - report_table = build_report_object(form, - media_entry=media, + report_object = build_report_object(form, + media_entry=media, comment=comment) # if the object was built successfully, report_table will not be None - if report_table: - report_table.save() + if report_object: + report_object.save() return redirect( request, 'index') @@ -671,5 +672,5 @@ def file_a_report(request, media, comment=None): @require_active_login @get_user_media_entry @get_media_comment_by_id -def file_a_comment_report(request, media, comment): +def file_a_comment_report(request, media, comment): return file_a_report(request, comment=comment) -- 2.25.1