Merge branch 'thumbnail', fixes #592.
[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, LocalUser, Report, TextComment, \
22 UserBan, GenericModelReference
23 from mediagoblin.tools import template, mail
24 from webtest import AppError
25
26 class TestModerationViews:
27 @pytest.fixture(autouse=True)
28 def _setup(self, test_app):
29 self.test_app = test_app
30
31 fixture_add_user(u'admin',
32 privileges=[u'admin',u'active'])
33 fixture_add_user(u'moderator',
34 privileges=[u'moderator',u'active'])
35 fixture_add_user(u'regular',
36 privileges=[u'active',u'commenter'])
37 self.query_for_users()
38
39 def login(self, username):
40 self.test_app.post(
41 '/auth/login/', {
42 'username': username,
43 'password': 'toast'})
44 self.query_for_users()
45
46 def logout(self):
47 self.test_app.get('/auth/logout/')
48 self.query_for_users()
49
50 def query_for_users(self):
51 self.admin_user = LocalUser.query.filter(LocalUser.username==u'admin').first()
52 self.mod_user = LocalUser.query.filter(LocalUser.username==u'moderator').first()
53 self.user = LocalUser.query.filter(LocalUser.username==u'regular').first()
54
55 def do_post(self, data, *context_keys, **kwargs):
56 url = kwargs.pop('url', '/submit/')
57 do_follow = kwargs.pop('do_follow', False)
58 template.clear_test_template_context()
59 response = self.test_app.post(url, data, **kwargs)
60 if do_follow:
61 response.follow()
62 context_data = template.TEMPLATE_TEST_CONTEXT
63 for key in context_keys:
64 context_data = context_data[key]
65 return response, context_data
66
67 def testGiveOrTakeAwayPrivileges(self):
68 self.login(u'admin')
69 # First, test an admin taking away a privilege from a user
70 #----------------------------------------------------------------------
71 response, context = self.do_post({'privilege_name':u'commenter'},
72 url='/mod/users/{0}/privilege/'.format(self.user.username))
73 assert response.status == '302 FOUND'
74 self.query_for_users()
75 assert not self.user.has_privilege(u'commenter')
76
77 # Then, test an admin giving a privilege to a user
78 #----------------------------------------------------------------------
79 response, context = self.do_post({'privilege_name':u'commenter'},
80 url='/mod/users/{0}/privilege/'.format(self.user.username))
81 assert response.status == '302 FOUND'
82 self.query_for_users()
83 assert self.user.has_privilege(u'commenter')
84
85 # Then, test a mod trying to take away a privilege from a user
86 # they are not allowed to do this, so this will raise an error
87 #----------------------------------------------------------------------
88 self.logout()
89 self.login(u'moderator')
90
91 with pytest.raises(AppError) as excinfo:
92 response, context = self.do_post({'privilege_name':u'commenter'},
93 url='/mod/users/{0}/privilege/'.format(self.user.username))
94 assert 'Bad response: 403 FORBIDDEN' in str(excinfo)
95 self.query_for_users()
96
97 assert self.user.has_privilege(u'commenter')
98
99 def testReportResolution(self):
100 self.login(u'moderator')
101
102 # First, test a moderators taking away a user's privilege in response
103 # to a reported comment
104 #----------------------------------------------------------------------
105 fixture_add_comment_report(reported_user=self.user)
106 comment_report = Report.query.filter(
107 Report.reported_user==self.user).first()
108
109 response = self.test_app.get('/mod/reports/{0}/'.format(
110 comment_report.id))
111 assert response.status == '200 OK'
112 self.query_for_users()
113 comment_report = Report.query.filter(
114 Report.reported_user==self.user).first()
115
116 response, context = self.do_post({'action_to_resolve':[u'takeaway'],
117 'take_away_privileges':[u'commenter'],
118 'targeted_user':self.user.id},
119 url='/mod/reports/{0}/'.format(comment_report.id))
120
121 self.query_for_users()
122 comment_report = Report.query.filter(
123 Report.reported_user==self.user).first()
124 assert response.status == '302 FOUND'
125 assert not self.user.has_privilege(u'commenter')
126 assert comment_report.is_archived_report() is True
127
128 fixture_add_comment_report(reported_user=self.user)
129 comment_report = Report.query.filter(
130 Report.reported_user==self.user).first()
131
132 # Then, test a moderator sending an email to a user in response to a
133 # reported comment
134 #----------------------------------------------------------------------
135 self.query_for_users()
136
137 response, context = self.do_post({'action_to_resolve':[u'sendmessage'],
138 'message_to_user':'This is your last warning, regular....',
139 'targeted_user':self.user.id},
140 url='/mod/reports/{0}/'.format(comment_report.id))
141
142 self.query_for_users()
143 comment_report = Report.query.filter(
144 Report.reported_user==self.user).first()
145 assert response.status == '302 FOUND'
146 assert mail.EMAIL_TEST_MBOX_INBOX == [{'to': [u'regular@example.com'],
147 'message': 'Content-Type: text/plain; charset="utf-8"\n\
148 MIME-Version: 1.0\nContent-Transfer-Encoding: base64\nSubject: Warning from- \
149 moderator \nFrom: notice@mediagoblin.example.org\nTo: regular@example.com\n\n\
150 VGhpcyBpcyB5b3VyIGxhc3Qgd2FybmluZywgcmVndWxhci4uLi4=\n',
151 'from': 'notice@mediagoblin.example.org'}]
152 assert comment_report.is_archived_report() is True
153
154 # Then test a moderator banning a user AND a moderator deleting the
155 # offending comment. This also serves as a test for taking multiple
156 # actions to resolve a report
157 #----------------------------------------------------------------------
158 self.query_for_users()
159 fixture_add_comment(author=self.user.id,
160 comment=u'Comment will be removed')
161 test_comment = TextComment.query.filter(
162 TextComment.actor==self.user.id).first()
163 fixture_add_comment_report(comment=test_comment,
164 reported_user=self.user)
165 comment_gmr = GenericModelReference.query.filter_by(
166 obj_pk=test_comment.id,
167 model_type=test_comment.__tablename__
168 ).first()
169 comment_report = Report.query.filter(
170 Report.object_id==comment_gmr.id).filter(
171 Report.resolved==None).first()
172
173 response, context = self.do_post(
174 {'action_to_resolve':[u'userban', u'delete'],
175 'targeted_user':self.user.id,
176 'why_user_was_banned':u'',
177 'user_banned_until':u''},
178 url='/mod/reports/{0}/'.format(comment_report.id))
179 assert response.status == '302 FOUND'
180 self.query_for_users()
181 test_user_ban = UserBan.query.filter(
182 UserBan.user_id == self.user.id).first()
183 assert test_user_ban is not None
184 test_comment = TextComment.query.filter(
185 TextComment.actor==self.user.id).first()
186 assert test_comment is None
187
188 # Then, test what happens when a moderator attempts to punish an admin
189 # from a reported comment on an admin.
190 #----------------------------------------------------------------------
191 fixture_add_comment_report(reported_user=self.admin_user)
192 comment_report = Report.query.filter(
193 Report.reported_user==self.admin_user).filter(
194 Report.resolved==None).first()
195
196 response, context = self.do_post({'action_to_resolve':[u'takeaway'],
197 'take_away_privileges':[u'active'],
198 'targeted_user':self.admin_user.id},
199 url='/mod/reports/{0}/'.format(comment_report.id))
200 self.query_for_users()
201
202 assert response.status == '200 OK'
203 assert self.admin_user.has_privilege(u'active')
204
205 def testAllModerationViews(self):
206 self.login(u'moderator')
207 username = self.user.username
208 self.query_for_users()
209 fixture_add_comment_report(reported_user=self.admin_user)
210 response = self.test_app.get('/mod/reports/')
211 assert response.status == "200 OK"
212
213 response = self.test_app.get('/mod/reports/1/')
214 assert response.status == "200 OK"
215
216 response = self.test_app.get('/mod/users/')
217 assert response.status == "200 OK"
218
219 user_page_url = '/mod/users/{0}/'.format(username)
220 response = self.test_app.get(user_page_url)
221 assert response.status == "200 OK"
222
223 self.test_app.get('/mod/media/')
224 assert response.status == "200 OK"
225
226 def testBanUnBanUser(self):
227 self.login(u'admin')
228 username = self.user.username
229 user_id = self.user.id
230 ban_url = '/mod/users/{0}/ban/'.format(username)
231 response, context = self.do_post({
232 'user_banned_until':u'',
233 'why_user_was_banned':u'Because I said so'},
234 url=ban_url)
235
236 assert response.status == "302 FOUND"
237 user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
238 assert user_banned is not None
239 assert user_banned.expiration_date is None
240 assert user_banned.reason == u'Because I said so'
241
242 response, context = self.do_post({},
243 url=ban_url)
244
245 assert response.status == "302 FOUND"
246 user_banned = UserBan.query.filter(UserBan.user_id==user_id).first()
247 assert user_banned is None