1 from datetime import datetime
2 from tests.test_basics import BasicTest
5 # no specific rights required
6 class GeneralTests(BasicTest):
19 def test_main_page(self):
20 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
21 self.assertEqual(response.status_code, 200)
23 def test_basic_results_data(self):
24 result = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
25 testtext= '<div class="motion card" id="motion-3">\n <div class="motion-title card-heading alert-warning">'\
26 + '\n <span class="title-text">Motion C</span> (Canceled)\n <span class="motion-type">group1</span>'\
27 + '\n <div># g1.20200402.003'\
28 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.003" role="button">Result</a>'\
29 + '\n </div>\n <div class="date">'\
30 + '\n <div>Proposed: 2020-04-02 21:47:24 (UTC) by User A</div>'\
31 + '\n <div>Canceled: 2020-04-03 21:48:24 (UTC) by User A</div>\n </div>\n </div>'\
32 + '\n <div class="card-body">\n <p><p>A third motion</p></p>'\
33 + '\n <p>\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
34 + '\nNo <span class="badge badge-pill badge-secondary">0</span><br>'\
35 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>'\
36 + '\n <p>Cancelation reason: Entered with wrong text</p>\n </div>\n</div>\n'
37 self.assertIn(str.encode(testtext), result.data)
38 testtext= '<div class="motion card" id="motion-2">\n <div class="motion-title card-heading alert-danger">'\
39 + '\n <span class="title-text">Motion B</span> (Finished)\n <span class="motion-type">group1</span>'\
40 + '\n <div># g1.20200402.002'\
41 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.002" role="button">Result</a>'\
42 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:41:26 (UTC) by User A</div>'\
43 + '\n <div>Votes until: 2020-04-04 21:41:26 (UTC)</div>\n </div>\n </div>'\
44 + '\n <div class="card-body">\n <p><p>A second motion</p></p>\n <p>'\
45 + '\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
46 + '\nNo <span class="badge badge-pill badge-secondary">2</span><br>'\
47 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
48 self.assertIn(str.encode(testtext), result.data)
49 testtext= '<div class="motion card" id="motion-1">\n <div class="motion-title card-heading alert-success">'\
50 + '\n <span class="title-text">Motion A</span> (Finished)\n <span class="motion-type">group1</span>'\
51 + '\n <div># g1.20200402.001'\
52 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.001" role="button">Result</a>'\
53 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:40:33 (UTC) by User A</div>'\
54 + '\n <div>Votes until: 2020-04-02 21:40:33 (UTC)</div>\n </div>\n </div>'\
55 + '\n <div class="card-body">\n <p><p>My special motion</p></p>\n <p>'\
56 + '\nYes <span class="badge badge-pill badge-secondary">2</span><br>'\
57 + '\nNo <span class="badge badge-pill badge-secondary">1</span><br>'\
58 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
59 self.assertIn(str.encode(testtext), result.data)
60 testtext= 'Proxy management'
61 self.assertNotIn(str.encode(testtext), result.data)
63 # start with second motion
64 result = self.app.get('/', environ_base={'USER_ROLES': user}, query_string=dict(start=2))
65 testtext= 'id=\"motion-3\">'
66 self.assertNotIn(str.encode(testtext), result.data)
67 testtext= 'id=\"motion-2">'
68 self.assertIn(str.encode(testtext), result.data)
69 testtext= 'id=\"motion-1\">'
70 self.assertIn(str.encode(testtext), result.data)
72 def test_basic_results_data_details(self):
73 motion='g1.20200402.002'
74 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
75 testtext= '<p>A second motion</p></p>\n </div>\n</div>\n<a href=\"/?start=2#motion-2\" class=\"btn btn-primary\">Back</a>'
76 self.assertIn(str.encode(testtext), result.data)
79 motion='g1.20200402.004'
80 response = self.createVote(user, motion, 'yes', userid)
81 self.assertEqual(response.status_code, 403)
82 self.assertIn(str.encode('Forbidden'), response.data)
84 def test_no_user(self):
85 result = self.app.get('/', follow_redirects=True)
86 self.assertEqual(result.status_code, 500)
87 self.assertIn(str.encode('Server misconfigured'), result.data)
89 def test_user_invalid(self):
90 result = self.app.get('/', environ_base={'USER_ROLES': '<invalid>/'}, follow_redirects=True)
91 self.assertEqual(result.status_code, 403)
92 self.assertIn(str.encode('Access denied'), result.data)
94 def test_basic_env(self):
95 result = self.app.get('/', environ_base={'USER': 'testuser', 'ROLES':''}, follow_redirects=True)
96 testtext= 'id=\"motion-3\">'
97 self.assertIn(str.encode(testtext), result.data)
99 def test_basic_results_data_details_not_given(self):
100 motion='g1.30190402.001'
101 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
102 self.assertEqual(result.status_code, 404)
103 self.assertIn(str.encode('Error, Not found'), result.data)
105 def test_no_proxy(self):
106 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
107 self.assertEqual(result.status_code, 403)
108 self.assertIn(str.encode('Forbidden'), result.data)
110 def test_no_proxy_add(self):
111 result = self.app.post('proxy/add', environ_base={'USER_ROLES': user}, follow_redirects=True)
112 self.assertEqual(result.status_code, 403)
113 self.assertIn(str.encode('Forbidden'), result.data)
115 def test_no_proxy_revoke(self):
116 result = self.app.post('proxy/revoke', environ_base={'USER_ROLES': user}, follow_redirects=True)
117 self.assertEqual(result.status_code, 403)
118 self.assertIn(str.encode('Forbidden'), result.data)
120 def test_no_proxy_revokeAll(self):
121 result = self.app.post('proxy/revokeall', environ_base={'USER_ROLES': user}, follow_redirects=True)
122 self.assertEqual(result.status_code, 403)
123 self.assertIn(str.encode('Forbidden'), result.data)
125 class VoterTests(BasicTest):
130 user='testuser/vote:*'
138 def test_main_page(self):
139 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
140 self.assertEqual(response.status_code, 200)
142 def test_home_data(self):
143 result = self.app.get('/', environ_base={'USER_ROLES': user})
144 self.assertNotIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
146 def test_vote_yes(self):
147 motion='g1.20200402.004'
148 response = self.createVote(user, motion, 'yes', userid)
149 self.assertEqual(response.status_code, 302)
150 result = self.app.get('/', environ_base={'USER_ROLES': user})
151 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
152 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
153 testtext= 'class=\"btn btn-success\" name=\"vote\" value="yes" id="vote-yes">Yes</button>'
154 self.assertIn(str.encode(testtext), result.data)
155 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
156 self.assertIn(str.encode(testtext), result.data)
157 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
158 self.assertIn(str.encode(testtext), result.data)
160 def test_vote_no(self):
161 motion='g1.20200402.004'
162 response = self.createVote(user, motion, 'no', userid)
163 self.assertEqual(response.status_code, 302)
164 result = self.app.get('/', environ_base={'USER_ROLES': user})
165 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
166 self.assertIn(str.encode(resulttext), result.data)
167 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
168 testtext= 'class="btn btn-primary" name="vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
169 self.assertIn(str.encode(testtext), result.data)
170 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
171 self.assertIn(str.encode(testtext), result.data)
172 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
173 self.assertIn(str.encode(testtext), result.data)
175 def test_vote_abstain(self):
176 motion='g1.20200402.004'
177 response = self.createVote(user, motion, 'abstain', userid)
178 self.assertEqual(response.status_code, 302)
179 result = self.app.get('/', environ_base={'USER_ROLES': user})
180 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
181 self.assertIn(str.encode(resulttext), result.data)
182 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
183 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
184 self.assertIn(str.encode(testtext), result.data)
185 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
186 self.assertIn(str.encode(testtext), result.data)
187 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
188 self.assertIn(str.encode(testtext), result.data)
190 def test_vote_change(self):
191 motion='g1.20200402.004'
192 response = self.createVote(user, motion, 'yes', userid)
193 self.assertEqual(response.status_code, 302)
194 result = self.app.get('/', environ_base={'USER_ROLES': user})
195 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
196 self.assertIn(str.encode(resulttext), result.data)
197 response = self.createVote(user, motion, 'no', userid)
198 self.assertEqual(response.status_code, 302)
199 result = self.app.get('/', environ_base={'USER_ROLES': user})
200 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
201 self.assertIn(str.encode(resulttext), result.data)
202 response = self.createVote(user, motion, 'abstain', userid)
203 self.assertEqual(response.status_code, 302)
204 result = self.app.get('/', environ_base={'USER_ROLES': user})
205 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
206 self.assertIn(str.encode(resulttext), result.data)
208 def test_vote_group(self):
209 motion='g1.20200402.004'
210 response = self.createVote(user, motion, 'yes', userid)
211 self.assertEqual(response.status_code, 302)
213 motion='g1.20200402.004'
214 user1='testuser/vote:group1'
215 response = self.createVote(user1, motion, 'yes', userid)
216 self.assertEqual(response.status_code, 302)
218 motion='g1.20200402.004'
219 user1='testuser/vote:group1 vote:group2'
220 response = self.createVote(user1, motion, 'yes', userid)
221 self.assertEqual(response.status_code, 302)
223 def test_vote_wrong_group(self):
224 motion='g1.20200402.004'
225 user1='testuser/vote:group2'
226 response = self.createVote(user1, motion, 'yes', userid)
227 self.assertEqual(response.status_code, 403)
228 self.assertIn(str.encode('Forbidden'), response.data)
230 def test_vote_closed(self):
231 motion='g1.20200402.002'
232 response = self.createVote(user, motion, 'abstain', userid)
233 self.assertEqual(response.status_code, 403)
234 self.assertIn(str.encode('Error, out of time'), response.data)
236 def test_vote_canceled(self):
237 motion='g1.20200402.003'
238 response = self.createVote(user, motion, 'abstain', userid)
239 self.assertEqual(response.status_code, 403)
240 self.assertIn(str.encode('Error, motion was canceled'), response.data)
242 def test_vote_not_given(self):
243 motion='g1.30190402.001'
244 response = self.createVote(user, motion, 'abstain', userid)
245 self.assertEqual(response.status_code, 404)
246 self.assertIn(str.encode('Error, Not found'), response.data)
248 def test_cancelMotion(self):
249 motion='g1.20200402.004'
251 response = self.cancelMotion(user, motion, reason)
252 self.assertEqual(response.status_code, 403)
253 self.assertIn(str.encode('Forbidden'), response.data)
255 def test_finishMotion(self):
256 motion='g1.20200402.004'
257 response = self.finishMotion(user, motion)
258 self.assertEqual(response.status_code, 403)
259 self.assertIn(str.encode('Forbidden'), response.data)
261 def test_see_old_vote(self):
262 motion='g1.20200402.002'
263 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
264 testtext= '<div>Proposed: 2020-04-02 21:41:26 (UTC) by User A</div>\n <div>Votes until: 2020-04-04 21:41:26 (UTC)</div>'\
265 + '\n </div>\n </div>\n <div class="card-body">\n <p><p>A second motion</p></p>\n </div>\n</div>'\
266 + '\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
267 self.assertIn(str.encode(testtext), result.data)
269 def test_createMotion(self):
272 response = self.createMotion(user, title, content, '3', 'group1')
273 self.assertEqual(response.status_code, 403)
274 self.assertIn(str.encode('Forbidden'), response.data)
277 class CreateMotionTests(BasicTest):
282 user='testuser/vote:* create:* cancel:* finish:*'
288 def test_main_page(self):
289 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
290 self.assertEqual(response.status_code, 200)
292 def test_home_data(self):
293 result = self.app.get('/', environ_base={'USER_ROLES': user})
295 # assert the response data
296 self.assertIn(b'User: testuser', result.data)
297 self.assertIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
299 def test_createMotion(self):
302 response = self.createMotion(user, title, content, '3', 'group1')
303 self.assertEqual(response.status_code, 302)
304 result = self.app.get('/', environ_base={'USER_ROLES': user})
305 self.assertIn(str.encode(title), result.data)
306 self.assertIn(str.encode(content), result.data)
307 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
308 testtext='<a class=\"btn btn-primary" href=\"/motion/g1.'+datetime.today().strftime('%Y%m%d')+'.001\" role=\"button\">Vote</a>'
309 self.assertIn(str.encode(testtext), result.data)
313 response = self.createMotion(user, title, content, '3', 'group1')
314 self.assertEqual(response.status_code, 302)
315 result = self.app.get('/', environ_base={'USER_ROLES': user})
316 self.assertIn(str.encode(title), result.data)
317 self.assertIn(str.encode(content), result.data)
318 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.002'), result.data)
322 response = self.createMotion(user, title, content, '3', 'group2')
323 self.assertEqual(response.status_code, 302)
324 result = self.app.get('/', environ_base={'USER_ROLES': user})
325 self.assertIn(str.encode(title), result.data)
326 self.assertIn(str.encode(content), result.data)
327 self.assertIn(str.encode('g2.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
331 user1='testuser/vote:* create:group1 cancel:*'
332 response = self.createMotion(user1, title, content, '3', 'group1')
333 self.assertEqual(response.status_code, 302)
337 user1='testuser/vote:* create:group1 create:group2 cancel:*'
338 response = self.createMotion(user1, title, content, '3', 'group1')
339 self.assertEqual(response.status_code, 302)
342 def test_createMotionMarkdown(self):
343 title='Markdown Test'
344 content= 'MyMotionBody MD [text](https//domain.tld/link)'
345 response = self.createMotion(user, title, content, '3', 'group1')
346 self.assertEqual(response.status_code, 302)
347 result = self.app.get('/', environ_base={'USER_ROLES': user})
348 self.assertIn(str.encode(title), result.data)
349 self.assertIn(b'MyMotionBody MD <a href=\"https//domain.tld/link\">text</a>', result.data)
351 def test_createMotionMarkdownDirectLink(self):
352 title='Markdown Test Link'
353 content='MyMotionBody MD <a href=\"https//domain.tld/link\">direct</a'
354 response = self.createMotion(user, title, content, '3', 'group1')
355 self.assertEqual(response.status_code, 302)
356 result = self.app.get('/', environ_base={'USER_ROLES': user})
357 self.assertIn(str.encode(title), result.data)
358 self.assertIn(b'MyMotionBody MD <a href="https//domain.tld/link">direct</a', result.data)
360 def test_createMotionMarkdownCombined(self):
361 title='Markdown Test Link'
362 content='Body [combined](https//domain.tld/link) <a href=\"https//domain.tld/link\">combined1</a'
363 response = self.createMotion(user, title, content, '3', 'group1')
364 self.assertEqual(response.status_code, 302)
365 result = self.app.get('/', environ_base={'USER_ROLES': user})
366 self.assertIn(str.encode(title), result.data)
367 self.assertIn(b'Body <a href=\"https//domain.tld/link\">combined</a> <a href="https//domain.tld/link">combined1</a', result.data)
369 def test_createMotionWrongDayLength(self):
372 response = self.createMotion(user, title, content, '21', 'group1')
373 self.assertEqual(response.status_code, 400)
374 self.assertIn(str.encode('Error, invalid length'), response.data)
376 def test_createMotionMissingData(self):
379 response = self.createMotion(user, title, content, '3', 'group1')
380 self.assertEqual(response.status_code, 400)
381 self.assertIn(str.encode('Error, missing title'), response.data)
383 response = self.createMotion(user, title, content, '3', 'group1')
384 self.assertEqual(response.status_code, 400)
385 self.assertIn(str.encode('Error, missing content'), response.data)
387 content='New Content'
388 response = self.createMotion(user, title, content, '3', 'group1')
389 self.assertEqual(response.status_code, 400)
390 self.assertIn(str.encode('Error, missing title'), response.data)
392 def test_createMotionWrongGroup(self):
395 response = self.createMotion(user, title, content, '3', 'test1')
396 self.assertEqual(response.status_code, 403)
397 self.assertIn(str.encode('Forbidden'), response.data)
399 user1='testuser/vote:* create:group1 cancel:*'
400 response = self.createMotion(user1, title, content, '3', 'group2')
401 self.assertEqual(response.status_code, 403)
402 self.assertIn(str.encode('Forbidden'), response.data)
404 def test_SeeCancelMotion(self):
407 motion='g1.20200402.004'
408 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
409 testtext= '<button type="submit" class="btn btn-danger" name="cancel" value="cancel" id="cancel">Cancel</button>'
410 self.assertIn(str.encode(testtext), result.data)
412 motion='g1.20200402.004'
413 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': 'testuser/vote:*'}, follow_redirects=True)
414 testtext= '<button type="submit" class="btn btn-danger" name="cancel" value="cancel" id="cancel">Cancel</button>'
415 self.assertNotIn(str.encode(testtext), result.data)
417 def test_cancelMotion(self):
420 motion='g1.20200402.004'
422 response = self.cancelMotion(user, motion, reason)
423 self.assertEqual(response.status_code, 500)
424 self.assertIn(str.encode('Error, form requires reason'), response.data)
427 response = self.cancelMotion(user, motion, reason)
428 self.assertEqual(response.status_code, 302)
429 result = self.app.get('/', environ_base={'USER_ROLES': user})
430 self.assertIn(b'Cancelation reason: ' + str.encode(reason), result.data)
432 motion='g1.20190402.001'
434 response = self.cancelMotion(user, motion, reason)
435 self.assertEqual(response.status_code, 404)
436 self.assertIn(str.encode('Error, Not found'), response.data)
438 motion='g1.30200402.001'
440 response = self.cancelMotion(user, motion, reason)
441 self.assertEqual(response.status_code, 404)
442 self.assertIn(str.encode('Error, Not found'), response.data)
444 motion='g1.20200402.004'
445 response = self.cancelMotion(user, motion, reason)
446 self.assertEqual(response.status_code, 403)
447 self.assertIn(str.encode('Error, motion was canceled'), response.data)
449 def test_SeeFinishMotion(self):
452 motion='g1.20200402.004'
453 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
454 testtext= '<button type="submit" class="btn btn-danger" name="finish" value="finish" id="finish">Finish</button>'
455 self.assertIn(str.encode(testtext), result.data)
457 motion='g1.20200402.004'
458 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': 'testuser/vote:*'}, follow_redirects=True)
459 testtext= '<button type="submit" class="btn btn-danger" name="finish" value="finish" id="finish">Finish</button>'
460 self.assertNotIn(str.encode(testtext), result.data)
462 def test_finishMotion(self):
465 motion='g1.20200402.004'
466 response = self.finishMotion(user, motion)
467 self.assertEqual(response.status_code, 302)
468 result = self.app.get('/', environ_base={'USER_ROLES': user})
469 self.assertIn(b'Motion D</span> (Finished)', result.data)
471 motion='g1.30190402.001'
472 response = self.finishMotion(user, motion)
473 self.assertEqual(response.status_code, 404)
474 self.assertIn(str.encode('Error, Not found'), response.data)
476 motion='g1.20200402.001'
477 response = self.finishMotion(user, motion)
478 self.assertEqual(response.status_code, 403)
479 self.assertIn(str.encode('Error, out of time'), response.data)
481 def test_createMotionWait(self):
482 # test no limit given
486 response = self.createMotion(user, title, content, '3', 'group1')
487 self.assertEqual(response.status_code, 302)
489 # test different host
490 app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5001':1})
491 response = self.createMotion(user, title, content, '3', 'group1')
492 self.assertEqual(response.status_code, 302)
495 app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5000':3})
496 response = self.createMotion(user, title, content, '3', 'group1')
497 self.assertIn(str.encode('Error, time between last motion to short. The current setting is 3 minute(s).'), response.data)
499 class AuditMotionTests(BasicTest):
504 user='testuser/audit:*'
510 def test_see_old_vote(self):
511 motion='g1.20200402.002'
512 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
513 testtext= '<div class="motion card" id="votes">\n <div class="card-heading text-white bg-info">\n Motion Votes\n </div>'\
514 + '\n <div class="card-body">\n <div>User A: yes</div>\n <div>User B: no</div>'\
515 + '\n <div>User C: no</div>\n </div>\n</div>\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
516 self.assertIn(str.encode(testtext), result.data)
518 class ProxyManagementTests(BasicTest):
523 user='testuser/proxyadmin:*'
531 def test_see_proxy(self):
532 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
533 testtext= 'div class="container">\n<form action="/proxy/add" method="POST">'
534 self.assertIn(str.encode(testtext), result.data)
535 testtext= 'proxy granted to:'
536 self.assertNotIn(str.encode(testtext), result.data)
537 testtext= 'holds proxy of:'
538 self.assertNotIn(str.encode(testtext), result.data)
539 testtext= '<select class="float form-control" name="voter">\n '\
540 + '<option>User A</option>\n <option>User B</option>\n '\
541 + '<option>User C</option>\n '\
542 + '<option>testuser</option>\n '\
544 self.assertIn(str.encode(testtext), result.data)
545 testtext= '<select class="float form-control" name="proxy">\n '\
546 + '<option>User A</option>\n '\
547 + '<option>User B</option>\n '\
548 + '<option>User C</option>\n '\
549 + '<option>testuser</option>\n '\
551 self.assertIn(str.encode(testtext), result.data)
552 testtext= '<table>\n '\
554 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n '\
556 self.assertIn(str.encode(testtext), result.data)
557 testtext= '<a class="nav-link" href="/proxy">Proxy management</a>'
558 self.assertIn(str.encode(testtext), result.data)
560 def test_add_proxy(self):
563 response = self.addProxy(user, voter, proxy)
564 self.assertEqual(response.status_code, 400)
565 self.assertIn(str.encode('Error, voter equals proxy.'), response.data)
568 response = self.addProxy(user, voter, proxy)
569 self.assertEqual(response.status_code, 400)
570 self.assertIn(str.encode('Error, proxy not found.'), response.data)
573 response = self.addProxy(user, voter, proxy)
574 self.assertEqual(response.status_code, 400)
575 self.assertIn(str.encode('Error, voter not found.'), response.data)
579 response = self.addProxy(user, voter, proxy)
580 self.assertEqual(response.status_code, 400)
581 self.assertIn(str.encode('Error, voter not found.'), response.data)
585 response = self.addProxy(user, voter, proxy)
586 self.assertEqual(response.status_code, 400)
587 self.assertIn(str.encode('Error, voter equals proxy.'), response.data)
591 response = self.addProxy(user, voter, proxy)
592 self.assertEqual(response.status_code, 400)
593 self.assertIn(str.encode('Error, proxy not found.'), response.data)
597 response = self.addProxy(user, voter, proxy)
598 self.assertEqual(response.status_code, 302)
599 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
600 testtext= '<form action="/proxy/revoke" method="POST">'
601 self.assertIn(str.encode(testtext), result.data)
602 testtext= '<table>\n '\
604 + '<th>Voter</th>\n '\
605 + '<th>Proxy</th>\n <th></th>\n </thead>\n '\
606 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
607 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n '\
608 + '</tr>\n </table>\n'
609 self.assertIn(str.encode(testtext), result.data)
611 response = self.addProxy(user, voter, proxy)
612 self.assertEqual(response.status_code, 400)
613 self.assertIn(str.encode('Error, proxy allready given.'), response.data)
617 response = self.addProxy(user, voter, proxy)
618 self.assertEqual(response.status_code, 400)
619 self.assertIn(str.encode('Error, proxy allready given.'), response.data)
623 response = self.addProxy(user, voter, proxy)
624 self.assertEqual(response.status_code, 302)
625 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
626 testtext= '<table>\n '\
628 + '<th>Voter</th>\n '\
629 + '<th>Proxy</th>\n <th></th>\n </thead>\n '\
630 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
631 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n </tr>\n '\
632 + '<tr>\n <td>User C</td>\n <td>User B</td>\n '\
633 + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n '\
634 + '</tr>\n </table>\n'
635 self.assertIn(str.encode(testtext), result.data)
636 testtext= 'proxy granted to:'
637 self.assertNotIn(str.encode(testtext), result.data)
638 testtext= 'holds proxy of:'
639 self.assertNotIn(str.encode(testtext), result.data)
643 response = self.addProxy(user, voter, proxy)
644 self.assertEqual(response.status_code, 400)
645 self.assertIn(str.encode('Error, Max proxy for \'User B\' reached.'), response.data)
649 response = self.addProxy(user, voter, proxy)
650 self.assertEqual(response.status_code, 302)
651 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
652 testtext= '<table>\n '\
654 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n '\
655 + '<tr>\n <td>testuser</td>\n <td>User A</td>\n '\
656 + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n </tr>\n '\
657 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
658 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n </tr>\n '\
659 + '<tr>\n <td>User C</td>\n <td>User B</td>\n '\
660 + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n '\
661 + '</tr>\n </table>\n'
662 self.assertIn(str.encode(testtext), result.data)
663 testtext= 'proxy granted to: User A\n'
664 self.assertIn(str.encode(testtext), result.data)
665 testtext= 'holds proxy of:'
666 self.assertNotIn(str.encode(testtext), result.data)
670 response = self.addProxy(user, voter, proxy)
671 self.assertEqual(response.status_code, 302)
672 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
673 testtext= '<table>\n '\
675 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n '\
676 + '<tr>\n <td>testuser</td>\n <td>User A</td>\n '\
677 + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n </tr>\n '\
678 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
679 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n </tr>\n '\
680 + '<tr>\n <td>User B</td>\n <td>testuser</td>\n '\
681 + '<td><button type="submit" class="btn btn-danger" name="id" value="4">Revoke</button></td>\n </tr>\n '\
682 + '<tr>\n <td>User C</td>\n <td>User B</td>\n '\
683 + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n '\
684 + '</tr>\n </table>\n'
685 self.assertIn(str.encode(testtext), result.data)
686 testtext= 'proxy granted to: User A\n'
687 self.assertIn(str.encode(testtext), result.data)
688 testtext= 'holds proxy of: User B\n'
689 self.assertIn(str.encode(testtext), result.data)
691 response = self.revokeProxy(user, userid)
692 self.assertEqual(response.status_code, 302)
693 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
694 testtext= '<table>\n '\
696 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n '\
697 + '<tr>\n <td>testuser</td>\n <td>User A</td>\n '\
698 + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n </tr>\n '\
699 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
700 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n </tr>\n '\
701 + '<tr>\n <td>User C</td>\n <td>User B</td>\n '\
702 + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n '\
703 + '</tr>\n </table>\n'
704 self.assertIn(str.encode(testtext), result.data)
705 testtext= 'proxy granted to: User A\n'
706 self.assertIn(str.encode(testtext), result.data)
707 testtext= 'holds proxy of:'
708 self.assertNotIn(str.encode(testtext), result.data)
710 response = self.revokeProxy(user, 3)
711 self.assertEqual(response.status_code, 302)
712 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
713 testtext= '<table>\n '\
715 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n '\
716 + '<tr>\n <td>User A</td>\n <td>User B</td>\n '\
717 + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n </tr>\n '\
718 + '<tr>\n <td>User C</td>\n <td>User B</td>\n '\
719 + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n '\
720 + '</tr>\n </table>\n'
721 self.assertIn(str.encode(testtext), result.data)
722 testtext= 'proxy granted to:'
723 self.assertNotIn(str.encode(testtext), result.data)
724 testtext= 'holds proxy of:'
725 self.assertNotIn(str.encode(testtext), result.data)
727 result = self.app.post('proxy/revokeall', environ_base={'USER_ROLES': user}, follow_redirects=True)
728 self.assertEqual(response.status_code, 302)
729 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
730 testtext= '<table>\n '\
732 + '<th>Voter</th>\n <th>Proxy</th>\n <th></th>\n </thead>\n'\
734 self.assertNotIn(str.encode(testtext), result.data)
736 proxytest="proxytest"
737 with self.open_DB() as db:
738 db.prepare("INSERT INTO voter(\"email\", \"host\") VALUES($1, $2)")(proxytest, '127.0.0.1:5001')
739 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
741 response = self.addProxy(user, proxytest, 'testuser')
742 self.assertEqual(response.status_code, 400)
743 self.assertIn(str.encode('Error, voter not found.'), response.data)
745 response = self.addProxy(user, 'testuser', proxytest)
746 self.assertEqual(response.status_code, 400)
747 self.assertIn(str.encode('Error, proxy not found.'), response.data)
749 def test_see_proxy_host_only(self):
750 proxytest="proxytest"
751 with self.open_DB() as db:
752 db.prepare("INSERT INTO voter(\"email\", \"host\") VALUES($1, $2)")(proxytest, '127.0.0.1:5001')
753 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
754 testtext= 'div class="container">\n<form action="/proxy/add" method="POST">'
755 self.assertIn(str.encode(testtext), result.data)
756 testtext= 'proxy granted to:'
757 self.assertNotIn(str.encode(testtext), result.data)
758 testtext= 'holds proxy of:'
759 self.assertNotIn(str.encode(testtext), result.data)
760 testtext= '<select class="float form-control" name="voter">\n '\
761 + '<option>User A</option>\n <option>User B</option>\n '\
762 + '<option>User C</option>\n '\
763 + '<option>testuser</option>\n '\
765 self.assertIn(str.encode(testtext), result.data)
766 testtext= '<select class="float form-control" name="proxy">\n '\
767 + '<option>User A</option>\n '\
768 + '<option>User B</option>\n '\
769 + '<option>User C</option>\n '\
770 + '<option>testuser</option>\n '\
772 self.assertIn(str.encode(testtext), result.data)
773 self.assertNotIn(str.encode(proxytest), result.data)
775 class ProxyVoteTests(BasicTest):
780 user='testuser/vote:* proxyadmin:*'
786 def test_proxy_vote(self):
790 proxyuser='User B/vote:*'
792 response = self.addProxy(user, proxy, voter)
793 self.assertEqual(response.status_code, 302)
795 motion='g1.20200402.004'
796 response = self.createVote(user, motion, 'yes', proxyid)
797 self.assertEqual(response.status_code, 302)
800 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
801 # own vote without change
802 testtext= '<form action="/motion/g1.20200402.004/vote/4" method="POST">\n'\
803 + '<button type="submit" class="btn btn-primary" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
804 + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
805 + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>'
806 self.assertIn(str.encode(testtext), result.data)
807 # proxy vote with change
808 testtext= '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
809 + '<button type="submit" class="btn btn-success" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
810 + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
811 + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>\n'
812 self.assertIn(str.encode(testtext), result.data)
815 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': proxyuser}, follow_redirects=True)
816 # own vote without change
817 testtext= '<h3>My vote</h3>\nGiven by testuser\n'\
818 + '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
819 + '<button type="submit" class="btn btn-success" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
820 + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
821 + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>'
822 self.assertIn(str.encode(testtext), result.data)
825 response = self.createVote(user, motion, 'no', proxyid)
826 self.assertEqual(response.status_code, 302)
828 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
829 testtext= '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
830 + '<button type="submit" class="btn btn-primary" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
831 + '<button type="submit" class="btn btn-success" name="vote" value="no" id="vote-no">No</button>\n'\
832 + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>\n'
833 self.assertIn(str.encode(testtext), result.data)
835 def test_proxy_vote_no_proxy(self):
841 response = self.addProxy(user, proxy, voter)
842 self.assertEqual(response.status_code, 302)
844 motion='g1.20200402.004'
845 response = self.createVote(user, motion, 'yes', proxyid)
846 self.assertEqual(response.status_code, 400)
847 self.assertIn(str.encode('Error, proxy not found'), response.data)
852 motion='g1.20200402.004'
853 response = self.createVote(user, motion, 'yes', proxyid)
854 self.assertEqual(response.status_code, 400)
855 self.assertIn(str.encode('Error, proxy not found'), response.data)
857 def test_proxy_vote_no_voter(self):
862 response = self.addProxy(user, proxy, voter)
863 self.assertEqual(response.status_code, 302)
866 motion='g1.20200402.004'
867 response = self.createVote(user1, motion, 'yes', proxyid)
868 self.assertEqual(response.status_code, 403)
869 self.assertIn(str.encode('Forbidden'), response.data)
873 if __name__ == "__main__":