test_pagure_flask_api_issue.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2016 - 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(
  36. os.path.join(self.path, 'tickets'), bare=True)
  37. tests.create_tokens(self.session)
  38. tests.create_tokens_acl(self.session)
  39. headers = {'Authorization': 'token aaabbbcccddd'}
  40. # Valid token, wrong project
  41. output = self.app.post('/api/0/test2/new_issue', headers=headers)
  42. self.assertEqual(output.status_code, 401)
  43. data = json.loads(output.get_data(as_text=True))
  44. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  45. data['error_code'])
  46. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  47. # No input
  48. output = self.app.post('/api/0/test/new_issue', headers=headers)
  49. self.assertEqual(output.status_code, 400)
  50. data = json.loads(output.get_data(as_text=True))
  51. self.assertDictEqual(
  52. data,
  53. {
  54. "error": "Invalid or incomplete input submited",
  55. "error_code": "EINVALIDREQ",
  56. }
  57. )
  58. data = {
  59. 'title': 'test issue',
  60. }
  61. # Invalid repo
  62. output = self.app.post(
  63. '/api/0/foo/new_issue', data=data, headers=headers)
  64. self.assertEqual(output.status_code, 404)
  65. data = json.loads(output.get_data(as_text=True))
  66. self.assertDictEqual(
  67. data,
  68. {
  69. "error": "Project not found",
  70. "error_code": "ENOPROJECT",
  71. }
  72. )
  73. # Incomplete request
  74. output = self.app.post(
  75. '/api/0/test/new_issue', data=data, headers=headers)
  76. self.assertEqual(output.status_code, 400)
  77. data = json.loads(output.get_data(as_text=True))
  78. self.assertDictEqual(
  79. data,
  80. {
  81. "error": "Invalid or incomplete input submited",
  82. "error_code": "EINVALIDREQ",
  83. }
  84. )
  85. data = {
  86. 'title': 'test issue',
  87. 'issue_content': 'This issue needs attention',
  88. }
  89. # Valid request
  90. output = self.app.post(
  91. '/api/0/test/new_issue', data=data, headers=headers)
  92. self.assertEqual(output.status_code, 200)
  93. data = json.loads(output.get_data(as_text=True))
  94. self.assertDictEqual(
  95. data,
  96. {'message': 'Issue created'}
  97. )
  98. def test_api_view_issues(self):
  99. """ Test the api_view_issues method of the flask api. """
  100. self.test_api_new_issue()
  101. # Invalid repo
  102. output = self.app.get('/api/0/foo/issues')
  103. self.assertEqual(output.status_code, 404)
  104. data = json.loads(output.get_data(as_text=True))
  105. self.assertDictEqual(
  106. data,
  107. {
  108. "error": "Project not found",
  109. "error_code": "ENOPROJECT",
  110. }
  111. )
  112. # List all opened issues
  113. output = self.app.get('/api/0/test/issues')
  114. self.assertEqual(output.status_code, 200)
  115. data = json.loads(output.get_data(as_text=True))
  116. data['issues'][0]['date_created'] = '1431414800'
  117. self.assertDictEqual(
  118. data,
  119. {
  120. "args": {
  121. "assignee": None,
  122. "author": None,
  123. "status": None,
  124. "tags": []
  125. },
  126. "total_issues": 1,
  127. "issues": [
  128. {
  129. "assignee": None,
  130. "blocks": [],
  131. "comments": [],
  132. "content": "This issue needs attention",
  133. "date_created": "1431414800",
  134. "closed_at": None,
  135. "depends": [],
  136. "id": 1,
  137. "milestone": None,
  138. "priority": None,
  139. "private": False,
  140. "status": "Open",
  141. "tags": [],
  142. "title": "test issue",
  143. "user": {
  144. "fullname": "PY C",
  145. "name": "pingou"
  146. }
  147. }
  148. ]
  149. }
  150. )
  151. # Create private issue
  152. repo = pagure.lib.get_project(self.session, 'test')
  153. msg = pagure.lib.new_issue(
  154. session=self.session,
  155. repo=repo,
  156. title='Test issue',
  157. content='We should work on this',
  158. user='pingou',
  159. ticketfolder=None,
  160. private=True,
  161. )
  162. self.session.commit()
  163. self.assertEqual(msg.title, 'Test issue')
  164. # Access issues un-authenticated
  165. output = self.app.get('/api/0/test/issues')
  166. self.assertEqual(output.status_code, 200)
  167. data = json.loads(output.get_data(as_text=True))
  168. data['issues'][0]['date_created'] = '1431414800'
  169. self.assertDictEqual(
  170. data,
  171. {
  172. "args": {
  173. "assignee": None,
  174. "author": None,
  175. "status": None,
  176. "tags": []
  177. },
  178. "total_issues": 1,
  179. "issues": [
  180. {
  181. "assignee": None,
  182. "blocks": [],
  183. "comments": [],
  184. "content": "This issue needs attention",
  185. "date_created": "1431414800",
  186. "closed_at": None,
  187. "depends": [],
  188. "id": 1,
  189. "milestone": None,
  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.get_data(as_text=True))
  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. "closed_at": None,
  240. "depends": [],
  241. "id": 1,
  242. "milestone": None,
  243. "priority": None,
  244. "private": False,
  245. "status": "Open",
  246. "tags": [],
  247. "title": "test issue",
  248. "user": {
  249. "fullname": "PY C",
  250. "name": "pingou"
  251. }
  252. }
  253. ]
  254. }
  255. )
  256. headers = {'Authorization': 'token aaabbbcccddd'}
  257. # Access issues authenticated correctly
  258. output = self.app.get('/api/0/test/issues', headers=headers)
  259. self.assertEqual(output.status_code, 200)
  260. data = json.loads(output.get_data(as_text=True))
  261. data['issues'][0]['date_created'] = '1431414800'
  262. data['issues'][1]['date_created'] = '1431414800'
  263. self.assertDictEqual(
  264. data,
  265. {
  266. "args": {
  267. "assignee": None,
  268. "author": None,
  269. "status": None,
  270. "tags": []
  271. },
  272. "total_issues": 2,
  273. "issues": [
  274. {
  275. "assignee": None,
  276. "blocks": [],
  277. "comments": [],
  278. "content": "We should work on this",
  279. "date_created": "1431414800",
  280. "closed_at": None,
  281. "depends": [],
  282. "id": 2,
  283. "milestone": None,
  284. "priority": None,
  285. "private": True,
  286. "status": "Open",
  287. "tags": [],
  288. "title": "Test issue",
  289. "user": {
  290. "fullname": "PY C",
  291. "name": "pingou"
  292. }
  293. },
  294. {
  295. "assignee": None,
  296. "blocks": [],
  297. "comments": [],
  298. "content": "This issue needs attention",
  299. "date_created": "1431414800",
  300. "closed_at": None,
  301. "depends": [],
  302. "id": 1,
  303. "milestone": None,
  304. "priority": None,
  305. "private": False,
  306. "status": "Open",
  307. "tags": [],
  308. "title": "test issue",
  309. "user": {
  310. "fullname": "PY C",
  311. "name": "pingou"
  312. }
  313. }
  314. ]
  315. }
  316. )
  317. # List closed issue
  318. output = self.app.get('/api/0/test/issues?status=Closed', headers=headers)
  319. self.assertEqual(output.status_code, 200)
  320. data = json.loads(output.get_data(as_text=True))
  321. self.assertDictEqual(
  322. data,
  323. {
  324. "args": {
  325. "assignee": None,
  326. "author": None,
  327. "status": "Closed",
  328. "tags": []
  329. },
  330. "total_issues": 0,
  331. "issues": []
  332. }
  333. )
  334. # List closed issue
  335. output = self.app.get('/api/0/test/issues?status=Invalid', headers=headers)
  336. self.assertEqual(output.status_code, 200)
  337. data = json.loads(output.get_data(as_text=True))
  338. self.assertDictEqual(
  339. data,
  340. {
  341. "args": {
  342. "assignee": None,
  343. "author": None,
  344. "status": "Invalid",
  345. "tags": []
  346. },
  347. "total_issues": 0,
  348. "issues": []
  349. }
  350. )
  351. # List all issues
  352. output = self.app.get('/api/0/test/issues?status=All', headers=headers)
  353. self.assertEqual(output.status_code, 200)
  354. data = json.loads(output.get_data(as_text=True))
  355. data['issues'][0]['date_created'] = '1431414800'
  356. data['issues'][1]['date_created'] = '1431414800'
  357. self.assertDictEqual(
  358. data,
  359. {
  360. "args": {
  361. "assignee": None,
  362. "author": None,
  363. "status": "All",
  364. "tags": []
  365. },
  366. "total_issues": 2,
  367. "issues": [
  368. {
  369. "assignee": None,
  370. "blocks": [],
  371. "comments": [],
  372. "content": "We should work on this",
  373. "date_created": "1431414800",
  374. "closed_at": None,
  375. "depends": [],
  376. "id": 2,
  377. "milestone": None,
  378. "priority": None,
  379. "private": True,
  380. "status": "Open",
  381. "tags": [],
  382. "title": "Test issue",
  383. "user": {
  384. "fullname": "PY C",
  385. "name": "pingou"
  386. }
  387. },
  388. {
  389. "assignee": None,
  390. "blocks": [],
  391. "comments": [],
  392. "content": "This issue needs attention",
  393. "date_created": "1431414800",
  394. "closed_at": None,
  395. "depends": [],
  396. "id": 1,
  397. "milestone": None,
  398. "priority": None,
  399. "private": False,
  400. "status": "Open",
  401. "tags": [],
  402. "title": "test issue",
  403. "user": {
  404. "fullname": "PY C",
  405. "name": "pingou"
  406. }
  407. }
  408. ],
  409. }
  410. )
  411. def test_api_view_issue(self):
  412. """ Test the api_view_issue method of the flask api. """
  413. self.test_api_new_issue()
  414. # Invalid repo
  415. output = self.app.get('/api/0/foo/issue/1')
  416. self.assertEqual(output.status_code, 404)
  417. data = json.loads(output.get_data(as_text=True))
  418. self.assertDictEqual(
  419. data,
  420. {
  421. "error": "Project not found",
  422. "error_code": "ENOPROJECT",
  423. }
  424. )
  425. # Invalid issue for this repo
  426. output = self.app.get('/api/0/test2/issue/1')
  427. self.assertEqual(output.status_code, 404)
  428. data = json.loads(output.get_data(as_text=True))
  429. self.assertDictEqual(
  430. data,
  431. {
  432. "error": "Issue not found",
  433. "error_code": "ENOISSUE",
  434. }
  435. )
  436. # Valid issue
  437. output = self.app.get('/api/0/test/issue/1')
  438. self.assertEqual(output.status_code, 200)
  439. data = json.loads(output.get_data(as_text=True))
  440. data['date_created'] = '1431414800'
  441. self.assertDictEqual(
  442. data,
  443. {
  444. "assignee": None,
  445. "blocks": [],
  446. "comments": [],
  447. "content": "This issue needs attention",
  448. "date_created": "1431414800",
  449. "closed_at": None,
  450. "depends": [],
  451. "id": 1,
  452. "milestone": None,
  453. "priority": None,
  454. "private": False,
  455. "status": "Open",
  456. "tags": [],
  457. "title": "test issue",
  458. "user": {
  459. "fullname": "PY C",
  460. "name": "pingou"
  461. }
  462. }
  463. )
  464. # Create private issue
  465. repo = pagure.lib.get_project(self.session, 'test')
  466. msg = pagure.lib.new_issue(
  467. session=self.session,
  468. repo=repo,
  469. title='Test issue',
  470. content='We should work on this',
  471. user='pingou',
  472. ticketfolder=None,
  473. private=True,
  474. issue_uid='aaabbbccc',
  475. )
  476. self.session.commit()
  477. self.assertEqual(msg.title, 'Test issue')
  478. # Access private issue un-authenticated
  479. output = self.app.get('/api/0/test/issue/2')
  480. self.assertEqual(output.status_code, 403)
  481. data = json.loads(output.get_data(as_text=True))
  482. self.assertDictEqual(
  483. data,
  484. {
  485. "error": "You are not allowed to view this issue",
  486. "error_code": "EISSUENOTALLOWED",
  487. }
  488. )
  489. headers = {'Authorization': 'token aaabbbccc'}
  490. # Access private issue authenticated but non-existing token
  491. output = self.app.get('/api/0/test/issue/2', headers=headers)
  492. self.assertEqual(output.status_code, 401)
  493. data = json.loads(output.get_data(as_text=True))
  494. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  495. data['error_code'])
  496. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  497. # Create a new token for another user
  498. item = pagure.lib.model.Token(
  499. id='bar_token',
  500. user_id=2,
  501. project_id=1,
  502. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  503. days=30)
  504. )
  505. self.session.add(item)
  506. headers = {'Authorization': 'token bar_token'}
  507. # Access private issue authenticated but wrong token
  508. output = self.app.get('/api/0/test/issue/2', headers=headers)
  509. self.assertEqual(output.status_code, 403)
  510. data = json.loads(output.get_data(as_text=True))
  511. self.assertDictEqual(
  512. data,
  513. {
  514. "error": "You are not allowed to view this issue",
  515. "error_code": "EISSUENOTALLOWED",
  516. }
  517. )
  518. headers = {'Authorization': 'token aaabbbcccddd'}
  519. # Access private issue authenticated correctly
  520. output = self.app.get('/api/0/test/issue/2', headers=headers)
  521. self.assertEqual(output.status_code, 200)
  522. data = json.loads(output.get_data(as_text=True))
  523. data['date_created'] = '1431414800'
  524. self.assertDictEqual(
  525. data,
  526. {
  527. "assignee": None,
  528. "blocks": [],
  529. "comments": [],
  530. "content": "We should work on this",
  531. "date_created": "1431414800",
  532. "closed_at": None,
  533. "depends": [],
  534. "id": 2,
  535. "milestone": None,
  536. "priority": None,
  537. "private": True,
  538. "status": "Open",
  539. "tags": [],
  540. "title": "Test issue",
  541. "user": {
  542. "fullname": "PY C",
  543. "name": "pingou"
  544. }
  545. }
  546. )
  547. # Access private issue authenticated correctly using the issue's uid
  548. output = self.app.get('/api/0/test/issue/aaabbbccc', headers=headers)
  549. self.assertEqual(output.status_code, 200)
  550. data = json.loads(output.get_data(as_text=True))
  551. data['date_created'] = '1431414800'
  552. self.assertDictEqual(
  553. data,
  554. {
  555. "assignee": None,
  556. "blocks": [],
  557. "comments": [],
  558. "content": "We should work on this",
  559. "date_created": "1431414800",
  560. "closed_at": None,
  561. "depends": [],
  562. "id": 2,
  563. "milestone": None,
  564. "priority": None,
  565. "private": True,
  566. "status": "Open",
  567. "tags": [],
  568. "title": "Test issue",
  569. "user": {
  570. "fullname": "PY C",
  571. "name": "pingou"
  572. }
  573. }
  574. )
  575. def test_api_change_status_issue(self):
  576. """ Test the api_change_status_issue method of the flask api. """
  577. tests.create_projects(self.session)
  578. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  579. tests.create_tokens(self.session)
  580. tests.create_tokens_acl(self.session)
  581. headers = {'Authorization': 'token aaabbbcccddd'}
  582. # Invalid project
  583. output = self.app.post('/api/0/foo/issue/1/status', headers=headers)
  584. self.assertEqual(output.status_code, 404)
  585. data = json.loads(output.get_data(as_text=True))
  586. self.assertDictEqual(
  587. data,
  588. {
  589. "error": "Project not found",
  590. "error_code": "ENOPROJECT",
  591. }
  592. )
  593. # Valid token, wrong project
  594. output = self.app.post('/api/0/test2/issue/1/status', headers=headers)
  595. self.assertEqual(output.status_code, 401)
  596. data = json.loads(output.get_data(as_text=True))
  597. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  598. data['error_code'])
  599. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  600. # No input
  601. output = self.app.post('/api/0/test/issue/1/status', headers=headers)
  602. self.assertEqual(output.status_code, 404)
  603. data = json.loads(output.get_data(as_text=True))
  604. self.assertDictEqual(
  605. data,
  606. {
  607. "error": "Issue not found",
  608. "error_code": "ENOISSUE",
  609. }
  610. )
  611. # Create normal issue
  612. repo = pagure.lib.get_project(self.session, 'test')
  613. msg = pagure.lib.new_issue(
  614. session=self.session,
  615. repo=repo,
  616. title='Test issue #1',
  617. content='We should work on this',
  618. user='pingou',
  619. ticketfolder=None,
  620. private=False,
  621. )
  622. self.session.commit()
  623. self.assertEqual(msg.title, 'Test issue #1')
  624. # Create another project
  625. item = pagure.lib.model.Project(
  626. user_id=2, # pingou
  627. name='foo',
  628. description='test project #3',
  629. hook_token='aaabbbdddeee',
  630. )
  631. self.session.add(item)
  632. self.session.commit()
  633. # Create a token for pingou for this project
  634. item = pagure.lib.model.Token(
  635. id='pingou_foo',
  636. user_id=1,
  637. project_id=3,
  638. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  639. days=30)
  640. )
  641. self.session.add(item)
  642. self.session.commit()
  643. # Give `change_status_issue` to this token
  644. item = pagure.lib.model.TokenAcl(
  645. token_id='pingou_foo',
  646. acl_id=1,
  647. )
  648. self.session.add(item)
  649. self.session.commit()
  650. repo = pagure.lib.get_project(self.session, 'foo')
  651. # Create private issue
  652. msg = pagure.lib.new_issue(
  653. session=self.session,
  654. repo=repo,
  655. title='Test issue',
  656. content='We should work on this',
  657. user='foo',
  658. ticketfolder=None,
  659. private=True,
  660. )
  661. self.session.commit()
  662. self.assertEqual(msg.title, 'Test issue')
  663. # Check status before
  664. repo = pagure.lib.get_project(self.session, 'test')
  665. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  666. self.assertEqual(issue.status, 'Open')
  667. data = {
  668. 'title': 'test issue',
  669. }
  670. # Incomplete request
  671. output = self.app.post(
  672. '/api/0/test/issue/1/status', data=data, headers=headers)
  673. self.assertEqual(output.status_code, 400)
  674. data = json.loads(output.get_data(as_text=True))
  675. self.assertDictEqual(
  676. data,
  677. {
  678. "error": "Invalid or incomplete input submited",
  679. "error_code": "EINVALIDREQ",
  680. }
  681. )
  682. # No change
  683. repo = pagure.lib.get_project(self.session, 'test')
  684. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  685. self.assertEqual(issue.status, 'Open')
  686. data = {
  687. 'status': 'Open',
  688. }
  689. # Valid request but no change
  690. output = self.app.post(
  691. '/api/0/test/issue/1/status', data=data, headers=headers)
  692. self.assertEqual(output.status_code, 200)
  693. data = json.loads(output.get_data(as_text=True))
  694. self.assertDictEqual(
  695. data,
  696. {'message': 'No changes'}
  697. )
  698. # No change
  699. repo = pagure.lib.get_project(self.session, 'test')
  700. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  701. self.assertEqual(issue.status, 'Open')
  702. data = {
  703. 'status': 'Fixed',
  704. }
  705. # Valid request
  706. output = self.app.post(
  707. '/api/0/test/issue/1/status', data=data, headers=headers)
  708. self.assertEqual(output.status_code, 200)
  709. data = json.loads(output.get_data(as_text=True))
  710. self.assertDictEqual(
  711. data,
  712. {'message': 'Successfully edited issue #1'}
  713. )
  714. headers = {'Authorization': 'token pingou_foo'}
  715. # Un-authorized issue
  716. output = self.app.post(
  717. '/api/0/foo/issue/1/status', data=data, headers=headers)
  718. self.assertEqual(output.status_code, 401)
  719. data = json.loads(output.get_data(as_text=True))
  720. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  721. data['error_code'])
  722. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  723. @patch('pagure.lib.git.update_git')
  724. @patch('pagure.lib.notify.send_email')
  725. def test_api_comment_issue(self, p_send_email, p_ugt):
  726. """ Test the api_comment_issue method of the flask api. """
  727. p_send_email.return_value = True
  728. p_ugt.return_value = True
  729. tests.create_projects(self.session)
  730. tests.create_tokens(self.session)
  731. tests.create_tokens_acl(self.session)
  732. headers = {'Authorization': 'token aaabbbcccddd'}
  733. # Invalid project
  734. output = self.app.post('/api/0/foo/issue/1/comment', headers=headers)
  735. self.assertEqual(output.status_code, 404)
  736. data = json.loads(output.get_data(as_text=True))
  737. self.assertDictEqual(
  738. data,
  739. {
  740. "error": "Project not found",
  741. "error_code": "ENOPROJECT",
  742. }
  743. )
  744. # Valid token, wrong project
  745. output = self.app.post('/api/0/test2/issue/1/comment', headers=headers)
  746. self.assertEqual(output.status_code, 401)
  747. data = json.loads(output.get_data(as_text=True))
  748. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  749. data['error_code'])
  750. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  751. # No input
  752. output = self.app.post('/api/0/test/issue/1/comment', headers=headers)
  753. self.assertEqual(output.status_code, 404)
  754. data = json.loads(output.get_data(as_text=True))
  755. self.assertDictEqual(
  756. data,
  757. {
  758. "error": "Issue not found",
  759. "error_code": "ENOISSUE",
  760. }
  761. )
  762. # Create normal issue
  763. repo = pagure.lib.get_project(self.session, 'test')
  764. msg = pagure.lib.new_issue(
  765. session=self.session,
  766. repo=repo,
  767. title='Test issue #1',
  768. content='We should work on this',
  769. user='pingou',
  770. ticketfolder=None,
  771. private=False,
  772. issue_uid='aaabbbccc#1',
  773. )
  774. self.session.commit()
  775. self.assertEqual(msg.title, 'Test issue #1')
  776. # Check comments before
  777. repo = pagure.lib.get_project(self.session, 'test')
  778. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  779. self.assertEqual(len(issue.comments), 0)
  780. data = {
  781. 'title': 'test issue',
  782. }
  783. # Incomplete request
  784. output = self.app.post(
  785. '/api/0/test/issue/1/comment', data=data, headers=headers)
  786. self.assertEqual(output.status_code, 400)
  787. data = json.loads(output.get_data(as_text=True))
  788. self.assertDictEqual(
  789. data,
  790. {
  791. "error": "Invalid or incomplete input submited",
  792. "error_code": "EINVALIDREQ",
  793. }
  794. )
  795. # No change
  796. repo = pagure.lib.get_project(self.session, 'test')
  797. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  798. self.assertEqual(issue.status, 'Open')
  799. data = {
  800. 'comment': 'This is a very interesting question',
  801. }
  802. # Valid request
  803. output = self.app.post(
  804. '/api/0/test/issue/1/comment', data=data, headers=headers)
  805. self.assertEqual(output.status_code, 200)
  806. data = json.loads(output.get_data(as_text=True))
  807. self.assertDictEqual(
  808. data,
  809. {'message': 'Comment added'}
  810. )
  811. # One comment added
  812. repo = pagure.lib.get_project(self.session, 'test')
  813. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  814. self.assertEqual(len(issue.comments), 1)
  815. # Create another project
  816. item = pagure.lib.model.Project(
  817. user_id=2, # foo
  818. name='foo',
  819. description='test project #3',
  820. hook_token='aaabbbdddeee',
  821. )
  822. self.session.add(item)
  823. self.session.commit()
  824. # Create a token for pingou for this project
  825. item = pagure.lib.model.Token(
  826. id='pingou_foo',
  827. user_id=1,
  828. project_id=3,
  829. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  830. days=30)
  831. )
  832. self.session.add(item)
  833. self.session.commit()
  834. # Give `issue_change_status` to this token when `issue_comment`
  835. # is required
  836. item = pagure.lib.model.TokenAcl(
  837. token_id='pingou_foo',
  838. acl_id=2,
  839. )
  840. self.session.add(item)
  841. self.session.commit()
  842. repo = pagure.lib.get_project(self.session, 'foo')
  843. # Create private issue
  844. msg = pagure.lib.new_issue(
  845. session=self.session,
  846. repo=repo,
  847. title='Test issue',
  848. content='We should work on this',
  849. user='foo',
  850. ticketfolder=None,
  851. private=True,
  852. issue_uid='aaabbbccc#2',
  853. )
  854. self.session.commit()
  855. self.assertEqual(msg.title, 'Test issue')
  856. # Check before
  857. repo = pagure.lib.get_project(self.session, 'foo')
  858. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  859. self.assertEqual(len(issue.comments), 0)
  860. data = {
  861. 'comment': 'This is a very interesting question',
  862. }
  863. headers = {'Authorization': 'token pingou_foo'}
  864. # Valid request but un-authorized
  865. output = self.app.post(
  866. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  867. self.assertEqual(output.status_code, 401)
  868. data = json.loads(output.get_data(as_text=True))
  869. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  870. data['error_code'])
  871. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  872. # No comment added
  873. repo = pagure.lib.get_project(self.session, 'foo')
  874. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  875. self.assertEqual(len(issue.comments), 0)
  876. # Create token for user foo
  877. item = pagure.lib.model.Token(
  878. id='foo_token2',
  879. user_id=2,
  880. project_id=3,
  881. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30)
  882. )
  883. self.session.add(item)
  884. self.session.commit()
  885. tests.create_tokens_acl(self.session, token_id='foo_token2')
  886. data = {
  887. 'comment': 'This is a very interesting question',
  888. }
  889. headers = {'Authorization': 'token foo_token2'}
  890. # Valid request and authorized
  891. output = self.app.post(
  892. '/api/0/foo/issue/1/comment', data=data, headers=headers)
  893. self.assertEqual(output.status_code, 200)
  894. data = json.loads(output.get_data(as_text=True))
  895. self.assertDictEqual(
  896. data,
  897. {'message': 'Comment added'}
  898. )
  899. @patch('pagure.lib.git.update_git')
  900. @patch('pagure.lib.notify.send_email')
  901. def test_api_view_issue_comment(self, p_send_email, p_ugt):
  902. """ Test the api_view_issue_comment endpoint. """
  903. p_send_email.return_value = True
  904. p_ugt.return_value = True
  905. self.test_api_comment_issue()
  906. # View a comment that does not exist
  907. output = self.app.get('/api/0/foo/issue/100/comment/2')
  908. self.assertEqual(output.status_code, 404)
  909. # Issue exists but not the comment
  910. output = self.app.get('/api/0/test/issue/1/comment/2')
  911. self.assertEqual(output.status_code, 404)
  912. # Issue and comment exists
  913. output = self.app.get('/api/0/test/issue/1/comment/1')
  914. self.assertEqual(output.status_code, 200)
  915. data = json.loads(output.get_data(as_text=True))
  916. data['date_created'] = '1435821770'
  917. data["comment_date"] = "2015-07-02 09:22"
  918. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  919. self.assertDictEqual(
  920. data,
  921. {
  922. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  923. "comment": "This is a very interesting question",
  924. "comment_date": "2015-07-02 09:22",
  925. "date_created": "1435821770",
  926. "edited_on": None,
  927. "editor": None,
  928. "notification": False,
  929. "id": 1,
  930. "parent": None,
  931. "user": {
  932. "fullname": "PY C",
  933. "name": "pingou"
  934. }
  935. }
  936. )
  937. # Issue and comment exists, using UID
  938. output = self.app.get('/api/0/test/issue/aaabbbccc#1/comment/1')
  939. self.assertEqual(output.status_code, 200)
  940. data = json.loads(output.get_data(as_text=True))
  941. data['date_created'] = '1435821770'
  942. data["comment_date"] = "2015-07-02 09:22"
  943. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  944. self.assertDictEqual(
  945. data,
  946. {
  947. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  948. "comment": "This is a very interesting question",
  949. "comment_date": "2015-07-02 09:22",
  950. "date_created": "1435821770",
  951. "edited_on": None,
  952. "editor": None,
  953. "notification": False,
  954. "id": 1,
  955. "parent": None,
  956. "user": {
  957. "fullname": "PY C",
  958. "name": "pingou"
  959. }
  960. }
  961. )
  962. # Private issue
  963. output = self.app.get('/api/0/foo/issue/1/comment/2')
  964. self.assertEqual(output.status_code, 403)
  965. # Private issue - Auth - wrong token
  966. headers = {'Authorization': 'token pingou_foo'}
  967. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  968. self.assertEqual(output.status_code, 403)
  969. # Private issue - Auth - Invalid token
  970. headers = {'Authorization': 'token aaabbbcccddd'}
  971. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  972. self.assertEqual(output.status_code, 401)
  973. # Private issue - Auth - valid token - unknown comment
  974. headers = {'Authorization': 'token foo_token2'}
  975. output = self.app.get('/api/0/foo/issue/1/comment/3', headers=headers)
  976. self.assertEqual(output.status_code, 404)
  977. # Private issue - Auth - valid token - known comment
  978. headers = {'Authorization': 'token foo_token2'}
  979. output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers)
  980. self.assertEqual(output.status_code, 200)
  981. data = json.loads(output.get_data(as_text=True))
  982. data['date_created'] = '1435821770'
  983. data["comment_date"] = "2015-07-02 09:22"
  984. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  985. self.assertDictEqual(
  986. data,
  987. {
  988. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  989. "comment": "This is a very interesting question",
  990. "comment_date": "2015-07-02 09:22",
  991. "date_created": "1435821770",
  992. "edited_on": None,
  993. "editor": None,
  994. "notification": False,
  995. "id": 2,
  996. "parent": None,
  997. "user": {
  998. "fullname": "foo bar",
  999. "name": "foo"
  1000. }
  1001. }
  1002. )
  1003. @patch('pagure.lib.git.update_git')
  1004. @patch('pagure.lib.notify.send_email')
  1005. def test_api_assign_issue(self, p_send_email, p_ugt):
  1006. """ Test the api_assign_issue method of the flask api. """
  1007. p_send_email.return_value = True
  1008. p_ugt.return_value = True
  1009. tests.create_projects(self.session)
  1010. tests.create_tokens(self.session)
  1011. tests.create_tokens_acl(self.session)
  1012. headers = {'Authorization': 'token aaabbbcccddd'}
  1013. # Invalid project
  1014. output = self.app.post('/api/0/foo/issue/1/assign', headers=headers)
  1015. self.assertEqual(output.status_code, 404)
  1016. data = json.loads(output.get_data(as_text=True))
  1017. self.assertDictEqual(
  1018. data,
  1019. {
  1020. "error": "Project not found",
  1021. "error_code": "ENOPROJECT",
  1022. }
  1023. )
  1024. # Valid token, wrong project
  1025. output = self.app.post('/api/0/test2/issue/1/assign', headers=headers)
  1026. self.assertEqual(output.status_code, 401)
  1027. data = json.loads(output.get_data(as_text=True))
  1028. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  1029. data['error_code'])
  1030. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1031. # No input
  1032. output = self.app.post('/api/0/test/issue/1/assign', headers=headers)
  1033. self.assertEqual(output.status_code, 404)
  1034. data = json.loads(output.get_data(as_text=True))
  1035. self.assertDictEqual(
  1036. data,
  1037. {
  1038. "error": "Issue not found",
  1039. "error_code": "ENOISSUE",
  1040. }
  1041. )
  1042. # Create normal issue
  1043. repo = pagure.lib.get_project(self.session, 'test')
  1044. msg = pagure.lib.new_issue(
  1045. session=self.session,
  1046. repo=repo,
  1047. title='Test issue #1',
  1048. content='We should work on this',
  1049. user='pingou',
  1050. ticketfolder=None,
  1051. private=False,
  1052. issue_uid='aaabbbccc#1',
  1053. )
  1054. self.session.commit()
  1055. self.assertEqual(msg.title, 'Test issue #1')
  1056. # Check comments before
  1057. repo = pagure.lib.get_project(self.session, 'test')
  1058. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1059. self.assertEqual(len(issue.comments), 0)
  1060. data = {
  1061. 'title': 'test issue',
  1062. }
  1063. # Incomplete request
  1064. output = self.app.post(
  1065. '/api/0/test/issue/1/assign', data=data, headers=headers)
  1066. self.assertEqual(output.status_code, 400)
  1067. data = json.loads(output.get_data(as_text=True))
  1068. self.assertDictEqual(
  1069. data,
  1070. {
  1071. "error": "Invalid or incomplete input submited",
  1072. "error_code": "EINVALIDREQ",
  1073. }
  1074. )
  1075. # No change
  1076. repo = pagure.lib.get_project(self.session, 'test')
  1077. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1078. self.assertEqual(issue.status, 'Open')
  1079. data = {
  1080. 'assignee': 'pingou',
  1081. }
  1082. # Valid request
  1083. output = self.app.post(
  1084. '/api/0/test/issue/1/assign', data=data, headers=headers)
  1085. self.assertEqual(output.status_code, 200)
  1086. data = json.loads(output.get_data(as_text=True))
  1087. self.assertDictEqual(
  1088. data,
  1089. {'message': 'Issue assigned'}
  1090. )
  1091. # One comment added
  1092. repo = pagure.lib.get_project(self.session, 'test')
  1093. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1094. self.assertEqual(issue.assignee.user, 'pingou')
  1095. # Create another project
  1096. item = pagure.lib.model.Project(
  1097. user_id=2, # foo
  1098. name='foo',
  1099. description='test project #3',
  1100. hook_token='aaabbbdddeee',
  1101. )
  1102. self.session.add(item)
  1103. self.session.commit()
  1104. # Create a token for pingou for this project
  1105. item = pagure.lib.model.Token(
  1106. id='pingou_foo',
  1107. user_id=1,
  1108. project_id=3,
  1109. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1110. days=30)
  1111. )
  1112. self.session.add(item)
  1113. self.session.commit()
  1114. # Give `issue_change_status` to this token when `issue_comment`
  1115. # is required
  1116. item = pagure.lib.model.TokenAcl(
  1117. token_id='pingou_foo',
  1118. acl_id=5,
  1119. )
  1120. self.session.add(item)
  1121. self.session.commit()
  1122. repo = pagure.lib.get_project(self.session, 'foo')
  1123. # Create private issue
  1124. msg = pagure.lib.new_issue(
  1125. session=self.session,
  1126. repo=repo,
  1127. title='Test issue',
  1128. content='We should work on this',
  1129. user='foo',
  1130. ticketfolder=None,
  1131. private=True,
  1132. issue_uid='aaabbbccc#2',
  1133. )
  1134. self.session.commit()
  1135. self.assertEqual(msg.title, 'Test issue')
  1136. # Check before
  1137. repo = pagure.lib.get_project(self.session, 'foo')
  1138. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1139. self.assertEqual(len(issue.comments), 0)
  1140. data = {
  1141. 'assignee': 'pingou',
  1142. }
  1143. headers = {'Authorization': 'token pingou_foo'}
  1144. # Valid request but un-authorized
  1145. output = self.app.post(
  1146. '/api/0/foo/issue/1/assign', data=data, headers=headers)
  1147. self.assertEqual(output.status_code, 401)
  1148. data = json.loads(output.get_data(as_text=True))
  1149. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name,
  1150. data['error_code'])
  1151. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1152. # No comment added
  1153. repo = pagure.lib.get_project(self.session, 'foo')
  1154. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1155. self.assertEqual(len(issue.comments), 0)
  1156. # Create token for user foo
  1157. item = pagure.lib.model.Token(
  1158. id='foo_token2',
  1159. user_id=2,
  1160. project_id=3,
  1161. expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30)
  1162. )
  1163. self.session.add(item)
  1164. self.session.commit()
  1165. tests.create_tokens_acl(self.session, token_id='foo_token2')
  1166. data = {
  1167. 'assignee': 'pingou',
  1168. }
  1169. headers = {'Authorization': 'token foo_token2'}
  1170. # Valid request and authorized
  1171. output = self.app.post(
  1172. '/api/0/foo/issue/1/assign', data=data, headers=headers)
  1173. self.assertEqual(output.status_code, 200)
  1174. data = json.loads(output.get_data(as_text=True))
  1175. self.assertDictEqual(
  1176. data,
  1177. {'message': 'Issue assigned'}
  1178. )
  1179. if __name__ == '__main__':
  1180. SUITE = unittest.TestLoader().loadTestsFromTestCase(
  1181. PagureFlaskApiIssuetests)
  1182. unittest.TextTestRunner(verbosity=2).run(SUITE)