test_pagure_flask_ui_issues_open_access.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals, absolute_import
  8. from unittest.case import SkipTest
  9. import json
  10. import unittest
  11. import shutil
  12. import sys
  13. import os
  14. try:
  15. import pyclamd
  16. except ImportError:
  17. pyclamd = None
  18. import six
  19. import tempfile
  20. import re
  21. from datetime import datetime, timedelta
  22. from six.moves.urllib.parse import urlparse, parse_qs
  23. import pygit2
  24. from bs4 import BeautifulSoup
  25. from mock import patch, MagicMock
  26. sys.path.insert(0, os.path.join(os.path.dirname(
  27. os.path.abspath(__file__)), '..'))
  28. import pagure
  29. import pagure.lib.query
  30. import tests
  31. class PagureFlaskIssuesOpenAccesstests(tests.Modeltests):
  32. """ Tests for flask issues controller of pagure """
  33. def setUp(self):
  34. """ Set up the environnment, ran before every tests. """
  35. super(PagureFlaskIssuesOpenAccesstests, self).setUp()
  36. tests.create_projects(self.session)
  37. tests.create_projects_git(
  38. os.path.join(self.path, 'repos'), bare=True)
  39. tests.create_projects_git(
  40. os.path.join(self.path, 'tickets'), bare=True)
  41. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  42. settings = repo.settings
  43. settings['open_metadata_access_to_all'] = True
  44. repo.settings = settings
  45. repo.milestones = {'v1.0': '', 'v2.0': 'Tomorrow!'}
  46. self.session.add(repo)
  47. self.session.commit()
  48. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  49. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  50. def test_new_issue_with_metadata(self):
  51. """ Test the new_issue endpoint when the user has access to the
  52. project. """
  53. user = tests.FakeUser()
  54. user.username = 'foo'
  55. with tests.user_set(self.app.application, user):
  56. output = self.app.get('/test/new_issue')
  57. self.assertEqual(output.status_code, 200)
  58. output_text = output.get_data(as_text=True)
  59. self.assertIn(
  60. '<h4 class="font-weight-bold mb-4">New Issue</h4>\n',
  61. output_text)
  62. self.assertIn('<strong>Tags</strong>', output_text)
  63. self.assertIn(
  64. '<strong>Assignee</strong>', output_text)
  65. csrf_token = self.get_csrf(output=output)
  66. data = {
  67. 'title': 'Test issue3',
  68. 'issue_content': 'We really should improve on this issue\n',
  69. 'status': 'Open',
  70. 'assignee': 'foo',
  71. 'milestone': 'v2.0',
  72. 'tag': 'tag2',
  73. 'csrf_token': csrf_token,
  74. }
  75. output = self.app.post(
  76. '/test/new_issue', data=data, follow_redirects=True)
  77. self.assertEqual(output.status_code, 200)
  78. output_text = output.get_data(as_text=True)
  79. self.assertIn(
  80. '<title>Issue #1: Test issue3 - test - Pagure</title>',
  81. output_text)
  82. self.assertIn(
  83. '<a class="btn btn-outline-secondary btn-sm border-0" '
  84. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  85. output_text)
  86. # Check the metadata
  87. self.assertIn(
  88. 'title="comma separated list of tags"\n '
  89. 'value="tag2" />', output_text)
  90. self.assertIn(
  91. 'placeholder="username"\n value="foo" />\n',
  92. output_text)
  93. self.assertIn(
  94. 'href="/test/roadmap/v2.0/"',
  95. output_text)
  96. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  97. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  98. def test_new_issue_with_metadata_not_user(self):
  99. """ Test the new_issue endpoint when the user does not have access
  100. to the project but still tries to.
  101. """
  102. user = tests.FakeUser()
  103. user.username = 'foo'
  104. with tests.user_set(self.app.application, user):
  105. output = self.app.get('/test/new_issue')
  106. self.assertEqual(output.status_code, 200)
  107. output_text = output.get_data(as_text=True)
  108. self.assertIn(
  109. '<h4 class="font-weight-bold mb-4">New Issue</h4>\n',
  110. output_text)
  111. self.assertIn('<strong>Tags</strong>', output_text)
  112. self.assertIn('<strong>Assignee</strong>', output_text)
  113. csrf_token = self.get_csrf(output=output)
  114. data = {
  115. 'title': 'Test issue3',
  116. 'issue_content': 'We really should improve on this issue\n',
  117. 'status': 'Open',
  118. 'assignee': 'foo',
  119. 'milestone': 'v2.0',
  120. 'tag': 'tag2',
  121. 'csrf_token': csrf_token,
  122. }
  123. output = self.app.post(
  124. '/test/new_issue', data=data, follow_redirects=True)
  125. self.assertEqual(output.status_code, 200)
  126. output_text = output.get_data(as_text=True)
  127. self.assertIn(
  128. '<title>Issue #1: Test issue3 - test - Pagure</title>',
  129. output_text)
  130. self.assertIn(
  131. '<a class="btn btn-outline-secondary btn-sm border-0" '
  132. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  133. output_text)
  134. # Check the metadata
  135. self.assertIn(
  136. 'title="comma separated list of tags"\n '
  137. 'value="tag2" />', output_text)
  138. self.assertIn(
  139. 'placeholder="username"\n value="foo" />\n',
  140. output_text)
  141. self.assertIn(
  142. '<div class="ml-2" id="milestone_plain">'
  143. '\n <span>'
  144. '\n <a href="/test/roadmap/v2.0/">'
  145. '\n v2.0\n', output_text)
  146. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  147. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  148. def test_view_issue(self):
  149. """ Test the view_issue endpoint. """
  150. output = self.app.get('/test/issue/1')
  151. self.assertEqual(output.status_code, 404)
  152. # Create issues to play with
  153. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  154. msg = pagure.lib.query.new_issue(
  155. session=self.session,
  156. repo=repo,
  157. title='Test issue',
  158. content='We should work on this',
  159. user='pingou',
  160. )
  161. self.session.commit()
  162. self.assertEqual(msg.title, 'Test issue')
  163. output = self.app.get('/test/issue/1')
  164. self.assertEqual(output.status_code, 200)
  165. output_text = output.get_data(as_text=True)
  166. # Not authentified = No edit
  167. self.assertNotIn(
  168. '<a class="btn btn-outline-secondary btn-sm border-0" '
  169. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  170. output_text)
  171. self.assertIn(
  172. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  173. 'Login</a>\n to comment on this ticket.',
  174. output_text)
  175. user = tests.FakeUser()
  176. with tests.user_set(self.app.application, user):
  177. output = self.app.get('/test/issue/1')
  178. self.assertEqual(output.status_code, 200)
  179. output_text = output.get_data(as_text=True)
  180. # Not author nor admin = No edit
  181. self.assertNotIn(
  182. '<a class="btn btn-outline-secondary btn-sm border-0"'
  183. ' href="/test/issue/1/edit" title="Edit this issue">',
  184. output_text)
  185. self.assertNotIn(
  186. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  187. ' title="Delete this ticket">\n',
  188. output_text)
  189. self.assertFalse(
  190. '<a href="/login/">Login</a> to comment on this ticket.'
  191. in output_text)
  192. # Not author nor admin but open_access = take
  193. self.assertIn('function take_issue(){', output_text)
  194. self.assertNotIn('function drop_issue(){', output_text)
  195. self.assertIn(
  196. '<a href="javascript:void(0)" id="take-btn"\n',
  197. output_text)
  198. csrf_token = self.get_csrf(output=output)
  199. # Create private issue
  200. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  201. msg = pagure.lib.query.new_issue(
  202. session=self.session,
  203. repo=repo,
  204. title='Test issue',
  205. content='We should work on this',
  206. user='pingou',
  207. private=True,
  208. )
  209. self.session.commit()
  210. self.assertEqual(msg.title, 'Test issue')
  211. # Not logged in
  212. output = self.app.get('/test/issue/2')
  213. self.assertEqual(output.status_code, 404)
  214. # Wrong user
  215. user = tests.FakeUser()
  216. with tests.user_set(self.app.application, user):
  217. output = self.app.get('/test/issue/2')
  218. self.assertEqual(output.status_code, 404)
  219. # another user
  220. user.username = 'foo'
  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. # Project w/o issue tracker
  225. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  226. repo.settings = {'issue_tracker': False}
  227. self.session.add(repo)
  228. self.session.commit()
  229. output = self.app.get('/test/issue/1')
  230. self.assertEqual(output.status_code, 404)
  231. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  232. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  233. def test_view_issue_user_ticket(self):
  234. """ Test the view_issue endpoint. """
  235. output = self.app.get('/test/issue/1')
  236. self.assertEqual(output.status_code, 404)
  237. # Create issues to play with
  238. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  239. msg = pagure.lib.query.new_issue(
  240. session=self.session,
  241. repo=repo,
  242. title='Test issue',
  243. content='We should work on this',
  244. user='pingou',
  245. )
  246. self.session.commit()
  247. self.assertEqual(msg.title, 'Test issue')
  248. output = self.app.get('/test/issue/1')
  249. self.assertEqual(output.status_code, 200)
  250. output_text = output.get_data(as_text=True)
  251. # Not authentified = No edit
  252. self.assertNotIn(
  253. '<a class="btn btn-outline-secondary btn-sm border-0" '
  254. 'href="/test/issue/1/edit" title="Edit this issue">\n',
  255. output_text)
  256. self.assertTrue(
  257. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  258. 'Login</a>\n to comment on this ticket.'
  259. in output_text)
  260. # Create issues to play with
  261. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  262. # Add user 'foo' with ticket access on repo
  263. msg = pagure.lib.query.add_user_to_project(
  264. self.session,
  265. repo,
  266. new_user='foo',
  267. user='pingou',
  268. access='ticket',
  269. )
  270. self.assertEqual(msg, 'User added')
  271. self.session.commit()
  272. user = tests.FakeUser(username='foo')
  273. with tests.user_set(self.app.application, user):
  274. output = self.app.get('/test/issue/1')
  275. self.assertEqual(output.status_code, 200)
  276. output_text = output.get_data(as_text=True)
  277. # Not author nor admin = No edit
  278. self.assertNotIn(
  279. '<a class="btn btn-outline-secondary btn-sm border-0"'
  280. ' href="/test/issue/1/edit" title="Edit this issue">',
  281. output_text)
  282. self.assertNotIn(
  283. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  284. ' title="Delete this ticket">\n',
  285. output_text)
  286. self.assertFalse(
  287. '<a href="/login/">Login</a> to comment on this ticket.'
  288. in output_text)
  289. # user has ticket = take ok
  290. self.assertIn('function take_issue(){', output_text)
  291. self.assertIn('function drop_issue(){', output_text)
  292. self.assertIn(
  293. '<a href="javascript:void(0)" id="take-btn"\n',
  294. output_text)
  295. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  296. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  297. def test_view_issue_custom_field_user_ticket(self):
  298. """ Test the view_issue endpoint. """
  299. output = self.app.get('/test/issue/1')
  300. self.assertEqual(output.status_code, 404)
  301. # Create issues to play with
  302. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  303. msg = pagure.lib.query.new_issue(
  304. session=self.session,
  305. repo=repo,
  306. title='Test issue',
  307. content='We should work on this',
  308. user='pingou',
  309. )
  310. self.session.commit()
  311. self.assertEqual(msg.title, 'Test issue')
  312. # Add user 'foo' with ticket access on repo
  313. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  314. msg = pagure.lib.query.add_user_to_project(
  315. self.session,
  316. repo,
  317. new_user='foo',
  318. user='pingou',
  319. access='ticket',
  320. )
  321. self.assertEqual(msg, 'User added')
  322. self.session.commit()
  323. # Set some custom fields
  324. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  325. msg = pagure.lib.query.set_custom_key_fields(
  326. self.session,
  327. repo,
  328. ['bugzilla', 'upstream', 'reviewstatus'],
  329. ['link', 'boolean', 'list'],
  330. ['unused data for non-list type', '', 'ack, nack , needs review'],
  331. [None, None, None])
  332. self.session.commit()
  333. self.assertEqual(msg, 'List of custom fields updated')
  334. # User with no rights
  335. user = tests.FakeUser()
  336. with tests.user_set(self.app.application, user):
  337. output = self.app.get('/test/issue/1')
  338. self.assertEqual(output.status_code, 200)
  339. output_text = output.get_data(as_text=True)
  340. self.assertNotIn(
  341. '<a class="btn btn-outline-secondary btn-sm border-0"'
  342. ' href="/test/issue/1/edit" title="Edit this issue">',
  343. output_text)
  344. self.assertNotIn(
  345. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  346. ' title="Delete this ticket">\n',
  347. output_text)
  348. # user no ACLs but open_access = take action/button - no drop
  349. self.assertIn('function take_issue(){', output_text)
  350. self.assertNotIn('function drop_issue(){', output_text)
  351. self.assertIn(
  352. '<a href="javascript:void(0)" id="take-btn"\n',
  353. output_text)
  354. # user no ACLs = no metadata form
  355. self.assertNotIn(
  356. '<input class="form-control" '
  357. 'name="bugzilla" id="bugzilla"/>', output_text)
  358. self.assertNotIn(
  359. '<select class="form-control" name="reviewstatus" '
  360. 'id="reviewstatus>', output_text)
  361. self.assertNotIn(
  362. '<input type="checkbox" '
  363. 'class="form-control" name="upstream" id="upstream"/>',
  364. output_text)
  365. user = tests.FakeUser(username='foo')
  366. with tests.user_set(self.app.application, user):
  367. output = self.app.get('/test/issue/1')
  368. self.assertEqual(output.status_code, 200)
  369. output_text = output.get_data(as_text=True)
  370. self.assertNotIn(
  371. '<a class="btn btn-outline-secondary btn-sm border-0"'
  372. ' href="/test/issue/1/edit" title="Edit this issue">',
  373. output_text)
  374. self.assertNotIn(
  375. '<a class="dropdown-item text-danger" href="javascript:void(0)" id="closeticket"\n'
  376. ' title="Delete this ticket">\n',
  377. output_text)
  378. self.assertNotIn(
  379. '<a href="/login/">Login</a> to comment on this ticket.',
  380. output_text)
  381. # user has ticket = take ok
  382. self.assertIn('function take_issue(){', output_text)
  383. self.assertIn('function drop_issue(){', output_text)
  384. self.assertIn(
  385. '<a href="javascript:void(0)" id="take-btn"\n',
  386. output_text)
  387. # user has ticket == Sees the metadata
  388. self.assertIn(
  389. '<input class="form-control" '
  390. 'name="bugzilla" id="bugzilla"/>', output_text)
  391. self.assertIn(
  392. '<select class="form-control"\n'
  393. ' name="reviewstatus"\n'
  394. ' id="reviewstatus">\n',
  395. output_text)
  396. self.assertIn(
  397. '<input type="checkbox" '
  398. 'class="form-control" name="upstream" id="upstream"/>',
  399. output_text)
  400. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  401. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  402. def test_view_issue_non_ascii_milestone(self):
  403. """ Test the view_issue endpoint with non-ascii milestone. """
  404. output = self.app.get('/test/issue/1')
  405. self.assertEqual(output.status_code, 404)
  406. stone = 'käpy'
  407. # Create issues to play with
  408. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  409. msg = pagure.lib.query.new_issue(
  410. session=self.session,
  411. repo=repo,
  412. title='Test issue',
  413. content='We should work on this',
  414. user='pingou',
  415. )
  416. self.session.commit()
  417. self.assertEqual(msg.title, 'Test issue')
  418. # Add a non-ascii milestone to the issue but project has no milestone
  419. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  420. message = pagure.lib.query.edit_issue(
  421. self.session,
  422. issue=issue,
  423. milestone=stone,
  424. private=False,
  425. user='pingou',
  426. )
  427. self.assertEqual(
  428. message,
  429. [
  430. 'Issue set to the milestone: k\xe4py'
  431. ]
  432. )
  433. self.session.commit()
  434. # View the issue
  435. output = self.app.get('/test/issue/1')
  436. self.assertEqual(output.status_code, 200)
  437. output_text = output.get_data(as_text=True)
  438. self.assertIn(
  439. '<title>Issue #1: Test issue - test - Pagure</title>',
  440. output_text)
  441. self.assertIn(stone, output_text)
  442. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  443. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  444. def test_view_issue_list_no_data(self):
  445. """ Test the view_issue endpoint when the issue has a custom field
  446. of type list with no data attached. """
  447. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  448. # Add custom fields to the project
  449. msg = pagure.lib.query.set_custom_key_fields(
  450. session=self.session,
  451. project=repo,
  452. fields=['test1'],
  453. types=['list'],
  454. data=[None],
  455. notify=[None]
  456. )
  457. self.session.commit()
  458. self.assertEqual(msg, 'List of custom fields updated')
  459. # Create issues to play with
  460. msg = pagure.lib.query.new_issue(
  461. session=self.session,
  462. repo=repo,
  463. title='Big problÈm!',
  464. content='We should work on this',
  465. user='pingou',
  466. )
  467. self.session.commit()
  468. self.assertEqual(msg.title, 'Big problÈm!')
  469. # Assign a value to the custom key on that ticket
  470. cfield = pagure.lib.query.get_custom_key(
  471. session=self.session,
  472. project=repo,
  473. keyname='test1')
  474. msg = pagure.lib.query.set_custom_key_value(
  475. session=self.session,
  476. issue=msg,
  477. key=cfield,
  478. value='item')
  479. self.session.commit()
  480. self.assertEqual(msg, 'Custom field test1 adjusted to item')
  481. user = tests.FakeUser(username='foo')
  482. with tests.user_set(self.app.application, user):
  483. output = self.app.get('/test/issue/1')
  484. self.assertEqual(output.status_code, 200)
  485. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  486. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  487. def test_update_issue(self):
  488. """ Test the update_issue endpoint. """
  489. output = self.app.get('/test/issue/1/update')
  490. self.assertEqual(output.status_code, 302)
  491. # Create issues to play with
  492. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  493. msg = pagure.lib.query.new_issue(
  494. session=self.session,
  495. repo=repo,
  496. title='Test issue',
  497. content='We should work on this',
  498. user='pingou',
  499. )
  500. self.session.commit()
  501. self.assertEqual(msg.title, 'Test issue')
  502. user = tests.FakeUser(username='foo')
  503. with tests.user_set(self.app.application, user):
  504. output = self.app.get('/test/issue/1')
  505. self.assertEqual(output.status_code, 200)
  506. output_text = output.get_data(as_text=True)
  507. self.assertIn(
  508. '<title>Issue #1: Test issue - test - Pagure</title>',
  509. output_text)
  510. self.assertNotIn(
  511. '<a class="btn btn-outline-secondary btn-sm border-0"'
  512. ' href="/test/issue/1/edit" title="Edit this issue">',
  513. output_text)
  514. self.assertEqual(output_text.count('title="PY C (pingou)"'), 1)
  515. csrf_token = self.get_csrf(output=output)
  516. data = {
  517. 'status': 'Closed',
  518. 'close_status': 'fixed'
  519. }
  520. # Invalid repo
  521. output = self.app.post('/bar/issue/1/update', data=data)
  522. self.assertEqual(output.status_code, 404)
  523. # Non-existing issue
  524. output = self.app.post('/test/issue/100/update', data=data)
  525. self.assertEqual(output.status_code, 404)
  526. output = self.app.post(
  527. '/test/issue/1/update', data=data, follow_redirects=True)
  528. self.assertEqual(output.status_code, 200)
  529. output_text = output.get_data(as_text=True)
  530. self.assertIn(
  531. '<title>Issue #1: Test issue - test - Pagure</title>',
  532. output_text)
  533. self.assertNotIn(
  534. '<a class="btn btn-outline-secondary btn-sm border-0"'
  535. ' href="/test/issue/1/edit" title="Edit this issue">',
  536. output_text)
  537. self.assertFalse(
  538. '<option selected value="Fixed">Fixed</option>'
  539. in output_text)
  540. # Right status, wrong csrf
  541. data['close_status'] = 'Fixed'
  542. output = self.app.post(
  543. '/test/issue/1/update', data=data, follow_redirects=True)
  544. self.assertEqual(output.status_code, 200)
  545. output_text = output.get_data(as_text=True)
  546. self.assertIn(
  547. '<title>Issue #1: Test issue - test - Pagure</title>',
  548. output_text)
  549. self.assertNotIn(
  550. '<a class="btn btn-outline-secondary btn-sm border-0"'
  551. ' href="/test/issue/1/edit" title="Edit this issue">',
  552. output_text)
  553. self.assertFalse(
  554. '<option selected value="Fixed">Fixed</option>'
  555. in output_text)
  556. # status update - blocked, open_access doesn't allow changing status
  557. data['csrf_token'] = csrf_token
  558. output = self.app.post(
  559. '/test/issue/1/update', data=data, follow_redirects=True)
  560. self.assertEqual(output.status_code, 200)
  561. output_text = output.get_data(as_text=True)
  562. self.assertIn(
  563. '<title>Issue #1: Test issue - test - Pagure</title>',
  564. output_text)
  565. self.assertNotIn(
  566. '<a class="btn btn-outline-secondary btn-sm border-0"'
  567. ' href="/test/issue/1/edit" title="Edit this issue">',
  568. output_text)
  569. self.assertNotIn(
  570. 'Issue close_status updated to: Fixed',
  571. output_text)
  572. self.assertNotIn(
  573. 'Issue status updated to: Closed (was: Open)',
  574. output_text)
  575. self.assertNotIn(
  576. '<option selected value="Fixed">Fixed</option>',
  577. output_text)
  578. # Add new comment
  579. data = {
  580. 'csrf_token': csrf_token,
  581. 'status': 'Closed',
  582. 'close_status': 'Fixed',
  583. 'comment': 'Woohoo a second comment!',
  584. }
  585. output = self.app.post(
  586. '/test/issue/1/update', data=data, follow_redirects=True)
  587. self.assertEqual(output.status_code, 200)
  588. output_text = output.get_data(as_text=True)
  589. self.assertIn(
  590. '<title>Issue #1: Test issue - test - Pagure</title>',
  591. output_text)
  592. self.assertNotIn(
  593. '<a class="btn btn-outline-secondary btn-sm border-0"'
  594. ' href="/test/issue/1/edit" title="Edit this issue">',
  595. output_text)
  596. self.assertIn(
  597. 'Comment added',
  598. output_text)
  599. self.assertNotIn(
  600. 'No changes to edit',
  601. output_text)
  602. self.assertIn(
  603. '<p>Woohoo a second comment!</p>',
  604. output_text)
  605. self.assertEqual(
  606. output_text.count('comment_body">'), 2)
  607. self.assertNotIn(
  608. '<option selected value="Fixed">Fixed</option>',
  609. output_text)
  610. # 1: one for the original comment
  611. self.assertEqual(
  612. output_text.count('title="PY C (pingou)"'),
  613. 1)
  614. # Add new tag
  615. data = {
  616. 'csrf_token': csrf_token,
  617. 'status': 'Closed',
  618. 'close_status': 'Fixed',
  619. 'tag': 'tag2',
  620. }
  621. output = self.app.post(
  622. '/test/issue/1/update', data=data, follow_redirects=True)
  623. self.assertEqual(output.status_code, 200)
  624. output_text = output.get_data(as_text=True)
  625. self.assertIn(
  626. '<title>Issue #1: Test issue - test - Pagure</title>',
  627. output_text)
  628. self.assertNotIn(
  629. '<a class="btn btn-outline-secondary btn-sm border-0"'
  630. ' href="/test/issue/1/edit" title="Edit this issue">',
  631. output_text)
  632. self.assertIn(
  633. '<p>Woohoo a second comment!</p>',
  634. output_text)
  635. self.assertEqual(
  636. output_text.count('comment_body">'), 2)
  637. self.assertNotIn(
  638. '<option selected value="Fixed">Fixed</option>',
  639. output_text)
  640. # Assign issue to an non-existent user
  641. data = {
  642. 'csrf_token': csrf_token,
  643. 'status': 'Closed',
  644. 'close_status': 'Fixed',
  645. 'assignee': 'ralph',
  646. }
  647. output = self.app.post(
  648. '/test/issue/1/update', data=data, follow_redirects=True)
  649. self.assertEqual(output.status_code, 200)
  650. output_text = output.get_data(as_text=True)
  651. self.assertIn(
  652. '<title>Issue #1: Test issue - test - Pagure</title>',
  653. output_text)
  654. self.assertNotIn(
  655. '<a class="btn btn-outline-secondary btn-sm border-0"'
  656. ' href="/test/issue/1/edit" title="Edit this issue">',
  657. output_text)
  658. self.assertIn(
  659. 'No user &#34;ralph&#34; found',
  660. output_text)
  661. self.assertIn(
  662. '<p>Woohoo a second comment!</p>',
  663. output_text)
  664. self.assertEqual(
  665. output_text.count('comment_body">'), 2)
  666. self.assertNotIn(
  667. '<option selected value="Fixed">Fixed</option>',
  668. output_text)
  669. # Assign issue properly
  670. data = {
  671. 'csrf_token': csrf_token,
  672. 'status': 'Closed',
  673. 'close_status': 'Fixed',
  674. 'assignee': 'pingou',
  675. }
  676. output = self.app.post(
  677. '/test/issue/1/update', data=data, follow_redirects=True)
  678. self.assertEqual(output.status_code, 200)
  679. output_text = output.get_data(as_text=True)
  680. self.assertIn(
  681. '<title>Issue #1: Test issue - test - Pagure</title>',
  682. output_text)
  683. self.assertNotIn(
  684. '<a class="btn btn-outline-secondary btn-sm border-0"'
  685. ' href="/test/issue/1/edit" title="Edit this issue">',
  686. output_text)
  687. self.assertIn('Issue assigned to pingou', output_text)
  688. self.assertIn(
  689. '<a href="/test/issues?assignee=pingou" title="PY C (pingou)"',
  690. output_text)
  691. self.assertIn(
  692. '<p>Woohoo a second comment!</p>', output_text)
  693. self.assertEqual(
  694. output_text.count('comment_body">'), 2)
  695. self.assertNotIn(
  696. '<option selected value="Fixed">Fixed</option>',
  697. output_text)
  698. # Create another issue with a dependency
  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. # Reset the status of the first issue
  710. parent_issue = pagure.lib.query.search_issues(
  711. self.session, repo, issueid=1)
  712. parent_issue.status = 'Open'
  713. self.session.add(parent_issue)
  714. # Add the dependency relationship
  715. self.session.add(parent_issue)
  716. issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
  717. issue.parents.append(parent_issue)
  718. self.session.add(issue)
  719. self.session.commit()
  720. with tests.user_set(self.app.application, user):
  721. data['csrf_token'] = csrf_token
  722. output = self.app.post(
  723. '/test/issue/2/update', data=data, follow_redirects=True)
  724. self.assertEqual(output.status_code, 200)
  725. output_text = output.get_data(as_text=True)
  726. self.assertIn(
  727. '<title>Issue #2: Test issue - test - Pagure</title>',
  728. output_text)
  729. self.assertNotIn(
  730. '<a class="btn btn-outline-secondary btn-sm border-0"'
  731. ' href="/test/issue/2/edit" title="Edit this issue">',
  732. output_text)
  733. self.assertNotIn(
  734. 'You cannot close a ticket '
  735. 'that has ticket depending that are still open.',
  736. output_text)
  737. self.assertNotIn(
  738. '<option selected value="Open">Open</option>',
  739. output_text)
  740. # Create private issue
  741. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  742. msg = pagure.lib.query.new_issue(
  743. session=self.session,
  744. repo=repo,
  745. title='Test issue',
  746. content='We should work on this',
  747. user='pingou',
  748. private=True,
  749. )
  750. self.session.commit()
  751. self.assertEqual(msg.title, 'Test issue')
  752. # Wrong user
  753. user = tests.FakeUser()
  754. with tests.user_set(self.app.application, user):
  755. output = self.app.post(
  756. '/test/issue/3/update', data=data, follow_redirects=True)
  757. self.assertEqual(output.status_code, 403)
  758. # Project w/o issue tracker
  759. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  760. repo.settings = {'issue_tracker': False}
  761. self.session.add(repo)
  762. self.session.commit()
  763. with tests.user_set(self.app.application, user):
  764. # Repo not set-up for issue tracker
  765. output = self.app.post('/test/issue/1/update', data=data)
  766. self.assertEqual(output.status_code, 404)
  767. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  768. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  769. def test_update_issue_depend(self):
  770. """ Test adding dependency via the update_issue endpoint. """
  771. # Create issues to play with
  772. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  773. msg = pagure.lib.query.new_issue(
  774. session=self.session,
  775. repo=repo,
  776. title='Test issue',
  777. content='We should work on this',
  778. user='pingou',
  779. )
  780. self.session.commit()
  781. self.assertEqual(msg.title, 'Test issue')
  782. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  783. msg = pagure.lib.query.new_issue(
  784. session=self.session,
  785. repo=repo,
  786. title='Test issue #2',
  787. content='We should work on this again',
  788. user='foo',
  789. )
  790. self.session.commit()
  791. self.assertEqual(msg.title, 'Test issue #2')
  792. user = tests.FakeUser(username='foo')
  793. with tests.user_set(self.app.application, user):
  794. output = self.app.get('/test/issue/1')
  795. self.assertEqual(output.status_code, 200)
  796. output_text = output.get_data(as_text=True)
  797. self.assertIn(
  798. '<title>Issue #1: Test issue - test - Pagure</title>',
  799. output_text)
  800. self.assertNotIn(
  801. '<a class="btn btn-outline-secondary btn-sm border-0"'
  802. ' href="/test/issue/1/edit" title="Edit this issue">',
  803. output_text)
  804. csrf_token = self.get_csrf(output=output)
  805. # Add a dependent ticket
  806. data = {
  807. 'csrf_token': csrf_token,
  808. 'depending': '2',
  809. }
  810. output = self.app.post(
  811. '/test/issue/1/update', data=data, follow_redirects=True)
  812. self.assertEqual(output.status_code, 200)
  813. output_text = output.get_data(as_text=True)
  814. self.assertIn(
  815. '<title>Issue #1: Test issue - test - Pagure</title>',
  816. output_text)
  817. self.assertNotIn(
  818. '<a class="btn btn-outline-secondary btn-sm border-0"'
  819. ' href="/test/issue/1/edit" title="Edit this issue">',
  820. output_text)
  821. # Add an invalid dependent ticket
  822. data = {
  823. 'csrf_token': csrf_token,
  824. 'depending': '2,abc',
  825. }
  826. output = self.app.post(
  827. '/test/issue/1/update', data=data, follow_redirects=True)
  828. self.assertEqual(output.status_code, 200)
  829. output_text = output.get_data(as_text=True)
  830. self.assertIn(
  831. '<title>Issue #1: Test issue - test - Pagure</title>',
  832. output_text)
  833. self.assertNotIn(
  834. '<a class="btn btn-outline-secondary btn-sm border-0"'
  835. ' href="/test/issue/1/edit" title="Edit this issue">',
  836. output_text)
  837. self.assertNotIn(
  838. 'Successfully edited issue #1',
  839. output_text)
  840. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  841. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  842. self.assertEqual(issue.depending_text, [2])
  843. self.assertEqual(issue.blocking_text, [])
  844. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  845. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  846. def test_update_issue_block(self):
  847. """ Test adding blocked issue via the update_issue endpoint. """
  848. # Create issues to play with
  849. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  850. msg = pagure.lib.query.new_issue(
  851. session=self.session,
  852. repo=repo,
  853. title='Test issue',
  854. content='We should work on this',
  855. user='pingou',
  856. )
  857. self.session.commit()
  858. self.assertEqual(msg.title, 'Test issue')
  859. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  860. msg = pagure.lib.query.new_issue(
  861. session=self.session,
  862. repo=repo,
  863. title='Test issue #2',
  864. content='We should work on this again',
  865. user='foo',
  866. )
  867. self.session.commit()
  868. self.assertEqual(msg.title, 'Test issue #2')
  869. # User is not an admin of the project
  870. user = tests.FakeUser(username='foo')
  871. with tests.user_set(self.app.application, user):
  872. output = self.app.get('/test/issue/1')
  873. self.assertEqual(output.status_code, 200)
  874. self.assertIn(
  875. '<title>Issue #1: Test issue - test - Pagure</title>',
  876. output.get_data(as_text=True))
  877. csrf_token = self.get_csrf(output=output)
  878. # Add a dependent ticket
  879. data = {
  880. 'csrf_token': csrf_token,
  881. 'blocking': '2',
  882. }
  883. output = self.app.post(
  884. '/test/issue/1/update', data=data, follow_redirects=True)
  885. self.assertEqual(output.status_code, 200)
  886. self.assertIn(
  887. '<title>Issue #1: Test issue - test - Pagure</title>',
  888. output.get_data(as_text=True))
  889. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  890. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  891. self.assertEqual(issue.depending_text, [])
  892. self.assertEqual(issue.blocking_text, [2])
  893. # Add an invalid dependent ticket
  894. data = {
  895. 'csrf_token': csrf_token,
  896. 'blocking': '2,abc',
  897. }
  898. output = self.app.post(
  899. '/test/issue/1/update', data=data, follow_redirects=True)
  900. self.assertEqual(output.status_code, 200)
  901. output_text = output.get_data(as_text=True)
  902. self.assertIn(
  903. '<title>Issue #1: Test issue - test - Pagure</title>',
  904. output_text)
  905. self.assertNotIn(
  906. '<a class="btn btn-outline-secondary btn-sm border-0"'
  907. ' href="/test/issue/1/edit" title="Edit this issue">',
  908. output_text)
  909. self.assertNotIn(
  910. 'Successfully edited issue #1',
  911. output_text)
  912. self.session.commit()
  913. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  914. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  915. self.assertEqual(issue.depending_text, [])
  916. self.assertEqual(issue.blocking_text, [2])
  917. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  918. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  919. def test_update_issue_edit_comment(self):
  920. """ Test the issues edit comment endpoint """
  921. # Create issues to play with
  922. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  923. msg = pagure.lib.query.new_issue(
  924. session=self.session,
  925. repo=repo,
  926. title='Test issue',
  927. content='We should work on this',
  928. user='pingou',
  929. )
  930. self.session.commit()
  931. self.assertEqual(msg.title, 'Test issue')
  932. user = tests.FakeUser(username='foo')
  933. with tests.user_set(self.app.application, user):
  934. output = self.app.get('/test/issue/1')
  935. self.assertEqual(output.status_code, 200)
  936. output_text = output.get_data(as_text=True)
  937. self.assertIn(
  938. '<title>Issue #1: Test issue - test - Pagure</title>',
  939. output_text)
  940. self.assertNotIn(
  941. '<a class="btn btn-outline-secondary btn-sm border-0"'
  942. ' href="/test/issue/1/edit" title="Edit this issue">\n',
  943. output_text)
  944. csrf_token = self.get_csrf(output=output)
  945. # Add new comment
  946. data = {
  947. 'csrf_token': csrf_token,
  948. 'comment': 'Woohoo a second comment!',
  949. }
  950. output = self.app.post(
  951. '/test/issue/1/update', data=data, follow_redirects=True)
  952. self.assertEqual(output.status_code, 200)
  953. output_text = output.get_data(as_text=True)
  954. self.assertIn(
  955. '<title>Issue #1: Test issue - test - Pagure</title>',
  956. output_text)
  957. self.assertNotIn(
  958. '<a class="btn btn-outline-secondary btn-sm border-0"'
  959. ' href="/test/issue/1/edit" title="Edit this issue">\n',
  960. output_text)
  961. self.assertIn('Comment added', output_text)
  962. self.assertIn(
  963. '<p>Woohoo a second comment!</p>',
  964. output_text)
  965. self.assertEqual(
  966. output_text.count('comment_body">'), 2)
  967. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  968. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  969. self.assertEqual(len(issue.comments), 1)
  970. self.assertEqual(
  971. issue.comments[0].comment,
  972. 'Woohoo a second comment!')
  973. data = {
  974. 'csrf_token': csrf_token,
  975. 'edit_comment': 1,
  976. 'update_comment': 'Updated comment',
  977. }
  978. user = tests.FakeUser()
  979. with tests.user_set(self.app.application, user):
  980. # Wrong issue id
  981. output = self.app.post(
  982. '/test/issue/3/update', data=data, follow_redirects=True)
  983. self.assertEqual(output.status_code, 404)
  984. # Wrong user
  985. output = self.app.post(
  986. '/test/issue/1/update', data=data, follow_redirects=True)
  987. self.assertEqual(output.status_code, 403)
  988. user = tests.FakeUser(username='foo')
  989. with tests.user_set(self.app.application, user):
  990. # Edit comment
  991. output = self.app.post(
  992. '/test/issue/1/update', data=data, follow_redirects=True)
  993. self.assertEqual(output.status_code, 200)
  994. output_text = output.get_data(as_text=True)
  995. self.assertIn(
  996. '<title>Issue #1: Test issue - test - Pagure</title>',
  997. output_text)
  998. self.assertNotIn(
  999. '<a class="btn btn-outline-secondary btn-sm border-0"'
  1000. ' href="/test/issue/1/edit" title="Edit this issue">',
  1001. output_text)
  1002. self.assertIn('Comment updated', output_text)
  1003. self.session.commit()
  1004. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  1005. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  1006. self.assertEqual(len(issue.comments), 1)
  1007. self.assertEqual(issue.comments[0].comment, 'Updated comment')
  1008. with tests.user_set(self.app.application, user):
  1009. output = self.app.get('/test/issue/1/comment/1/edit')
  1010. output_text = output.get_data(as_text=True)
  1011. self.assertIn(
  1012. '<title>test - Pagure</title>', output_text)
  1013. self.assertTrue('<div id="edit">' in output_text)
  1014. self.assertTrue('<section class="edit_comment">' in output_text)
  1015. self.assertTrue(
  1016. '<textarea class="form-control" id="update_comment"'
  1017. in output_text)
  1018. csrf_token = self.get_csrf(output=output)
  1019. data['csrf_token'] = csrf_token
  1020. data['update_comment'] = 'Second update'
  1021. # Edit the comment with the other endpoint
  1022. output = self.app.post(
  1023. '/test/issue/1/comment/1/edit',
  1024. data=data,
  1025. follow_redirects=True)
  1026. self.assertEqual(output.status_code, 200)
  1027. output_text = output.get_data(as_text=True)
  1028. self.assertIn(
  1029. '<title>Issue #1: Test issue - test - Pagure</title>',
  1030. output_text)
  1031. self.assertNotIn(
  1032. '<a class="btn btn-outline-secondary btn-sm border-0"'
  1033. ' href="/test/issue/1/edit" title="Edit this issue">',
  1034. output_text)
  1035. self.assertIn('Comment updated', output_text)
  1036. self.session.commit()
  1037. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  1038. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  1039. self.assertEqual(len(issue.comments), 1)
  1040. self.assertEqual(issue.comments[0].comment, 'Second update')
  1041. # Create another issue from someone else
  1042. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  1043. msg = pagure.lib.query.new_issue(
  1044. session=self.session,
  1045. repo=repo,
  1046. title='Test issue',
  1047. content='We should work on this',
  1048. user='foo',
  1049. )
  1050. self.session.commit()
  1051. self.assertEqual(msg.title, 'Test issue')
  1052. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  1053. self.assertEqual(len(issue.comments), 1)
  1054. self.assertEqual(issue.status, 'Open')
  1055. issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
  1056. self.assertEqual(len(issue.comments), 0)
  1057. self.assertEqual(issue.status, 'Open')
  1058. user = tests.FakeUser(username="foo")
  1059. with tests.user_set(self.app.application, user):
  1060. data = {
  1061. 'csrf_token': csrf_token,
  1062. 'comment': 'Nevermind figured it out',
  1063. 'status': 'Closed',
  1064. 'close_status': 'Invalid'
  1065. }
  1066. # Add a comment and close the ticket #1
  1067. output = self.app.post(
  1068. '/test/issue/1/update', data=data, follow_redirects=True)
  1069. self.assertEqual(output.status_code, 200)
  1070. output_text = output.get_data(as_text=True)
  1071. self.assertNotIn('Successfully edited issue #1\n', output_text)
  1072. self.assertIn('Comment added', output_text)
  1073. self.assertIn(
  1074. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  1075. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  1076. '<i class="fa fa-fw fa-pencil">',
  1077. output_text
  1078. )
  1079. data = {
  1080. 'csrf_token': csrf_token,
  1081. 'comment': 'Nevermind figured it out',
  1082. 'status': 'Closed',
  1083. 'close_status': 'Invalid'
  1084. }
  1085. # Add a comment and close the ticket #2
  1086. output = self.app.post(
  1087. '/test/issue/2/update', data=data, follow_redirects=True)
  1088. self.assertEqual(output.status_code, 200)
  1089. output_text = output.get_data(as_text=True)
  1090. self.assertIn(
  1091. 'Issue close_status updated to: Invalid',
  1092. output_text
  1093. )
  1094. self.assertIn('Comment added', output_text)
  1095. self.assertIn(
  1096. 'Issue status updated to: Closed (was: Open)',
  1097. output_text
  1098. )
  1099. self.assertIn(
  1100. '<a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display'
  1101. ' editmetadatatoggle" href="javascript:void(0)" style="display: inline-block;">'
  1102. '<i class="fa fa-fw fa-pencil">',
  1103. output_text
  1104. )
  1105. # Ticket #1 has one more comment and is still open
  1106. self.session.commit()
  1107. issue = pagure.lib.query.search_issues(self.session, repo, issueid=1)
  1108. self.assertEqual(len(issue.comments), 2)
  1109. self.assertEqual(issue.status, 'Open')
  1110. # Ticket #2 has one less comment and is closed
  1111. issue = pagure.lib.query.search_issues(self.session, repo, issueid=2)
  1112. self.assertEqual(len(issue.comments), 2)
  1113. self.assertEqual(
  1114. issue.comments[0].comment,
  1115. 'Nevermind figured it out')
  1116. self.assertEqual(
  1117. issue.comments[1].comment,
  1118. '**Metadata Update from @foo**:\n'
  1119. '- Issue close_status updated to: Invalid\n'
  1120. '- Issue status updated to: Closed (was: Open)')
  1121. self.assertEqual(issue.status, 'Closed')
  1122. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  1123. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1124. def test_view_issue_closed(self):
  1125. """ Test viewing a closed issue. """
  1126. # Create issues to play with
  1127. repo = pagure.lib.query.get_authorized_project(self.session, 'test')
  1128. msg = pagure.lib.query.new_issue(
  1129. session=self.session,
  1130. repo=repo,
  1131. title='Test issue',
  1132. content='We should work on this',
  1133. user='pingou',
  1134. )
  1135. self.session.commit()
  1136. self.assertEqual(msg.title, 'Test issue')
  1137. user = tests.FakeUser(username='foo')
  1138. with tests.user_set(self.app.application, user):
  1139. output = self.app.get('/test/issue/1')
  1140. self.assertEqual(output.status_code, 200)
  1141. output_text = output.get_data(as_text=True)
  1142. self.assertIn(
  1143. '<title>Issue #1: Test issue - test - Pagure</title>',
  1144. output_text)
  1145. self.assertNotIn(
  1146. '<a class="btn btn-outline-secondary btn-sm border-0"'
  1147. ' href="/test/issue/1/edit" title="Edit this issue">',
  1148. output_text)
  1149. csrf_token = self.get_csrf(output=output)
  1150. # Add new comment
  1151. data = {
  1152. 'csrf_token': csrf_token,
  1153. 'status': 'Closed',
  1154. 'close_status': 'Fixed',
  1155. 'comment': 'Woohoo a second comment!',
  1156. }
  1157. output = self.app.post(
  1158. '/test/issue/1/update', data=data, follow_redirects=True)
  1159. self.assertEqual(output.status_code, 200)
  1160. output_text = output.get_data(as_text=True)
  1161. self.assertIn(
  1162. '<title>Issue #1: Test issue - test - Pagure</title>',
  1163. output_text)
  1164. self.assertNotIn(
  1165. '<a class="btn btn-outline-secondary btn-sm border-0"'
  1166. ' href="/test/issue/1/edit" title="Edit this issue">',
  1167. output_text)
  1168. self.assertIn('Comment added', output_text)
  1169. self.assertIn(
  1170. '<p>Woohoo a second comment!</p>', output_text)
  1171. self.assertEqual(output_text.count('comment_body">'), 2)
  1172. self.assertNotIn(
  1173. '<option selected value="Fixed">Fixed</option>',
  1174. output_text)
  1175. if __name__ == '__main__':
  1176. unittest.main(verbosity=2)