test_pagure_flask_api_ui_private_repo.py 118 KB

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