This is a quick commit. I gave admins the ability to ban or unban users

straight from the moderation.users_detail page. I also changed the
UserBan.expiration_date type from DateTime into Date. I also began work on the
Terms of Service, pulled from another website (which will be cited clearly
before I'm done). I added new tests as well for the ban/unbanning. Lastly,
I added a few `user_not_banned` decorators to relevant views, so banned users
cannot access any pages.
This commit is contained in:
tilly-Q 2013-08-29 17:31:19 -04:00
parent dfd66b789c
commit 1bb367f613
11 changed files with 395 additions and 23 deletions

View File

@ -19,7 +19,7 @@ import uuid
from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger, from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger,
Integer, Unicode, UnicodeText, DateTime, Integer, Unicode, UnicodeText, DateTime,
ForeignKey) ForeignKey, Date)
from sqlalchemy.exc import ProgrammingError from sqlalchemy.exc import ProgrammingError
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import and_ from sqlalchemy.sql import and_
@ -501,7 +501,7 @@ class UserBan_v0(declarative_base()):
__tablename__ = 'core__user_bans' __tablename__ = 'core__user_bans'
user_id = Column('id',Integer, ForeignKey(User.id), nullable=False, user_id = Column('id',Integer, ForeignKey(User.id), nullable=False,
primary_key=True) primary_key=True)
expiration_date = Column(DateTime) expiration_date = Column(Date)
reason = Column(UnicodeText, nullable=False) reason = Column(UnicodeText, nullable=False)
class Privilege_v0(declarative_base()): class Privilege_v0(declarative_base()):

View File

@ -23,7 +23,7 @@ import datetime
from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \ from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \
Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \ Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \
SmallInteger SmallInteger, Date
from sqlalchemy.orm import relationship, backref, with_polymorphic from sqlalchemy.orm import relationship, backref, with_polymorphic
from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.sql.expression import desc from sqlalchemy.sql.expression import desc
@ -777,7 +777,7 @@ class UserBan(Base):
user_id = Column(Integer, ForeignKey(User.id), nullable=False, user_id = Column(Integer, ForeignKey(User.id), nullable=False,
primary_key=True) primary_key=True)
expiration_date = Column(DateTime) expiration_date = Column(Date)
reason = Column(UnicodeText, nullable=False) reason = Column(UnicodeText, nullable=False)

View File

@ -38,6 +38,15 @@ class MultiCheckboxField(wtforms.SelectMultipleField):
class PrivilegeAddRemoveForm(wtforms.Form): class PrivilegeAddRemoveForm(wtforms.Form):
privilege_name = wtforms.HiddenField('',[wtforms.validators.required()]) privilege_name = wtforms.HiddenField('',[wtforms.validators.required()])
class BanForm(wtforms.Form):
user_banned_until = wtforms.DateField(
_(u'User will be banned until:'),
format='%Y-%m-%d',
validators=[wtforms.validators.optional()])
why_user_was_banned = wtforms.TextAreaField(
_(u'Why are you banning this User?'),
validators=[wtforms.validators.optional()])
class ReportResolutionForm(wtforms.Form): class ReportResolutionForm(wtforms.Form):
action_to_resolve = MultiCheckboxField( action_to_resolve = MultiCheckboxField(
_(u'What action will you take to resolve the report?'), _(u'What action will you take to resolve the report?'),

View File

@ -30,6 +30,9 @@ moderation_routes = [
('mediagoblin.moderation.give_or_take_away_privilege', ('mediagoblin.moderation.give_or_take_away_privilege',
'/users/<string:user>/privilege/', '/users/<string:user>/privilege/',
'mediagoblin.moderation.views:give_or_take_away_privilege'), 'mediagoblin.moderation.views:give_or_take_away_privilege'),
('mediagoblin.moderation.ban_or_unban',
'/users/<string:user>/ban/',
'mediagoblin.moderation.views:ban_or_unban'),
('mediagoblin.moderation.reports_detail', ('mediagoblin.moderation.reports_detail',
'/reports/<int:report_id>/', '/reports/<int:report_id>/',
'mediagoblin.moderation.views:moderation_reports_detail')] 'mediagoblin.moderation.views:moderation_reports_detail')]

View File

@ -43,11 +43,9 @@ def take_punitive_actions(request, form, report, user):
if u'userban' in form.action_to_resolve.data: if u'userban' in form.action_to_resolve.data:
reason = form.resolution_content.data + \ reason = form.resolution_content.data + \
"<br>"+request.user.username "<br>"+request.user.username
user_ban = UserBan( user_ban = ban_user(form.targeted_user.data,
user_id=form.targeted_user.data,
expiration_date=form.user_banned_until.data, expiration_date=form.user_banned_until.data,
reason= form.why_user_was_banned.data reason=form.why_user_was_banned.data)
)
Session.add(user_ban) Session.add(user_ban)
if form.user_banned_until.data is not None: if form.user_banned_until.data is not None:
@ -162,3 +160,40 @@ def give_privileges(user,*privileges):
return (give_privileges(user, privileges[0]) and \ return (give_privileges(user, privileges[0]) and \
give_privileges(user, *privileges[1:])) give_privileges(user, *privileges[1:]))
def ban_user(user_id, expiration_date=None, reason=None):
"""
This function is used to ban a user. If the user is already banned, the
function returns False. If the user is not already banned, this function
bans the user using the arguments to build a new UserBan object.
:returns False if the user is already banned and the ban is not updated
:returns UserBan object if there is a new ban that was created.
"""
user_ban =UserBan.query.filter(
UserBan.user_id==user_id)
if user_ban.count():
return False
new_user_ban = UserBan(
user_id=user_id,
expiration_date=expiration_date,
reason=reason)
return new_user_ban
def unban_user(user_id):
"""
This function is used to unban a user. If the user is not currently banned,
nothing happens.
:returns True if the operation was completed successfully and the user
has been unbanned
:returns False if the user was never banned.
"""
user_ban = UserBan.query.filter(
UserBan.user_id==user_id)
if user_ban.count() == 0:
return False
user_ban.first().delete()
return True

View File

@ -24,7 +24,7 @@ from mediagoblin.decorators import (require_admin_or_moderator_login, \
from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.tools.response import render_to_response, redirect
from mediagoblin.moderation import forms as moderation_forms 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) take_away_privileges, give_privileges, ban_user, unban_user)
from datetime import datetime from datetime import datetime
@require_admin_or_moderator_login @require_admin_or_moderator_login
@ -74,6 +74,7 @@ def moderation_users_detail(request):
ReportBase.discriminator=='archived_report').all() ReportBase.discriminator=='archived_report').all()
privileges = Privilege.query privileges = Privilege.query
user_banned = UserBan.query.get(user.id) user_banned = UserBan.query.get(user.id)
ban_form = moderation_forms.BanForm()
return render_to_response( return render_to_response(
request, request,
@ -81,7 +82,8 @@ def moderation_users_detail(request):
{'user':user, {'user':user,
'privileges': privileges, 'privileges': privileges,
'reports':active_reports, 'reports':active_reports,
'user_banned':user_banned}) 'user_banned':user_banned,
'ban_form':ban_form})
@require_admin_or_moderator_login @require_admin_or_moderator_login
def moderation_reports_panel(request): def moderation_reports_panel(request):
@ -154,3 +156,23 @@ def give_or_take_away_privilege(request, url_user):
request, request,
'mediagoblin.moderation.users_detail', 'mediagoblin.moderation.users_detail',
user=url_user.username) user=url_user.username)
@user_has_privilege(u'admin')
@active_user_from_url
def ban_or_unban(request, url_user):
"""
A page to ban or unban a user. Only can be used by an admin.
"""
form = moderation_forms.BanForm(request.form)
print "accessed page"
if request.method == "POST" and form.validate():
already_banned = unban_user(url_user.id)
if not already_banned:
user_ban = ban_user(url_user.id,
expiration_date = form.user_banned_until.data,
reason = form.why_user_was_banned.data)
user_ban.save()
return redirect(
request,
'mediagoblin.moderation.users_detail',
user=url_user.username)

View File

@ -125,6 +125,7 @@ def submit_start(request):
@require_active_login @require_active_login
@user_not_banned
def add_collection(request, media=None): def add_collection(request, media=None):
""" """
View to create a new collection View to create a new collection

View File

@ -0,0 +1,243 @@
<h2>The gist</h2>
<h2>Terms of Service</h2>
The following terms and conditions govern all use of the
{{ app_config['html_title'] }} website and all content, services and products
available at or through the website (taken together, the Website). The Website
is owned and operated by Status.net (“Operator”). The Website is offered
subject to your acceptance without modification of all of the terms and
conditions contained herein and all other operating rules, policies
(including, without limitation, Operators Privacy Policy) and procedures
that may be published from time to time on this Site by Operator (collectively,
the “Agreement”).
Please read this Agreement carefully before accessing or using the Website. By accessing or using any part of the web site, you agree to become bound by the terms and conditions of this agreement. If you do not agree to all the terms and conditions of this agreement, then you may not access the Website or use any services. If these terms and conditions are considered an offer by Operator, acceptance is expressly limited to these terms. The Website is available only to individuals who are at least 13 years old.
<ol>
<li>Your {{ app_config['html_title'] }} Account and Site. If you create a
notice stream on the Website, you are responsible for maintaining the
security of your account and notice stream, and you are fully responsible
for all activities that occur under the account and any other actions taken
in connection with the notice stream. You must not describe or assign
keywords to your notice stream in a misleading or unlawful manner,
including in a manner intended to trade on the name or reputation of
others, and Operator may change or remove any description or keyword that
it considers inappropriate or unlawful, or otherwise likely to cause
Operator liability. You must immediately notify Operator of any
unauthorized uses of your notice stream, your account or any other breaches
of security. Operator will not be liable for any acts or omissions by You,
including any damages of any kind incurred as a result of such acts or
omissions.
</li>
<li>Responsibility of Contributors. If you operate a notice stream, comment
on a notice stream, post material to the Website, post links on the
Website, or otherwise make (or allow any third party to make) material
available by means of the Website (any such material, “Content”), You are
entirely responsible for the content of, and any harm resulting from, that
Content. That is the case regardless of whether the Content in question
constitutes text, graphics, an audio file, or computer software. By making
Content available, you represent and warrant that:
<ul>
<li>the downloading, copying and use of the Content will not infringe
the proprietary rights, including but not limited to the copyright,
patent, trademark or trade secret rights, of any third party;
</li>
<li>if your employer has rights to intellectual property you create, you
have either (i) received permission from your employer to post or make
available the Content, including but not limited to any software, or
(ii) secured from your employer a waiver as to all rights in or to the
Content;
</li>
<li>you have fully complied with any third-party licenses relating to the
Content, and have done all things necessary to successfully pass
through to end users any required terms;
</li>
<li>the Content does not contain or install any viruses, worms, malware,
Trojan horses or other harmful or destructive content;
</li>
<li>the Content is not spam, and does not contain unethical or unwanted
commercial content designed to drive traffic to third party sites or
boost the search engine rankings of third party sites, or to further
unlawful acts (such as phishing) or mislead recipients as to the
source of the material (such as spoofing);
</li>
<li>if the Content is machine- or randomly-generated, it is for purposes
of direct entertainment, information and/or utility for you or other
users, and not for spam,
</li>
<li>the Content is not libelous or defamatory (more info on what that
means), does not contain threats or incite violence towards individuals
or entities, and does not violate the privacy or publicity rights of
any third party;
</li>
<li>your notice stream is not getting advertised via unwanted electronic
messages such as spam links on newsgroups, email lists, other notice
streams and web sites, and similar unsolicited promotional methods;
</li>
<li>your notice stream is not named in a manner that misleads your
readers into thinking that you are another person or company. For
example, your notice streams URL or name is not the name of a person
other than yourself or company other than your own; and
</li>
<li>you have, in the case of Content that includes computer code,
accurately categorized and/or described the type, nature, uses and
effects of the materials, whether requested to do so by Operator or
otherwise.</li>
</ul>
By submitting Content to Operator for inclusion on your Website, you grant
Operator a world-wide, royalty-free, and non-exclusive license to
reproduce, modify, adapt and publish the Content solely for the purpose of
displaying, distributing and promoting your notice stream.
By submitting Content to Operator for inclusion on your Website, you grant
all readers the right to use, re-use, modify and/or re-distribute the
Content under the terms of the Creative Commons Attribution 3.0.
If you delete Content, Operator will use reasonable efforts to remove it
from the Website, but you acknowledge that caching or references to the
Content may not be made immediately unavailable.
Without limiting any of those representations or warranties, Operator has
the right (though not the obligation) to, in Operators sole discretion
(i) refuse or remove any content that, in Operators reasonable opinion,
violates any Operator policy or is in any way harmful or objectionable, or
(ii) terminate or deny access to and use of the Website to any individual
or entity for any reason, in Operators sole discretion.
</li>
<li>Responsibility of Website Visitors. Operator has not reviewed, and cannot
review, all of the material, including computer software, posted to the
Website, and cannot therefore be responsible for that materials content,
use or effects. By operating the Website, Operator does not represent or
imply that it endorses the material there posted, or that it believes such
material to be accurate, useful or non-harmful. You are responsible for
taking precautions as necessary to protect yourself and your computer
systems from viruses, worms, Trojan horses, and other harmful or
destructive content. The Website may contain content that is offensive,
indecent, or otherwise objectionable, as well as content containing
technical inaccuracies, typographical mistakes, and other errors. The
Website may also contain material that violates the privacy or publicity
rights, or infringes the intellectual property and other proprietary
rights, of third parties, or the downloading, copying or use of which is
subject to additional terms and conditions, stated or unstated. Operator
disclaims any responsibility for any harm resulting from the use by
visitors of the Website, or from any downloading by those visitors of
content there posted.
</li>
<li>Content Posted on Other Websites. We have not reviewed, and cannot
review, all of the material, including computer software, made available
through the websites and webpages to which {{ app_config['html_title'] }}
links, and that link to {{ app_config['html_title'] }}. Operator does not
have any control over those external websites and webpages, and is not
responsible for their contents or their use. By linking to a external
website or webpage, Operator does not represent or imply that it endorses
such website or webpage. You are responsible for taking precautions as
necessary to protect yourself and your computer systems from viruses,
worms, Trojan horses, and other harmful or destructive content. Operator
disclaims any responsibility for any harm resulting from your use of
external websites and webpages.
</li>
<li>Copyright Infringement and DMCA Policy. As Operator asks others to
respect its intellectual property rights, it respects the intellectual
property rights of others. If you believe that material located on or
linked to by {{ app_config['html_title'] }} violates your copyright, you
are encouraged to notify Operator in accordance with Operators Digital
Millennium Copyright Act (”DMCA”) Policy. Operator will respond to all
such notices, including as required or appropriate by removing the
infringing material or disabling all links to the infringing material. In
the case of a visitor who may infringe or repeatedly infringes the
copyrights or other intellectual property rights of Operator or others,
Operator may, in its discretion, terminate or deny access to and use of
the Website. In the case of such termination, Operator will have no
obligation to provide a refund of any amounts previously paid to Operator.
</li>
<li>Intellectual Property. This Agreement does not transfer from Operator to
you any Operator or third party intellectual property, and all right,
title and interest in and to such property will remain (as between the
parties) solely with Operator. {{ app_config['html_title'] }}, the
{{ app_config['html_title'] }} logo, and all other trademarks, service
marks, graphics and logos used in connection with
{{ app_config['html_title'] }}, or the Website are trademarks or
registered trademarks of Operator or Operators licensors. Other
trademarks, service marks, graphics and logos used in connection with the
Website may be the trademarks of other third parties. Your use of the
Website grants you no right or license to reproduce or otherwise use any
Operator or third-party trademarks.
</li>
<li>Changes. Operator reserves the right, at its sole discretion, to modify
or replace any part of this Agreement. It is your responsibility to check
this Agreement periodically for changes. Your continued use of or access
to the Website following the posting of any changes to this Agreement
constitutes acceptance of those changes. Operator may also, in the future,
offer new services and/or features through the Website (including, the
release of new tools and resources). Such new features and/or services
shall be subject to the terms and conditions of this Agreement.
</li>
<li>Termination. Operator may terminate your access to all or any part of
the Website at any time, with or without cause, with or without notice,
effective immediately. If you wish to terminate this Agreement or your
{{ app_config['html_title'] }} account (if you have one), you may simply
discontinue using the Website. All provisions of this Agreement which by
their nature should survive termination shall survive termination,
including, without limitation, ownership provisions, warranty disclaimers,
indemnity and limitations of liability.
</li>
<li>Disclaimer of Warranties. The Website is provided “as is”. Operator and
its suppliers and licensors hereby disclaim all warranties of any kind,
express or implied, including, without limitation, the warranties of
merchantability, fitness for a particular purpose and non-infringement.
Neither Operator nor its suppliers and licensors, makes any warranty that
the Website will be error free or that access thereto will be continuous
or uninterrupted. If youre actually reading this, heres a treat. You
understand that you download from, or otherwise obtain content or services
through, the Website at your own discretion and risk.
</li>
<li>Limitation of Liability. In no event will Operator, or its suppliers or
licensors, be liable with respect to any subject matter of this agreement
under any contract, negligence, strict liability or other legal or
equitable theory for: (i) any special, incidental or consequential damages;
(ii) the cost of procurement or substitute products or services; (iii) for
interruption of use or loss or corruption of data; or (iv) for any amounts
that exceed the fees paid by you to Operator under this agreement during
the twelve (12) month period prior to the cause of action. Operator shall
have no liability for any failure or delay due to matters beyond their
reasonable control. The foregoing shall not apply to the extent prohibited
by applicable law.
</li>
<li>General Representation and Warranty. You represent and warrant that (i)
your use of the Website will be in strict accordance with the Operator
Privacy Policy, with this Agreement and with all applicable laws and
regulations (including without limitation any local laws or regulations in
your country, state, city, or other governmental area, regarding online
conduct and acceptable content, and including all applicable laws regarding
the transmission of technical data exported from the United States or the
country in which you reside) and (ii) your use of the Website will not
infringe or misappropriate the intellectual property rights of any third
party.
</li>
<li>Indemnification. You agree to indemnify and hold harmless Operator, its
contractors, and its licensors, and their respective directors, officers,
employees and agents from and against any and all claims and expenses,
including attorneys fees, arising out of your use of the Website,
including but not limited to out of your violation this Agreement.
</li>
<li>Miscellaneous. This Agreement constitutes the entire agreement between
Operator and you concerning the subject matter hereof, and they may only
be modified by a written amendment signed by an authorized executive of
Operator, or by the posting by Operator of a revised version. If any part
of this Agreement is held invalid or unenforceable, that part will be
construed to reflect the parties original intent, and the remaining
portions will remain in full force and effect. A waiver by either party of
any term or condition of this Agreement or any breach thereof, in any one
instance, will not waive such term or condition or any subsequent breach
thereof. You may assign your rights under this Agreement to any party that
consents to, and agrees to be bound by, its terms and conditions; Operator
may assign its rights under this Agreement without condition. This
Agreement will be binding upon and will inure to the benefit of the
parties, their successors and permitted assigns.
</li>
</ol>
Originally published by Automattic, Inc. as the WordPress.com Terms of Service
and made available by them under the Creative Commons Attribution-
ShareAlike 3.0 License. Modifications to remove reference to "VIP services",
rename "blog" to "notice stream", remove the choice-of-venue clause, and add
variables specific to instances of this software made by Control Yourself, Inc.
and made available under the terms of the same license.

View File

@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
#} #}
{% extends "mediagoblin/base.html" %} {% extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block title %} {% block title %}
{%- if user -%} {%- if user -%}
@ -130,15 +130,22 @@
<a class="right_align">{{ user.username }}'s report history</a> <a class="right_align">{{ user.username }}'s report history</a>
<span class=clear></span> <span class=clear></span>
<h2>{{ user.username }}'s Privileges</h2> <h2>{{ user.username }}'s Privileges</h2>
{% if request.user.has_privilege('admin') and not user_banned and <form method=POST action="{{ request.urlgen(
not user.id == request.user.id %} 'mediagoblin.moderation.ban_or_unban',
<input type=button class="button_action right_align" user=user.username) }}" class="right_align">
value="Ban User" /> {{ csrf_token }}
{% elif request.user.has_privilege('admin') and {% if request.user.has_privilege('admin') and not user_banned and
not user.id == request.user.id %} not user.id == request.user.id %}
<input type=button class="button_action right_align" {{ wtforms_util.render_divs(ban_form) }}
value="UnBan User" /> <input type=submit class="button_action"
{% endif %} value="{% trans %}Ban User{% endtrans %}"
id="ban_user_submit" />
{% elif request.user.has_privilege('admin') and
not user.id == request.user.id %}
<input type=submit class="button_action right_align"
value="{% trans %}UnBan User{% endtrans %}" />
{% endif %}
</form>
<form action="{{ request.urlgen('mediagoblin.moderation.give_or_take_away_privilege', <form action="{{ request.urlgen('mediagoblin.moderation.give_or_take_away_privilege',
user=user.username) }}" user=user.username) }}"
method=post > method=post >
@ -172,7 +179,7 @@
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
{{ csrf_token }} {{ csrf_token }}
<input type=hidden name=privilege_name id=hidden_privilege_name /> <input type=hidden name=privilege_name id=hidden_privilege_name />
</form> </form>
{% endif %} {% endif %}
@ -181,6 +188,16 @@ $(document).ready(function(){
$('.submit_button').click(function(){ $('.submit_button').click(function(){
$('#hidden_privilege_name').val($(this).attr('id')); $('#hidden_privilege_name').val($(this).attr('id'));
}); });
$('#user_banned_until').val("YYYY-MM-DD")
$("#user_banned_until").focus(function() {
$(this).val("");
$(this).unbind('focus');
});
$("#ban_user_submit").click(function(){
if ($("#user_banned_until").val() == 'YYYY-MM-DD'){
$("#user_banned_until").val("");
}
});
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -21,6 +21,7 @@ from mediagoblin.tests.tools import (fixture_add_user,
from mediagoblin.db.models import User, CommentReport, MediaComment, UserBan from mediagoblin.db.models import User, CommentReport, MediaComment, UserBan
from mediagoblin.moderation.tools import take_away_privileges, give_privileges from mediagoblin.moderation.tools import take_away_privileges, give_privileges
from mediagoblin.tools import template, mail from mediagoblin.tools import template, mail
from datetime import date, timedelta
from webtest import AppError from webtest import AppError
@ -160,7 +161,9 @@ VGhpcyBpcyB5b3VyIGxhc3Qgd2FybmluZywgcmVndWxhci4uLi4=\n',
response, context = self.do_post( response, context = self.do_post(
{'action_to_resolve':[u'userban', u'delete'], {'action_to_resolve':[u'userban', u'delete'],
'targeted_user':self.user.id}, 'targeted_user':self.user.id,
'why_user_was_banned':u'',
'user_banned_until':u''},
url='/mod/reports/{0}/'.format(comment_report.id)) url='/mod/reports/{0}/'.format(comment_report.id))
assert response.status == '302 FOUND' assert response.status == '302 FOUND'
self.query_for_users() self.query_for_users()
@ -189,6 +192,44 @@ VGhpcyBpcyB5b3VyIGxhc3Qgd2FybmluZywgcmVndWxhci4uLi4=\n',
def testAllModerationViews(self): def testAllModerationViews(self):
self.login(u'moderator') self.login(u'moderator')
self.test_app.get('/mod/reports/') username = self.user.username
self.test_app.get('/mod/users/') fixture_add_comment_report(reported_user=self.admin_user)
response = self.test_app.get('/mod/reports/')
assert response.status == "200 OK"
response = self.test_app.get('/mod/reports/1/')
assert response.status == "200 OK"
response = self.test_app.get('/mod/users/')
assert response.status == "200 OK"
user_page_url = '/mod/users/{0}/'.format(username)
response = self.test_app.get(user_page_url)
assert response.status == "200 OK"
self.test_app.get('/mod/media/') self.test_app.get('/mod/media/')
assert response.status == "200 OK"
def testBanUnBanUser(self):
self.login(u'admin')
username = self.user.username
user_id = self.user.id
ban_url = '/mod/users/{0}/ban/'.format(username)
response, context = self.do_post({
'user_banned_until':u'',
'why_user_was_banned':u'Because I said so'},
url=ban_url)
assert response.status == "302 FOUND"
user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
assert user_banned is not None
assert user_banned.expiration_date is None
assert user_banned.reason == u'Because I said so'
response, context = self.do_post({},
url=ban_url)
assert response.status == "302 FOUND"
user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
assert user_banned is None

View File

@ -367,6 +367,7 @@ def collection_list(request, url_user=None):
@get_user_collection_item @get_user_collection_item
@require_active_login @require_active_login
@user_may_alter_collection @user_may_alter_collection
@user_not_banned
def collection_item_confirm_remove(request, collection_item): def collection_item_confirm_remove(request, collection_item):
form = user_forms.ConfirmCollectionItemRemoveForm(request.form) form = user_forms.ConfirmCollectionItemRemoveForm(request.form)