test_pagure_flask_api_ui_private_repo.py 119 KB

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