test_pagure_flask_api_issue.py 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.8']
  8. import pkg_resources
  9. import datetime
  10. import unittest
  11. import shutil
  12. import sys
  13. import os
  14. import json
  15. from mock import patch
  16. sys.path.insert(0, os.path.join(os.path.dirname(
  17. os.path.abspath(__file__)), '..'))
  18. import pagure.lib
  19. import tests
  20. class PagureFlaskApiIssuetests(tests.Modeltests):
  21. """ Tests for the flask API of pagure for issue """
  22. def setUp(self):
  23. """ Set up the environnment, ran before every tests. """
  24. super(PagureFlaskApiIssuetests, self).setUp()
  25. pagure.APP.config['TESTING'] = True
  26. pagure.SESSION = self.session
  27. pagure.api.SESSION = self.session
  28. pagure.api.issue.SESSION = self.session
  29. pagure.lib.SESSION = self.session
  30. pagure.APP.config['TICKETS_FOLDER'] = None
  31. self.app = pagure.APP.test_client()
  32. def test_api_new_issue(self):
  33. """ Test the api_new_issue method of the flask api. """
  34. tests.create_projects(self.session)
  35. tests.create_projects_git(os.path.join(tests.HERE, 'tickets'))
  36. tests.create_tokens(self.session)
  37. tests.create_tokens_acl(self.session)
  38. headers = {'Authorization': 'token aaabbbcccddd'}
  39. # Valid token, wrong project
  40. output = self.app.post('/api/0/test2/new_issue', headers=headers)
  41. self.assertEqual(output.status_code, 401)
  42. data = json.loads(output.data)
  43. self.assertDictEqual(
  44. data,
  45. {
  46. "error": "Invalid or expired token. Please visit " \
  47. "https://pagure.org/ to get or renew your API token.",
  48. "error_code": "EINVALIDTOK",
  49. }
  50. )
  51. # No input
  52. output = self.app.post('/api/0/test/new_issue', headers=headers)
  53. self.assertEqual(output.status_code, 400)
  54. data = json.loads(output.data)
  55. self.assertDictEqual(
  56. data,
  57. {
  58. "error": "Invalid or incomplete input submited",
  59. "error_code": "EINVALIDREQ",
  60. }
  61. )
  62. data = {
  63. 'title': 'test issue',
  64. }
  65. # Invalid repo
  66. output = self.app.post(
  67. '/api/0/foo/new_issue', data=data, headers=headers)
  68. self.assertEqual(output.status_code, 404)
  69. data = json.loads(output.data)
  70. self.assertDictEqual(
  71. data,
  72. {
  73. "error": "Project not found",
  74. "error_code": "ENOPROJECT",
  75. }
  76. )
  77. # Incomplete request
  78. output = self.app.post(
  79. '/api/0/test/new_issue', data=data, headers=headers)
  80. self.assertEqual(output.status_code, 400)
  81. data = json.loads(output.data)
  82. self.assertDictEqual(
  83. data,
  84. {
  85. "error": "Invalid or incomplete input submited",
  86. "error_code": "EINVALIDREQ",
  87. }
  88. )
  89. data = {
  90. 'title': 'test issue',
  91. 'issue_content': 'This issue needs attention',
  92. }
  93. # Valid request
  94. output = self.app.post(
  95. '/api/0/test/new_issue', data=data, headers=headers)
  96. self.assertEqual(output.status_code, 200)
  97. data = json.loads(output.data)
  98. self.assertDictEqual(
  99. data,
  100. {'message': 'Issue created'}
  101. )
  102. def test_api_view_issues(self):
  103. """ Test the api_view_issues method of the flask api. """
  104. self.test_api_new_issue()
  105. # Invalid repo
  106. output = self.app.get('/api/0/foo/issues')
  107. self.assertEqual(output.status_code, 404)
  108. data = json.loads(output.data)
  109. self.assertDictEqual(
  110. data,
  111. {
  112. "error": "Project not found",
  113. "error_code": "ENOPROJECT",
  114. }
  115. )
  116. # List all opened issues
  117. output = self.app.get('/api/0/test/issues')
  118. self.assertEqual(output.status_code, 200)
  119. data = json.loads(output.data)
  120. data['issues'][0]['date_created'] = '1431414800'
  121. self.assertDictEqual(
  122. data,
  123. {
  124. "args": {
  125. "assignee": None,
  126. "author": None,
  127. "status": None,
  128. "tags": []
  129. },
  130. "total_issues": 1,
  131. "issues": [
  132. {
  133. "assignee": None,
  134. "blocks": [],
  135. "comments": [],
  136. "content": "This issue needs attention",
  137. "date_created": "1431414800",
  138. "depends": [],
  139. "id": 1,
  140. "priority": None,
  141. "private": False,
  142. "status": "Open",
  143. "tags": [],
  144. "title": "test issue",
  145. "user": {
  146. "fullname": "PY C",
  147. "name": "pingou"
  148. }
  149. }
  150. ]
  151. }
  152. )
  153. # Create private issue
  154. repo = pagure.lib.get_project(self.session, 'test')
  155. msg = pagure.lib.new_issue(
  156. session=self.session,
  157. repo=repo,
  158. title='Test issue',
  159. content='We should work on this',
  160. user='pingou',
  161. ticketfolder=None,
  162. private=True,
  163. )
  164. self.session.commit()
  165. self.assertEqual(msg.title, 'Test issue')
  166. # Access issues un-authenticated
  167. output = self.app.get('/api/0/test/issues')
  168. self.assertEqual(output.status_code, 200)
  169. data = json.loads(output.data)
  170. data['issues'][0]['date_created'] = '1431414800'
  171. self.assertDictEqual(
  172. data,
  173. {
  174. "args": {
  175. "assignee": None,
  176. "author": None,
  177. "status": None,
  178. "tags": []
  179. },
  180. "total_issues": 1,
  181. "issues": [
  182. {
  183. "assignee": None,
  184. "blocks": [],
  185. "comments": [],
  186. "content": "This issue needs attention",
  187. "date_created": "1431414800",
  188. "depends": [],
  189. "id": 1,
  190. "priority": None,
  191. "private": False,
  192. "status": "Open",
  193. "tags": [],
  194. "title": "test issue",
  195. "user": {
  196. "fullname": "PY C",
  197. "name": "pingou"
  198. }
  199. }
  200. ]
  201. }
  202. )
  203. headers = {'Authorization': 'token aaabbbccc'}
  204. # Access issues authenticated but non-existing token
  205. output = self.app.get('/api/0/test/issues', headers=headers)
  206. self.assertEqual(output.status_code, 401)
  207. # Create a new token for another user
  208. item = pagure.lib.model.Token(
  209. id='bar_token',
  210. user_id=2,
  211. project_id=1,
  212. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  213. days=30)
  214. )
  215. self.session.add(item)
  216. headers = {'Authorization': 'token bar_token'}
  217. # Access issues authenticated but wrong token
  218. output = self.app.get('/api/0/test/issues', headers=headers)
  219. self.assertEqual(output.status_code, 200)
  220. data = json.loads(output.data)
  221. data['issues'][0]['date_created'] = '1431414800'
  222. self.assertDictEqual(
  223. data,
  224. {
  225. "args": {
  226. "assignee": None,
  227. "author": None,
  228. "status": None,
  229. "tags": []
  230. },
  231. "total_issues": 1,
  232. "issues": [
  233. {
  234. "assignee": None,
  235. "blocks": [],
  236. "comments": [],
  237. "content": "This issue needs attention",
  238. "date_created": "1431414800",
  239. "depends": [],
  240. "id": 1,
  241. "priority": None,
  242. "private": False,
  243. "status": "Open",
  244. "tags": [],
  245. "title": "test issue",
  246. "user": {
  247. "fullname": "PY C",
  248. "name": "pingou"
  249. }
  250. }
  251. ]
  252. }
  253. )
  254. headers = {'Authorization': 'token aaabbbcccddd'}
  255. # Access issues authenticated correctly
  256. output = self.app.get('/api/0/test/issues', headers=headers)
  257. self.assertEqual(output.status_code, 200)
  258. data = json.loads(output.data)
  259. data['issues'][0]['date_created'] = '1431414800'
  260. data['issues'][1]['date_created'] = '1431414800'
  261. self.assertDictEqual(
  262. data,
  263. {
  264. "args": {
  265. "assignee": None,
  266. "author": None,
  267. "status": None,
  268. "tags": []
  269. },
  270. "total_issues": 2,
  271. "issues": [
  272. {
  273. "assignee": None,
  274. "blocks": [],
  275. "comments": [],
  276. "content": "This issue needs attention",
  277. "date_created": "1431414800",
  278. "depends": [],
  279. "id": 1,
  280. "priority": None,
  281. "private": False,
  282. "status": "Open",
  283. "tags": [],
  284. "title": "test issue",
  285. "user": {
  286. "fullname": "PY C",
  287. "name": "pingou"
  288. }
  289. },
  290. {
  291. "assignee": None,
  292. "blocks": [],
  293. "comments": [],
  294. "content": "We should work on this",
  295. "date_created": "1431414800",
  296. "depends": [],
  297. "id": 2,
  298. "priority": None,
  299. "private": True,
  300. "status": "Open",
  301. "tags": [],
  302. "title": "Test issue",
  303. "user": {
  304. "fullname": "PY C",
  305. "name": "pingou"
  306. }
  307. }
  308. ]
  309. }
  310. )
  311. # List closed issue
  312. output = self.app.get('/api/0/test/issues?status=Closed', headers=headers)
  313. self.assertEqual(output.status_code, 200)
  314. data = json.loads(output.data)
  315. self.assertDictEqual(
  316. data,
  317. {
  318. "args": {
  319. "assignee": None,
  320. "author": None,
  321. "status": "Closed",
  322. "tags": []
  323. },
  324. "total_issues": 0,
  325. "issues": []
  326. }
  327. )
  328. # List closed issue
  329. output = self.app.get('/api/0/test/issues?status=Invalid', headers=headers)
  330. self.assertEqual(output.status_code, 200)
  331. data = json.loads(output.data)
  332. self.assertDictEqual(
  333. data,
  334. {
  335. "args": {
  336. "assignee": None,
  337. "author": None,
  338. "status": "Invalid",
  339. "tags": []
  340. },
  341. "total_issues": 0,
  342. "issues": []
  343. }
  344. )
  345. # List all issues
  346. output = self.app.get('/api/0/test/issues?status=All', headers=headers)
  347. self.assertEqual(output.status_code, 200)
  348. data = json.loads(output.data)
  349. data['issues'][0]['date_created'] = '1431414800'
  350. data['issues'][1]['date_created'] = '1431414800'
  351. self.assertDictEqual(
  352. data,
  353. {
  354. "args": {
  355. "assignee": None,
  356. "author": None,
  357. "status": "All",
  358. "tags": []
  359. },
  360. "total_issues": 2,
  361. "issues": [
  362. {
  363. "assignee": None,
  364. "blocks": [],
  365. "comments": [],
  366. "content": "This issue needs attention",
  367. "date_created": "1431414800",
  368. "depends": [],
  369. "id": 1,
  370. "priority": None,
  371. "private": False,
  372. "status": "Open",
  373. "tags": [],
  374. "title": "test issue",
  375. "user": {
  376. "fullname": "PY C",
  377. "name": "pingou"
  378. }
  379. },
  380. {
  381. "assignee": None,
  382. "blocks": [],
  383. "comments": [],
  384. "content": "We should work on this",
  385. "date_created": "1431414800",
  386. "depends": [],
  387. "id": 2,
  388. "priority": None,
  389. "private": True,
  390. "status": "Open",
  391. "tags": [],
  392. "title": "Test issue",
  393. "user": {
  394. "fullname": "PY C",
  395. "name": "pingou"
  396. }
  397. }
  398. ],
  399. }
  400. )
  401. def test_api_view_issue(self):
  402. """ Test the api_view_issue method of the flask api. """
  403. self.test_api_new_issue()
  404. # Invalid repo
  405. output = self.app.get('/api/0/foo/issue/1')
  406. self.assertEqual(output.status_code, 404)
  407. data = json.loads(output.data)
  408. self.assertDictEqual(
  409. data,
  410. {
  411. "error": "Project not found",
  412. "error_code": "ENOPROJECT",
  413. }
  414. )
  415. # Invalid issue for this repo
  416. output = self.app.get('/api/0/test2/issue/1')
  417. self.assertEqual(output.status_code, 404)
  418. data = json.loads(output.data)
  419. self.assertDictEqual(
  420. data,
  421. {
  422. "error": "Issue not found",
  423. "error_code": "ENOISSUE",
  424. }
  425. )
  426. # Valid issue
  427. output = self.app.get('/api/0/test/issue/1')
  428. self.assertEqual(output.status_code, 200)
  429. data = json.loads(output.data)
  430. data['date_created'] = '1431414800'
  431. self.assertDictEqual(
  432. data,
  433. {
  434. "assignee": None,
  435. "blocks": [],
  436. "comments": [],
  437. "content": "This issue needs attention",
  438. "date_created": "1431414800",
  439. "depends": [],
  440. "id": 1,
  441. "priority": None,
  442. "private": False,
  443. "status": "Open",
  444. "tags": [],
  445. "title": "test issue",
  446. "user": {
  447. "fullname": "PY C",
  448. "name": "pingou"
  449. }
  450. }
  451. )
  452. # Create private issue
  453. repo = pagure.lib.get_project(self.session, 'test')
  454. msg = pagure.lib.new_issue(
  455. session=self.session,
  456. repo=repo,
  457. title='Test issue',
  458. content='We should work on this',
  459. user='pingou',
  460. ticketfolder=None,
  461. private=True,
  462. issue_uid='aaabbbccc',
  463. )
  464. self.session.commit()
  465. self.assertEqual(msg.title, 'Test issue')
  466. # Access private issue un-authenticated
  467. output = self.app.get('/api/0/test/issue/2')
  468. self.assertEqual(output.status_code, 403)
  469. data = json.loads(output.data)
  470. self.assertDictEqual(
  471. data,
  472. {
  473. "error": "You are not allowed to view this issue",
  474. "error_code": "EISSUENOTALLOWED",
  475. }
  476. )
  477. headers = {'Authorization': 'token aaabbbccc'}
  478. # Access private issue authenticated but non-existing token
  479. output = self.app.get('/api/0/test/issue/2', headers=headers)
  480. self.assertEqual(output.status_code, 401)
  481. data = json.loads(output.data)
  482. self.assertDictEqual(
  483. data,
  484. {
  485. "error": "Invalid or expired token. Please visit https://pagure.org/ to get or renew your API token.",
  486. "error_code": "EINVALIDTOK"
  487. }
  488. )
  489. # Create a new token for another user
  490. item = pagure.lib.model.Token(
  491. id='bar_token',
  492. user_id=2,
  493. project_id=1,
  494. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  495. days=30)
  496. )
  497. self.session.add(item)
  498. headers = {'Authorization': 'token bar_token'}
  499. # Access private issue authenticated but wrong token
  500. output = self.app.get('/api/0/test/issue/2', headers=headers)
  501. self.assertEqual(output.status_code, 403)
  502. data = json.loads(output.data)
  503. self.assertDictEqual(
  504. data,
  505. {
  506. "error": "You are not allowed to view this issue",
  507. "error_code": "EISSUENOTALLOWED",
  508. }
  509. )
  510. headers = {'Authorization': 'token aaabbbcccddd'}
  511. # Access private issue authenticated correctly
  512. output = self.app.get('/api/0/test/issue/2', headers=headers)
  513. self.assertEqual(output.status_code, 200)
  514. data = json.loads(output.data)
  515. data['date_created'] = '1431414800'
  516. self.assertDictEqual(
  517. data,
  518. {
  519. "assignee": None,
  520. "blocks": [],
  521. "comments": [],
  522. "content": "We should work on this",
  523. "date_created": "1431414800",
  524. "depends": [],
  525. "id": 2,
  526. "priority": None,
  527. "private": True,
  528. "status": "Open",
  529. "tags": [],
  530. "title": "Test issue",
  531. "user": {
  532. "fullname": "PY C",
  533. "name": "pingou"
  534. }
  535. }
  536. )
  537. # Access private issue authenticated correctly using the issue's uid
  538. output = self.app.get('/api/0/test/issue/aaabbbccc', headers=headers)
  539. self.assertEqual(output.status_code, 200)
  540. data = json.loads(output.data)
  541. data['date_created'] = '1431414800'
  542. self.assertDictEqual(
  543. data,
  544. {
  545. "assignee": None,
  546. "blocks": [],
  547. "comments": [],
  548. "content": "We should work on this",
  549. "date_created": "1431414800",
  550. "depends": [],
  551. "id": 2,
  552. "priority": None,
  553. "private": True,
  554. "status": "Open",
  555. "tags": [],
  556. "title": "Test issue",
  557. "user": {
  558. "fullname": "PY C",
  559. "name": "pingou"
  560. }
  561. }
  562. )
  563. def test_api_change_status_issue(self):
  564. """ Test the api_change_status_issue method of the flask api. """
  565. tests.create_projects(self.session)
  566. tests.create_projects_git(os.path.join(tests.HERE, 'tickets'))
  567. tests.create_tokens(self.session)
  568. tests.create_tokens_acl(self.session)
  569. headers = {'Authorization': 'token aaabbbcccddd'}
  570. # Invalid project
  571. output = self.app.post('/api/0/foo/issue/1/status', headers=headers)
  572. self.assertEqual(output.status_code, 404)
  573. data = json.loads(output.data)
  574. self.assertDictEqual(
  575. data,
  576. {
  577. "error": "Project not found",
  578. "error_code": "ENOPROJECT",
  579. }
  580. )
  581. # Valid token, wrong project
  582. output = self.app.post('/api/0/test2/issue/1/status', headers=headers)
  583. self.assertEqual(output.status_code, 401)
  584. data = json.loads(output.data)
  585. self.assertDictEqual(
  586. data,
  587. {
  588. "error": "Invalid or expired token. Please visit " \
  589. "https://pagure.org/ to get or renew your API token.",
  590. "error_code": "EINVALIDTOK",
  591. }
  592. )
  593. # No input
  594. output = self.app.post('/api/0/test/issue/1/status', headers=headers)
  595. self.assertEqual(output.status_code, 404)
  596. data = json.loads(output.data)
  597. self.assertDictEqual(
  598. data,
  599. {
  600. "error": "Issue not found",
  601. "error_code": "ENOISSUE",
  602. }
  603. )
  604. # Create normal issue
  605. repo = pagure.lib.get_project(self.session, 'test')
  606. msg = pagure.lib.new_issue(
  607. session=self.session,
  608. repo=repo,
  609. title='Test issue #1',
  610. content='We should work on this',
  611. user='pingou',
  612. ticketfolder=None,
  613. private=False,
  614. )
  615. self.session.commit()
  616. self.assertEqual(msg.title, 'Test issue #1')
  617. # Create another project
  618. item = pagure.lib.model.Project(
  619. user_id=2, # pingou
  620. name='foo',
  621. description='test project #3',
  622. hook_token='aaabbbdddeee',
  623. )
  624. self.session.add(item)
  625. self.session.commit()
  626. # Create a token for pingou for this project
  627. item = pagure.lib.model.Token(
  628. id='pingou_foo',
  629. user_id=1,
  630. project_id=3,
  631. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  632. days=30)
  633. )
  634. self.session.add(item)
  635. self.session.commit()
  636. # Give `change_status_issue` to this token
  637. item = pagure.lib.model.TokenAcl(
  638. token_id='pingou_foo',
  639. acl_id=6,
  640. )
  641. self.session.add(item)
  642. self.session.commit()
  643. repo = pagure.lib.get_project(self.session, 'foo')
  644. # Create private issue
  645. msg = pagure.lib.new_issue(
  646. session=self.session,
  647. repo=repo,
  648. title='Test issue',
  649. content='We should work on this',
  650. user='foo',
  651. ticketfolder=None,
  652. private=True,
  653. )
  654. self.session.commit()
  655. self.assertEqual(msg.title, 'Test issue')
  656. # Check status before
  657. repo = pagure.lib.get_project(self.session, 'test')
  658. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  659. self.assertEqual(issue.status, 'Open')
  660. data = {
  661. 'title': 'test issue',
  662. }
  663. # Incomplete request
  664. output = self.app.post(
  665. '/api/0/test/issue/1/status', data=data, headers=headers)
  666. self.assertEqual(output.status_code, 400)
  667. data = json.loads(output.data)
  668. self.assertDictEqual(
  669. data,
  670. {
  671. "error": "Invalid or incomplete input submited",
  672. "error_code": "EINVALIDREQ",
  673. }
  674. )
  675. # No change
  676. repo = pagure.lib.get_project(self.session, 'test')
  677. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  678. self.assertEqual(issue.status, 'Open')
  679. data = {
  680. 'status': 'Open',
  681. }
  682. # Valid request but no change
  683. output = self.app.post(
  684. '/api/0/test/issue/1/status', data=data, headers=headers)
  685. self.assertEqual(output.status_code, 200)
  686. data = json.loads(output.data)
  687. self.assertDictEqual(
  688. data,
  689. {'message': 'No changes'}
  690. )
  691. # No change
  692. repo = pagure.lib.get_project(self.session, 'test')
  693. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  694. self.assertEqual(issue.status, 'Open')
  695. data = {
  696. 'status': 'Fixed',
  697. }
  698. # Valid request
  699. output = self.app.post(
  700. '/api/0/test/issue/1/status', data=data, headers=headers)
  701. self.assertEqual(output.status_code, 200)
  702. data = json.loads(output.data)
  703. self.assertDictEqual(
  704. data,
  705. {'message': 'Successfully edited issue #1'}
  706. )
  707. headers = {'Authorization': 'token pingou_foo'}
  708. # Un-authorized issue
  709. output = self.app.post(
  710. '/api/0/foo/issue/1/status', data=data, headers=headers)
  711. self.assertEqual(output.status_code, 403)
  712. data = json.loads(output.data)
  713. self.assertDictEqual(
  714. data,
  715. {
  716. "error": "You are not allowed to view this issue",
  717. "error_code": "EISSUENOTALLOWED",
  718. }
  719. )
  720. @patch('pagure.lib.git.update_git')
  721. @patch('pagure.lib.notify.send_email')
  722. def test_api_comment_issue(self, p_send_email, p_ugt):
  723. """ Test the api_comment_issue method of the flask api. """
  724. p_send_email.return_value = True
  725. p_ugt.return_value = True
  726. tests.create_projects(self.session)
  727. tests.create_tokens(self.session)
  728. tests.create_tokens_acl(self.session)
  729. headers = {'Authorization': 'token aaabbbcccddd'}
  730. # Invalid project
  731. output = self.app.post('/api/0/foo/issue/1/comment', headers=headers)
  732. self.assertEqual(output.status_code, 404)
  733. data = json.loads(output.data)
  734. self.assertDictEqual(
  735. data,
  736. {
  737. "error": "Project not found",
  738. "error_code": "ENOPROJECT",
  739. }
  740. )
  741. # Valid token, wrong project
  742. output = self.app.post('/api/0/test2/issue/1/comment', headers=headers)
  743. self.assertEqual(output.status_code, 401)
  744. data = json.loads(output.data)
  745. self.assertDictEqual(
  746. data,
  747. {
  748. "error": "Invalid or expired token. Please visit " \
  749. "https://pagure.org/ to get or renew your API token.",
  750. "error_code": "EINVALIDTOK",
  751. }
  752. )
  753. # No input
  754. output = self.app.post('/api/0/test/issue/1/comment', headers=headers)
  755. self.assertEqual(output.status_code, 404)
  756. data = json.loads(output.data)
  757. self.assertDictEqual(
  758. data,
  759. {
  760. "error": "Issue not found",
  761. "error_code": "ENOISSUE",
  762. }
  763. )
  764. # Create normal issue
  765. repo = pagure.lib.get_project(self.session, 'test')
  766. msg = pagure.lib.new_issue(
  767. session=self.session,
  768. repo=repo,
  769. title='Test issue #1',
  770. content='We should work on this',
  771. user='pingou',
  772. ticketfolder=None,
  773. private=False,
  774. issue_uid='aaabbbccc#1',
  775. )
  776. self.session.commit()
  777. self.assertEqual(msg.title, 'Test issue #1')
  778. # Check comments before
  779. repo = pagure.lib.get_project(self.session, 'test')
  780. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  781. self.assertEqual(len(issue.comments), 0)
  782. data = {
  783. 'title': 'test issue',
  784. }
  785. # Incomplete request
  786. output = self.app.post(
  787. '/api/0/test/issue/1/comment', data=data, headers=headers)
  788. self.assertEqual(output.status_code, 400)
  789. data = json.loads(output.data)
  790. self.assertDictEqual(
  791. data,
  792. {
  793. "error": "Invalid or incomplete input submited",
  794. "error_code": "EINVALIDREQ",
  795. }
  796. )
  797. # No change
  798. repo = pagure.lib.get_project(self.session, 'test')
  799. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  800. self.assertEqual(issue.status, 'Open')
  801. data = {
  802. 'comment': 'This is a very interesting question',
  803. }
  804. # Valid request
  805. output = self.app.post(
  806. '/api/0/test/issue/1/comment', data=data, headers=headers)
  807. self.assertEqual(output.status_code, 200)
  808. data = json.loads(output.data)
  809. self.assertDictEqual(
  810. data,
  811. {'message': 'Comment added'}
  812. )
  813. # One comment added
  814. repo = pagure.lib.get_project(self.session, 'test')
  815. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  816. self.assertEqual(len(issue.comments), 1)
  817. # Create another project
  818. item = pagure.lib.model.Project(
  819. user_id=2, # foo
  820. name='foo',
  821. description='test project #3',
  822. hook_token='aaabbbdddeee',
  823. )
  824. self.session.add(item)
  825. self.session.commit()
  826. # Create a token for pingou for this project
  827. item = pagure.lib.model.Token(
  828. id='pingou_foo',
  829. user_id=1,
  830. project_id=3,
  831. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  832. days=30)
  833. )
  834. self.session.add(item)
  835. self.session.commit()
  836. # Give `change_status_issue` to this token
  837. item = pagure.lib.model.TokenAcl(
  838. token_id='pingou_foo',
  839. acl_id=1,
  840. )
  841. self.session.add(item)
  842. self.session.commit()
  843. repo = pagure.lib.get_project(self.session, 'foo')
  844. # Create private issue
  845. msg = pagure.lib.new_issue(
  846. session=self.session,
  847. repo=repo,
  848. title='Test issue',
  849. content='We should work on this',
  850. user='foo',
  851. ticketfolder=None,
  852. private=True,
  853. issue_uid='aaabbbccc#2',
  854. )
  855. self.session.commit()
  856. self.assertEqual(msg.title, 'Test issue')
  857. # Check before
  858. repo = pagure.lib.get_project(self.session, 'foo')
  859. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  860. self.assertEqual(len(issue.comments), 0)
  861. data = {
  862. 'comment': 'This is a very interesting question',
  863. }
  864. headers = {'Authorization': 'token pingou_foo'}
  865. # Valid request but un-authorized
  866. output = self.app.post(
  867. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  868. self.assertEqual(output.status_code, 403)
  869. data = json.loads(output.data)
  870. self.assertDictEqual(
  871. data,
  872. {
  873. "error": "You are not allowed to view this issue",
  874. "error_code": "EISSUENOTALLOWED",
  875. }
  876. )
  877. # No comment added
  878. repo = pagure.lib.get_project(self.session, 'foo')
  879. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  880. self.assertEqual(len(issue.comments), 0)
  881. # Create token for user foo
  882. item = pagure.lib.model.Token(
  883. id='foo_token2',
  884. user_id=2,
  885. project_id=3,
  886. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30)
  887. )
  888. self.session.add(item)
  889. self.session.commit()
  890. tests.create_tokens_acl(self.session, token_id='foo_token2')
  891. data = {
  892. 'comment': 'This is a very interesting question',
  893. }
  894. headers = {'Authorization': 'token foo_token2'}
  895. # Valid request and authorized
  896. output = self.app.post(
  897. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  898. self.assertEqual(output.status_code, 200)
  899. data = json.loads(output.data)
  900. self.assertDictEqual(
  901. data,
  902. {'message': 'Comment added'}
  903. )
  904. @patch('pagure.lib.git.update_git')
  905. @patch('pagure.lib.notify.send_email')
  906. def test_api_view_issue_comment(self, p_send_email, p_ugt):
  907. """ Test the api_view_issue_comment endpoint. """
  908. p_send_email.return_value = True
  909. p_ugt.return_value = True
  910. self.test_api_comment_issue()
  911. # View a comment that does not exist
  912. output = self.app.get('/api/0/foo/issue/100/comment/2')
  913. self.assertEqual(output.status_code, 404)
  914. # Issue exists but not the comment
  915. output = self.app.get('/api/0/test/issue/1/comment/2')
  916. self.assertEqual(output.status_code, 404)
  917. # Issue and comment exists
  918. output = self.app.get('/api/0/test/issue/1/comment/1')
  919. self.assertEqual(output.status_code, 200)
  920. data = json.loads(output.data)
  921. data['date_created'] = '1435821770'
  922. data["comment_date"] = "2015-07-02 09:22"
  923. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  924. self.assertDictEqual(
  925. data,
  926. {
  927. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  928. "comment": "This is a very interesting question",
  929. "comment_date": "2015-07-02 09:22",
  930. "date_created": "1435821770",
  931. "edited_on": None,
  932. "editor": None,
  933. "id": 1,
  934. "parent": None,
  935. "user": {
  936. "fullname": "PY C",
  937. "name": "pingou"
  938. }
  939. }
  940. )
  941. # Issue and comment exists, using UID
  942. output = self.app.get('/api/0/test/issue/aaabbbccc#1/comment/1')
  943. self.assertEqual(output.status_code, 200)
  944. data = json.loads(output.data)
  945. data['date_created'] = '1435821770'
  946. data["comment_date"] = "2015-07-02 09:22"
  947. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  948. self.assertDictEqual(
  949. data,
  950. {
  951. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  952. "comment": "This is a very interesting question",
  953. "comment_date": "2015-07-02 09:22",
  954. "date_created": "1435821770",
  955. "edited_on": None,
  956. "editor": None,
  957. "id": 1,
  958. "parent": None,
  959. "user": {
  960. "fullname": "PY C",
  961. "name": "pingou"
  962. }
  963. }
  964. )
  965. # Private issue
  966. output = self.app.get('/api/0/foo/issue/1/comment/2')
  967. self.assertEqual(output.status_code, 403)
  968. # Private issue - Auth - wrong token
  969. headers = {'Authorization': 'token pingou_foo'}
  970. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  971. self.assertEqual(output.status_code, 403)
  972. # Private issue - Auth - Invalid token
  973. headers = {'Authorization': 'token aaabbbcccddd'}
  974. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  975. self.assertEqual(output.status_code, 401)
  976. # Private issue - Auth - valid token - unknown comment
  977. headers = {'Authorization': 'token foo_token2'}
  978. output = self.app.get('/api/0/foo/issue/1/comment/3', headers=headers)
  979. self.assertEqual(output.status_code, 404)
  980. # Private issue - Auth - valid token - known comment
  981. headers = {'Authorization': 'token foo_token2'}
  982. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  983. self.assertEqual(output.status_code, 200)
  984. data = json.loads(output.data)
  985. data['date_created'] = '1435821770'
  986. data["comment_date"] = "2015-07-02 09:22"
  987. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  988. self.assertDictEqual(
  989. data,
  990. {
  991. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  992. "comment": "This is a very interesting question",
  993. "comment_date": "2015-07-02 09:22",
  994. "date_created": "1435821770",
  995. "edited_on": None,
  996. "editor": None,
  997. "id": 2,
  998. "parent": None,
  999. "user": {
  1000. "fullname": "foo bar",
  1001. "name": "foo"
  1002. }
  1003. }
  1004. )
  1005. if __name__ == '__main__':
  1006. SUITE = unittest.TestLoader().loadTestsFromTestCase(
  1007. PagureFlaskApiIssuetests)
  1008. unittest.TextTestRunner(verbosity=2).run(SUITE)