test_pagure_flask_ui_issues_acl_checks.py 37 KB

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