test_pagure_flask_ui_issues_open_access.py 52 KB

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