test_pagure_flask_api_ui_private_repo.py 119 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. __requires__ = ['SQLAlchemy >= 0.8']
  4. import pkg_resources
  5. import datetime
  6. import unittest
  7. import shutil
  8. import sys
  9. import tempfile
  10. import os
  11. import json
  12. import pygit2
  13. from mock import patch, MagicMock
  14. sys.path.insert(0, os.path.join(os.path.dirname(
  15. os.path.abspath(__file__)), '..'))
  16. import pagure.lib
  17. import tests
  18. from pagure.lib.repo import PagureRepo
  19. FULL_ISSUE_LIST = [
  20. {
  21. "assignee": None,
  22. "blocks": [],
  23. "close_status": None,
  24. "closed_at": None,
  25. "comments": [],
  26. "content": "We should work on this",
  27. "custom_fields": [],
  28. "date_created": "1431414800",
  29. "depends": [],
  30. "id": 8,
  31. "last_updated": "1431414800",
  32. "milestone": None,
  33. "priority": None,
  34. "private": True,
  35. "status": "Open",
  36. "tags": [],
  37. "title": "Test issue",
  38. "user": {
  39. "fullname": "PY C",
  40. "name": "pingou"
  41. }
  42. },
  43. {
  44. "assignee": None,
  45. "blocks": [],
  46. "close_status": None,
  47. "closed_at": None,
  48. "comments": [],
  49. "content": "This issue needs attention",
  50. "custom_fields": [],
  51. "date_created": "1431414800",
  52. "depends": [],
  53. "id": 7,
  54. "last_updated": "1431414800",
  55. "milestone": None,
  56. "priority": None,
  57. "private": True,
  58. "status": "Open",
  59. "tags": [],
  60. "title": "test issue",
  61. "user": {
  62. "fullname": "PY C",
  63. "name": "pingou"
  64. }
  65. },
  66. {
  67. "assignee": None,
  68. "blocks": [],
  69. "close_status": None,
  70. "closed_at": None,
  71. "comments": [],
  72. "content": "This issue needs attention",
  73. "custom_fields": [],
  74. "date_created": "1431414800",
  75. "depends": [],
  76. "id": 6,
  77. "last_updated": "1431414800",
  78. "milestone": None,
  79. "priority": None,
  80. "private": True,
  81. "status": "Open",
  82. "tags": [],
  83. "title": "test issue",
  84. "user": {
  85. "fullname": "PY C",
  86. "name": "pingou"
  87. }
  88. },
  89. {
  90. "assignee": None,
  91. "blocks": [],
  92. "close_status": None,
  93. "closed_at": None,
  94. "comments": [],
  95. "content": "This issue needs attention",
  96. "custom_fields": [],
  97. "date_created": "1431414800",
  98. "depends": [],
  99. "id": 5,
  100. "last_updated": "1431414800",
  101. "milestone": None,
  102. "priority": None,
  103. "private": False,
  104. "status": "Open",
  105. "tags": [],
  106. "title": "test issue",
  107. "user": {
  108. "fullname": "PY C",
  109. "name": "pingou"
  110. }
  111. },
  112. {
  113. "assignee": None,
  114. "blocks": [],
  115. "close_status": None,
  116. "closed_at": None,
  117. "comments": [],
  118. "content": "This issue needs attention",
  119. "custom_fields": [],
  120. "date_created": "1431414800",
  121. "depends": [],
  122. "id": 4,
  123. "last_updated": "1431414800",
  124. "milestone": None,
  125. "priority": None,
  126. "private": False,
  127. "status": "Open",
  128. "tags": [],
  129. "title": "test issue",
  130. "user": {
  131. "fullname": "PY C",
  132. "name": "pingou"
  133. }
  134. },
  135. {
  136. "assignee": None,
  137. "blocks": [],
  138. "close_status": None,
  139. "closed_at": None,
  140. "comments": [],
  141. "content": "This issue needs attention",
  142. "custom_fields": [],
  143. "date_created": "1431414800",
  144. "depends": [],
  145. "id": 3,
  146. "last_updated": "1431414800",
  147. "milestone": None,
  148. "priority": None,
  149. "private": False,
  150. "status": "Open",
  151. "tags": [],
  152. "title": "test issue",
  153. "user": {
  154. "fullname": "PY C",
  155. "name": "pingou"
  156. }
  157. },
  158. {
  159. "assignee": None,
  160. "blocks": [],
  161. "close_status": None,
  162. "closed_at": None,
  163. "comments": [],
  164. "content": "This issue needs attention",
  165. "custom_fields": [],
  166. "date_created": "1431414800",
  167. "depends": [],
  168. "id": 2,
  169. "last_updated": "1431414800",
  170. "milestone": None,
  171. "priority": None,
  172. "private": False,
  173. "status": "Open",
  174. "tags": [],
  175. "title": "test issue",
  176. "user": {
  177. "fullname": "PY C",
  178. "name": "pingou"
  179. }
  180. },
  181. {
  182. "assignee": None,
  183. "blocks": [],
  184. "close_status": None,
  185. "closed_at": None,
  186. "comments": [],
  187. "content": "This issue needs attention",
  188. "custom_fields": [],
  189. "date_created": "1431414800",
  190. "depends": [],
  191. "id": 1,
  192. "last_updated": "1431414800",
  193. "milestone": None,
  194. "priority": None,
  195. "private": False,
  196. "status": "Open",
  197. "tags": [],
  198. "title": "test issue",
  199. "user": {
  200. "fullname": "PY C",
  201. "name": "pingou"
  202. }
  203. }
  204. ]
  205. class PagurePrivateRepotest(tests.Modeltests):
  206. """ Tests for private repo in pagure """
  207. maxDiff = None
  208. def setUp(self):
  209. """ Set up the environnment, ran before every tests. """
  210. super(PagurePrivateRepotest, self).setUp()
  211. pagure.config.config['TESTING'] = True
  212. pagure.config.config['DATAGREPPER_URL'] = None
  213. pagure.config.config['PRIVATE_PROJECTS'] = True
  214. pagure.config.config['VIRUS_SCAN_ATTACHMENTS'] = False
  215. def set_up_git_repo(
  216. self, new_project=None, branch_from='feature', mtype='FF'):
  217. """ Set up the git repo and create the corresponding PullRequest
  218. object.
  219. """
  220. # Create a git repo to play with
  221. gitrepo = os.path.join(self.path, 'repos', 'pmc.git')
  222. repo = pygit2.init_repository(gitrepo, bare=True)
  223. newpath = tempfile.mkdtemp(prefix='pagure-private-test')
  224. repopath = os.path.join(newpath, 'test')
  225. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  226. # Create a file in that git repo
  227. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  228. stream.write('foo\n bar')
  229. clone_repo.index.add('sources')
  230. clone_repo.index.write()
  231. # Commits the files added
  232. tree = clone_repo.index.write_tree()
  233. author = pygit2.Signature(
  234. 'Alice Author', 'alice@authors.tld')
  235. committer = pygit2.Signature(
  236. 'Cecil Committer', 'cecil@committers.tld')
  237. clone_repo.create_commit(
  238. 'refs/heads/master', # the name of the reference to update
  239. author,
  240. committer,
  241. 'Add sources file for testing',
  242. # binary string representing the tree object ID
  243. tree,
  244. # list of binary strings representing parents of the new commit
  245. []
  246. )
  247. refname = 'refs/heads/master:refs/heads/master'
  248. ori_remote = clone_repo.remotes[0]
  249. PagureRepo.push(ori_remote, refname)
  250. first_commit = repo.revparse_single('HEAD')
  251. if mtype == 'merge':
  252. with open(os.path.join(repopath, '.gitignore'), 'w') as stream:
  253. stream.write('*~')
  254. clone_repo.index.add('.gitignore')
  255. clone_repo.index.write()
  256. # Commits the files added
  257. tree = clone_repo.index.write_tree()
  258. author = pygit2.Signature(
  259. 'Alice Äuthòr', 'alice@äuthòrs.tld')
  260. committer = pygit2.Signature(
  261. 'Cecil Cõmmîttër', 'cecil@cõmmîttërs.tld')
  262. clone_repo.create_commit(
  263. 'refs/heads/master',
  264. author,
  265. committer,
  266. 'Add .gitignore file for testing',
  267. # binary string representing the tree object ID
  268. tree,
  269. # list of binary strings representing parents of the new commit
  270. [first_commit.oid.hex]
  271. )
  272. refname = 'refs/heads/master:refs/heads/master'
  273. ori_remote = clone_repo.remotes[0]
  274. PagureRepo.push(ori_remote, refname)
  275. if mtype == 'conflicts':
  276. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  277. stream.write('foo\n bar\nbaz')
  278. clone_repo.index.add('sources')
  279. clone_repo.index.write()
  280. # Commits the files added
  281. tree = clone_repo.index.write_tree()
  282. author = pygit2.Signature(
  283. 'Alice Author', 'alice@authors.tld')
  284. committer = pygit2.Signature(
  285. 'Cecil Committer', 'cecil@committers.tld')
  286. clone_repo.create_commit(
  287. 'refs/heads/master',
  288. author,
  289. committer,
  290. 'Add sources conflicting',
  291. # binary string representing the tree object ID
  292. tree,
  293. # list of binary strings representing parents of the new commit
  294. [first_commit.oid.hex]
  295. )
  296. refname = 'refs/heads/master:refs/heads/master'
  297. ori_remote = clone_repo.remotes[0]
  298. PagureRepo.push(ori_remote, refname)
  299. # Set the second repo
  300. new_gitrepo = repopath
  301. if new_project:
  302. # Create a new git repo to play with
  303. new_gitrepo = os.path.join(newpath, new_project.fullname)
  304. if not os.path.exists(new_gitrepo):
  305. os.makedirs(new_gitrepo)
  306. new_repo = pygit2.clone_repository(gitrepo, new_gitrepo)
  307. repo = pygit2.Repository(new_gitrepo)
  308. if mtype != 'nochanges':
  309. # Edit the sources file again
  310. with open(os.path.join(new_gitrepo, 'sources'), 'w') as stream:
  311. stream.write('foo\n bar\nbaz\n boose')
  312. repo.index.add('sources')
  313. repo.index.write()
  314. # Commits the files added
  315. tree = repo.index.write_tree()
  316. author = pygit2.Signature(
  317. 'Alice Author', 'alice@authors.tld')
  318. committer = pygit2.Signature(
  319. 'Cecil Committer', 'cecil@committers.tld')
  320. repo.create_commit(
  321. 'refs/heads/%s' % branch_from,
  322. author,
  323. committer,
  324. 'A commit on branch %s' % branch_from,
  325. tree,
  326. [first_commit.oid.hex]
  327. )
  328. refname = 'refs/heads/%s' % (branch_from)
  329. ori_remote = repo.remotes[0]
  330. PagureRepo.push(ori_remote, refname)
  331. # Create a PR for these changes
  332. project = pagure.lib._get_project(self.session, 'pmc')
  333. req = pagure.lib.new_pull_request(
  334. session=self.session,
  335. repo_from=project,
  336. branch_from=branch_from,
  337. repo_to=project,
  338. branch_to='master',
  339. title='PR from the %s branch' % branch_from,
  340. user='pingou',
  341. )
  342. self.session.commit()
  343. self.assertEqual(req.id, 1)
  344. self.assertEqual(req.title, 'PR from the %s branch' % branch_from)
  345. shutil.rmtree(newpath)
  346. def test_index(self):
  347. """ Test the index endpoint. """
  348. output = self.app.get('/')
  349. self.assertEqual(output.status_code, 200)
  350. self.assertIn(
  351. '<h3 class="m-0 font-weight-bold">All Projects '
  352. '<span class="badge badge-secondary">0</span></h3>',
  353. output.get_data(as_text=True))
  354. # Add a private project
  355. item = pagure.lib.model.Project(
  356. user_id=2, # foo
  357. name='test3',
  358. description='test project description',
  359. hook_token='aaabbbeee',
  360. private=True,
  361. )
  362. self.session.add(item)
  363. # Add a public project
  364. item = pagure.lib.model.Project(
  365. user_id=2, # foo
  366. name='test4',
  367. description='test project description',
  368. hook_token='aaabbbeeeccceee',
  369. )
  370. self.session.add(item)
  371. self.session.commit()
  372. output = self.app.get('/?page=abc')
  373. self.assertEqual(output.status_code, 200)
  374. output_text = output.get_data(as_text=True)
  375. self.assertIn(
  376. '<h3 class="m-0 font-weight-bold">All Projects '
  377. '<span class="badge badge-secondary">1</span></h3>',
  378. output_text)
  379. user = tests.FakeUser(username='foo')
  380. with tests.user_set(self.app.application, user):
  381. output = self.app.get('/', follow_redirects=True)
  382. output_text = output.get_data(as_text=True)
  383. self.assertIn(
  384. '<h4 class="font-weight-bold mb-0">My Projects</h4>',
  385. output_text)
  386. self.assertIn('2 Projects</span>', output_text)
  387. self.assertNotIn(
  388. '<span class="d-none d-md-inline">Forks', output_text)
  389. self.assertEqual(
  390. output_text.count('<span class="d-none d-md-inline">Groups'), 0)
  391. def test_view_user(self):
  392. """ Test the view_user endpoint. """
  393. output = self.app.get('/user/foo?repopage=abc&forkpage=def')
  394. self.assertEqual(output.status_code, 200)
  395. output_text = output.get_data(as_text=True)
  396. self.assertIn(
  397. """<span>
  398. <i class="fa fa-fw text-muted fa-calendar-o fa-rotate-270"></i>
  399. <span class="d-none d-md-inline">Projects&nbsp;</span>
  400. </span>
  401. <div class="ml-auto">
  402. <span class="badge badge-secondary">
  403. 0
  404. </span>
  405. </div>""", output_text)
  406. self.assertIn(
  407. """<span>
  408. <i class="fa fa-fw text-muted fa-code-fork"></i>
  409. <span class="d-none d-md-inline">Forks&nbsp;</span>
  410. </span>
  411. <div class="ml-auto">
  412. <span class="badge badge-secondary">
  413. 0
  414. </span>
  415. </div>""", output_text)
  416. self.assertIn(
  417. """<span>
  418. <i class="fa fa-fw text-muted fa-users"></i>
  419. <span class="d-none d-md-inline">Groups&nbsp;</span>
  420. </span>
  421. <div class="ml-auto">
  422. <span class="badge badge-secondary">
  423. 0
  424. </span>
  425. </div>""", output_text)
  426. # Add a private project
  427. item = pagure.lib.model.Project(
  428. user_id=2, # foo
  429. name='test3',
  430. description='test project description',
  431. hook_token='aaabbbeee',
  432. private=True,
  433. )
  434. self.session.add(item)
  435. # Add a public project
  436. item = pagure.lib.model.Project(
  437. user_id=2, # foo
  438. name='test4',
  439. description='test project description',
  440. hook_token='aaabbbeeeccceee',
  441. )
  442. self.session.add(item)
  443. self.session.commit()
  444. self.gitrepos = tests.create_projects_git(
  445. pagure.config.config['GIT_FOLDER'])
  446. output = self.app.get('/user/foo')
  447. self.assertEqual(output.status_code, 200)
  448. output_text = output.get_data(as_text=True)
  449. self.assertIn(
  450. """<span>
  451. <i class="fa fa-fw text-muted fa-calendar-o fa-rotate-270"></i>
  452. <span class="d-none d-md-inline">Projects&nbsp;</span>
  453. </span>
  454. <div class="ml-auto">
  455. <span class="badge badge-secondary">
  456. 1
  457. </span>
  458. </div>""", output_text)
  459. self.assertIn(
  460. """<span>
  461. <i class="fa fa-fw text-muted fa-code-fork"></i>
  462. <span class="d-none d-md-inline">Forks&nbsp;</span>
  463. </span>
  464. <div class="ml-auto">
  465. <span class="badge badge-secondary">
  466. 0
  467. </span>
  468. </div>""", output_text)
  469. self.assertIn(
  470. """<span>
  471. <i class="fa fa-fw text-muted fa-users"></i>
  472. <span class="d-none d-md-inline">Groups&nbsp;</span>
  473. </span>
  474. <div class="ml-auto">
  475. <span class="badge badge-secondary">
  476. 0
  477. </span>
  478. </div>""", output_text)
  479. user = tests.FakeUser(username='foo')
  480. with tests.user_set(self.app.application, user):
  481. output = self.app.get('/user/foo')
  482. output_text = output.get_data(as_text=True)
  483. self.assertIn(
  484. """<span>
  485. <i class="fa fa-fw text-muted fa-calendar-o fa-rotate-270"></i>
  486. <span class="d-none d-md-inline">Projects&nbsp;</span>
  487. </span>
  488. <div class="ml-auto">
  489. <span class="badge badge-secondary">
  490. 1
  491. </span>
  492. </div>""", output_text)
  493. self.assertIn(
  494. """<span>
  495. <i class="fa fa-fw text-muted fa-code-fork"></i>
  496. <span class="d-none d-md-inline">Forks&nbsp;</span>
  497. </span>
  498. <div class="ml-auto">
  499. <span class="badge badge-secondary">
  500. 0
  501. </span>
  502. </div>""", output_text)
  503. self.assertIn(
  504. """<span>
  505. <i class="fa fa-fw text-muted fa-users"></i>
  506. <span class="d-none d-md-inline">Groups&nbsp;</span>
  507. </span>
  508. <div class="ml-auto">
  509. <span class="badge badge-secondary">
  510. 0
  511. </span>
  512. </div>""", output_text)
  513. user.username = 'pingou'
  514. with tests.user_set(self.app.application, user):
  515. output = self.app.get('/user/foo')
  516. output_text = output.get_data(as_text=True)
  517. self.assertIn(
  518. """<span>
  519. <i class="fa fa-fw text-muted fa-calendar-o fa-rotate-270"></i>
  520. <span class="d-none d-md-inline">Projects&nbsp;</span>
  521. </span>
  522. <div class="ml-auto">
  523. <span class="badge badge-secondary">
  524. 1
  525. </span>
  526. </div>""", output_text)
  527. self.assertIn(
  528. """<span>
  529. <i class="fa fa-fw text-muted fa-code-fork"></i>
  530. <span class="d-none d-md-inline">Forks&nbsp;</span>
  531. </span>
  532. <div class="ml-auto">
  533. <span class="badge badge-secondary">
  534. 0
  535. </span>
  536. </div>""", output_text)
  537. self.assertIn(
  538. """<span>
  539. <i class="fa fa-fw text-muted fa-users"></i>
  540. <span class="d-none d-md-inline">Groups&nbsp;</span>
  541. </span>
  542. <div class="ml-auto">
  543. <span class="badge badge-secondary">
  544. 0
  545. </span>
  546. </div>""", output_text)
  547. # Check pingou has 0 projects
  548. user.username = 'pingou'
  549. with tests.user_set(self.app.application, user):
  550. output = self.app.get('/', follow_redirects=True)
  551. output_text = output.get_data(as_text=True)
  552. self.assertIn(
  553. '<h4 class="font-weight-bold mb-0">My Projects</h4>',
  554. output_text)
  555. self.assertIn(
  556. '0 Projects</span>',
  557. output_text)
  558. self.assertNotIn(
  559. '<span class="d-none d-md-inline">Forks',
  560. output_text)
  561. self.assertEqual(
  562. output_text.count('<span class="d-none d-md-inline">Groups'), 0)
  563. repo = pagure.lib._get_project(self.session, 'test3')
  564. msg = pagure.lib.add_user_to_project(
  565. session=self.session,
  566. project=repo,
  567. new_user='pingou',
  568. user='foo',
  569. )
  570. self.session.commit()
  571. self.assertEqual(msg, 'User added')
  572. # New user added to private projects
  573. user.username = 'pingou'
  574. with tests.user_set(self.app.application, user):
  575. output = self.app.get('/', follow_redirects=True)
  576. output_text = output.get_data(as_text=True)
  577. self.assertIn(
  578. '<h4 class="font-weight-bold mb-0">My Projects</h4>',
  579. output_text)
  580. self.assertIn(
  581. '1 Projects</span>',
  582. output_text)
  583. self.assertNotIn(
  584. '<span class="d-none d-md-inline">Forks',
  585. output_text)
  586. self.assertEqual(
  587. output_text.count('<span class="d-none d-md-inline">Groups'), 0)
  588. @patch('pagure.decorators.admin_session_timedout')
  589. def test_private_settings_ui(self, ast):
  590. """ Test UI for private repo"""
  591. ast.return_value = False
  592. # Add private repo
  593. item = pagure.lib.model.Project(
  594. user_id=1, # pingou
  595. name='test4',
  596. description='test project description',
  597. hook_token='aaabbbeeeceee',
  598. private=True,
  599. )
  600. self.session.add(item)
  601. self.session.commit()
  602. # Add a git repo
  603. repo_path = os.path.join(
  604. pagure.config.config.get('GIT_FOLDER'), 'test4.git')
  605. if not os.path.exists(repo_path):
  606. os.makedirs(repo_path)
  607. pygit2.init_repository(repo_path)
  608. user = tests.FakeUser(username='pingou')
  609. with tests.user_set(self.app.application, user):
  610. tests.create_projects(self.session)
  611. tests.create_projects_git(pagure.config.config.get('GIT_FOLDER'))
  612. output = self.app.get('/test/settings')
  613. # Check for a public repo
  614. self.assertEqual(output.status_code, 200)
  615. self.assertNotIn(
  616. '<input type="checkbox" value="private" name="private"',
  617. output.get_data(as_text=True))
  618. output = self.app.get('/test4/settings')
  619. # Check for private repo
  620. self.assertEqual(output.status_code, 200)
  621. self.assertIn(
  622. '<input type="checkbox" value="private" name="private" checked="" />',
  623. output.get_data(as_text=True))
  624. # Check the new project form has 'private' checkbox
  625. output = self.app.get('/new')
  626. self.assertEqual(output.status_code, 200)
  627. self.assertIn(
  628. '<input id="private" name="private" type="checkbox" value="y">',
  629. output.get_data(as_text=True))
  630. @patch('pagure.decorators.admin_session_timedout')
  631. def test_private_settings_ui_update_privacy_false(self, ast):
  632. """ Test UI for private repo"""
  633. ast.return_value = False
  634. # Add private repo
  635. item = pagure.lib.model.Project(
  636. user_id=1, # pingou
  637. name='test4',
  638. description='test project description',
  639. hook_token='aaabbbeeeceee',
  640. private=True,
  641. )
  642. self.session.add(item)
  643. self.session.commit()
  644. # Add a git repo
  645. repo_path = os.path.join(
  646. pagure.config.config.get('GIT_FOLDER'), 'test4.git')
  647. pygit2.init_repository(repo_path)
  648. user = tests.FakeUser(username='pingou')
  649. with tests.user_set(self.app.application, user):
  650. # Check for private repo
  651. output = self.app.get('/test4/settings')
  652. self.assertEqual(output.status_code, 200)
  653. self.assertIn(
  654. '<input type="checkbox" value="private" name="private" checked="" />',
  655. output.get_data(as_text=True))
  656. self.session.commit()
  657. repo = pagure.lib._get_project(self.session, 'test4')
  658. self.assertTrue(repo.private)
  659. # Make the project public
  660. data = {
  661. 'description': 'test project description',
  662. 'private': False,
  663. 'csrf_token': self.get_csrf(),
  664. }
  665. output = self.app.post(
  666. '/test4/update', data=data, follow_redirects=True)
  667. self.assertEqual(output.status_code, 200)
  668. self.assertIn(
  669. 'Project updated',
  670. output.get_data(as_text=True))
  671. self.assertNotIn(
  672. '<input type="checkbox" value="private" name="private" checked="" />',
  673. output.get_data(as_text=True))
  674. self.session.commit()
  675. repo = pagure.lib._get_project(self.session, 'test4')
  676. self.assertFalse(repo.private)
  677. @patch('pagure.decorators.admin_session_timedout')
  678. def test_private_settings_ui_update_privacy_true(self, ast):
  679. """ Test UI for private repo"""
  680. ast.return_value = False
  681. # Add private repo
  682. item = pagure.lib.model.Project(
  683. user_id=1, # pingou
  684. name='test4',
  685. description='test project description',
  686. hook_token='aaabbbeeeceee',
  687. private=False,
  688. )
  689. self.session.add(item)
  690. self.session.commit()
  691. # Add a git repo
  692. repo_path = os.path.join(
  693. pagure.config.config.get('GIT_FOLDER'), 'test4.git')
  694. pygit2.init_repository(repo_path)
  695. user = tests.FakeUser(username='pingou')
  696. with tests.user_set(self.app.application, user):
  697. # Check for public repo
  698. output = self.app.get('/test4/settings')
  699. self.assertEqual(output.status_code, 200)
  700. self.assertNotIn(
  701. '<input type="checkbox" value="private" name="private" checked=""/>',
  702. output.get_data(as_text=True))
  703. self.session.commit()
  704. repo = pagure.lib._get_project(self.session, 'test4')
  705. self.assertFalse(repo.private)
  706. # Make the project private
  707. data = {
  708. 'description': 'test project description',
  709. 'private': True,
  710. 'csrf_token': self.get_csrf(),
  711. }
  712. output = self.app.post(
  713. '/test4/update', data=data, follow_redirects=True)
  714. self.assertEqual(output.status_code, 200)
  715. self.assertIn(
  716. 'Project updated',
  717. output.get_data(as_text=True))
  718. self.assertNotIn(
  719. '<input type="checkbox" value="private" name="private" checked=""/>',
  720. output.get_data(as_text=True))
  721. # No change since we can't do public -> private
  722. self.session.commit()
  723. repo = pagure.lib._get_project(self.session, 'test4')
  724. self.assertFalse(repo.private)
  725. @patch('pagure.lib.notify.send_email')
  726. def test_private_pr(self, send_email):
  727. """Test pull request made to the private repo"""
  728. send_email.return_value = True
  729. # Add a private project
  730. item = pagure.lib.model.Project(
  731. user_id=1, # pingou
  732. name='pmc',
  733. description='test project description',
  734. hook_token='aaabbbeeeceee',
  735. private=True,
  736. )
  737. self.session.add(item)
  738. self.session.commit()
  739. repo = pagure.lib._get_project(self.session, 'pmc')
  740. msg = pagure.lib.add_user_to_project(
  741. session=self.session,
  742. project=repo,
  743. new_user='foo',
  744. user='pingou',
  745. )
  746. self.session.commit()
  747. self.assertEqual(msg, 'User added')
  748. # Create all the git repos
  749. tests.create_projects_git(
  750. os.path.join(self.path, 'requests'), bare=True)
  751. # Add a git repo
  752. repo_path = os.path.join(
  753. pagure.config.config.get('REQUESTS_FOLDER'), 'pmc.git')
  754. if not os.path.exists(repo_path):
  755. os.makedirs(repo_path)
  756. pygit2.init_repository(repo_path, bare=True)
  757. # Check repo was created - Doesn't show on the public page
  758. user = tests.FakeUser(username='pingou')
  759. with tests.user_set(self.app.application, user):
  760. output = self.app.get('/user/pingou/')
  761. self.assertEqual(output.status_code, 200)
  762. self.assertIn(
  763. """<span>
  764. <i class="fa fa-fw text-muted fa-calendar-o fa-rotate-270"></i>
  765. <span class="d-none d-md-inline">Projects&nbsp;</span>
  766. </span>
  767. <div class="ml-auto">
  768. <span class="badge badge-secondary">
  769. 0
  770. </span>
  771. </div>""", output.get_data(as_text=True))
  772. self.assertIn(
  773. """<span>
  774. <i class="fa fa-fw text-muted fa-code-fork"></i>
  775. <span class="d-none d-md-inline">Forks&nbsp;</span>
  776. </span>
  777. <div class="ml-auto">
  778. <span class="badge badge-secondary">
  779. 0
  780. </span>
  781. </div>""", output.get_data(as_text=True))
  782. # Shows on the front page
  783. output = self.app.get('/dashboard/projects')
  784. self.assertEqual(output.status_code, 200)
  785. self.assertIn(
  786. """<span>
  787. <i class="fa fa-calendar-o fa-rotate-270 fa-fw text-muted"></i>
  788. <span class="d-none d-md-inline">Projects&nbsp;</span>
  789. </span>
  790. <div class="ml-auto">
  791. <span class="badge badge-secondary">
  792. 1
  793. </span>
  794. </div>""", output.get_data(as_text=True))
  795. self.set_up_git_repo(new_project=None, branch_from='feature')
  796. project = pagure.lib._get_project(self.session, 'pmc')
  797. self.assertEqual(len(project.requests), 1)
  798. output = self.app.get('/pmc/pull-request/1')
  799. self.assertEqual(output.status_code, 200)
  800. # Check repo was created
  801. user = tests.FakeUser()
  802. with tests.user_set(self.app.application, user):
  803. output = self.app.get('/pmc/pull-requests')
  804. self.assertEqual(output.status_code, 404)
  805. user = tests.FakeUser(username='pingou')
  806. with tests.user_set(self.app.application, user):
  807. output = self.app.get('/pmc/pull-requests')
  808. self.assertEqual(output.status_code, 200)
  809. user = tests.FakeUser(username='foo')
  810. with tests.user_set(self.app.application, user):
  811. output = self.app.get('/pmc/pull-requests')
  812. self.assertEqual(output.status_code, 200)
  813. @patch('pagure.lib.git.update_git')
  814. @patch('pagure.lib.notify.send_email')
  815. def test_private_repo_issues_ui(self, p_send_email, p_ugt):
  816. """ Test issues made to private repo"""
  817. p_send_email.return_value = True
  818. p_ugt.return_value = True
  819. # Add private repo
  820. item = pagure.lib.model.Project(
  821. user_id=1, # pingou
  822. name='test4',
  823. description='test project description',
  824. hook_token='aaabbbeeeceee',
  825. private=True,
  826. )
  827. self.session.add(item)
  828. self.session.commit()
  829. for repo in ['GIT_FOLDER', 'TICKETS_FOLDER']:
  830. # Add a git repo
  831. repo_path = os.path.join(
  832. pagure.config.config.get(repo), 'test4.git')
  833. if not os.path.exists(repo_path):
  834. os.makedirs(repo_path)
  835. pygit2.init_repository(repo_path)
  836. # Check if the private repo issues are publicly not accesible
  837. output = self.app.get('/test4/issues')
  838. self.assertEqual(output.status_code, 404)
  839. # Create issues to play with
  840. repo = pagure.lib._get_project(self.session, 'test4')
  841. msg = pagure.lib.new_issue(
  842. session=self.session,
  843. repo=repo,
  844. title='Test issue',
  845. content='We should work on this',
  846. user='pingou',
  847. )
  848. self.session.commit()
  849. self.assertEqual(msg.title, 'Test issue')
  850. user = tests.FakeUser()
  851. with tests.user_set(self.app.application, user):
  852. # Whole list
  853. output = self.app.get('/test4/issues')
  854. self.assertEqual(output.status_code, 404)
  855. # Check single issue
  856. output = self.app.get('/test4/issue/1')
  857. self.assertEqual(output.status_code, 404)
  858. user = tests.FakeUser()
  859. with tests.user_set(self.app.application, user):
  860. # Whole list
  861. output = self.app.get('/test4/issues')
  862. self.assertEqual(output.status_code, 404)
  863. user = tests.FakeUser(username='pingou')
  864. with tests.user_set(self.app.application, user):
  865. # Whole list
  866. output = self.app.get('/test4/issues')
  867. self.assertEqual(output.status_code, 200)
  868. self.assertIn(
  869. '<title>Issues - test4 - Pagure</title>', output.get_data(as_text=True))
  870. self.assertTrue(
  871. '<span class="fa fa-fw fa-exclamation-circle"></span> 1 Open Issues\n' in output.get_data(as_text=True))
  872. # Check single issue
  873. output = self.app.get('/test4/issue/1')
  874. self.assertEqual(output.status_code, 200)
  875. repo = pagure.lib._get_project(self.session, 'test4')
  876. msg = pagure.lib.add_user_to_project(
  877. session=self.session,
  878. project=repo,
  879. new_user='foo',
  880. user='pingou',
  881. )
  882. self.session.commit()
  883. self.assertEqual(msg, 'User added')
  884. user.username = 'foo'
  885. with tests.user_set(self.app.application, user):
  886. # Whole list
  887. output = self.app.get('/test4/issues')
  888. self.assertEqual(output.status_code, 200)
  889. self.assertIn(
  890. '<title>Issues - test4 - Pagure</title>', output.get_data(as_text=True))
  891. self.assertTrue(
  892. '<span class="fa fa-fw fa-exclamation-circle"></span> 1 Open Issues\n' in output.get_data(as_text=True))
  893. # Check single issue
  894. output = self.app.get('/test4/issue/1')
  895. self.assertEqual(output.status_code, 200)
  896. @patch('pagure.decorators.admin_session_timedout')
  897. def test_private_repo_ui_for_different_repo_user(self, ast):
  898. """ Test the private repo for different ACLS"""
  899. ast.return_value = False
  900. # Add private repo
  901. item = pagure.lib.model.Project(
  902. user_id=1, # pingou
  903. name='test4',
  904. description='test project description',
  905. hook_token='aaabbbeeeceee',
  906. private=True,
  907. )
  908. self.session.add(item)
  909. self.session.commit()
  910. repo = pagure.lib._get_project(self.session, "test4")
  911. # Add a git repo
  912. repo_path = os.path.join(
  913. pagure.config.config.get('GIT_FOLDER'), 'test4.git')
  914. pygit2.init_repository(repo_path)
  915. user = tests.FakeUser(username='pingou')
  916. with tests.user_set(self.app.application, user):
  917. # Check for private repo
  918. output = self.app.get('/test4')
  919. self.assertEqual(output.status_code, 200)
  920. # Check if the user who doesn't have access to private repo can access it
  921. user = tests.FakeUser(username="foo")
  922. with tests.user_set(self.app.application, user):
  923. output = self.app.get('/test4')
  924. self.assertEqual(output.status_code, 404)
  925. # Add commit access to a user
  926. pagure.lib.add_user_to_project(
  927. self.session,
  928. project=repo,
  929. new_user="foo",
  930. user="pingou",
  931. access='commit'
  932. )
  933. self.session.commit()
  934. repo = pagure.lib._get_project(self.session, "test4")
  935. self.assertEqual(len(repo.users), 1)
  936. # Check if the user can access private repo
  937. user = tests.FakeUser(username="foo")
  938. with tests.user_set(self.app.application, user):
  939. output = self.app.get('/test4')
  940. self.assertEqual(output.status_code, 200)
  941. # Making a new user bar
  942. item = pagure.lib.model.User(
  943. user='bar',
  944. fullname='bar baz',
  945. password='foo',
  946. default_email='bar@bar.com',
  947. )
  948. self.session.add(item)
  949. item = pagure.lib.model.UserEmail(
  950. user_id=3,
  951. email='bar@bar.com')
  952. self.session.add(item)
  953. self.session.commit()
  954. # Check that bar shouldn't be able to access the project
  955. user = tests.FakeUser(username="bar")
  956. with tests.user_set(self.app.application, user):
  957. output = self.app.get('/test4')
  958. self.assertEqual(output.status_code, 404)
  959. # Adding a ticket level access to bar
  960. pagure.lib.add_user_to_project(
  961. self.session,
  962. project=repo,
  963. new_user="bar",
  964. user="pingou",
  965. access='ticket'
  966. )
  967. self.session.commit()
  968. repo = pagure.lib._get_project(self.session, "test4")
  969. self.assertEqual(len(repo.users), 2)
  970. # Check if the ticket level access user can access the project
  971. user = tests.FakeUser(username="bar")
  972. with tests.user_set(self.app.application, user):
  973. output = self.app.get('/test4')
  974. self.assertEqual(output.status_code, 200)
  975. # API checks
  976. def test_api_private_repo_projects(self):
  977. """ Test api points for private repo for projects"""
  978. # Add private repo
  979. item = pagure.lib.model.Project(
  980. user_id=1, # pingou
  981. name='test4',
  982. description='test project description',
  983. hook_token='aaabbbeeeceee',
  984. private=True,
  985. )
  986. self.session.add(item)
  987. self.session.commit()
  988. # Create a git repo to play with
  989. gitrepo = os.path.join(self.path, 'repos', 'test4.git')
  990. repo = pygit2.init_repository(gitrepo, bare=True)
  991. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  992. repopath = os.path.join(newpath, 'repos', 'test4')
  993. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  994. # Create a file in that git repo
  995. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  996. stream.write('foo\n bar')
  997. clone_repo.index.add('sources')
  998. clone_repo.index.write()
  999. # Commits the files added
  1000. tree = clone_repo.index.write_tree()
  1001. author = pygit2.Signature(
  1002. 'Alice Author', 'alice@authors.tld')
  1003. committer = pygit2.Signature(
  1004. 'Cecil Committer', 'cecil@committers.tld')
  1005. clone_repo.create_commit(
  1006. 'refs/heads/master', # the name of the reference to update
  1007. author,
  1008. committer,
  1009. 'Add sources file for testing',
  1010. # binary string representing the tree object ID
  1011. tree,
  1012. # list of binary strings representing parents of the new commit
  1013. []
  1014. )
  1015. refname = 'refs/heads/master:refs/heads/master'
  1016. ori_remote = clone_repo.remotes[0]
  1017. PagureRepo.push(ori_remote, refname)
  1018. # Tag our first commit
  1019. first_commit = repo.revparse_single('HEAD')
  1020. tagger = pygit2.Signature('Alice Doe', 'adoe@example.com', 12347, 0)
  1021. repo.create_tag(
  1022. "0.0.1", first_commit.oid.hex, pygit2.GIT_OBJ_COMMIT, tagger,
  1023. "Release 0.0.1")
  1024. # Create a token for foo for this project
  1025. item = pagure.lib.model.Token(
  1026. id='foobar_token',
  1027. user_id=1,
  1028. project_id=1,
  1029. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1030. days=30)
  1031. )
  1032. self.session.add(item)
  1033. self.session.commit()
  1034. item = pagure.lib.model.TokenAcl(
  1035. token_id='foobar_token',
  1036. acl_id=1,
  1037. )
  1038. self.session.add(item)
  1039. self.session.commit()
  1040. # Check if the admin requests
  1041. user = tests.FakeUser(username='pingou')
  1042. with tests.user_set(self.app.application, user):
  1043. # Check tags
  1044. output = self.app.get('/api/0/test4/git/tags')
  1045. self.assertEqual(output.status_code, 200)
  1046. data = json.loads(output.get_data(as_text=True))
  1047. self.assertDictEqual(
  1048. data,
  1049. {'tags': ['0.0.1'], 'total_tags': 1}
  1050. )
  1051. output = self.app.get('/api/0/test4/git/tags')
  1052. self.assertEqual(output.status_code, 404)
  1053. # Chekc if user is not admin
  1054. user = tests.FakeUser()
  1055. with tests.user_set(self.app.application, user):
  1056. output = self.app.get('/api/0/test4/git/tags')
  1057. self.assertEqual(output.status_code, 404)
  1058. shutil.rmtree(newpath)
  1059. # Check before adding
  1060. repo = pagure.lib._get_project(self.session, 'test4')
  1061. self.assertEqual(repo.tags, [])
  1062. # Adding a tag
  1063. output = pagure.lib.update_tags(
  1064. self.session, repo, 'infra', 'pingou')
  1065. self.assertEqual(output, ['Project tagged with: infra'])
  1066. # Check after adding
  1067. repo = pagure.lib._get_project(self.session, 'test4')
  1068. self.assertEqual(len(repo.tags), 1)
  1069. self.assertEqual(repo.tags_text, ['infra'])
  1070. # Check the API
  1071. output = self.app.get('/api/0/projects?tags=inf')
  1072. self.assertEqual(output.status_code, 200)
  1073. data = json.loads(output.get_data(as_text=True))
  1074. del data['pagination']
  1075. self.assertDictEqual(
  1076. data,
  1077. {
  1078. 'args': {
  1079. 'fork': None,
  1080. 'namespace': None,
  1081. 'owner': None,
  1082. 'page': 1,
  1083. 'pattern': None,
  1084. 'per_page': 20,
  1085. 'short': False,
  1086. 'tags': ['inf'],
  1087. 'username': None
  1088. },
  1089. 'projects': [],
  1090. 'total_projects': 0
  1091. }
  1092. )
  1093. # Request by not a loggged in user
  1094. output = self.app.get('/api/0/projects?tags=infra')
  1095. self.assertEqual(output.status_code, 200)
  1096. data = json.loads(output.get_data(as_text=True))
  1097. del data['pagination']
  1098. self.assertDictEqual(
  1099. data,
  1100. {
  1101. 'args': {
  1102. 'fork': None,
  1103. 'namespace': None,
  1104. 'owner': None,
  1105. 'page': 1,
  1106. 'pattern': None,
  1107. 'per_page': 20,
  1108. 'short': False,
  1109. 'tags': ['infra'],
  1110. 'username': None
  1111. },
  1112. 'projects': [],
  1113. 'total_projects': 0
  1114. }
  1115. )
  1116. user = tests.FakeUser()
  1117. with tests.user_set(self.app.application, user):
  1118. # Request by a non authorized user
  1119. output = self.app.get('/api/0/projects?tags=infra')
  1120. self.assertEqual(output.status_code, 200)
  1121. data = json.loads(output.get_data(as_text=True))
  1122. del data['pagination']
  1123. self.assertDictEqual(
  1124. data,
  1125. {
  1126. 'args': {
  1127. 'fork': None,
  1128. 'namespace': None,
  1129. 'owner': None,
  1130. 'page': 1,
  1131. 'pattern': None,
  1132. 'per_page': 20,
  1133. 'short': False,
  1134. 'tags': ['infra'],
  1135. 'username': None
  1136. },
  1137. 'projects': [],
  1138. 'total_projects': 0
  1139. }
  1140. )
  1141. user.username = 'pingou'
  1142. with tests.user_set(self.app.application, user):
  1143. # Private repo username is compulsion to pass
  1144. output = self.app.get('/api/0/projects?tags=infra')
  1145. self.assertEqual(output.status_code, 200)
  1146. data = json.loads(output.get_data(as_text=True))
  1147. del data['pagination']
  1148. self.assertDictEqual(
  1149. data,
  1150. {
  1151. 'args': {
  1152. 'fork': None,
  1153. 'namespace': None,
  1154. 'owner': None,
  1155. 'page': 1,
  1156. 'pattern': None,
  1157. 'per_page': 20,
  1158. 'short': False,
  1159. 'tags': ['infra'],
  1160. 'username': None
  1161. },
  1162. 'projects': [],
  1163. 'total_projects': 0
  1164. }
  1165. )
  1166. output = self.app.get('/api/0/projects?username=pingou')
  1167. self.assertEqual(output.status_code, 200)
  1168. data = json.loads(output.get_data(as_text=True))
  1169. data['projects'][0]['date_created'] = "1436527638"
  1170. data['projects'][0]['date_modified'] = "1436527638"
  1171. del data['pagination']
  1172. self.assertDictEqual(
  1173. data,
  1174. {
  1175. "args": {
  1176. "fork": None,
  1177. "namespace": None,
  1178. "owner": None,
  1179. "page": 1,
  1180. "pattern": None,
  1181. "per_page": 20,
  1182. "short": False,
  1183. "tags": [],
  1184. "username": "pingou"
  1185. },
  1186. "total_projects": 1,
  1187. "projects": [
  1188. {
  1189. "access_groups": {
  1190. "admin": [],
  1191. "commit": [],
  1192. "ticket": []
  1193. },
  1194. "access_users": {
  1195. "admin": [],
  1196. "commit": [],
  1197. "owner": [
  1198. "pingou"
  1199. ],
  1200. "ticket": []
  1201. },
  1202. "close_status": [],
  1203. "custom_keys": [],
  1204. "date_created": "1436527638",
  1205. "date_modified": "1436527638",
  1206. "description": "test project description",
  1207. "id": 1,
  1208. "milestones": {},
  1209. "name": "test4",
  1210. "fullname": "test4",
  1211. "url_path": "test4",
  1212. "namespace": None,
  1213. "parent": None,
  1214. "priorities": {},
  1215. "tags": ["infra"],
  1216. "user": {
  1217. "fullname": "PY C",
  1218. "name": "pingou"
  1219. }
  1220. },
  1221. ]
  1222. }
  1223. )
  1224. output = self.app.get('/api/0/projects?username=pingou&tags=infra')
  1225. self.assertEqual(output.status_code, 200)
  1226. data = json.loads(output.get_data(as_text=True))
  1227. data['projects'][0]['date_created'] = "1436527638"
  1228. data['projects'][0]['date_modified'] = "1436527638"
  1229. del data['pagination']
  1230. self.assertDictEqual(
  1231. data,
  1232. {
  1233. "args": {
  1234. "fork": None,
  1235. "namespace": None,
  1236. "owner": None,
  1237. "page": 1,
  1238. "pattern": None,
  1239. "per_page": 20,
  1240. "short": False,
  1241. "tags": ["infra"],
  1242. "username": "pingou"
  1243. },
  1244. "total_projects": 1,
  1245. "projects": [
  1246. {
  1247. "access_groups": {
  1248. "admin": [],
  1249. "commit": [],
  1250. "ticket": []
  1251. },
  1252. "access_users": {
  1253. "admin": [],
  1254. "commit": [],
  1255. "owner": [
  1256. "pingou"
  1257. ],
  1258. "ticket": []
  1259. },
  1260. "close_status": [],
  1261. "custom_keys": [],
  1262. "date_created": "1436527638",
  1263. "date_modified": "1436527638",
  1264. "description": "test project description",
  1265. "id": 1,
  1266. "milestones": {},
  1267. "name": "test4",
  1268. "fullname": "test4",
  1269. "url_path": "test4",
  1270. "namespace": None,
  1271. "parent": None,
  1272. "priorities": {},
  1273. "tags": ["infra"],
  1274. "user": {
  1275. "fullname": "PY C",
  1276. "name": "pingou"
  1277. }
  1278. }
  1279. ]
  1280. }
  1281. )
  1282. # Api pull-request views
  1283. @patch('pagure.lib.notify.send_email')
  1284. def test_api_private_repo_fork(self, send_email):
  1285. """ Test api endpoints in api/fork"""
  1286. send_email.return_value = True
  1287. # Add private repo
  1288. item = pagure.lib.model.Project(
  1289. user_id=1, # pingou
  1290. name='test4',
  1291. description='test project description',
  1292. hook_token='aaabbbeeeceee',
  1293. private=True,
  1294. )
  1295. self.session.add(item)
  1296. self.session.commit()
  1297. tests.create_tokens(self.session)
  1298. tests.create_tokens_acl(self.session)
  1299. headers = {'Authorization': 'token aaabbbcccddd'}
  1300. # Create a pull-request
  1301. repo = pagure.lib._get_project(self.session, 'test4')
  1302. forked_repo = pagure.lib._get_project(self.session, 'test4')
  1303. req = pagure.lib.new_pull_request(
  1304. session=self.session,
  1305. repo_from=forked_repo,
  1306. branch_from='master',
  1307. repo_to=repo,
  1308. branch_to='master',
  1309. title='test pull-request',
  1310. user='pingou',
  1311. )
  1312. self.session.commit()
  1313. self.assertEqual(req.id, 1)
  1314. self.assertEqual(req.title, 'test pull-request')
  1315. # Check list of PR
  1316. output = self.app.get('/api/0/test4/pull-requests')
  1317. self.assertEqual(output.status_code, 404)
  1318. # Check single PR
  1319. output = self.app.get('/api/0/test/pull-request/1')
  1320. self.assertEqual(output.status_code, 404)
  1321. user = tests.FakeUser(username='pingou')
  1322. with tests.user_set(self.app.application, user):
  1323. # List pull-requests
  1324. output = self.app.get('/api/0/test4/pull-requests')
  1325. self.assertEqual(output.status_code, 200)
  1326. data = json.loads(output.get_data(as_text=True))
  1327. data['requests'][0]['date_created'] = '1431414800'
  1328. data['requests'][0]['updated_on'] = '1431414800'
  1329. data['requests'][0]['project']['date_created'] = '1431414800'
  1330. data['requests'][0]['project']['date_modified'] = '1431414800'
  1331. data['requests'][0]['repo_from']['date_created'] = '1431414800'
  1332. data['requests'][0]['repo_from']['date_modified'] = '1431414800'
  1333. data['requests'][0]['uid'] = '1431414800'
  1334. data['requests'][0]['last_updated'] = '1431414800'
  1335. for k in ['first', 'last']:
  1336. self.assertIsNotNone(data['pagination'][k])
  1337. data['pagination'][k] = 'http://localhost...'
  1338. self.assertDictEqual(
  1339. data,
  1340. {
  1341. "args": {
  1342. "assignee": None,
  1343. "author": None,
  1344. "page": 1,
  1345. "per_page": 20,
  1346. "status": True
  1347. },
  1348. "pagination": {
  1349. "first": 'http://localhost...',
  1350. "last": 'http://localhost...',
  1351. "next": None,
  1352. "page": 1,
  1353. "pages": 1,
  1354. "per_page": 20,
  1355. "prev": None
  1356. },
  1357. "requests": [
  1358. {
  1359. "assignee": None,
  1360. "branch": "master",
  1361. "branch_from": "master",
  1362. "cached_merge_status": "unknown",
  1363. "closed_at": None,
  1364. "closed_by": None,
  1365. "comments": [],
  1366. "commit_start": None,
  1367. "commit_stop": None,
  1368. "date_created": "1431414800",
  1369. "last_updated": "1431414800",
  1370. "id": 1,
  1371. "initial_comment": None,
  1372. "project": {
  1373. "access_groups": {
  1374. "admin": [],
  1375. "commit": [],
  1376. "ticket": []
  1377. },
  1378. "access_users": {
  1379. "admin": [],
  1380. "commit": [],
  1381. "owner": [
  1382. "pingou"
  1383. ],
  1384. "ticket": []
  1385. },
  1386. "close_status": [],
  1387. "custom_keys": [],
  1388. "date_created": "1431414800",
  1389. "date_modified": "1431414800",
  1390. "description": "test project description",
  1391. "id": 1,
  1392. "milestones": {},
  1393. "name": "test4",
  1394. "fullname": "test4",
  1395. "url_path": "test4",
  1396. "namespace": None,
  1397. "parent": None,
  1398. "priorities": {},
  1399. "tags": [],
  1400. "user": {
  1401. "fullname": "PY C",
  1402. "name": "pingou"
  1403. }
  1404. },
  1405. "remote_git": None,
  1406. "repo_from": {
  1407. "access_groups": {
  1408. "admin": [],
  1409. "commit": [],
  1410. "ticket": []
  1411. },
  1412. "access_users": {
  1413. "admin": [],
  1414. "commit": [],
  1415. "owner": [
  1416. "pingou"
  1417. ],
  1418. "ticket": []
  1419. },
  1420. "close_status": [],
  1421. "custom_keys": [],
  1422. "date_created": "1431414800",
  1423. "date_modified": "1431414800",
  1424. "description": "test project description",
  1425. "id": 1,
  1426. "milestones": {},
  1427. "fullname": "test4",
  1428. "url_path": "test4",
  1429. "name": "test4",
  1430. "namespace": None,
  1431. "parent": None,
  1432. "priorities": {},
  1433. "tags": [],
  1434. "user": {
  1435. "fullname": "PY C",
  1436. "name": "pingou"
  1437. }
  1438. },
  1439. "status": "Open",
  1440. "title": "test pull-request",
  1441. "uid": "1431414800",
  1442. "updated_on": "1431414800",
  1443. "user": {
  1444. "fullname": "PY C",
  1445. "name": "pingou"
  1446. }
  1447. }
  1448. ],
  1449. "total_requests": 1
  1450. }
  1451. )
  1452. headers = {'Authorization': 'token foobar_token'}
  1453. # Access Pull-Request authenticated
  1454. output = self.app.get(
  1455. '/api/0/test4/pull-requests', headers=headers)
  1456. self.assertEqual(output.status_code, 200)
  1457. data2 = json.loads(output.get_data(as_text=True))
  1458. data2['requests'][0]['date_created'] = '1431414800'
  1459. data2['requests'][0]['updated_on'] = '1431414800'
  1460. data2['requests'][0]['project']['date_created'] = '1431414800'
  1461. data2['requests'][0]['project']['date_modified'] = '1431414800'
  1462. data2['requests'][0]['repo_from']['date_created'] = '1431414800'
  1463. data2['requests'][0]['repo_from']['date_modified'] = '1431414800'
  1464. data2['requests'][0]['uid'] = '1431414800'
  1465. data2['requests'][0]['last_updated'] = '1431414800'
  1466. for k in ['first', 'last']:
  1467. self.assertIsNotNone(data['pagination'][k])
  1468. data2['pagination'][k] = 'http://localhost...'
  1469. self.assertDictEqual(data, data2)
  1470. # For single PR
  1471. output = self.app.get('/api/0/test4/pull-request/1')
  1472. self.assertEqual(output.status_code, 200)
  1473. data = json.loads(output.get_data(as_text=True))
  1474. data['date_created'] = '1431414800'
  1475. data['updated_on'] = '1431414800'
  1476. data['project']['date_created'] = '1431414800'
  1477. data['project']['date_modified'] = '1431414800'
  1478. data['repo_from']['date_created'] = '1431414800'
  1479. data['repo_from']['date_modified'] = '1431414800'
  1480. data['uid'] = '1431414800'
  1481. data['last_updated'] = '1431414800'
  1482. self.assertDictEqual(
  1483. data,
  1484. {
  1485. "assignee": None,
  1486. "branch": "master",
  1487. "branch_from": "master",
  1488. "cached_merge_status": "unknown",
  1489. "closed_at": None,
  1490. "closed_by": None,
  1491. "comments": [],
  1492. "commit_start": None,
  1493. "commit_stop": None,
  1494. "date_created": "1431414800",
  1495. "last_updated": "1431414800",
  1496. "id": 1,
  1497. "initial_comment": None,
  1498. "project": {
  1499. "access_groups": {
  1500. "admin": [],
  1501. "commit": [],
  1502. "ticket": []
  1503. },
  1504. "access_users": {
  1505. "admin": [],
  1506. "commit": [],
  1507. "owner": [
  1508. "pingou"
  1509. ],
  1510. "ticket": []
  1511. },
  1512. "close_status": [],
  1513. "custom_keys": [],
  1514. "date_created": "1431414800",
  1515. "date_modified": "1431414800",
  1516. "description": "test project description",
  1517. "id": 1,
  1518. "milestones": {},
  1519. "name": "test4",
  1520. "fullname": "test4",
  1521. "url_path": "test4",
  1522. "namespace": None,
  1523. "parent": None,
  1524. "priorities": {},
  1525. "tags": [],
  1526. "user": {
  1527. "fullname": "PY C",
  1528. "name": "pingou"
  1529. }
  1530. },
  1531. "remote_git": None,
  1532. "repo_from": {
  1533. "access_groups": {
  1534. "admin": [],
  1535. "commit": [],
  1536. "ticket": []
  1537. },
  1538. "access_users": {
  1539. "admin": [],
  1540. "commit": [],
  1541. "owner": [
  1542. "pingou"
  1543. ],
  1544. "ticket": []
  1545. },
  1546. "close_status": [],
  1547. "custom_keys": [],
  1548. "date_created": "1431414800",
  1549. "date_modified": "1431414800",
  1550. "description": "test project description",
  1551. "id": 1,
  1552. "milestones": {},
  1553. "name": "test4",
  1554. "fullname": "test4",
  1555. "url_path": "test4",
  1556. "namespace": None,
  1557. "parent": None,
  1558. "priorities": {},
  1559. "tags": [],
  1560. "user": {
  1561. "fullname": "PY C",
  1562. "name": "pingou"
  1563. }
  1564. },
  1565. "status": "Open",
  1566. "title": "test pull-request",
  1567. "uid": "1431414800",
  1568. "updated_on": "1431414800",
  1569. "user": {
  1570. "fullname": "PY C",
  1571. "name": "pingou"
  1572. },
  1573. }
  1574. )
  1575. # Access Pull-Request authenticated
  1576. output = self.app.get(
  1577. '/api/0/test4/pull-request/1', headers=headers)
  1578. self.assertEqual(output.status_code, 200)
  1579. data2 = json.loads(output.get_data(as_text=True))
  1580. data2['date_created'] = '1431414800'
  1581. data2['project']['date_created'] = '1431414800'
  1582. data2['project']['date_modified'] = '1431414800'
  1583. data2['repo_from']['date_created'] = '1431414800'
  1584. data2['repo_from']['date_modified'] = '1431414800'
  1585. data2['uid'] = '1431414800'
  1586. data2['date_created'] = '1431414800'
  1587. data2['updated_on'] = '1431414800'
  1588. data2['last_updated'] = '1431414800'
  1589. self.assertDictEqual(data, data2)
  1590. @patch('pagure.lib.notify.send_email')
  1591. def test_api_pr_private_repo_add_comment(self, mockemail):
  1592. """ Test the api_pull_request_add_comment method of the flask api. """
  1593. mockemail.return_value = True
  1594. pagure.config.config['REQUESTS_FOLDER'] = None
  1595. # Add private repo
  1596. item = pagure.lib.model.Project(
  1597. user_id=1, # pingou
  1598. name='test4',
  1599. description='test project description',
  1600. hook_token='aaabbbeeeceee',
  1601. private=True,
  1602. )
  1603. self.session.add(item)
  1604. self.session.commit()
  1605. tests.create_tokens(self.session)
  1606. tests.create_tokens_acl(self.session)
  1607. headers = {'Authorization': 'token aaabbbcccddd'}
  1608. # Create a pull-request
  1609. repo = pagure.lib._get_project(self.session, 'test4')
  1610. forked_repo = pagure.lib._get_project(self.session, 'test4')
  1611. req = pagure.lib.new_pull_request(
  1612. session=self.session,
  1613. repo_from=forked_repo,
  1614. branch_from='master',
  1615. repo_to=repo,
  1616. branch_to='master',
  1617. title='test pull-request',
  1618. user='pingou',
  1619. )
  1620. self.session.commit()
  1621. self.assertEqual(req.id, 1)
  1622. self.assertEqual(req.title, 'test pull-request')
  1623. # Check comments before
  1624. self.session.commit()
  1625. request = pagure.lib.search_pull_requests(
  1626. self.session, project_id=1, requestid=1)
  1627. self.assertEqual(len(request.comments), 0)
  1628. data = {
  1629. 'title': 'test issue',
  1630. }
  1631. # Incomplete request
  1632. output = self.app.post(
  1633. '/api/0/test4/pull-request/1/comment', data=data, headers=headers)
  1634. self.assertEqual(output.status_code, 400)
  1635. data = json.loads(output.get_data(as_text=True))
  1636. self.assertDictEqual(
  1637. data,
  1638. {
  1639. "error": "Invalid or incomplete input submitted",
  1640. "error_code": "EINVALIDREQ",
  1641. "errors": {"comment": ["This field is required."]}
  1642. }
  1643. )
  1644. # No change
  1645. self.session.commit()
  1646. request = pagure.lib.search_pull_requests(
  1647. self.session, project_id=1, requestid=1)
  1648. self.assertEqual(len(request.comments), 0)
  1649. data = {
  1650. 'comment': 'This is a very interesting question',
  1651. }
  1652. # Valid request
  1653. output = self.app.post(
  1654. '/api/0/test4/pull-request/1/comment', data=data, headers=headers)
  1655. self.assertEqual(output.status_code, 200)
  1656. data = json.loads(output.get_data(as_text=True))
  1657. self.assertDictEqual(
  1658. data,
  1659. {'message': 'Comment added'}
  1660. )
  1661. # One comment added
  1662. self.session.commit()
  1663. request = pagure.lib.search_pull_requests(
  1664. self.session, project_id=1, requestid=1)
  1665. self.assertEqual(len(request.comments), 1)
  1666. @patch('pagure.lib.notify.send_email')
  1667. def test_api_private_repo_pr_add_flag(self, mockemail):
  1668. """ Test the api_pull_request_add_flag method of the flask api. """
  1669. mockemail.return_value = True
  1670. pagure.config.config['REQUESTS_FOLDER'] = None
  1671. # Add private repo
  1672. item = pagure.lib.model.Project(
  1673. user_id=1, # pingou
  1674. name='test4',
  1675. description='test project description',
  1676. hook_token='aaabbbeeeceee',
  1677. private=True,
  1678. )
  1679. self.session.add(item)
  1680. self.session.commit()
  1681. # Add private repo
  1682. item = pagure.lib.model.Project(
  1683. user_id=1, # pingou
  1684. name='test2',
  1685. description='test project description',
  1686. hook_token='foo_bar',
  1687. private=True,
  1688. )
  1689. self.session.add(item)
  1690. self.session.commit()
  1691. tests.create_tokens(self.session)
  1692. tests.create_tokens_acl(self.session)
  1693. headers = {'Authorization': 'token aaabbbcccddd'}
  1694. # Invalid project
  1695. output = self.app.post(
  1696. '/api/0/foo/pull-request/1/flag', headers=headers)
  1697. self.assertEqual(output.status_code, 404)
  1698. data = json.loads(output.get_data(as_text=True))
  1699. self.assertDictEqual(
  1700. data,
  1701. {
  1702. "error": "Project not found",
  1703. "error_code": "ENOPROJECT",
  1704. }
  1705. )
  1706. # Valid token, wrong project
  1707. output = self.app.post(
  1708. '/api/0/test2/pull-request/1/flag', headers=headers)
  1709. self.assertEqual(output.status_code, 401)
  1710. data = json.loads(output.get_data(as_text=True))
  1711. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  1712. self.assertEqual(
  1713. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1714. self.assertEqual(
  1715. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  1716. # No input
  1717. output = self.app.post(
  1718. '/api/0/test4/pull-request/1/flag', headers=headers)
  1719. self.assertEqual(output.status_code, 404)
  1720. data = json.loads(output.get_data(as_text=True))
  1721. self.assertDictEqual(
  1722. data,
  1723. {
  1724. "error": "Pull-Request not found",
  1725. "error_code": "ENOREQ",
  1726. }
  1727. )
  1728. # Create a pull-request
  1729. repo = pagure.lib._get_project(self.session, 'test4')
  1730. forked_repo = pagure.lib._get_project(self.session, 'test4')
  1731. req = pagure.lib.new_pull_request(
  1732. session=self.session,
  1733. repo_from=forked_repo,
  1734. branch_from='master',
  1735. repo_to=repo,
  1736. branch_to='master',
  1737. title='test pull-request',
  1738. user='pingou',
  1739. )
  1740. self.session.commit()
  1741. self.assertEqual(req.id, 1)
  1742. self.assertEqual(req.title, 'test pull-request')
  1743. # Check comments before
  1744. self.session.commit()
  1745. request = pagure.lib.search_pull_requests(
  1746. self.session, project_id=1, requestid=1)
  1747. self.assertEqual(len(request.flags), 0)
  1748. data = {
  1749. 'username': 'Jenkins',
  1750. 'percent': 100,
  1751. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  1752. 'uid': 'jenkins_build_pagure_100+seed',
  1753. }
  1754. # Incomplete request
  1755. output = self.app.post(
  1756. '/api/0/test4/pull-request/1/flag', data=data, headers=headers)
  1757. self.assertEqual(output.status_code, 400)
  1758. data = json.loads(output.get_data(as_text=True))
  1759. self.assertDictEqual(
  1760. data,
  1761. {
  1762. "error": "Invalid or incomplete input submitted",
  1763. "error_code": "EINVALIDREQ",
  1764. "errors": {"comment": ["This field is required."]}
  1765. }
  1766. )
  1767. # No change
  1768. self.session.commit()
  1769. request = pagure.lib.search_pull_requests(
  1770. self.session, project_id=1, requestid=1)
  1771. self.assertEqual(len(request.flags), 0)
  1772. data = {
  1773. 'username': 'Jenkins',
  1774. 'percent': 0,
  1775. 'comment': 'Tests failed',
  1776. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  1777. 'uid': 'jenkins_build_pagure_100+seed',
  1778. }
  1779. # Valid request
  1780. output = self.app.post(
  1781. '/api/0/test4/pull-request/1/flag', data=data, headers=headers)
  1782. self.assertEqual(output.status_code, 200)
  1783. data = json.loads(output.get_data(as_text=True))
  1784. data['flag']['date_created'] = '1510742565'
  1785. data['flag']['pull_request_uid'] = '62b49f00d489452994de5010565fab81'
  1786. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1787. self.assertDictEqual(
  1788. data,
  1789. {
  1790. 'flag': {
  1791. 'comment': 'Tests failed',
  1792. 'date_created': '1510742565',
  1793. 'percent': 0,
  1794. 'pull_request_uid': '62b49f00d489452994de5010565fab81',
  1795. 'status': 'failure',
  1796. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  1797. 'user': {
  1798. 'default_email': 'bar@pingou.com',
  1799. 'emails': ['bar@pingou.com', 'foo@pingou.com'],
  1800. 'fullname': 'PY C',
  1801. 'name': 'pingou'},
  1802. 'username': 'Jenkins'},
  1803. 'message': 'Flag added',
  1804. 'uid': 'jenkins_build_pagure_100+seed',
  1805. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1806. 'user': 'pingou'
  1807. }
  1808. )
  1809. # One flag added
  1810. self.session.commit()
  1811. request = pagure.lib.search_pull_requests(
  1812. self.session, project_id=1, requestid=1)
  1813. self.assertEqual(len(request.flags), 1)
  1814. self.assertEqual(request.flags[0].comment, 'Tests failed')
  1815. self.assertEqual(request.flags[0].percent, 0)
  1816. # Update flag
  1817. data = {
  1818. 'username': 'Jenkins',
  1819. 'percent': 100,
  1820. 'comment': 'Tests passed',
  1821. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  1822. 'uid': 'jenkins_build_pagure_100+seed',
  1823. }
  1824. output = self.app.post(
  1825. '/api/0/test4/pull-request/1/flag', data=data, headers=headers)
  1826. self.assertEqual(output.status_code, 200)
  1827. data = json.loads(output.get_data(as_text=True))
  1828. data['flag']['date_created'] = '1510742565'
  1829. data['flag']['pull_request_uid'] = '62b49f00d489452994de5010565fab81'
  1830. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  1831. self.assertDictEqual(
  1832. data,
  1833. {
  1834. 'flag': {
  1835. 'comment': 'Tests passed',
  1836. 'date_created': '1510742565',
  1837. 'percent': 100,
  1838. 'pull_request_uid': '62b49f00d489452994de5010565fab81',
  1839. 'status': 'success',
  1840. 'url': 'http://jenkins.cloud.fedoraproject.org/',
  1841. 'user': {
  1842. 'default_email': 'bar@pingou.com',
  1843. 'emails': ['bar@pingou.com', 'foo@pingou.com'],
  1844. 'fullname': 'PY C',
  1845. 'name': 'pingou'},
  1846. 'username': 'Jenkins'},
  1847. 'message': 'Flag updated',
  1848. 'uid': 'jenkins_build_pagure_100+seed',
  1849. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  1850. 'user': 'pingou'
  1851. }
  1852. )
  1853. # One flag added
  1854. self.session.commit()
  1855. request = pagure.lib.search_pull_requests(
  1856. self.session, project_id=1, requestid=1)
  1857. self.assertEqual(len(request.flags), 1)
  1858. self.assertEqual(request.flags[0].comment, 'Tests passed')
  1859. self.assertEqual(request.flags[0].percent, 100)
  1860. @patch('pagure.lib.notify.send_email')
  1861. def test_api_private_repo_pr_close(self, send_email):
  1862. """ Test the api_pull_request_close method of the flask api. """
  1863. send_email.return_value = True
  1864. pagure.config.config['REQUESTS_FOLDER'] = None
  1865. # Add private repo
  1866. item = pagure.lib.model.Project(
  1867. user_id=1, # pingou
  1868. name='test4',
  1869. description='test project description',
  1870. hook_token='aaabbbeeeceee',
  1871. private=True,
  1872. )
  1873. self.session.add(item)
  1874. self.session.commit()
  1875. tests.create_tokens(self.session)
  1876. tests.create_tokens_acl(self.session)
  1877. # Add private repo
  1878. item = pagure.lib.model.Project(
  1879. user_id=1, # pingou
  1880. name='test2',
  1881. description='test project description',
  1882. hook_token='foo_bar',
  1883. private=True,
  1884. )
  1885. self.session.add(item)
  1886. self.session.commit()
  1887. # Create the pull-request to close
  1888. repo = pagure.lib._get_project(self.session, 'test4')
  1889. forked_repo = pagure.lib._get_project(self.session, 'test4')
  1890. req = pagure.lib.new_pull_request(
  1891. session=self.session,
  1892. repo_from=forked_repo,
  1893. branch_from='master',
  1894. repo_to=repo,
  1895. branch_to='master',
  1896. title='test pull-request',
  1897. user='pingou',
  1898. )
  1899. self.session.commit()
  1900. self.assertEqual(req.id, 1)
  1901. self.assertEqual(req.title, 'test pull-request')
  1902. headers = {'Authorization': 'token aaabbbcccddd'}
  1903. # Invalid project
  1904. output = self.app.post(
  1905. '/api/0/foo/pull-request/1/close', headers=headers)
  1906. self.assertEqual(output.status_code, 404)
  1907. data = json.loads(output.get_data(as_text=True))
  1908. self.assertDictEqual(
  1909. data,
  1910. {
  1911. "error": "Project not found",
  1912. "error_code": "ENOPROJECT",
  1913. }
  1914. )
  1915. # Valid token, wrong project
  1916. output = self.app.post(
  1917. '/api/0/test2/pull-request/1/close', headers=headers)
  1918. self.assertEqual(output.status_code, 401)
  1919. data = json.loads(output.get_data(as_text=True))
  1920. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  1921. self.assertEqual(
  1922. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  1923. self.assertEqual(
  1924. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  1925. # Invalid PR
  1926. output = self.app.post(
  1927. '/api/0/test4/pull-request/2/close', headers=headers)
  1928. self.assertEqual(output.status_code, 404)
  1929. data = json.loads(output.get_data(as_text=True))
  1930. self.assertDictEqual(
  1931. data,
  1932. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  1933. )
  1934. # Create a token for foo for this project
  1935. item = pagure.lib.model.Token(
  1936. id='foobar_token',
  1937. user_id=2,
  1938. project_id=1,
  1939. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  1940. days=30)
  1941. )
  1942. self.session.add(item)
  1943. self.session.commit()
  1944. # Allow the token to close PR
  1945. acls = pagure.lib.get_acls(self.session)
  1946. acl = None
  1947. for acl in acls:
  1948. if acl.name == 'pull_request_close':
  1949. break
  1950. item = pagure.lib.model.TokenAcl(
  1951. token_id='foobar_token',
  1952. acl_id=acl.id,
  1953. )
  1954. self.session.add(item)
  1955. self.session.commit()
  1956. headers = {'Authorization': 'token foobar_token'}
  1957. # User not admin
  1958. output = self.app.post(
  1959. '/api/0/test4/pull-request/1/close', headers=headers)
  1960. self.assertEqual(output.status_code, 404)
  1961. data = json.loads(output.get_data(as_text=True))
  1962. self.assertDictEqual(
  1963. data,
  1964. {
  1965. "error": "Project not found",
  1966. "error_code": "ENOPROJECT",
  1967. }
  1968. )
  1969. headers = {'Authorization': 'token aaabbbcccddd'}
  1970. # Close PR
  1971. output = self.app.post(
  1972. '/api/0/test4/pull-request/1/close', headers=headers)
  1973. self.assertEqual(output.status_code, 200)
  1974. data = json.loads(output.get_data(as_text=True))
  1975. self.assertDictEqual(
  1976. data,
  1977. {"message": "Pull-request closed!"}
  1978. )
  1979. @patch('pagure.lib.notify.send_email')
  1980. def test_api_private_repo_pr_merge(self, send_email):
  1981. """ Test the api_pull_request_merge method of the flask api. """
  1982. send_email.return_value = True
  1983. pagure.config.config['REQUESTS_FOLDER'] = None
  1984. # Add private repo
  1985. item = pagure.lib.model.Project(
  1986. user_id=1, # pingou
  1987. name='test4',
  1988. description='test project description',
  1989. hook_token='aaabbbeeeceee',
  1990. private=True,
  1991. )
  1992. self.session.add(item)
  1993. self.session.commit()
  1994. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  1995. tests.create_projects_git(os.path.join(self.path, 'requests'),
  1996. bare=True)
  1997. tests.add_readme_git_repo(os.path.join(self.path, 'repos',
  1998. 'test4.git'))
  1999. tests.add_commit_git_repo(os.path.join(self.path, 'repos',
  2000. 'test4.git'),
  2001. branch='test')
  2002. tests.create_tokens(self.session)
  2003. tests.create_tokens_acl(self.session)
  2004. # Add private repo
  2005. item = pagure.lib.model.Project(
  2006. user_id=1, # pingou
  2007. name='test2',
  2008. description='test project description',
  2009. hook_token='foo_bar',
  2010. private=True,
  2011. )
  2012. self.session.add(item)
  2013. self.session.commit()
  2014. # Create the pull-request to close
  2015. repo = pagure.lib._get_project(self.session, 'test4')
  2016. forked_repo = pagure.lib._get_project(self.session, 'test4')
  2017. req = pagure.lib.new_pull_request(
  2018. session=self.session,
  2019. repo_from=forked_repo,
  2020. branch_from='test',
  2021. repo_to=repo,
  2022. branch_to='master',
  2023. title='test pull-request',
  2024. user='pingou',
  2025. )
  2026. self.session.commit()
  2027. self.assertEqual(req.id, 1)
  2028. self.assertEqual(req.title, 'test pull-request')
  2029. headers = {'Authorization': 'token aaabbbcccddd'}
  2030. # Invalid project
  2031. output = self.app.post(
  2032. '/api/0/foo/pull-request/1/merge', headers=headers)
  2033. self.assertEqual(output.status_code, 404)
  2034. data = json.loads(output.get_data(as_text=True))
  2035. self.assertDictEqual(
  2036. data,
  2037. {
  2038. "error": "Project not found",
  2039. "error_code": "ENOPROJECT",
  2040. }
  2041. )
  2042. # Valid token, wrong project
  2043. output = self.app.post(
  2044. '/api/0/test2/pull-request/1/merge', headers=headers)
  2045. self.assertEqual(output.status_code, 401)
  2046. data = json.loads(output.get_data(as_text=True))
  2047. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2048. self.assertEqual(
  2049. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2050. self.assertEqual(
  2051. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2052. # Invalid PR
  2053. output = self.app.post(
  2054. '/api/0/test4/pull-request/2/merge', headers=headers)
  2055. self.assertEqual(output.status_code, 404)
  2056. data = json.loads(output.get_data(as_text=True))
  2057. self.assertDictEqual(
  2058. data,
  2059. {'error': 'Pull-Request not found', 'error_code': "ENOREQ"}
  2060. )
  2061. # Create a token for foo for this project
  2062. item = pagure.lib.model.Token(
  2063. id='foobar_token',
  2064. user_id=2,
  2065. project_id=1,
  2066. expiration=datetime.datetime.utcnow() + datetime.timedelta(
  2067. days=30)
  2068. )
  2069. self.session.add(item)
  2070. self.session.commit()
  2071. # Allow the token to merge PR
  2072. acls = pagure.lib.get_acls(self.session)
  2073. acl = None
  2074. for acl in acls:
  2075. if acl.name == 'pull_request_merge':
  2076. break
  2077. item = pagure.lib.model.TokenAcl(
  2078. token_id='foobar_token',
  2079. acl_id=acl.id,
  2080. )
  2081. self.session.add(item)
  2082. self.session.commit()
  2083. headers = {'Authorization': 'token foobar_token'}
  2084. # User not admin
  2085. output = self.app.post(
  2086. '/api/0/test4/pull-request/1/merge', headers=headers)
  2087. self.assertEqual(output.status_code, 404)
  2088. data = json.loads(output.get_data(as_text=True))
  2089. self.assertDictEqual(
  2090. data,
  2091. {
  2092. "error": "Project not found",
  2093. "error_code": "ENOPROJECT",
  2094. }
  2095. )
  2096. headers = {'Authorization': 'token aaabbbcccddd'}
  2097. # Merge PR
  2098. output = self.app.post(
  2099. '/api/0/test4/pull-request/1/merge', headers=headers)
  2100. self.assertEqual(output.status_code, 200)
  2101. data = json.loads(output.get_data(as_text=True))
  2102. self.assertDictEqual(
  2103. data,
  2104. {"message": "Changes merged!"}
  2105. )
  2106. def test_api_private_repo_new_issue(self):
  2107. """ Test the api_new_issue method of the flask api. """
  2108. # Add private repo
  2109. item = pagure.lib.model.Project(
  2110. user_id=1, # pingou
  2111. name='test4',
  2112. description='test project description',
  2113. hook_token='aaabbbeeeceee',
  2114. private=True,
  2115. )
  2116. self.session.add(item)
  2117. self.session.commit()
  2118. for repo in ['GIT_FOLDER', 'TICKETS_FOLDER']:
  2119. # Add a git repo
  2120. repo_path = os.path.join(
  2121. pagure.config.config.get(repo), 'test4.git')
  2122. if not os.path.exists(repo_path):
  2123. os.makedirs(repo_path)
  2124. pygit2.init_repository(repo_path, bare=True)
  2125. tests.create_tokens(self.session)
  2126. tests.create_tokens_acl(self.session)
  2127. # Add private repo
  2128. item = pagure.lib.model.Project(
  2129. user_id=1, # pingou
  2130. name='test2',
  2131. description='test project description',
  2132. hook_token='foo_bar',
  2133. private=True,
  2134. )
  2135. self.session.add(item)
  2136. self.session.commit()
  2137. headers = {'Authorization': 'token aaabbbcccddd'}
  2138. # Valid token, wrong project
  2139. output = self.app.post('/api/0/test2/new_issue', headers=headers)
  2140. self.assertEqual(output.status_code, 401)
  2141. data = json.loads(output.get_data(as_text=True))
  2142. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2143. self.assertEqual(
  2144. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2145. self.assertEqual(
  2146. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2147. # No input
  2148. output = self.app.post('/api/0/test4/new_issue', headers=headers)
  2149. self.assertEqual(output.status_code, 400)
  2150. data = json.loads(output.get_data(as_text=True))
  2151. self.assertDictEqual(
  2152. data,
  2153. {
  2154. "error": "Invalid or incomplete input submitted",
  2155. "error_code": "EINVALIDREQ",
  2156. "errors": {
  2157. "issue_content": ["This field is required."],
  2158. "title": ["This field is required."]
  2159. }
  2160. })
  2161. data = {
  2162. 'title': 'test issue',
  2163. }
  2164. # Invalid repo
  2165. output = self.app.post(
  2166. '/api/0/foo/new_issue', data=data, headers=headers)
  2167. self.assertEqual(output.status_code, 404)
  2168. data = json.loads(output.get_data(as_text=True))
  2169. self.assertDictEqual(
  2170. data,
  2171. {
  2172. "error": "Project not found",
  2173. "error_code": "ENOPROJECT",
  2174. }
  2175. )
  2176. # Incomplete request
  2177. output = self.app.post(
  2178. '/api/0/test4/new_issue', data=data, headers=headers)
  2179. self.assertEqual(output.status_code, 400)
  2180. data = json.loads(output.get_data(as_text=True))
  2181. self.assertDictEqual(
  2182. data,
  2183. {
  2184. "error": "Invalid or incomplete input submitted",
  2185. "error_code": "EINVALIDREQ",
  2186. "errors": {
  2187. "issue_content": ["This field is required."],
  2188. "title": ["This field is required."]
  2189. }
  2190. }
  2191. )
  2192. data = {
  2193. 'title': 'test issue',
  2194. 'issue_content': 'This issue needs attention',
  2195. }
  2196. # Valid request
  2197. output = self.app.post(
  2198. '/api/0/test4/new_issue', data=data, headers=headers)
  2199. self.assertEqual(output.status_code, 200)
  2200. data = json.loads(output.get_data(as_text=True))
  2201. data['issue']['date_created'] = '1431414800'
  2202. data['issue']['last_updated'] = '1431414800'
  2203. self.assertDictEqual(
  2204. data,
  2205. {
  2206. 'issue': FULL_ISSUE_LIST[7],
  2207. 'message': 'Issue created'
  2208. }
  2209. )
  2210. def test_api_private_repo_view_issues(self):
  2211. """ Test the api_view_issues method of the flask api. """
  2212. self.test_api_private_repo_new_issue()
  2213. # Invalid repo
  2214. output = self.app.get('/api/0/foo/issues')
  2215. self.assertEqual(output.status_code, 404)
  2216. data = json.loads(output.get_data(as_text=True))
  2217. self.assertDictEqual(
  2218. data,
  2219. {
  2220. "error": "Project not found",
  2221. "error_code": "ENOPROJECT",
  2222. }
  2223. )
  2224. # List all opened issues
  2225. user = tests.FakeUser(username='pingou')
  2226. with tests.user_set(self.app.application, user):
  2227. output = self.app.get('/api/0/test4/issues')
  2228. self.assertEqual(output.status_code, 200)
  2229. data = json.loads(output.get_data(as_text=True))
  2230. data['issues'][0]['date_created'] = '1431414800'
  2231. data['issues'][0]['last_updated'] = '1431414800'
  2232. for k in ['first', 'last']:
  2233. self.assertIsNotNone(data['pagination'][k])
  2234. data['pagination'][k] = 'http://localhost...'
  2235. self.assertDictEqual(
  2236. data,
  2237. {
  2238. "args": {
  2239. "assignee": None,
  2240. "author": None,
  2241. "milestones": [],
  2242. "no_stones": None,
  2243. "order": None,
  2244. "priority": None,
  2245. "since": None,
  2246. "status": None,
  2247. "tags": []
  2248. },
  2249. "total_issues": 1,
  2250. "issues": [
  2251. {
  2252. "assignee": None,
  2253. "blocks": [],
  2254. "close_status": None,
  2255. "closed_at": None,
  2256. "comments": [],
  2257. "content": "This issue needs attention",
  2258. "custom_fields": [],
  2259. "date_created": "1431414800",
  2260. "last_updated": "1431414800",
  2261. "depends": [],
  2262. "id": 1,
  2263. "milestone": None,
  2264. "priority": None,
  2265. "private": False,
  2266. "status": "Open",
  2267. "tags": [],
  2268. "title": "test issue",
  2269. "user": {
  2270. "fullname": "PY C",
  2271. "name": "pingou"
  2272. }
  2273. }
  2274. ],
  2275. 'pagination': {
  2276. u'first': u'http://localhost...',
  2277. u'last': u'http://localhost...',
  2278. u'next': None,
  2279. u'page': 1,
  2280. u'pages': 1,
  2281. u'per_page': 20,
  2282. u'prev': None
  2283. },
  2284. }
  2285. )
  2286. # Create private issue
  2287. repo = pagure.lib._get_project(self.session, 'test4')
  2288. msg = pagure.lib.new_issue(
  2289. session=self.session,
  2290. repo=repo,
  2291. title='Test issue',
  2292. content='We should work on this',
  2293. user='pingou',
  2294. private=True,
  2295. )
  2296. self.session.commit()
  2297. self.assertEqual(msg.title, 'Test issue')
  2298. # Private issues are retrieved
  2299. user = tests.FakeUser(username='pingou')
  2300. with tests.user_set(self.app.application, user):
  2301. output = self.app.get('/api/0/test4/issues')
  2302. self.assertEqual(output.status_code, 200)
  2303. data = json.loads(output.get_data(as_text=True))
  2304. data['issues'][0]['date_created'] = '1431414800'
  2305. data['issues'][0]['last_updated'] = '1431414800'
  2306. data['issues'][1]['date_created'] = '1431414800'
  2307. data['issues'][1]['last_updated'] = '1431414800'
  2308. for k in ['first', 'last']:
  2309. self.assertIsNotNone(data['pagination'][k])
  2310. data['pagination'][k] = 'http://localhost...'
  2311. self.assertDictEqual(
  2312. data,
  2313. {
  2314. "args": {
  2315. "assignee": None,
  2316. "author": None,
  2317. "milestones": [],
  2318. "no_stones": None,
  2319. "order": None,
  2320. "priority": None,
  2321. "status": None,
  2322. "since": None,
  2323. "tags": []
  2324. },
  2325. "issues": [
  2326. {
  2327. "assignee": None,
  2328. "blocks": [],
  2329. "close_status": None,
  2330. "closed_at": None,
  2331. "comments": [],
  2332. "content": "We should work on this",
  2333. "custom_fields": [],
  2334. "date_created": "1431414800",
  2335. "last_updated": "1431414800",
  2336. "depends": [],
  2337. "id": 2,
  2338. "milestone": None,
  2339. "priority": None,
  2340. "private": True,
  2341. "status": "Open",
  2342. "tags": [],
  2343. "title": "Test issue",
  2344. "user": {
  2345. "fullname": "PY C",
  2346. "name": "pingou"
  2347. }
  2348. },
  2349. {
  2350. "assignee": None,
  2351. "blocks": [],
  2352. "close_status": None,
  2353. "closed_at": None,
  2354. "comments": [],
  2355. "content": "This issue needs attention",
  2356. "custom_fields": [],
  2357. "date_created": "1431414800",
  2358. "last_updated": "1431414800",
  2359. "depends": [],
  2360. "id": 1,
  2361. "milestone": None,
  2362. "priority": None,
  2363. "private": False,
  2364. "status": "Open",
  2365. "tags": [],
  2366. "title": "test issue",
  2367. "user": {
  2368. "fullname": "PY C",
  2369. "name": "pingou"
  2370. }
  2371. }
  2372. ],
  2373. 'pagination': {
  2374. u'first': u'http://localhost...',
  2375. u'last': u'http://localhost...',
  2376. u'next': None,
  2377. u'page': 1,
  2378. u'pages': 1,
  2379. u'per_page': 20,
  2380. u'prev': None
  2381. },
  2382. "total_issues": 2
  2383. }
  2384. )
  2385. # Access issues authenticated but non-existing token
  2386. headers = {'Authorization': 'token aaabbbccc'}
  2387. output = self.app.get('/api/0/test4/issues', headers=headers)
  2388. self.assertEqual(output.status_code, 401)
  2389. headers = {'Authorization': 'token aaabbbcccddd'}
  2390. # Access issues authenticated correctly
  2391. output = self.app.get('/api/0/test4/issues', headers=headers)
  2392. self.assertEqual(output.status_code, 200)
  2393. data = json.loads(output.get_data(as_text=True))
  2394. data['issues'][0]['date_created'] = '1431414800'
  2395. data['issues'][0]['last_updated'] = '1431414800'
  2396. data['issues'][1]['date_created'] = '1431414800'
  2397. data['issues'][1]['last_updated'] = '1431414800'
  2398. for k in ['first', 'last']:
  2399. self.assertIsNotNone(data['pagination'][k])
  2400. data['pagination'][k] = 'http://localhost...'
  2401. self.assertDictEqual(
  2402. data,
  2403. {
  2404. "args": {
  2405. "assignee": None,
  2406. "author": None,
  2407. "milestones": [],
  2408. "no_stones": None,
  2409. "order": None,
  2410. "priority": None,
  2411. "status": None,
  2412. "since": None,
  2413. "tags": []
  2414. },
  2415. "issues": [
  2416. {
  2417. "assignee": None,
  2418. "blocks": [],
  2419. "close_status": None,
  2420. "closed_at": None,
  2421. "comments": [],
  2422. "content": "We should work on this",
  2423. "custom_fields": [],
  2424. "date_created": "1431414800",
  2425. "last_updated": "1431414800",
  2426. "depends": [],
  2427. "id": 2,
  2428. "milestone": None,
  2429. "priority": None,
  2430. "private": True,
  2431. "status": "Open",
  2432. "tags": [],
  2433. "title": "Test issue",
  2434. "user": {
  2435. "fullname": "PY C",
  2436. "name": "pingou"
  2437. }
  2438. },
  2439. {
  2440. "assignee": None,
  2441. "blocks": [],
  2442. "close_status": None,
  2443. "closed_at": None,
  2444. "comments": [],
  2445. "content": "This issue needs attention",
  2446. "custom_fields": [],
  2447. "date_created": "1431414800",
  2448. "last_updated": "1431414800",
  2449. "depends": [],
  2450. "id": 1,
  2451. "milestone": None,
  2452. "priority": None,
  2453. "private": False,
  2454. "status": "Open",
  2455. "tags": [],
  2456. "title": "test issue",
  2457. "user": {
  2458. "fullname": "PY C",
  2459. "name": "pingou"
  2460. }
  2461. }
  2462. ],
  2463. 'pagination': {
  2464. u'first': u'http://localhost...',
  2465. u'last': u'http://localhost...',
  2466. u'next': None,
  2467. u'page': 1,
  2468. u'pages': 1,
  2469. u'per_page': 20,
  2470. u'prev': None
  2471. },
  2472. "total_issues": 2
  2473. }
  2474. )
  2475. # List closed issue
  2476. output = self.app.get(
  2477. '/api/0/test4/issues?status=Closed', headers=headers)
  2478. self.assertEqual(output.status_code, 200)
  2479. data = json.loads(output.get_data(as_text=True))
  2480. for k in ['first', 'last']:
  2481. self.assertIsNotNone(data['pagination'][k])
  2482. data['pagination'][k] = 'http://localhost...'
  2483. self.assertDictEqual(
  2484. data,
  2485. {
  2486. "args": {
  2487. "assignee": None,
  2488. "author": None,
  2489. "milestones": [],
  2490. "no_stones": None,
  2491. "order": None,
  2492. "priority": None,
  2493. "status": "Closed",
  2494. "since": None,
  2495. "tags": []
  2496. },
  2497. "issues": [],
  2498. 'pagination': {
  2499. u'first': u'http://localhost...',
  2500. u'last': u'http://localhost...',
  2501. u'next': None,
  2502. u'page': 1,
  2503. u'pages': 0,
  2504. u'per_page': 20,
  2505. u'prev': None
  2506. },
  2507. "total_issues": 0,
  2508. }
  2509. )
  2510. # List closed issue
  2511. output = self.app.get(
  2512. '/api/0/test4/issues?status=Invalid', headers=headers)
  2513. self.assertEqual(output.status_code, 200)
  2514. data = json.loads(output.get_data(as_text=True))
  2515. for k in ['first', 'last']:
  2516. self.assertIsNotNone(data['pagination'][k])
  2517. data['pagination'][k] = 'http://localhost...'
  2518. self.assertDictEqual(
  2519. data,
  2520. {
  2521. "args": {
  2522. "assignee": None,
  2523. "author": None,
  2524. "milestones": [],
  2525. "no_stones": None,
  2526. "order": None,
  2527. "priority": None,
  2528. "status": "Invalid",
  2529. "since": None,
  2530. "tags": []
  2531. },
  2532. "issues": [],
  2533. 'pagination': {
  2534. u'first': u'http://localhost...',
  2535. u'last': u'http://localhost...',
  2536. u'next': None,
  2537. u'page': 1,
  2538. u'pages': 0,
  2539. u'per_page': 20,
  2540. u'prev': None
  2541. },
  2542. "total_issues": 0,
  2543. }
  2544. )
  2545. # List all issues
  2546. output = self.app.get(
  2547. '/api/0/test4/issues?status=All', headers=headers)
  2548. self.assertEqual(output.status_code, 200)
  2549. data = json.loads(output.get_data(as_text=True))
  2550. data['issues'][0]['date_created'] = '1431414800'
  2551. data['issues'][0]['last_updated'] = '1431414800'
  2552. data['issues'][1]['date_created'] = '1431414800'
  2553. data['issues'][1]['last_updated'] = '1431414800'
  2554. for k in ['first', 'last']:
  2555. self.assertIsNotNone(data['pagination'][k])
  2556. data['pagination'][k] = 'http://localhost...'
  2557. self.assertDictEqual(
  2558. data,
  2559. {
  2560. "args": {
  2561. "assignee": None,
  2562. "author": None,
  2563. "milestones": [],
  2564. "no_stones": None,
  2565. "order": None,
  2566. "priority": None,
  2567. "since": None,
  2568. "status": "All",
  2569. "tags": []
  2570. },
  2571. "issues": [
  2572. {
  2573. "assignee": None,
  2574. "blocks": [],
  2575. "close_status": None,
  2576. "closed_at": None,
  2577. "comments": [],
  2578. "content": "We should work on this",
  2579. "custom_fields": [],
  2580. "date_created": "1431414800",
  2581. "last_updated": "1431414800",
  2582. "depends": [],
  2583. "id": 2,
  2584. "milestone": None,
  2585. "priority": None,
  2586. "private": True,
  2587. "status": "Open",
  2588. "tags": [],
  2589. "title": "Test issue",
  2590. "user": {
  2591. "fullname": "PY C",
  2592. "name": "pingou"
  2593. }
  2594. },
  2595. {
  2596. "assignee": None,
  2597. "blocks": [],
  2598. "close_status": None,
  2599. "closed_at": None,
  2600. "comments": [],
  2601. "content": "This issue needs attention",
  2602. "custom_fields": [],
  2603. "date_created": "1431414800",
  2604. "last_updated": "1431414800",
  2605. "depends": [],
  2606. "id": 1,
  2607. "milestone": None,
  2608. "priority": None,
  2609. "private": False,
  2610. "status": "Open",
  2611. "tags": [],
  2612. "title": "test issue",
  2613. "user": {
  2614. "fullname": "PY C",
  2615. "name": "pingou"
  2616. }
  2617. }
  2618. ],
  2619. 'pagination': {
  2620. u'first': u'http://localhost...',
  2621. u'last': u'http://localhost...',
  2622. u'next': None,
  2623. u'page': 1,
  2624. u'pages': 1,
  2625. u'per_page': 20,
  2626. u'prev': None
  2627. },
  2628. "total_issues": 2
  2629. }
  2630. )
  2631. def test_api_pivate_repo_view_issue(self):
  2632. """ Test the api_view_issue method of the flask api. """
  2633. self.test_api_private_repo_new_issue()
  2634. # Invalid repo
  2635. output = self.app.get('/api/0/foo/issue/1')
  2636. self.assertEqual(output.status_code, 404)
  2637. data = json.loads(output.get_data(as_text=True))
  2638. self.assertDictEqual(
  2639. data,
  2640. {
  2641. "error": "Project not found",
  2642. "error_code": "ENOPROJECT",
  2643. }
  2644. )
  2645. # Invalid issue for this repo
  2646. output = self.app.get('/api/0/test4/issue/1')
  2647. self.assertEqual(output.status_code, 404)
  2648. data = json.loads(output.get_data(as_text=True))
  2649. self.assertDictEqual(
  2650. data,
  2651. {
  2652. "error": "Project not found",
  2653. "error_code": "ENOPROJECT",
  2654. }
  2655. )
  2656. # Un-authorized user
  2657. user = tests.FakeUser()
  2658. with tests.user_set(self.app.application, user):
  2659. output = self.app.get('/api/0/test4/issue/1')
  2660. self.assertEqual(output.status_code, 404)
  2661. data = json.loads(output.get_data(as_text=True))
  2662. self.assertDictEqual(
  2663. data,
  2664. {
  2665. "error": "Project not found",
  2666. "error_code": "ENOPROJECT",
  2667. }
  2668. )
  2669. # Valid issue
  2670. user = tests.FakeUser(username='pingou')
  2671. with tests.user_set(self.app.application, user):
  2672. output = self.app.get('/api/0/test4/issue/1')
  2673. self.assertEqual(output.status_code, 200)
  2674. data = json.loads(output.get_data(as_text=True))
  2675. data['date_created'] = '1431414800'
  2676. data['last_updated'] = '1431414800'
  2677. self.assertDictEqual(
  2678. data,
  2679. {
  2680. "assignee": None,
  2681. "blocks": [],
  2682. "close_status": None,
  2683. "closed_at": None,
  2684. "comments": [],
  2685. "content": "This issue needs attention",
  2686. "custom_fields": [],
  2687. "date_created": "1431414800",
  2688. "depends": [],
  2689. "id": 1,
  2690. "last_updated": "1431414800",
  2691. "milestone": None,
  2692. "priority": None,
  2693. "private": False,
  2694. "status": "Open",
  2695. "tags": [],
  2696. "title": "test issue",
  2697. "user": {
  2698. "fullname": "PY C",
  2699. "name": "pingou"
  2700. }
  2701. }
  2702. )
  2703. headers = {'Authorization': 'token aaabbbccc'}
  2704. # Access issue authenticated but non-existing token
  2705. output = self.app.get('/api/0/test4/issue/1', headers=headers)
  2706. self.assertEqual(output.status_code, 401)
  2707. data = json.loads(output.get_data(as_text=True))
  2708. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2709. self.assertEqual(
  2710. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2711. self.assertEqual(
  2712. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2713. headers = {'Authorization': 'token aaabbbcccddd'}
  2714. # Access issue authenticated correctly
  2715. output = self.app.get('/api/0/test4/issue/1', headers=headers)
  2716. self.assertEqual(output.status_code, 200)
  2717. data = json.loads(output.get_data(as_text=True))
  2718. data['date_created'] = '1431414800'
  2719. data['last_updated'] = '1431414800'
  2720. self.assertDictEqual(
  2721. data,
  2722. {
  2723. "assignee": None,
  2724. "blocks": [],
  2725. "close_status": None,
  2726. "closed_at": None,
  2727. "comments": [],
  2728. "content": "This issue needs attention",
  2729. "custom_fields": [],
  2730. "date_created": "1431414800",
  2731. "depends": [],
  2732. "id": 1,
  2733. "last_updated": "1431414800",
  2734. "milestone": None,
  2735. "priority": None,
  2736. "private": False,
  2737. "status": "Open",
  2738. "tags": [],
  2739. "title": "test issue",
  2740. "user": {
  2741. "fullname": "PY C",
  2742. "name": "pingou"
  2743. }
  2744. }
  2745. )
  2746. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2747. def test_api_private_repo_change_status_issue(self):
  2748. """ Test the api_change_status_issue method of the flask api. """
  2749. item = pagure.lib.model.Project(
  2750. user_id=1, # pingou
  2751. name='test4',
  2752. description='test project description',
  2753. hook_token='aaabbbeeeceee',
  2754. private=True,
  2755. )
  2756. item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
  2757. self.session.add(item)
  2758. self.session.commit()
  2759. for repo in ['GIT_FOLDER', 'TICKETS_FOLDER']:
  2760. # Add a git repo
  2761. repo_path = os.path.join(
  2762. pagure.config.config.get(repo), 'test4.git')
  2763. if not os.path.exists(repo_path):
  2764. os.makedirs(repo_path)
  2765. pygit2.init_repository(repo_path, bare=True)
  2766. tests.create_tokens(self.session)
  2767. tests.create_tokens_acl(self.session)
  2768. headers = {'Authorization': 'token aaabbbcccddd'}
  2769. # Invalid project
  2770. output = self.app.post('/api/0/foo/issue/1/status', headers=headers)
  2771. self.assertEqual(output.status_code, 404)
  2772. data = json.loads(output.get_data(as_text=True))
  2773. self.assertDictEqual(
  2774. data,
  2775. {
  2776. "error": "Project not found",
  2777. "error_code": "ENOPROJECT",
  2778. }
  2779. )
  2780. # Valid token, wrong project
  2781. user = tests.FakeUser(username='pingou')
  2782. with tests.user_set(self.app.application, user):
  2783. output = self.app.post(
  2784. '/api/0/test2/issue/1/status', headers=headers)
  2785. self.assertEqual(output.status_code, 404)
  2786. data = json.loads(output.get_data(as_text=True))
  2787. self.assertDictEqual(
  2788. data,
  2789. {
  2790. "error": "Project not found",
  2791. "error_code": "ENOPROJECT",
  2792. }
  2793. )
  2794. # No input
  2795. output = self.app.post('/api/0/test4/issue/1/status', headers=headers)
  2796. self.assertEqual(output.status_code, 404)
  2797. data = json.loads(output.get_data(as_text=True))
  2798. self.assertDictEqual(
  2799. data,
  2800. {
  2801. "error": "Issue not found",
  2802. "error_code": "ENOISSUE",
  2803. }
  2804. )
  2805. # Create normal issue
  2806. repo = pagure.lib._get_project(self.session, 'test4')
  2807. msg = pagure.lib.new_issue(
  2808. session=self.session,
  2809. repo=repo,
  2810. title='Test issue #1',
  2811. content='We should work on this',
  2812. user='pingou',
  2813. private=False,
  2814. )
  2815. self.session.commit()
  2816. self.assertEqual(msg.title, 'Test issue #1')
  2817. # Check status before
  2818. repo = pagure.lib._get_project(self.session, 'test4')
  2819. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2820. self.assertEqual(issue.status, 'Open')
  2821. data = {
  2822. 'title': 'test issue',
  2823. }
  2824. user = tests.FakeUser(username='pingou')
  2825. with tests.user_set(self.app.application, user):
  2826. # Incomplete request
  2827. output = self.app.post(
  2828. '/api/0/test4/issue/1/status', data=data, headers=headers)
  2829. self.assertEqual(output.status_code, 400)
  2830. data = json.loads(output.get_data(as_text=True))
  2831. self.assertDictEqual(
  2832. data,
  2833. {
  2834. "error": "Invalid or incomplete input submitted",
  2835. "error_code": "EINVALIDREQ",
  2836. "errors": {"status": ["Not a valid choice"]}
  2837. }
  2838. )
  2839. # No change
  2840. repo = pagure.lib._get_project(self.session, 'test4')
  2841. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2842. self.assertEqual(issue.status, 'Open')
  2843. data = {
  2844. 'status': 'Open',
  2845. }
  2846. # Valid request but no change
  2847. output = self.app.post(
  2848. '/api/0/test4/issue/1/status', data=data, headers=headers)
  2849. self.assertEqual(output.status_code, 200)
  2850. data = json.loads(output.get_data(as_text=True))
  2851. self.assertDictEqual(
  2852. data,
  2853. {'message': 'No changes'}
  2854. )
  2855. # No change
  2856. repo = pagure.lib._get_project(self.session, 'test4')
  2857. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2858. self.assertEqual(issue.status, 'Open')
  2859. data = {
  2860. 'status': 'Fixed',
  2861. }
  2862. # Valid request
  2863. output = self.app.post(
  2864. '/api/0/test4/issue/1/status', data=data, headers=headers)
  2865. self.assertEqual(output.status_code, 200)
  2866. data = json.loads(output.get_data(as_text=True))
  2867. self.assertDictEqual(
  2868. data,
  2869. {'message':[
  2870. 'Issue status updated to: Closed (was: Open)',
  2871. 'Issue close_status updated to: Fixed'
  2872. ]}
  2873. )
  2874. @patch('pagure.lib.git.update_git')
  2875. @patch('pagure.lib.notify.send_email')
  2876. def test_api_private_repo_comment_issue(self, p_send_email, p_ugt):
  2877. """ Test the api_comment_issue method of the flask api. """
  2878. p_send_email.return_value = True
  2879. p_ugt.return_value = True
  2880. item = pagure.lib.model.Project(
  2881. user_id=1, # pingou
  2882. name='test4',
  2883. description='test project description',
  2884. hook_token='aaabbbeeeceee',
  2885. private=True,
  2886. )
  2887. self.session.add(item)
  2888. self.session.commit()
  2889. tests.create_tokens(self.session)
  2890. tests.create_tokens_acl(self.session)
  2891. headers = {'Authorization': 'token aaabbbcccddd'}
  2892. # Invalid project
  2893. output = self.app.post('/api/0/foo/issue/1/comment', headers=headers)
  2894. self.assertEqual(output.status_code, 404)
  2895. data = json.loads(output.get_data(as_text=True))
  2896. self.assertDictEqual(
  2897. data,
  2898. {
  2899. "error": "Project not found",
  2900. "error_code": "ENOPROJECT",
  2901. }
  2902. )
  2903. # Invalid token, right project
  2904. headers = {'Authorization': 'token aaabbbccc'}
  2905. output = self.app.post('/api/0/test4/issue/1/comment', headers=headers)
  2906. self.assertEqual(output.status_code, 401)
  2907. data = json.loads(output.get_data(as_text=True))
  2908. self.assertEqual(sorted(data.keys()), ['error', 'error_code'])
  2909. self.assertEqual(
  2910. pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
  2911. self.assertEqual(
  2912. pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
  2913. headers = {'Authorization': 'token aaabbbcccddd'}
  2914. # No input
  2915. output = self.app.post('/api/0/test4/issue/1/comment', headers=headers)
  2916. self.assertEqual(output.status_code, 404)
  2917. data = json.loads(output.get_data(as_text=True))
  2918. self.assertDictEqual(
  2919. data,
  2920. {
  2921. "error": "Issue not found",
  2922. "error_code": "ENOISSUE",
  2923. }
  2924. )
  2925. # Create normal issue
  2926. repo = pagure.lib._get_project(self.session, 'test4')
  2927. msg = pagure.lib.new_issue(
  2928. session=self.session,
  2929. repo=repo,
  2930. title='Test issue #1',
  2931. content='We should work on this',
  2932. user='pingou',
  2933. private=False,
  2934. issue_uid='aaabbbccc1',
  2935. )
  2936. self.session.commit()
  2937. self.assertEqual(msg.title, 'Test issue #1')
  2938. # Check comments before
  2939. self.session.commit()
  2940. repo = pagure.lib._get_project(self.session, 'test4')
  2941. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2942. self.assertEqual(len(issue.comments), 0)
  2943. data = {
  2944. 'title': 'test issue',
  2945. }
  2946. # Incomplete request
  2947. output = self.app.post(
  2948. '/api/0/test4/issue/1/comment', data=data, headers=headers)
  2949. self.assertEqual(output.status_code, 400)
  2950. data = json.loads(output.get_data(as_text=True))
  2951. self.assertDictEqual(
  2952. data,
  2953. {
  2954. "error": "Invalid or incomplete input submitted",
  2955. "error_code": "EINVALIDREQ",
  2956. "errors": {"comment": ["This field is required."]}
  2957. }
  2958. )
  2959. # No change
  2960. self.session.commit()
  2961. repo = pagure.lib._get_project(self.session, 'test4')
  2962. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2963. self.assertEqual(issue.status, 'Open')
  2964. data = {
  2965. 'comment': 'This is a very interesting question',
  2966. }
  2967. # Valid request
  2968. output = self.app.post(
  2969. '/api/0/test4/issue/1/comment', data=data, headers=headers)
  2970. self.assertEqual(output.status_code, 200)
  2971. data = json.loads(output.get_data(as_text=True))
  2972. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  2973. self.assertDictEqual(
  2974. data,
  2975. {'message': 'Comment added',
  2976. 'avatar_url': 'https://seccdn.libravatar.org/avatar/...',
  2977. 'user': 'pingou'}
  2978. )
  2979. # One comment added
  2980. self.session.commit()
  2981. repo = pagure.lib._get_project(self.session, 'test4')
  2982. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2983. self.assertEqual(len(issue.comments), 1)
  2984. @patch('pagure.lib.git.update_git')
  2985. @patch('pagure.lib.notify.send_email')
  2986. def test_api_view_issue_comment(self, p_send_email, p_ugt):
  2987. """ Test the api_view_issue_comment endpoint. """
  2988. p_send_email.return_value = True
  2989. p_ugt.return_value = True
  2990. self.test_api_private_repo_comment_issue()
  2991. # View a comment that does not exist
  2992. output = self.app.get('/api/0/foo/issue/100/comment/2')
  2993. self.assertEqual(output.status_code, 404)
  2994. # Issue exists but not the comment
  2995. output = self.app.get('/api/0/test/issue/1/comment/2')
  2996. self.assertEqual(output.status_code, 404)
  2997. # Issue and comment exists
  2998. output = self.app.get('/api/0/test/issue/1/comment/1')
  2999. self.assertEqual(output.status_code, 404)
  3000. user = tests.FakeUser(username='pingou')
  3001. with tests.user_set(self.app.application, user):
  3002. output = self.app.get('/api/0/test4/issue/1/comment/1')
  3003. self.assertEqual(output.status_code, 200)
  3004. data = json.loads(output.get_data(as_text=True))
  3005. data['date_created'] = '1435821770'
  3006. data["comment_date"] = "2015-07-02 09:22"
  3007. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  3008. self.assertDictEqual(
  3009. data,
  3010. {
  3011. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  3012. "comment": "This is a very interesting question",
  3013. "comment_date": "2015-07-02 09:22",
  3014. "notification": False,
  3015. "date_created": "1435821770",
  3016. "edited_on": None,
  3017. "editor": None,
  3018. "id": 1,
  3019. "parent": None,
  3020. "reactions": {},
  3021. "user": {
  3022. "fullname": "PY C",
  3023. "name": "pingou"
  3024. }
  3025. }
  3026. )
  3027. # Issue and comment exists, using UID
  3028. output = self.app.get('/api/0/test4/issue/aaabbbccc1/comment/1')
  3029. self.assertEqual(output.status_code, 200)
  3030. data = json.loads(output.get_data(as_text=True))
  3031. data['date_created'] = '1435821770'
  3032. data["comment_date"] = "2015-07-02 09:22"
  3033. data["avatar_url"] = "https://seccdn.libravatar.org/avatar/..."
  3034. self.assertDictEqual(
  3035. data,
  3036. {
  3037. "avatar_url": "https://seccdn.libravatar.org/avatar/...",
  3038. "comment": "This is a very interesting question",
  3039. "comment_date": "2015-07-02 09:22",
  3040. "notification": False,
  3041. "date_created": "1435821770",
  3042. "edited_on": None,
  3043. "editor": None,
  3044. "id": 1,
  3045. "parent": None,
  3046. "reactions": {},
  3047. "user": {
  3048. "fullname": "PY C",
  3049. "name": "pingou"
  3050. }
  3051. }
  3052. )
  3053. if __name__ == '__main__':
  3054. unittest.main(verbosity=2)