Fix #1056 - Add flag to accept URLs without a trailing slash
[mediagoblin.git] / mediagoblin / tests / test_moderation.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import pytest
18
19 from mediagoblin.tests.tools import (fixture_add_user,
20 fixture_add_comment_report, fixture_add_comment)
21 from mediagoblin.db.models import User, CommentReport, MediaComment, UserBan
22 from mediagoblin.tools import template, mail
23 from webtest import AppError
24
25 class TestModerationViews:
26 @pytest.fixture(autouse=True)
27 def _setup(self, test_app):
28 self.test_app = test_app
29
30 fixture_add_user(u'admin',
31 privileges=[u'admin',u'active'])
32 fixture_add_user(u'moderator',
33 privileges=[u'moderator',u'active'])
34 fixture_add_user(u'regular',
35 privileges=[u'active',u'commenter'])
36 self.query_for_users()
37
38 def login(self, username):
39 self.test_app.post(
40 '/auth/login/', {
41 'username': username,
42 'password': 'toast'})
43 self.query_for_users()
44
45 def logout(self):
46 self.test_app.get('/auth/logout/')
47 self.query_for_users()
48
49 def query_for_users(self):
50 self.admin_user = User.query.filter(User.username==u'admin').first()
51 self.mod_user = User.query.filter(User.username==u'moderator').first()
52 self.user = User.query.filter(User.username==u'regular').first()
53
54 def do_post(self, data, *context_keys, **kwargs):
55 url = kwargs.pop('url', '/submit/')
56 do_follow = kwargs.pop('do_follow', False)
57 template.clear_test_template_context()
58 response = self.test_app.post(url, data, **kwargs)
59 if do_follow:
60 response.follow()
61 context_data = template.TEMPLATE_TEST_CONTEXT
62 for key in context_keys:
63 context_data = context_data[key]
64 return response, context_data
65
66 def testGiveOrTakeAwayPrivileges(self):
67 self.login(u'admin')
68 # First, test an admin taking away a privilege from a user
69 #----------------------------------------------------------------------
70 response, context = self.do_post({'privilege_name':u'commenter'},
71 url='/mod/users/{0}/privilege/'.format(self.user.username))
72 assert response.status == '302 FOUND'
73 self.query_for_users()
74 assert not self.user.has_privilege(u'commenter')
75
76 # Then, test an admin giving a privilege to a user
77 #----------------------------------------------------------------------
78 response, context = self.do_post({'privilege_name':u'commenter'},
79 url='/mod/users/{0}/privilege/'.format(self.user.username))
80 assert response.status == '302 FOUND'
81 self.query_for_users()
82 assert self.user.has_privilege(u'commenter')
83
84 # Then, test a mod trying to take away a privilege from a user
85 # they are not allowed to do this, so this will raise an error
86 #----------------------------------------------------------------------
87 self.logout()
88 self.login(u'moderator')
89
90 with pytest.raises(AppError) as excinfo:
91 response, context = self.do_post({'privilege_name':u'commenter'},
92 url='/mod/users/{0}/privilege/'.format(self.user.username))
93 assert 'Bad response: 403 FORBIDDEN' in str(excinfo)
94 self.query_for_users()
95
96 assert self.user.has_privilege(u'commenter')
97
98 def testReportResolution(self):
99 self.login(u'moderator')
100
101 # First, test a moderators taking away a user's privilege in response
102 # to a reported comment
103 #----------------------------------------------------------------------
104 fixture_add_comment_report(reported_user=self.user)
105 comment_report = CommentReport.query.filter(
106 CommentReport.reported_user==self.user).first()
107
108 response = self.test_app.get('/mod/reports/{0}/'.format(
109 comment_report.id))
110 assert response.status == '200 OK'
111 self.query_for_users()
112 comment_report = CommentReport.query.filter(
113 CommentReport.reported_user==self.user).first()
114
115 response, context = self.do_post({'action_to_resolve':[u'takeaway'],
116 'take_away_privileges':[u'commenter'],
117 'targeted_user':self.user.id},
118 url='/mod/reports/{0}/'.format(comment_report.id))
119
120 self.query_for_users()
121 comment_report = CommentReport.query.filter(
122 CommentReport.reported_user==self.user).first()
123 assert response.status == '302 FOUND'
124 assert not self.user.has_privilege(u'commenter')
125 assert comment_report.is_archived_report() is True
126
127 fixture_add_comment_report(reported_user=self.user)
128 comment_report = CommentReport.query.filter(
129 CommentReport.reported_user==self.user).first()
130
131 # Then, test a moderator sending an email to a user in response to a
132 # reported comment
133 #----------------------------------------------------------------------
134 self.query_for_users()
135
136 response, context = self.do_post({'action_to_resolve':[u'sendmessage'],
137 'message_to_user':'This is your last warning, regular....',
138 'targeted_user':self.user.id},
139 url='/mod/reports/{0}/'.format(comment_report.id))
140
141 self.query_for_users()
142 comment_report = CommentReport.query.filter(
143 CommentReport.reported_user==self.user).first()
144 assert response.status == '302 FOUND'
145 assert mail.EMAIL_TEST_MBOX_INBOX == [{'to': [u'regular@example.com'],
146 'message': 'Content-Type: text/plain; charset="utf-8"\n\
147 MIME-Version: 1.0\nContent-Transfer-Encoding: base64\nSubject: Warning from- \
148 moderator \nFrom: notice@mediagoblin.example.org\nTo: regular@example.com\n\n\
149 VGhpcyBpcyB5b3VyIGxhc3Qgd2FybmluZywgcmVndWxhci4uLi4=\n',
150 'from': 'notice@mediagoblin.example.org'}]
151 assert comment_report.is_archived_report() is True
152
153 # Then test a moderator banning a user AND a moderator deleting the
154 # offending comment. This also serves as a test for taking multiple
155 # actions to resolve a report
156 #----------------------------------------------------------------------
157 self.query_for_users()
158 fixture_add_comment(author=self.user.id,
159 comment=u'Comment will be removed')
160 test_comment = MediaComment.query.filter(
161 MediaComment.author==self.user.id).first()
162 fixture_add_comment_report(comment=test_comment,
163 reported_user=self.user)
164 comment_report = CommentReport.query.filter(
165 CommentReport.comment==test_comment).filter(
166 CommentReport.resolved==None).first()
167
168 response, context = self.do_post(
169 {'action_to_resolve':[u'userban', u'delete'],
170 'targeted_user':self.user.id,
171 'why_user_was_banned':u'',
172 'user_banned_until':u''},
173 url='/mod/reports/{0}/'.format(comment_report.id))
174 assert response.status == '302 FOUND'
175 self.query_for_users()
176 test_user_ban = UserBan.query.filter(
177 UserBan.user_id == self.user.id).first()
178 assert test_user_ban is not None
179 test_comment = MediaComment.query.filter(
180 MediaComment.author==self.user.id).first()
181 assert test_comment is None
182
183 # Then, test what happens when a moderator attempts to punish an admin
184 # from a reported comment on an admin.
185 #----------------------------------------------------------------------
186 fixture_add_comment_report(reported_user=self.admin_user)
187 comment_report = CommentReport.query.filter(
188 CommentReport.reported_user==self.admin_user).filter(
189 CommentReport.resolved==None).first()
190
191 response, context = self.do_post({'action_to_resolve':[u'takeaway'],
192 'take_away_privileges':[u'active'],
193 'targeted_user':self.admin_user.id},
194 url='/mod/reports/{0}/'.format(comment_report.id))
195 self.query_for_users()
196
197 assert response.status == '200 OK'
198 assert self.admin_user.has_privilege(u'active')
199
200 def testAllModerationViews(self):
201 self.login(u'moderator')
202 username = self.user.username
203 self.query_for_users()
204 fixture_add_comment_report(reported_user=self.admin_user)
205 response = self.test_app.get('/mod/reports/')
206 assert response.status == "200 OK"
207
208 response = self.test_app.get('/mod/reports/1/')
209 assert response.status == "200 OK"
210
211 response = self.test_app.get('/mod/users/')
212 assert response.status == "200 OK"
213
214 user_page_url = '/mod/users/{0}/'.format(username)
215 response = self.test_app.get(user_page_url)
216 assert response.status == "200 OK"
217
218 self.test_app.get('/mod/media/')
219 assert response.status == "200 OK"
220
221 def testBanUnBanUser(self):
222 self.login(u'admin')
223 username = self.user.username
224 user_id = self.user.id
225 ban_url = '/mod/users/{0}/ban/'.format(username)
226 response, context = self.do_post({
227 'user_banned_until':u'',
228 'why_user_was_banned':u'Because I said so'},
229 url=ban_url)
230
231 assert response.status == "302 FOUND"
232 user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
233 assert user_banned is not None
234 assert user_banned.expiration_date is None
235 assert user_banned.reason == u'Because I said so'
236
237 response, context = self.do_post({},
238 url=ban_url)
239
240 assert response.status == "302 FOUND"
241 user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
242 assert user_banned is None