test_pagure_flask_ui_issues_acl_checks.py 37 KB

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