test_pagure_flask_ui_issues_open_access.py 51 KB

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