Whew. This is a big update. I did some significant keeping work. I moved all of
the folders and enpoints labeled 'admin' to the more accurate term of 'moderat- ion.' I also created the ability for admins and moderators to add or remove pr- ivileges or to ban a user in response to a report. This also meant implementing the UserBan class in various places. I also had to add a column called result to the ReportBase table. This allows the moderator/admin to leave comments when they respond to a report, allowing for archiving of what responses they do/n't take. --\ mediagoblin/db/migrations.py --| Added result column to ReportBase --\ mediagoblin/db/models.py --| Added result column to ReportBase --| Added documentation to tables I had made previously --\ mediagoblin/decorators.py --| Editted the user_has_privilege decorator to check whether a user has been | banned or not --| Created a seperate user_not_banned decorator to prevent banned users from | accessing any pages --| Changed require_admin_login into require_admin_or_moderator login --\ mediagoblin/gmg_commands/users.py --| Made the gmg command `adduser` create a user w/ the appropriate privileges --\ mediagoblin/moderation/routing.py << formerly mediagoblin/admin/routing.py --| Renamed all of the routes from admin -> moderation --\ mediagoblin/routing.py --| Renamed all of the routes from admin -> moderation --\ mediagoblin/moderation/views.py << formerly mediagoblin/admin/views.py --| Renamed all of the routes & functions from admin -> moderation --| Expanded greatly on the moderation_reports_detail view and functionality --| Added in the give_or_take_away_privilege form, however this might be a use- | -less function which I could remove (because privilege changes should happe- | n in response to a report so they can be archived and visible) --\ mediagoblin/static/css/base.css --| Added in a style for the reports_detail page --\ mediagoblin/templates/mediagoblin/base.html --| Renamed all of the routes from admin -> moderation --\ mediagoblin/templates/mediagoblin/moderation/report.html --| Added form to allow moderators and admins to respond to reports. --\ mediagoblin/templates/mediagoblin/moderation/reports_panel.html --| Fixed the table for closed reports --\ mediagoblin/templates/mediagoblin/moderation/user.html --| Added in a table w/ all of the user's privileges and the option to add or | remove them. Again, this is probably vestigial --| Renamed all of the routes from admin -> moderation --\ mediagoblin/templates/mediagoblin/moderation/user_panel.html --| Renamed all of the routes from admin -> moderation --\ mediagoblin/tools/response.py --| Added function render_user_banned, this is the view function for the redir- | -ect that happens when a user tries to access the site whilst banned --\ mediagoblin/user_pages/forms.py --| Added important translate function where I had text --\ mediagoblin/user_pages/lib.py --| Renamed functiion for clarity --\ mediagoblin/user_pages/views.py --| Added the user_not_banned decorator to every view --\ mediagoblin/views.py --| Added the user_not_banned decorator --\ mediagoblin/moderation/forms.py --| Created this new file --\ mediagoblin/templates/mediagoblin/banned.html --| Created this new file --| This is the page which people are redirected to when they access the site | while banned
This commit is contained in:
16
mediagoblin/moderation/__init__.py
Normal file
16
mediagoblin/moderation/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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/>.
|
||||
|
||||
40
mediagoblin/moderation/forms.py
Normal file
40
mediagoblin/moderation/forms.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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/>.
|
||||
|
||||
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'))]
|
||||
|
||||
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()],
|
||||
choices=ACTION_CHOICES)
|
||||
targeted_user = wtforms.HiddenField('',
|
||||
validators=[wtforms.validators.required()])
|
||||
user_banned_until = wtforms.DateField(
|
||||
_('User will be banned until:'),
|
||||
format='%Y-%m-%d',
|
||||
validators=[wtforms.validators.optional()])
|
||||
resolution_content = wtforms.TextAreaField()
|
||||
|
||||
35
mediagoblin/moderation/routing.py
Normal file
35
mediagoblin/moderation/routing.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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/>.
|
||||
|
||||
moderation_routes = [
|
||||
('mediagoblin.moderation.media_panel',
|
||||
'/media/',
|
||||
'mediagoblin.moderation.views:moderation_media_processing_panel'),
|
||||
('mediagoblin.moderation.users',
|
||||
'/users/',
|
||||
'mediagoblin.moderation.views:moderation_users_panel'),
|
||||
('mediagoblin.moderation.reports',
|
||||
'/reports/',
|
||||
'mediagoblin.moderation.views:moderation_reports_panel'),
|
||||
('mediagoblin.moderation.users_detail',
|
||||
'/users/<string:user>/',
|
||||
'mediagoblin.moderation.views:moderation_users_detail'),
|
||||
('mediagoblin.moderation.give_or_take_away_privilege',
|
||||
'/users/<string:user>/privilege/',
|
||||
'mediagoblin.moderation.views:give_or_take_away_privilege'),
|
||||
('mediagoblin.moderation.reports_detail',
|
||||
'/reports/<int:report_id>/',
|
||||
'mediagoblin.moderation.views:moderation_reports_detail')]
|
||||
200
mediagoblin/moderation/views.py
Normal file
200
mediagoblin/moderation/views.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# 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 werkzeug.exceptions import Forbidden
|
||||
|
||||
from mediagoblin.db.models import (MediaEntry, User, MediaComment, \
|
||||
CommentReport, ReportBase, Privilege, \
|
||||
UserBan)
|
||||
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 datetime import datetime
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
def moderation_media_processing_panel(request):
|
||||
'''
|
||||
Show the global media processing panel for this instance
|
||||
'''
|
||||
processing_entries = MediaEntry.query.filter_by(state = u'processing').\
|
||||
order_by(MediaEntry.created.desc())
|
||||
|
||||
# Get media entries which have failed to process
|
||||
failed_entries = MediaEntry.query.filter_by(state = u'failed').\
|
||||
order_by(MediaEntry.created.desc())
|
||||
|
||||
processed_entries = MediaEntry.query.filter_by(state = u'processed').\
|
||||
order_by(MediaEntry.created.desc()).limit(10)
|
||||
|
||||
# Render to response
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/moderation/media_panel.html',
|
||||
{'processing_entries': processing_entries,
|
||||
'failed_entries': failed_entries,
|
||||
'processed_entries': processed_entries})
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
def moderation_users_panel(request):
|
||||
'''
|
||||
Show the global panel for monitoring users in this instance
|
||||
'''
|
||||
user_list = User.query
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/moderation/user_panel.html',
|
||||
{'user_list': user_list})
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
def moderation_users_detail(request):
|
||||
'''
|
||||
Shows details about a particular user.
|
||||
'''
|
||||
user = User.query.filter_by(username=request.matchdict['user']).first()
|
||||
active_reports = user.reports_filed_on.filter(
|
||||
ReportBase.resolved==None).limit(5)
|
||||
closed_reports = user.reports_filed_on.filter(
|
||||
ReportBase.resolved!=None).all()
|
||||
privileges = Privilege.query
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/moderation/user.html',
|
||||
{'user':user,
|
||||
'privileges':privileges,
|
||||
'reports':active_reports})
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
def moderation_reports_panel(request):
|
||||
'''
|
||||
Show the global panel for monitoring reports filed against comments or
|
||||
media entries for this instance.
|
||||
'''
|
||||
report_list = ReportBase.query.filter(
|
||||
ReportBase.resolved==None).order_by(
|
||||
ReportBase.created.desc()).limit(10)
|
||||
closed_report_list = ReportBase.query.filter(
|
||||
ReportBase.resolved!=None).order_by(
|
||||
ReportBase.created.desc()).limit(10)
|
||||
|
||||
# Render to response
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/moderation/report_panel.html',
|
||||
{'report_list':report_list,
|
||||
'closed_report_list':closed_report_list})
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
def moderation_reports_detail(request):
|
||||
"""
|
||||
This is the page an admin or moderator goes to see the details of a report.
|
||||
The report can be resolved or unresolved. This is also the page that a mod-
|
||||
erator would go to to take an action to resolve a report.
|
||||
"""
|
||||
form = moderation_forms.ReportResolutionForm(request.form)
|
||||
report = ReportBase.query.get(request.matchdict['report_id'])
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/moderation/report.html',
|
||||
{'report':report,
|
||||
'media_entry':media_entry,
|
||||
'comment':comment,
|
||||
'form':form})
|
||||
|
||||
@require_admin_or_moderator_login
|
||||
@active_user_from_url
|
||||
def give_or_take_away_privilege(request, url_user):
|
||||
'''
|
||||
A form action to give or take away a particular privilege from a 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:
|
||||
url_user.all_privileges.remove(privilege)
|
||||
else:
|
||||
url_user.all_privileges.append(privilege)
|
||||
url_user.save()
|
||||
return redirect(
|
||||
request,
|
||||
'mediagoblin.moderation.users_detail',
|
||||
user=url_user.username)
|
||||
Reference in New Issue
Block a user