test_pagure_flask_api_ui_private_repo.py 119 KB

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