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:
tilly-Q
2013-07-17 16:16:07 -04:00
parent 650a0aa90d
commit 6bba33d7e6
23 changed files with 509 additions and 189 deletions

View 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/>.

View 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()

View 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')]

View 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)