+++ /dev/null
-# 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)
-from mediagoblin.decorators import require_admin_login
-from mediagoblin.tools.response import render_to_response
-
-@require_admin_login
-def admin_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/admin/media_panel.html',
- {'processing_entries': processing_entries,
- 'failed_entries': failed_entries,
- 'processed_entries': processed_entries})
-
-@require_admin_login
-def admin_users_panel(request):
- '''
- Show the global panel for monitoring users in this instance
- '''
- user_list = User.query
-
- return render_to_response(
- request,
- 'mediagoblin/admin/user_panel.html',
- {'user_list': user_list})
-
-@require_admin_login
-def admin_users_detail(request):
- '''
- Shows details about a particular user.
- '''
- user = User.query.filter_by(username=request.matchdict['user']).first()
- privileges = Privilege.query
- active_reports = user.reports_filed_on.filter(
- ReportBase.resolved==None).limit(5)
- closed_reports = user.reports_filed_on.filter(
- ReportBase.resolved!=None).all()
-
- return render_to_response(
- request,
- 'mediagoblin/admin/user.html',
- {'user':user,
- 'privileges':privileges,
- 'reports':active_reports})
-
-@require_admin_login
-def admin_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/admin/report_panel.html',
- {'report_list':report_list,
- 'closed_report_list':closed_report_list})
-
-@require_admin_login
-def admin_reports_detail(request):
- report = ReportBase.query.get(request.matchdict['report_id'])
- 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
-
- return render_to_response(
- request,
- 'mediagoblin/admin/report.html',
- {'report':report,
- 'media_entry':media_entry,
- 'comment':comment})
-
-
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}
This will *not* automatically delete unused collections, which
can remain empty...
- :param del_orphan_tags: True/false if we delete unused Tags too
- :param commit: True/False if this should end the db transaction"""
+ :keyword del_orphan_tags: True/false if we delete unused Tags too
+ :keyword commit: True/False if this should end the db transaction"""
# User's CollectionItems are automatically deleted via "cascade".
# Comments on this Media are deleted by cascade, hopefully.
class ReportBase(Base):
"""
+ This is the basic report table which the other reports are based off of.
+ :keyword reporter_id
+ :keyword report_content
+ :keyword reported_user_id
+ :keyword created
+ :keyword resolved
+ :keyword result
+ :keyword discriminator
"""
__tablename__ = 'core__reports'
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}
the reason why they are banned and when (if ever) the ban will be
lifted
- :param user_id Holds the id of the user this object is
+ :keyword user_id Holds the id of the user this object is
attached to. This is a one-to-one
relationship.
- :param expiration_date Holds the date that the ban will be lifted.
+ :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.
- :param reason Holds the reason why the user was banned.
+ :keyword reason Holds the reason why the user was banned.
"""
__tablename__ = 'core__user_bans'
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.
+
+ :keyword privilege_name Holds a unicode object that is the recognizable
+ 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)
secondary="core__privileges_users")
def __init__(self, privilege_name):
+ '''
+ Currently consructors are required for tables that are initialized thru
+ the FOUNDATIONS system. This is because they need to be able to be con-
+ -structed by a list object holding their arg*s
+ '''
self.privilege_name = privilege_name
def __repr__(self):
return "<Privilege %s>" % (self.privilege_name)
+ def is_admin_or_moderator(self):
+ '''
+ This method is necessary to check if a user is able to take moderation
+ actions.
+ '''
+
+ return (self.privilege_name==u'admin' or
+ self.privilege_name==u'moderator')
+
class PrivilegeUserAssociation(Base):
+ '''
+ This table holds the many-to-many relationship between User and Privilege
+ '''
+
__tablename__ = 'core__privileges_users'
privilege_id = Column(
from werkzeug.urls import url_quote
from mediagoblin import mg_globals as mgg
-from mediagoblin.db.models import MediaEntry, User, MediaComment, Privilege
-from mediagoblin.tools.response import redirect, render_404
+from mediagoblin.db.models import MediaEntry, User, MediaComment, Privilege, \
+ UserBan
+from mediagoblin.tools.response import redirect, render_404, render_user_banned
def require_active_login(controller):
return wrapper
def user_has_privilege(privilege_name):
+
def user_has_privilege_decorator(controller):
@wraps(controller)
def wrapper(request, *args, **kwargs):
privileges_of_user = Privilege.query.filter(
Privilege.all_users.any(
User.id==user_id))
- if not privileges_of_user.filter(
+ if UserBan.query.filter(UserBan.user_id==user_id).count():
+ return render_user_banned(request)
+ elif not privileges_of_user.filter(
Privilege.privilege_name==privilege_name).count():
raise Forbidden()
return new_func
-def require_admin_login(controller):
+def require_admin_or_moderator_login(controller):
"""
- Require an login from an administrator.
+ Require an login from an administrator or a moderator.
"""
@wraps(controller)
def new_controller_func(request, *args, **kwargs):
+ admin_privilege = Privilege.one({'privilege_name':u'admin'})
+ moderator_privilege = Privilege.one({'privilege_name':u'moderator'})
if request.user and \
- not request.user.is_admin:
+ not admin_privilege in request.user.all_privileges and \
+ not moderator_privilege in request.user.all_privileges:
+
raise Forbidden()
elif not request.user:
next_url = urljoin(
return new_controller_func
+def user_not_banned(controller):
+ """
+ Requires that the user has not been banned. Otherwise redirects to the page
+ explaining why they have been banned
+ """
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ if request.user:
+ user_banned = UserBan.query.get(request.user.id)
+ if user_banned:
+ return render_user_banned(request)
+ return controller(request, *args, **kwargs)
+
+ return wrapper
+
entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password)
entry.status = u'active'
entry.email_verified = True
+ default_privileges = [
+ db.Privilege.one({'privilege_name':u'commenter'}),
+ db.Privilege.one({'privilege_name':u'uploader'}),
+ db.Privilege.one({'privilege_name':u'reporter'}),
+ db.Privilege.one({'privilege_name':u'active'})
+]
+ entry.all_privileges = default_privileges
entry.save()
print "User created (and email marked as verified)"
--- /dev/null
+# 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()
+
--- /dev/null
+# 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')]
--- /dev/null
+# 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)
from mediagoblin.tools.routing import add_route, mount, url_map
from mediagoblin.tools.pluginapi import PluginManager
-from mediagoblin.admin.routing import admin_routes
+from mediagoblin.moderation.routing import moderation_routes
from mediagoblin.auth.routing import auth_routes
def get_url_map():
add_route('index', '/', 'mediagoblin.views:root_view')
mount('/auth', auth_routes)
- mount('/a', admin_routes)
+ mount('/mod', moderation_routes)
import mediagoblin.submit.routing
import mediagoblin.user_pages.routing
color: #D486B1;
}
+ul#action_to_resolve {list-style:none; margin-left:10px;}
+
/* media galleries */
.media_thumbnail {
+{#
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
#
#
# 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/>.
+#}
+{% extends "mediagoblin/base.html" %}
-admin_routes = [
- ('mediagoblin.admin.media_panel',
- '/media',
- 'mediagoblin.admin.views:admin_media_processing_panel'),
- ('mediagoblin.admin.users',
- '/users',
- 'mediagoblin.admin.views:admin_users_panel'),
- ('mediagoblin.admin.reports',
- '/reports',
- 'mediagoblin.admin.views:admin_reports_panel'),
- ('mediagoblin.admin.users_detail',
- '/users/<string:user>',
- 'mediagoblin.admin.views:admin_users_detail'),
- ('mediagoblin.admin.reports_detail',
- '/reports/<int:report_id>',
- 'mediagoblin.admin.views:admin_reports_detail')]
+{% block title %}You are Banned.{% endblock %}
+
+{% block mediagoblin_content %}
+ <img class="right_align" src="{{ request.staticdirect('/images/404.png') }}"
+ alt="{% trans %}Image of goblin stressing out{% endtrans %}" />
+ <h1>You have been banned until {{ expiration_date }}</h1>
+ <p>{{ reason|safe }}</p>
+ <div class="clear"></div>
+{% endblock %}
{% if request.user.is_admin %}
<p>
<span class="dropdown_title">Admin powers:</span>
- <a href="{{ request.urlgen('mediagoblin.admin.media_panel') }}">
+ <a href="{{ request.urlgen('mediagoblin.moderation.media_panel') }}">
{%- trans %}Media processing panel{% endtrans -%}
</a>
+ <a href="{{ request.urlgen('mediagoblin.moderation.users') }}">
+ {%- trans %}User management panel{% endtrans -%}
+ </a>
</p>
{% endif %}
</div>
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{%- extends "mediagoblin/base.html" %}
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{%- block mediagoblin_content %}
{% if not report %}
class="comment_wrapper">
<div class="comment_author">
<img src="{{ request.staticdirect('/images/icon_comment.png') }}" />
- <a href="{{ request.urlgen('mediagoblin.admin.users_detail',
+ <a href="{{ request.urlgen('mediagoblin.moderation.users_detail',
user=comment.get_author.username) }}"
class="comment_authorlink">
{{- reported_user.username -}}
<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" />
- <a href="{{ request.urlgen('mediagoblin.admin.users_detail',
+ <a href="{{ request.urlgen('mediagoblin.moderation.users_detail',
user=report.reporter.username) }}"
class="report_authorlink">
{{- report.reporter.username -}}
</a>
- <a href="{{ request.urlgen('mediagoblin.admin.reports_detail',
+ <a href="{{ request.urlgen('mediagoblin.moderation.reports_detail',
report_id=report.id) }}"
class="report_whenlink">
<span title='{{- report.created.strftime("%I:%M%p %Y-%m-%d") -}}'>
{{ report.report_content }}
</div>
</div>
+ {% if not report.resolved %}
+ <input type=button value=Resolve id=open_resolution_form />
+ <form action="" method="POST" id=resolution_form>
+ {{ wtforms_util.render_divs(form) }}
+ {{ csrf_token }}
+ <input type=submit id="submit_this_report" value="Resolve This Report"/>
+ </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("");
+ }
+ });
+ });
+ </script>
+ {% else %}
+ <h2>Status:</h2>
+ RESOLVED on {{ report.resolved.strftime("%I:%M%p %Y-%m-%d") }}
+ {% autoescape False %}
+ <p>{{ report.result }}</p>
+ {% endautoescape %}
+ {% endif %}
{% endif %}
{% endblock %}
{% trans %}Here you can look up users in order to take punitive actions on them.{% endtrans %}
</p>
-<h2>{% trans %}Reports Filed on Comments{% endtrans %}</h2>
+<h2>{% trans %}Reports Filed{% endtrans %}</h2>
{% if report_list.count() %}
<table class="admin_panel processing">
</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>{{ report.id }}</td>
<td>Comment Report</td>
<td>{{ report.comment.get_author.username }}</td>
<td>{{ report.created.strftime("%F %R") }}</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.id }}</td>
<td>Media Report</td>
<td>{{ report.media_entry.get_uploader.username }}</td>
<td>{{ report.created.strftime("%F %R") }}</td>
{% else %}
<p><em>{% trans %}No open reports found.{% endtrans %}</em></p>
{% endif %}
-<h2>{% trans %}Closed Reports on Comments{% endtrans %}</h2>
+<h2>{% trans %}Closed Reports{% endtrans %}</h2>
{% if closed_report_list.count() %}
<table class="media_panel processing">
<tr>
<th>ID</th>
+ <th>Resolved</th>
<th>Offender</th>
- <th>When Reported</th>
+ <th>Action Taken</th>
<th>Reported By</th>
<th>Reason</th>
- <th>Comment Posted On</th>
+ <th>Reported Comment or Media Entry</th>
</tr>
{% for report in closed_report_list %}
- <tr>
- <td>{{ report.id }}</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>
- </tr>
+ <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 %}
{% endfor %}
</table>
{% else %}
</div>
{% endif %}
{% if user %}
- <h2>{%- trans %}Active Reports on{% endtrans -%} {{ user.username }}</h2>
+ <h2>{%- trans %}Active Reports on {% endtrans -%}{{ user.username }}</h2>
{% if reports.count() %}
<table class="admin_side_panel">
<tr>
<tr>
<td>
<img src="{{ request.staticdirect('/images/icon_clipboard.png') }}" />
- <a href="{{ request.urlgen('mediagoblin.admin.reports_detail',
+ <a href="{{ request.urlgen('mediagoblin.moderation.reports_detail',
report_id=report.id) }}">
{%- trans %}Report #{% endtrans -%}{{ report.id }}
</a>
<tr><td></td><td></td>
</table>
{% else %}
- {%- trans %}No active reports filed on{% endtrans -%} {{ user.username }}
+ {%- trans %}No active reports filed on {% endtrans -%} {{ user.username }}
{% endif %}
<a class="right_align">{{ user.username }}'s report history</a>
<span class=clear></span>
<tr>
<th>{% trans %}Privilege{% endtrans %}</th>
<th>{% trans %}User Has Privilege{% endtrans %}</th>
- {% for privilege in privileges %}
- <tr>
- <td>{{ privilege.privilege_name }}</td>
- <td>{% if privilege in user.all_privileges %}Yes{% else %}No{% endif %}</td>
- <td>{% if privilege in user.all_privileges and privilege.id < request.user.get_highest_privilege().id %}<a>{% trans %}Take Away{% endtrans %}</a>{% else %}<a>{% trans %}Give Privilege{% endtrans %}</a>{% endif %}</td>
</tr>
- {% endfor %}
+ {% 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>
+ {% endfor %}
</table>
{% endif %}
{% endblock %}
{% for user in user_list %}
<tr>
<td>{{ user.id }}</td>
- <td><a href="{{ request.urlgen('mediagoblin.admin.users_detail',
+ <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>
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
class Response(wz_Response):
"""Set default response mimetype to HTML, otherwise we get text/plain"""
"you're looking for has been moved or deleted.")
return render_error(request, 404, err_msg=err_msg)
+def render_user_banned(request):
+ """Renders the page which tells a user they have been banned, for how long
+ and the reason why they have been banned"
+ """
+ user_ban = UserBan.query.get(request.user.id)
+ return render_to_response(request,
+ 'mediagoblin/banned.html',
+ {'reason':user_ban.reason,
+ 'expiration_date':user_ban.expiration_date})
def render_http_exception(request, exc, description):
"""Return Response() given a werkzeug.HTTPException
Markdown</a> for formatting."""))
class CommentReportForm(wtforms.Form):
- report_reason = wtforms.TextAreaField('Reason for Reporting')
+ report_reason = wtforms.TextAreaField(
+ _('Reason for Reporting'),
+ [wtforms.validators.Required()])
comment_id = wtforms.IntegerField()
reporter_id = wtforms.IntegerField()
class MediaReportForm(wtforms.Form):
- report_reason = wtforms.TextAreaField('Reason for Reporting')
+ report_reason = wtforms.TextAreaField(
+ _('Reason for Reporting'),
+ [wtforms.validators.Required()])
media_entry_id = wtforms.IntegerField()
reporter_id = wtforms.IntegerField()
if commit:
Session.commit()
-def build_report_form(form_dict):
+def build_report_table(form_dict):
"""
This function is used to convert a form dictionary (from a User filing a
report) into either a MediaReport or CommentReport object.
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.pagination import Pagination
from mediagoblin.user_pages import forms as user_forms
-from mediagoblin.user_pages.lib import (send_comment_email, build_report_form,
+from mediagoblin.user_pages.lib import (send_comment_email, build_report_table,
add_media_to_collection)
from mediagoblin.decorators import (uses_pagination, get_user_media_entry,
get_media_entry_by_id, user_has_privilege,
require_active_login, user_may_delete_media, user_may_alter_collection,
get_user_collection, get_user_collection_item, active_user_from_url,
- get_media_comment_by_id)
+ get_media_comment_by_id, user_not_banned)
from werkzeug.contrib.atom import AtomFeed
_log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)
-
+@user_not_banned
@uses_pagination
def user_home(request, page):
"""'Homepage' of a User()"""
'media_entries': media_entries,
'pagination': pagination})
-
+@user_not_banned
@active_user_from_url
@uses_pagination
def user_gallery(request, page, url_user=None):
MEDIA_COMMENTS_PER_PAGE = 50
-
+@user_not_banned
@get_user_media_entry
@uses_pagination
def media_home(request, media, page, **kwargs):
return redirect_obj(request, media)
-
+@user_not_banned
@get_media_entry_by_id
@require_active_login
def media_collect(request, media):
#TODO: Why does @user_may_delete_media not implicate @require_active_login?
+@user_not_banned
@get_media_entry_by_id
@require_active_login
@user_may_delete_media
{'media': media,
'form': form})
-
+@user_not_banned
@active_user_from_url
@uses_pagination
def user_collection(request, page, url_user=None):
'collection_items': collection_items,
'pagination': pagination})
-
+@user_not_banned
@active_user_from_url
def collection_list(request, url_user=None):
"""A User-defined Collection"""
{'collection_item': collection_item,
'form': form})
-
+@user_not_banned
@get_user_collection
@require_active_login
@user_may_alter_collection
return feed.get_response()
-
+@user_not_banned
@require_active_login
def processing_panel(request):
"""
@user_has_privilege(u'reporter')
def file_a_report(request, media, comment=None):
if request.method == "POST":
- report_form = build_report_form(request.form)
- report_form.save()
+ report_table = build_report_table(request.form)
+ report_table.save()
return redirect(
request,
from mediagoblin.db.models import MediaEntry
from mediagoblin.tools.pagination import Pagination
from mediagoblin.tools.response import render_to_response
-from mediagoblin.decorators import uses_pagination
-
+from mediagoblin.decorators import uses_pagination, user_not_banned
+@user_not_banned
@uses_pagination
def root_view(request, page):
cursor = MediaEntry.query.filter_by(state=u'processed').\