test_pagure_flask_ui_issues_acl_checks.py 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. """
  4. (c) 2017 - Copyright Red Hat Inc
  5. Authors:
  6. Vivek Anand <vivekanand1101@gmail.com>
  7. """
  8. from __future__ import unicode_literals
  9. __requires__ = ['SQLAlchemy >= 0.8']
  10. import pkg_resources
  11. from unittest.case import SkipTest
  12. import json
  13. import unittest
  14. import shutil
  15. import sys
  16. import os
  17. try:
  18. import pyclamd
  19. except ImportError:
  20. pyclamd = None
  21. import tempfile
  22. import pygit2
  23. from mock import patch
  24. sys.path.insert(0, os.path.join(os.path.dirname(
  25. os.path.abspath(__file__)), '..'))
  26. import pagure.config
  27. import pagure.lib.query
  28. import tests
  29. class PagureFlaskIssuesACLtests(tests.Modeltests):
  30. """ Tests for flask issues controller of pagure for acls """
  31. @patch('pagure.lib.git.update_git')
  32. @patch('pagure.lib.notify.send_email')
  33. def test_view_issue_no_access(self, p_send_email, p_ugt):
  34. """ Test the view_issue endpoint. when a user has no access on repo """
  35. p_send_email.return_value = True
  36. p_ugt.return_value = True
  37. output = self.app.get('/foo/issue/1')
  38. self.assertEqual(output.status_code, 404)
  39. tests.create_projects(self.session)
  40. tests.create_projects_git(
  41. os.path.join(self.path, 'repos'), bare=True)
  42. output = self.app.get('/test/issue/1')
  43. self.assertEqual(output.status_code, 404)
  44. # Create issues to play with
  45. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  46. msg = pagure.lib.query.new_issue(
  47. session=self.session,
  48. repo=repo,
  49. title='Test issue',
  50. content='We should work on this',
  51. user='pingou',
  52. )
  53. self.session.commit()
  54. self.assertEqual(msg.title, 'Test issue')
  55. # Add milestone
  56. repo.milestones = {'77': None}
  57. self.session.add(repo)
  58. issue = pagure.lib.query.search_issues(
  59. self.session,
  60. repo=repo,
  61. issueid=1
  62. )
  63. pagure.lib.query.edit_issue(
  64. self.session,
  65. issue,
  66. user='pingou',
  67. milestone='77'
  68. )
  69. self.session.add(repo)
  70. self.session.add(issue)
  71. msg = pagure.lib.query.set_custom_key_fields(
  72. self.session,
  73. project=repo,
  74. fields=['abc', 'xyz'],
  75. types=['boolean', 'boolean'],
  76. data=[None, None],
  77. )
  78. self.assertEqual(msg, 'List of custom fields updated')
  79. self.session.add(repo)
  80. msg = pagure.lib.query.set_custom_key_value(
  81. self.session,
  82. issue=issue,
  83. key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
  84. value=1
  85. )
  86. self.session.add(issue)
  87. self.session.commit()
  88. output = self.app.get('/test/issue/1')
  89. self.assertEqual(output.status_code, 200)
  90. # Not authentified = No edit
  91. self.assertNotIn(
  92. '<a class="btn btn-outline-secondary btn-sm border-0" '
  93. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  94. output.get_data(as_text=True))
  95. self.assertTrue(
  96. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  97. 'Login</a>\n to comment on this ticket.'
  98. in output.get_data(as_text=True))
  99. user = tests.FakeUser()
  100. with tests.user_set(self.app.application, user):
  101. output = self.app.get('/test/issue/1')
  102. self.assertEqual(output.status_code, 200)
  103. output_text = output.get_data(as_text=True)
  104. # Not author nor admin = No edit
  105. self.assertNotIn(
  106. '<a class="btn btn-outline-secondary btn-sm border-0" '
  107. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  108. output_text)
  109. self.assertNotIn(
  110. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  111. ' title="Delete this ticket">\n',
  112. output.get_data(as_text=True))
  113. # no edit metadata
  114. self.assertNotIn(
  115. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  116. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  117. '<i class="fa fa-fw fa-pencil">',
  118. output_text)
  119. self.assertNotIn(
  120. '<a href="/login/">Login</a> to comment on this ticket.',
  121. output_text)
  122. # can view the milestone
  123. self.assertIn(
  124. '<strong>Milestone</strong>',
  125. output_text)
  126. self.assertIn(
  127. '\n <a href="/test/roadmap/77/">'
  128. '\n 77\n', output_text)
  129. # but can't edit them
  130. self.assertNotIn(
  131. '<select class="form-control c-select" id="milestone" '
  132. ' name="milestone"><option value=""></option><option '
  133. 'selected value="77">77</option></select>',
  134. output_text)
  135. # can view depending
  136. self.assertIn(
  137. '<strong>Depending on</strong>',
  138. output.get_data(as_text=True))
  139. # can't edit depending on
  140. self.assertNotIn(
  141. '<input class="form-control" id="depending" type="text"\n\
  142. placeholder="issue depending" name="depending"\n\
  143. value="" />',
  144. output_text)
  145. # no checkbox for private
  146. self.assertNotIn(
  147. '<input id="private" name="private" type="checkbox" value="y">',
  148. output_text)
  149. user.username = 'foo'
  150. with tests.user_set(self.app.application, user):
  151. output = self.app.get('/test/issue/1')
  152. self.assertEqual(output.status_code, 200)
  153. output_text = output.get_data(as_text=True)
  154. self.assertNotIn(
  155. '<a class="btn btn-outline-secondary btn-sm border-0" '
  156. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  157. output_text)
  158. self.assertNotIn(
  159. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  160. ' title="Delete this ticket">\n',
  161. output_text)
  162. csrf_token = self.get_csrf(output=output)
  163. # no edit metadata
  164. self.assertNotIn(
  165. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  166. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  167. '<i class="fa fa-fw fa-pencil">',
  168. output_text)
  169. self.assertNotIn(
  170. '<a href="/login/">Login</a> to comment on this ticket.',
  171. output_text)
  172. # can't see the custom field as a checkbox
  173. self.assertNotIn(
  174. '<input type="checkbox" '
  175. 'class="form-control" name="abc" id="abc"checked/>',
  176. output_text)
  177. # can view the milestone
  178. self.assertIn(
  179. '<strong>Milestone</strong>',
  180. output.get_data(as_text=True))
  181. self.assertIn(
  182. '<a href="/test/roadmap/77/">\n 77',
  183. output.get_data(as_text=True))
  184. # but can't edit them
  185. self.assertNotIn(
  186. '<select class="form-control c-select" id="milestone" '
  187. ' name="milestone"><option value=""></option><option '
  188. 'selected value="77">77</option></select>',
  189. output_text)
  190. # can view depending
  191. self.assertIn(
  192. '<strong>Depending on</strong>',
  193. output_text)
  194. # can't edit depending on
  195. self.assertNotIn(
  196. '<input class="form-control" id="depending" type="text"\n\
  197. placeholder="issue depending" name="depending"\n\
  198. value="" />',
  199. output_text)
  200. # no checkbox for private
  201. self.assertNotIn(
  202. '<input id="private" name="private" type="checkbox" value="y">',
  203. output_text)
  204. # Create private issue
  205. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  206. msg = pagure.lib.query.new_issue(
  207. session=self.session,
  208. repo=repo,
  209. title='Test issue',
  210. content='We should work on this',
  211. user='pingou',
  212. private=True,
  213. )
  214. self.session.commit()
  215. self.assertEqual(msg.title, 'Test issue')
  216. # Not logged in
  217. output = self.app.get('/test/issue/2')
  218. self.assertEqual(output.status_code, 404)
  219. # Wrong user
  220. user = tests.FakeUser()
  221. with tests.user_set(self.app.application, user):
  222. output = self.app.get('/test/issue/2')
  223. self.assertEqual(output.status_code, 404)
  224. # reporter
  225. user.username = 'pingou'
  226. with tests.user_set(self.app.application, user):
  227. output = self.app.get('/test/issue/2')
  228. self.assertEqual(output.status_code, 200)
  229. output_text = output.get_data(as_text=True)
  230. self.assertIn(
  231. '<title>Issue #2: Test issue - test - Pagure</title>',
  232. output_text)
  233. self.assertIn(
  234. '<span title="Private ticket" class="text-danger '
  235. 'fa fa-fw fa-lock"></span>', output_text)
  236. self.assertIn(
  237. '<a class="btn btn-outline-secondary btn-sm border-0" '
  238. 'href="/test/issue/2/edit" title="Edit this issue">\n',
  239. output_text)
  240. @patch('pagure.lib.git.update_git')
  241. @patch('pagure.lib.notify.send_email')
  242. def test_view_issue_ticket_access(self, p_send_email, p_ugt):
  243. """ Test the view_issue endpoint. when a user has ticket access on repo """
  244. p_send_email.return_value = True
  245. p_ugt.return_value = True
  246. output = self.app.get('/foo/issue/1')
  247. self.assertEqual(output.status_code, 404)
  248. tests.create_projects(self.session)
  249. tests.create_projects_git(
  250. os.path.join(self.path, 'repos'), bare=True)
  251. output = self.app.get('/test/issue/1')
  252. self.assertEqual(output.status_code, 404)
  253. # Create issues to play with
  254. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  255. # Add user 'foo' with ticket access on repo
  256. msg = pagure.lib.query.add_user_to_project(
  257. self.session,
  258. repo,
  259. new_user='foo',
  260. user='pingou',
  261. access='ticket',
  262. )
  263. self.assertEqual(msg, 'User added')
  264. self.session.commit()
  265. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  266. msg = pagure.lib.query.new_issue(
  267. session=self.session,
  268. repo=repo,
  269. title='Test issue',
  270. content='We should work on this',
  271. user='pingou',
  272. )
  273. self.session.commit()
  274. self.assertEqual(msg.title, 'Test issue')
  275. # Add milestone
  276. repo.milestones = {'77': None}
  277. self.session.add(repo)
  278. issue = pagure.lib.query.search_issues(
  279. self.session,
  280. repo=repo,
  281. issueid=1
  282. )
  283. pagure.lib.query.edit_issue(
  284. self.session,
  285. issue,
  286. user='pingou',
  287. milestone='77'
  288. )
  289. self.session.add(repo)
  290. self.session.add(issue)
  291. msg = pagure.lib.query.set_custom_key_fields(
  292. self.session,
  293. project=repo,
  294. fields=['abc', 'xyz'],
  295. types=['boolean', 'boolean'],
  296. data=[None, None],
  297. )
  298. self.assertEqual(msg, 'List of custom fields updated')
  299. self.session.add(repo)
  300. msg = pagure.lib.query.set_custom_key_value(
  301. self.session,
  302. issue=issue,
  303. key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
  304. value=1
  305. )
  306. self.session.add(issue)
  307. self.session.commit()
  308. output = self.app.get('/test/issue/1')
  309. self.assertEqual(output.status_code, 200)
  310. output_text = output.get_data(as_text=True)
  311. # Not authentified = No edit
  312. self.assertNotIn(
  313. '<a class="btn btn-outline-secondary btn-sm border-0" '
  314. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  315. output_text)
  316. self.assertIn(
  317. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  318. 'Login</a>\n to comment on this ticket.',
  319. output_text)
  320. user = tests.FakeUser()
  321. with tests.user_set(self.app.application, user):
  322. output = self.app.get('/test/issue/1')
  323. self.assertEqual(output.status_code, 200)
  324. output_text = output.get_data(as_text=True)
  325. # Not author nor admin = No edit
  326. self.assertNotIn(
  327. '<a class="btn btn-outline-secondary btn-sm border-0" '
  328. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  329. output_text)
  330. self.assertNotIn(
  331. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  332. ' title="Delete this ticket">\n',
  333. output_text)
  334. # no edit metadata
  335. self.assertNotIn(
  336. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  337. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  338. '<i class="fa fa-fw fa-pencil">',
  339. output_text)
  340. self.assertNotIn(
  341. '<a href="/login/">Login</a> to comment on this ticket.',
  342. output_text)
  343. # can view the milestone
  344. self.assertIn(
  345. '<strong>Milestone</strong>',
  346. output_text)
  347. self.assertIn(
  348. '<a href="/test/roadmap/77/">\n 77',
  349. output_text)
  350. # but can't edit them
  351. self.assertNotIn(
  352. '<select class="form-control c-select" id="milestone" '
  353. ' name="milestone"><option value=""></option><option '
  354. 'selected value="77">77</option></select>',
  355. output_text)
  356. # can view depending
  357. self.assertIn(
  358. '<strong>Depending on</strong>',
  359. output_text)
  360. # can't edit depending on
  361. self.assertNotIn(
  362. '<input class="form-control" id="depending" type="text"\n\
  363. placeholder="issue depending" name="depending"\n\
  364. value="" />',
  365. output_text)
  366. # no checkbox for private
  367. self.assertNotIn(
  368. '<input id="private" name="private" type="checkbox" value="y">',
  369. output_text)
  370. user.username = 'foo'
  371. with tests.user_set(self.app.application, user):
  372. output = self.app.get('/test/issue/1')
  373. self.assertEqual(output.status_code, 200)
  374. output_text = output.get_data(as_text=True)
  375. # the user can't edit the issue
  376. self.assertNotIn(
  377. '<a class="btn btn-outline-secondary btn-sm border-0" '
  378. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  379. output_text)
  380. # the user still can't delete the ticket
  381. self.assertNotIn(
  382. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  383. ' title="Delete this ticket">\n',
  384. output_text)
  385. csrf_token = self.get_csrf(output=output)
  386. # the user can do the following things
  387. # edit metadata
  388. self.assertIn(
  389. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  390. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  391. '<i class="fa fa-fw fa-pencil">',
  392. output_text)
  393. # can view the milestone
  394. self.assertIn(
  395. '<strong>Milestone</strong>',
  396. output_text)
  397. self.assertIn(
  398. '<a href="/test/roadmap/77/">\n 77',
  399. output_text)
  400. # can edit them
  401. self.assertIn(
  402. '<select class="form-control c-select" id="milestone" '
  403. 'name="milestone"><option value=""></option><option selected '
  404. 'value="77">77</option></select>\n <div>\n',
  405. output_text)
  406. # can view depending
  407. self.assertIn(
  408. '<strong>Depending on</strong>',
  409. output_text)
  410. # can edit depending on
  411. self.assertIn(
  412. '<input class="form-control" id="depending" type="text"'
  413. '\n placeholder="issue depending" name="depending"\n',
  414. output_text)
  415. # the user should be able to do public -> private
  416. # the other way round won't be possible since GET and POST
  417. # to this endpoint for this user will be blocked
  418. # checkbox for private
  419. self.assertIn(
  420. '<input id="private" name="private" type="checkbox" value="y">',
  421. output_text)
  422. # Create private issue
  423. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  424. msg = pagure.lib.query.new_issue(
  425. session=self.session,
  426. repo=repo,
  427. title='Test issue',
  428. content='We should work on this',
  429. user='pingou',
  430. private=True,
  431. )
  432. self.session.commit()
  433. self.assertEqual(msg.title, 'Test issue')
  434. # Not logged in
  435. output = self.app.get('/test/issue/2')
  436. self.assertEqual(output.status_code, 404)
  437. # Wrong user
  438. user = tests.FakeUser()
  439. with tests.user_set(self.app.application, user):
  440. output = self.app.get('/test/issue/2')
  441. self.assertEqual(output.status_code, 404)
  442. # reporter
  443. user.username = 'pingou'
  444. with tests.user_set(self.app.application, user):
  445. output = self.app.get('/test/issue/2')
  446. self.assertEqual(output.status_code, 200)
  447. output_text = output.get_data(as_text=True)
  448. self.assertIn(
  449. '<title>Issue #2: Test issue - test - Pagure</title>',
  450. output_text)
  451. self.assertIn(
  452. '<span title="Private ticket" class="text-danger '
  453. 'fa fa-fw fa-lock"></span>', output_text)
  454. self.assertIn(
  455. '<a class="btn btn-outline-secondary btn-sm border-0" '
  456. 'href="/test/issue/2/edit" title="Edit this issue">\n',
  457. output_text)
  458. @patch('pagure.lib.git.update_git')
  459. @patch('pagure.lib.notify.send_email')
  460. def test_view_issue_commit_access(self, p_send_email, p_ugt):
  461. """ Test the view_issue endpoint. when a user has commit access on repo """
  462. p_send_email.return_value = True
  463. p_ugt.return_value = True
  464. output = self.app.get('/foo/issue/1')
  465. self.assertEqual(output.status_code, 404)
  466. tests.create_projects(self.session)
  467. tests.create_projects_git(
  468. os.path.join(self.path, 'repos'), bare=True)
  469. output = self.app.get('/test/issue/1')
  470. self.assertEqual(output.status_code, 404)
  471. # Create issues to play with
  472. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  473. # Add user 'foo' with ticket access on repo
  474. msg = pagure.lib.query.add_user_to_project(
  475. self.session,
  476. repo,
  477. new_user='foo',
  478. user='pingou',
  479. access='commit',
  480. )
  481. self.assertEqual(msg, 'User added')
  482. self.session.commit()
  483. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  484. msg = pagure.lib.query.new_issue(
  485. session=self.session,
  486. repo=repo,
  487. title='Test issue',
  488. content='We should work on this',
  489. user='pingou',
  490. )
  491. self.session.commit()
  492. self.assertEqual(msg.title, 'Test issue')
  493. # Add milestone
  494. repo.milestones = {'77': None}
  495. self.session.add(repo)
  496. issue = pagure.lib.query.search_issues(
  497. self.session,
  498. repo=repo,
  499. issueid=1
  500. )
  501. pagure.lib.query.edit_issue(
  502. self.session,
  503. issue,
  504. user='pingou',
  505. milestone='77'
  506. )
  507. self.session.add(repo)
  508. self.session.add(issue)
  509. msg = pagure.lib.query.set_custom_key_fields(
  510. self.session,
  511. project=repo,
  512. fields=['abc', 'xyz'],
  513. types=['boolean', 'boolean'],
  514. data=[None, None],
  515. )
  516. self.assertEqual(msg, 'List of custom fields updated')
  517. self.session.add(repo)
  518. msg = pagure.lib.query.set_custom_key_value(
  519. self.session,
  520. issue=issue,
  521. key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
  522. value=1
  523. )
  524. self.session.add(issue)
  525. self.session.commit()
  526. output = self.app.get('/test/issue/1')
  527. self.assertEqual(output.status_code, 200)
  528. output_text = output.get_data(as_text=True)
  529. # Not authentified = No edit
  530. self.assertNotIn(
  531. '<a class="btn btn-outline-secondary btn-sm border-0" '
  532. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  533. output_text)
  534. self.assertTrue(
  535. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  536. 'Login</a>\n to comment on this ticket.',
  537. output_text)
  538. user = tests.FakeUser()
  539. with tests.user_set(self.app.application, user):
  540. output = self.app.get('/test/issue/1')
  541. self.assertEqual(output.status_code, 200)
  542. output_text = output.get_data(as_text=True)
  543. # Not author nor admin = No edit
  544. self.assertNotIn(
  545. '<a class="btn btn-outline-secondary btn-sm border-0" '
  546. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  547. output_text)
  548. self.assertNotIn(
  549. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  550. ' title="Delete this ticket">\n',
  551. output_text)
  552. # no edit metadata
  553. self.assertNotIn(
  554. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  555. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  556. '<i class="fa fa-fw fa-pencil">',
  557. output_text)
  558. self.assertNotIn(
  559. '<a href="/login/">Login</a> to comment on this ticket.',
  560. output_text)
  561. # can view the milestone
  562. self.assertIn(
  563. '<strong>Milestone</strong>',
  564. output_text)
  565. self.assertIn(
  566. '<a href="/test/roadmap/77/">\n 77',
  567. output_text)
  568. # but can't edit them
  569. self.assertNotIn(
  570. '<select class="form-control c-select" id="milestone" '
  571. ' name="milestone"><option value=""></option><option '
  572. 'selected value="77">77</option></select>',
  573. output_text)
  574. # can view depending
  575. self.assertIn(
  576. '<strong>Depending on</strong>',
  577. output_text)
  578. # can't edit depending on
  579. self.assertNotIn(
  580. '<input class="form-control" id="depending" type="text"\n\
  581. placeholder="issue depending" name="depending"\n\
  582. value="" />',
  583. output_text)
  584. # no checkbox for private
  585. self.assertNotIn(
  586. '<input id="private" name="private" type="checkbox" value="y">',
  587. output_text)
  588. user.username = 'foo'
  589. with tests.user_set(self.app.application, user):
  590. output = self.app.get('/test/issue/1')
  591. self.assertEqual(output.status_code, 200)
  592. output_text = output.get_data(as_text=True)
  593. # the user can edit the issue
  594. self.assertIn(
  595. '<a class="btn btn-outline-secondary btn-sm border-0" '
  596. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  597. output_text)
  598. # the user can delete the ticket
  599. self.assertIn(
  600. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  601. ' title="Delete this ticket">\n',
  602. output_text)
  603. csrf_token = self.get_csrf(output=output)
  604. # the user can do the following things
  605. # edit metadata
  606. self.assertIn(
  607. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  608. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  609. '<i class="fa fa-fw fa-pencil">',
  610. output_text)
  611. # can view the milestone
  612. self.assertIn(
  613. '<strong>Milestone</strong>',
  614. output_text)
  615. self.assertIn(
  616. '<a href="/test/roadmap/77/">\n 77',
  617. output_text)
  618. # can edit them
  619. self.assertIn(
  620. '<select class="form-control c-select" id="milestone" '
  621. 'name="milestone"><option value=""></option><option selected '
  622. 'value="77">77</option></select>\n <div>\n',
  623. output_text)
  624. # can view depending
  625. self.assertIn(
  626. '<strong>Depending on</strong>',
  627. output_text)
  628. # can edit depending on
  629. self.assertIn(
  630. '<input class="form-control" id="depending" type="text"'
  631. '\n placeholder="issue depending" name="depending"\n',
  632. output_text)
  633. # the user should be able to do public -> private
  634. # the other way round won't be possible since GET and POST
  635. # to this endpoint for this user will be blocked
  636. # checkbox for private
  637. self.assertIn(
  638. '<input id="private" name="private" type="checkbox" value="y">',
  639. output_text)
  640. # Create private issue
  641. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  642. msg = pagure.lib.query.new_issue(
  643. session=self.session,
  644. repo=repo,
  645. title='Test issue',
  646. content='We should work on this',
  647. user='pingou',
  648. private=True,
  649. )
  650. self.session.commit()
  651. self.assertEqual(msg.title, 'Test issue')
  652. # Not logged in
  653. output = self.app.get('/test/issue/2')
  654. self.assertEqual(output.status_code, 404)
  655. # Wrong user
  656. user = tests.FakeUser()
  657. with tests.user_set(self.app.application, user):
  658. output = self.app.get('/test/issue/2')
  659. self.assertEqual(output.status_code, 404)
  660. # reporter
  661. user.username = 'pingou'
  662. with tests.user_set(self.app.application, user):
  663. output = self.app.get('/test/issue/2')
  664. self.assertEqual(output.status_code, 200)
  665. output_text = output.get_data(as_text=True)
  666. self.assertIn(
  667. '<title>Issue #2: Test issue - test - Pagure</title>',
  668. output_text)
  669. self.assertIn(
  670. '<span title="Private ticket" class="text-danger '
  671. 'fa fa-fw fa-lock"></span>', output_text)
  672. self.assertIn(
  673. '<a class="btn btn-outline-secondary btn-sm border-0" '
  674. 'href="/test/issue/2/edit" title="Edit this issue">\n',
  675. output_text)
  676. @patch('pagure.lib.git.update_git')
  677. @patch('pagure.lib.notify.send_email')
  678. def test_view_issue_admin_access(self, p_send_email, p_ugt):
  679. """ Test the view_issue endpoint. when a user has admin access on repo """
  680. p_send_email.return_value = True
  681. p_ugt.return_value = True
  682. output = self.app.get('/foo/issue/1')
  683. self.assertEqual(output.status_code, 404)
  684. tests.create_projects(self.session)
  685. tests.create_projects_git(
  686. os.path.join(self.path, 'repos'), bare=True)
  687. output = self.app.get('/test/issue/1')
  688. self.assertEqual(output.status_code, 404)
  689. # Create issues to play with
  690. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  691. # Add user 'foo' with ticket access on repo
  692. msg = pagure.lib.query.add_user_to_project(
  693. self.session,
  694. repo,
  695. new_user='foo',
  696. user='pingou',
  697. access='admin',
  698. )
  699. self.assertEqual(msg, 'User added')
  700. self.session.commit()
  701. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  702. msg = pagure.lib.query.new_issue(
  703. session=self.session,
  704. repo=repo,
  705. title='Test issue',
  706. content='We should work on this',
  707. user='pingou',
  708. )
  709. self.session.commit()
  710. self.assertEqual(msg.title, 'Test issue')
  711. # Add milestone
  712. repo.milestones = {'77': None}
  713. self.session.add(repo)
  714. issue = pagure.lib.query.search_issues(
  715. self.session,
  716. repo=repo,
  717. issueid=1
  718. )
  719. pagure.lib.query.edit_issue(
  720. self.session,
  721. issue,
  722. user='pingou',
  723. milestone='77'
  724. )
  725. self.session.add(repo)
  726. self.session.add(issue)
  727. msg = pagure.lib.query.set_custom_key_fields(
  728. self.session,
  729. project=repo,
  730. fields=['abc', 'xyz'],
  731. types=['boolean', 'boolean'],
  732. data=[None, None],
  733. )
  734. self.assertEqual(msg, 'List of custom fields updated')
  735. self.session.add(repo)
  736. msg = pagure.lib.query.set_custom_key_value(
  737. self.session,
  738. issue=issue,
  739. key=pagure.lib.query.get_custom_key(self.session, repo, 'abc'),
  740. value=1
  741. )
  742. self.session.add(issue)
  743. self.session.commit()
  744. output = self.app.get('/test/issue/1')
  745. self.assertEqual(output.status_code, 200)
  746. # Not authentified = No edit
  747. self.assertNotIn(
  748. '<a class="btn btn-outline-secondary btn-sm border-0" '
  749. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  750. output.get_data(as_text=True))
  751. self.assertTrue(
  752. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  753. 'Login</a>\n to comment on this ticket.'
  754. in output.get_data(as_text=True))
  755. user = tests.FakeUser()
  756. with tests.user_set(self.app.application, user):
  757. output = self.app.get('/test/issue/1')
  758. self.assertEqual(output.status_code, 200)
  759. output_text = output.get_data(as_text=True)
  760. # Not author nor admin = No edit
  761. self.assertNotIn(
  762. '<a class="btn btn-outline-secondary btn-sm border-0" '
  763. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  764. output_text)
  765. self.assertNotIn(
  766. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  767. ' title="Delete this ticket">\n',
  768. output_text)
  769. # no edit metadata
  770. self.assertNotIn(
  771. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  772. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  773. '<i class="fa fa-fw fa-pencil">',
  774. output_text)
  775. self.assertNotIn(
  776. '<a href="/login/">Login</a> to comment on this ticket.',
  777. output_text)
  778. # can view the milestone
  779. self.assertIn(
  780. '<strong>Milestone</strong>',
  781. output_text)
  782. self.assertIn(
  783. '<a href="/test/roadmap/77/">\n 77',
  784. output_text)
  785. # but can't edit them
  786. self.assertNotIn(
  787. '<select class="form-control c-select" id="milestone" '
  788. ' name="milestone"><option value=""></option><option '
  789. 'selected value="77">77</option></select>',
  790. output_text)
  791. # can view depending
  792. self.assertIn(
  793. '<strong>Depending on</strong>',
  794. output_text)
  795. # can't edit depending on
  796. self.assertNotIn(
  797. '<input class="form-control" id="depending" type="text"\n\
  798. placeholder="issue depending" name="depending"\n\
  799. value="" />',
  800. output_text)
  801. # no checkbox for private
  802. self.assertNotIn(
  803. '<input id="private" name="private" type="checkbox" value="y">',
  804. output_text)
  805. user.username = 'foo'
  806. with tests.user_set(self.app.application, user):
  807. output = self.app.get('/test/issue/1')
  808. self.assertEqual(output.status_code, 200)
  809. output_text = output.get_data(as_text=True)
  810. # the user can edit the issue
  811. self.assertIn(
  812. '<a class="btn btn-outline-secondary btn-sm border-0" '
  813. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  814. output_text)
  815. self.assertIn(
  816. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  817. ' title="Delete this ticket">\n',
  818. output_text)
  819. csrf_token = self.get_csrf(output=output)
  820. # the user can do the following things
  821. # edit metadata
  822. self.assertIn(
  823. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  824. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  825. '<i class="fa fa-fw fa-pencil">',
  826. output_text)
  827. # can view the milestone
  828. self.assertIn(
  829. '<strong>Milestone</strong>',
  830. output_text)
  831. self.assertIn(
  832. '<a href="/test/roadmap/77/">\n 77',
  833. output_text)
  834. # can edit them
  835. self.assertIn(
  836. '<select class="form-control c-select" id="milestone" '
  837. 'name="milestone"><option value=""></option><option selected '
  838. 'value="77">77</option></select>\n <div>\n',
  839. output_text)
  840. # can view depending
  841. self.assertIn(
  842. '<strong>Depending on</strong>',
  843. output_text)
  844. # can edit depending on
  845. self.assertIn(
  846. '<input class="form-control" id="depending" type="text"'
  847. '\n placeholder="issue depending" name="depending"\n',
  848. output_text)
  849. # the user should be able to do public -> private
  850. # the other way round won't be possible since GET and POST
  851. # to this endpoint for this user will be blocked
  852. # checkbox for private
  853. self.assertIn(
  854. '<input id="private" name="private" type="checkbox" value="y">',
  855. output_text)
  856. # Create private issue
  857. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  858. msg = pagure.lib.query.new_issue(
  859. session=self.session,
  860. repo=repo,
  861. title='Test issue',
  862. content='We should work on this',
  863. user='pingou',
  864. private=True,
  865. )
  866. self.session.commit()
  867. self.assertEqual(msg.title, 'Test issue')
  868. # Not logged in
  869. output = self.app.get('/test/issue/2')
  870. self.assertEqual(output.status_code, 404)
  871. # Wrong user
  872. user = tests.FakeUser()
  873. with tests.user_set(self.app.application, user):
  874. output = self.app.get('/test/issue/2')
  875. self.assertEqual(output.status_code, 404)
  876. # reporter
  877. user.username = 'pingou'
  878. with tests.user_set(self.app.application, user):
  879. output = self.app.get('/test/issue/2')
  880. self.assertEqual(output.status_code, 200)
  881. output_text = output.get_data(as_text=True)
  882. self.assertIn(
  883. '<title>Issue #2: Test issue - test - Pagure</title>',
  884. output_text)
  885. self.assertIn(
  886. '<span title="Private ticket" class="text-danger '
  887. 'fa fa-fw fa-lock"></span>', output_text)
  888. self.assertIn(
  889. '<a class="btn btn-outline-secondary btn-sm border-0" '
  890. 'href="/test/issue/2/edit" title="Edit this issue">\n',
  891. output_text)
  892. if __name__ == '__main__':
  893. unittest.main(verbosity=2)