1
0

test_pagure_flask_api_project.py 155 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. Karsten Hopp <karsten@redhat.com>
  7. """
  8. from __future__ import unicode_literals, absolute_import
  9. import datetime
  10. import json
  11. import unittest
  12. import shutil
  13. import sys
  14. import tempfile
  15. import os
  16. import pygit2
  17. from celery.result import EagerResult
  18. from mock import patch, Mock
  19. sys.path.insert(
  20. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  21. )
  22. import pagure.flask_app
  23. import pagure.lib.query
  24. import tests
  25. from pagure.lib.repo import PagureRepo
  26. class PagureFlaskApiProjecttests(tests.Modeltests):
  27. """ Tests for the flask API of pagure for issue """
  28. def setUp(self):
  29. super(PagureFlaskApiProjecttests, self).setUp()
  30. self.gga_patcher = patch(
  31. "pagure.lib.tasks.generate_gitolite_acls.delay"
  32. )
  33. self.mock_gen_acls = self.gga_patcher.start()
  34. task_result = EagerResult("abc-1234", True, "SUCCESS")
  35. self.mock_gen_acls.return_value = task_result
  36. def tearDown(self):
  37. self.gga_patcher.stop()
  38. super(PagureFlaskApiProjecttests, self).tearDown()
  39. def test_api_git_tags(self):
  40. """ Test the api_git_tags method of the flask api. """
  41. tests.create_projects(self.session)
  42. # Create a git repo to play with
  43. gitrepo = os.path.join(self.path, "repos", "test.git")
  44. repo = pygit2.init_repository(gitrepo, bare=True)
  45. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  46. repopath = os.path.join(newpath, "test")
  47. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  48. # Create a file in that git repo
  49. with open(os.path.join(repopath, "sources"), "w") as stream:
  50. stream.write("foo\n bar")
  51. clone_repo.index.add("sources")
  52. clone_repo.index.write()
  53. # Commits the files added
  54. tree = clone_repo.index.write_tree()
  55. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  56. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  57. clone_repo.create_commit(
  58. "refs/heads/master", # the name of the reference to update
  59. author,
  60. committer,
  61. "Add sources file for testing",
  62. # binary string representing the tree object ID
  63. tree,
  64. # list of binary strings representing parents of the new commit
  65. [],
  66. )
  67. refname = "refs/heads/master:refs/heads/master"
  68. ori_remote = clone_repo.remotes[0]
  69. PagureRepo.push(ori_remote, refname)
  70. # Tag our first commit
  71. first_commit = repo.revparse_single("HEAD")
  72. tagger = pygit2.Signature("Alice Doe", "adoe@example.com", 12347, 0)
  73. repo.create_tag(
  74. "0.0.1",
  75. first_commit.oid.hex,
  76. pygit2.GIT_OBJ_COMMIT,
  77. tagger,
  78. "Release 0.0.1",
  79. )
  80. # Check tags
  81. output = self.app.get("/api/0/test/git/tags")
  82. self.assertEqual(output.status_code, 200)
  83. data = json.loads(output.get_data(as_text=True))
  84. self.assertDictEqual(data, {"tags": ["0.0.1"], "total_tags": 1})
  85. # Check tags with commits
  86. output = self.app.get("/api/0/test/git/tags?with_commits=True")
  87. self.assertEqual(output.status_code, 200)
  88. data = json.loads(output.get_data(as_text=True))
  89. data["tags"]["0.0.1"] = "bb8fa2aa199da08d6085e1c9badc3d83d188d38c"
  90. self.assertDictEqual(
  91. data,
  92. {
  93. "tags": {"0.0.1": "bb8fa2aa199da08d6085e1c9badc3d83d188d38c"},
  94. "total_tags": 1,
  95. },
  96. )
  97. shutil.rmtree(newpath)
  98. def test_api_git_branches(self):
  99. """ Test the api_git_branches method of the flask api. """
  100. # Create a git repo to add branches to
  101. tests.create_projects(self.session)
  102. repo_path = os.path.join(self.path, "repos", "test.git")
  103. tests.add_content_git_repo(repo_path)
  104. new_repo_path = tempfile.mkdtemp(prefix="pagure-api-git-branches-test")
  105. clone_repo = pygit2.clone_repository(repo_path, new_repo_path)
  106. # Create two other branches based on master
  107. for branch in ["pats-win-49", "pats-win-51"]:
  108. clone_repo.create_branch(branch, clone_repo.head.peel())
  109. refname = "refs/heads/{0}:refs/heads/{0}".format(branch)
  110. PagureRepo.push(clone_repo.remotes[0], refname)
  111. # Check that the branches show up on the API
  112. output = self.app.get("/api/0/test/git/branches")
  113. # Delete the cloned git repo after the API call
  114. shutil.rmtree(new_repo_path)
  115. # Verify the API data
  116. self.assertEqual(output.status_code, 200)
  117. data = json.loads(output.get_data(as_text=True))
  118. self.assertDictEqual(
  119. data,
  120. {
  121. "branches": ["master", "pats-win-49", "pats-win-51"],
  122. "total_branches": 3,
  123. },
  124. )
  125. def test_api_git_branches_empty_repo(self):
  126. """ Test the api_git_branches method of the flask api when the repo is
  127. empty.
  128. """
  129. # Create a git repo without any branches
  130. tests.create_projects(self.session)
  131. repo_base_path = os.path.join(self.path, "repos")
  132. tests.create_projects_git(repo_base_path)
  133. # Check that no branches show up on the API
  134. output = self.app.get("/api/0/test/git/branches")
  135. self.assertEqual(output.status_code, 200)
  136. data = json.loads(output.get_data(as_text=True))
  137. self.assertDictEqual(data, {"branches": [], "total_branches": 0})
  138. def test_api_git_branches_no_repo(self):
  139. """ Test the api_git_branches method of the flask api when there is no
  140. repo on a project.
  141. """
  142. tests.create_projects(self.session)
  143. output = self.app.get("/api/0/test/git/branches")
  144. self.assertEqual(output.status_code, 404)
  145. def test_api_git_urls(self):
  146. """ Test the api_project_git_urls method of the flask api.
  147. """
  148. tests.create_projects(self.session)
  149. output = self.app.get("/api/0/test/git/urls")
  150. self.assertEqual(output.status_code, 200)
  151. expected_rv = {
  152. "urls": {
  153. "git": "git://localhost.localdomain/test.git",
  154. "ssh": "ssh://git@localhost.localdomain/test.git",
  155. },
  156. "total_urls": 2,
  157. }
  158. data = json.loads(output.get_data(as_text=True))
  159. self.assertDictEqual(data, expected_rv)
  160. def test_api_git_urls_no_project(self):
  161. """ Test the api_project_git_urls method of the flask api when there is
  162. no project.
  163. """
  164. output = self.app.get("/api/0/test1234/git/urls")
  165. self.assertEqual(output.status_code, 404)
  166. expected_rv = {
  167. "error": "Project not found",
  168. "error_code": "ENOPROJECT",
  169. }
  170. data = json.loads(output.get_data(as_text=True))
  171. self.assertDictEqual(data, expected_rv)
  172. @patch.dict("pagure.config.config", {"PRIVATE_PROJECTS": True})
  173. def test_api_git_urls_private_project(self):
  174. """ Test the api_project_git_urls method of the flask api when the
  175. project is private.
  176. """
  177. tests.create_projects(self.session)
  178. tests.create_tokens(self.session)
  179. tests.create_tokens_acl(self.session, "aaabbbcccddd")
  180. headers = {"Authorization": "token aaabbbcccddd"}
  181. test_project = pagure.lib.query._get_project(self.session, "test")
  182. test_project.private = True
  183. self.session.add(test_project)
  184. self.session.commit()
  185. output = self.app.get("/api/0/test/git/urls", headers=headers)
  186. self.assertEqual(output.status_code, 200)
  187. expected_rv = {
  188. "urls": {
  189. "git": "git://localhost.localdomain/test.git",
  190. "ssh": "ssh://git@localhost.localdomain/test.git",
  191. },
  192. "total_urls": 2,
  193. }
  194. data = json.loads(output.get_data(as_text=True))
  195. self.assertDictEqual(data, expected_rv)
  196. @patch.dict("pagure.config.config", {"PRIVATE_PROJECTS": True})
  197. def test_api_git_urls_private_project_no_login(self):
  198. """ Test the api_project_git_urls method of the flask api when the
  199. project is private and the user is not logged in.
  200. """
  201. tests.create_projects(self.session)
  202. test_project = pagure.lib.query._get_project(self.session, "test")
  203. test_project.private = True
  204. self.session.add(test_project)
  205. self.session.commit()
  206. output = self.app.get("/api/0/test/git/urls")
  207. self.assertEqual(output.status_code, 404)
  208. expected_rv = {
  209. "error": "Project not found",
  210. "error_code": "ENOPROJECT",
  211. }
  212. data = json.loads(output.get_data(as_text=True))
  213. self.assertDictEqual(data, expected_rv)
  214. def test_api_projects_pattern(self):
  215. """ Test the api_projects method of the flask api. """
  216. tests.create_projects(self.session)
  217. output = self.app.get("/api/0/projects?pattern=test")
  218. self.assertEqual(output.status_code, 200)
  219. data = json.loads(output.get_data(as_text=True))
  220. data["projects"][0]["date_created"] = "1436527638"
  221. data["projects"][0]["date_modified"] = "1436527638"
  222. del data["pagination"]
  223. expected_data = {
  224. "args": {
  225. "fork": None,
  226. "namespace": None,
  227. "owner": None,
  228. "page": 1,
  229. "pattern": "test",
  230. "per_page": 20,
  231. "short": False,
  232. "tags": [],
  233. "username": None,
  234. },
  235. "projects": [
  236. {
  237. "access_groups": {"admin": [], "commit": [], "ticket": []},
  238. "access_users": {
  239. "admin": [],
  240. "commit": [],
  241. "owner": ["pingou"],
  242. "ticket": [],
  243. },
  244. "close_status": [
  245. "Invalid",
  246. "Insufficient data",
  247. "Fixed",
  248. "Duplicate",
  249. ],
  250. "custom_keys": [],
  251. "date_created": "1436527638",
  252. "date_modified": "1436527638",
  253. "description": "test project #1",
  254. "fullname": "test",
  255. "url_path": "test",
  256. "id": 1,
  257. "milestones": {},
  258. "name": "test",
  259. "namespace": None,
  260. "parent": None,
  261. "priorities": {},
  262. "tags": [],
  263. "user": {"fullname": "PY C", "name": "pingou"},
  264. }
  265. ],
  266. "total_projects": 1,
  267. }
  268. self.assertDictEqual(data, expected_data)
  269. def test_api_projects_pattern_short(self):
  270. """ Test the api_projects method of the flask api. """
  271. tests.create_projects(self.session)
  272. output = self.app.get("/api/0/projects?pattern=te*&short=1")
  273. self.assertEqual(output.status_code, 200)
  274. data = json.loads(output.get_data(as_text=True))
  275. del data["pagination"]
  276. expected_data = {
  277. "args": {
  278. "fork": None,
  279. "namespace": None,
  280. "owner": None,
  281. "page": 1,
  282. "pattern": "te*",
  283. "per_page": 20,
  284. "short": True,
  285. "tags": [],
  286. "username": None,
  287. },
  288. "projects": [
  289. {
  290. "description": "test project #1",
  291. "fullname": "test",
  292. "name": "test",
  293. "namespace": None,
  294. },
  295. {
  296. "description": "test project #2",
  297. "fullname": "test2",
  298. "name": "test2",
  299. "namespace": None,
  300. },
  301. {
  302. "description": "namespaced test project",
  303. "fullname": "somenamespace/test3",
  304. "name": "test3",
  305. "namespace": "somenamespace",
  306. },
  307. ],
  308. "total_projects": 3,
  309. }
  310. self.maxDiff = None
  311. self.assertDictEqual(data, expected_data)
  312. def test_api_projects_owner(self):
  313. """ Test the api_projects method of the flask api. """
  314. tests.create_projects(self.session)
  315. output = self.app.get("/api/0/projects?owner=foo")
  316. self.assertEqual(output.status_code, 200)
  317. data = json.loads(output.get_data(as_text=True))
  318. del data["pagination"]
  319. expected_data = {
  320. "args": {
  321. "fork": None,
  322. "namespace": None,
  323. "owner": "foo",
  324. "page": 1,
  325. "pattern": None,
  326. "per_page": 20,
  327. "short": False,
  328. "tags": [],
  329. "username": None,
  330. },
  331. "projects": [],
  332. "total_projects": 0,
  333. }
  334. self.maxDiff = None
  335. self.assertDictEqual(data, expected_data)
  336. def test_api_projects_not_owner(self):
  337. """ Test the api_projects method of the flask api. """
  338. tests.create_projects(self.session)
  339. output = self.app.get("/api/0/projects?owner=!foo&short=1")
  340. self.assertEqual(output.status_code, 200)
  341. data = json.loads(output.get_data(as_text=True))
  342. del data["pagination"]
  343. expected_data = {
  344. "args": {
  345. "fork": None,
  346. "namespace": None,
  347. "owner": "!foo",
  348. "page": 1,
  349. "pattern": None,
  350. "per_page": 20,
  351. "short": True,
  352. "tags": [],
  353. "username": None,
  354. },
  355. "projects": [
  356. {
  357. "description": "test project #1",
  358. "fullname": "test",
  359. "name": "test",
  360. "namespace": None,
  361. },
  362. {
  363. "description": "test project #2",
  364. "fullname": "test2",
  365. "name": "test2",
  366. "namespace": None,
  367. },
  368. {
  369. "description": "namespaced test project",
  370. "fullname": "somenamespace/test3",
  371. "name": "test3",
  372. "namespace": "somenamespace",
  373. },
  374. ],
  375. "total_projects": 3,
  376. }
  377. self.maxDiff = None
  378. self.assertDictEqual(data, expected_data)
  379. def test_api_projects(self):
  380. """ Test the api_projects method of the flask api. """
  381. tests.create_projects(self.session)
  382. # Check before adding
  383. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  384. self.assertEqual(repo.tags, [])
  385. # Adding a tag
  386. output = pagure.lib.query.update_tags(
  387. self.session, repo, "infra", "pingou"
  388. )
  389. self.assertEqual(output, ["Project tagged with: infra"])
  390. # Check after adding
  391. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  392. self.assertEqual(len(repo.tags), 1)
  393. self.assertEqual(repo.tags_text, ["infra"])
  394. # Check the API
  395. output = self.app.get("/api/0/projects?tags=inf")
  396. self.assertEqual(output.status_code, 200)
  397. data = json.loads(output.get_data(as_text=True))
  398. null = None
  399. del data["pagination"]
  400. self.assertDictEqual(
  401. data,
  402. {
  403. "total_projects": 0,
  404. "projects": [],
  405. "args": {
  406. "fork": None,
  407. "namespace": None,
  408. "owner": None,
  409. "page": 1,
  410. "pattern": None,
  411. "per_page": 20,
  412. "short": False,
  413. "tags": ["inf"],
  414. "username": None,
  415. },
  416. },
  417. )
  418. output = self.app.get("/api/0/projects?tags=infra")
  419. self.assertEqual(output.status_code, 200)
  420. data = json.loads(output.get_data(as_text=True))
  421. data["projects"][0]["date_created"] = "1436527638"
  422. data["projects"][0]["date_modified"] = "1436527638"
  423. del data["pagination"]
  424. expected_data = {
  425. "args": {
  426. "fork": None,
  427. "namespace": None,
  428. "owner": None,
  429. "page": 1,
  430. "pattern": None,
  431. "per_page": 20,
  432. "short": False,
  433. "tags": ["infra"],
  434. "username": None,
  435. },
  436. "projects": [
  437. {
  438. "access_groups": {"admin": [], "commit": [], "ticket": []},
  439. "access_users": {
  440. "admin": [],
  441. "commit": [],
  442. "owner": ["pingou"],
  443. "ticket": [],
  444. },
  445. "close_status": [
  446. "Invalid",
  447. "Insufficient data",
  448. "Fixed",
  449. "Duplicate",
  450. ],
  451. "custom_keys": [],
  452. "date_created": "1436527638",
  453. "date_modified": "1436527638",
  454. "description": "test project #1",
  455. "fullname": "test",
  456. "url_path": "test",
  457. "id": 1,
  458. "milestones": {},
  459. "name": "test",
  460. "namespace": None,
  461. "parent": None,
  462. "priorities": {},
  463. "tags": ["infra"],
  464. "user": {"fullname": "PY C", "name": "pingou"},
  465. }
  466. ],
  467. "total_projects": 1,
  468. }
  469. self.assertDictEqual(data, expected_data)
  470. output = self.app.get("/api/0/projects?owner=pingou")
  471. self.assertEqual(output.status_code, 200)
  472. data = json.loads(output.get_data(as_text=True))
  473. data["projects"][0]["date_created"] = "1436527638"
  474. data["projects"][0]["date_modified"] = "1436527638"
  475. data["projects"][1]["date_created"] = "1436527638"
  476. data["projects"][1]["date_modified"] = "1436527638"
  477. data["projects"][2]["date_created"] = "1436527638"
  478. data["projects"][2]["date_modified"] = "1436527638"
  479. del data["pagination"]
  480. expected_data = {
  481. "args": {
  482. "fork": None,
  483. "namespace": None,
  484. "owner": "pingou",
  485. "page": 1,
  486. "pattern": None,
  487. "per_page": 20,
  488. "short": False,
  489. "tags": [],
  490. "username": None,
  491. },
  492. "projects": [
  493. {
  494. "access_groups": {"admin": [], "commit": [], "ticket": []},
  495. "access_users": {
  496. "admin": [],
  497. "commit": [],
  498. "owner": ["pingou"],
  499. "ticket": [],
  500. },
  501. "close_status": [
  502. "Invalid",
  503. "Insufficient data",
  504. "Fixed",
  505. "Duplicate",
  506. ],
  507. "custom_keys": [],
  508. "date_created": "1436527638",
  509. "date_modified": "1436527638",
  510. "description": "test project #1",
  511. "fullname": "test",
  512. "url_path": "test",
  513. "id": 1,
  514. "milestones": {},
  515. "name": "test",
  516. "namespace": None,
  517. "parent": None,
  518. "priorities": {},
  519. "tags": ["infra"],
  520. "user": {"fullname": "PY C", "name": "pingou"},
  521. },
  522. {
  523. "access_groups": {"admin": [], "commit": [], "ticket": []},
  524. "access_users": {
  525. "admin": [],
  526. "commit": [],
  527. "owner": ["pingou"],
  528. "ticket": [],
  529. },
  530. "close_status": [
  531. "Invalid",
  532. "Insufficient data",
  533. "Fixed",
  534. "Duplicate",
  535. ],
  536. "custom_keys": [],
  537. "date_created": "1436527638",
  538. "date_modified": "1436527638",
  539. "description": "test project #2",
  540. "fullname": "test2",
  541. "url_path": "test2",
  542. "id": 2,
  543. "milestones": {},
  544. "name": "test2",
  545. "namespace": None,
  546. "parent": None,
  547. "priorities": {},
  548. "tags": [],
  549. "user": {"fullname": "PY C", "name": "pingou"},
  550. },
  551. {
  552. "access_groups": {"admin": [], "commit": [], "ticket": []},
  553. "access_users": {
  554. "admin": [],
  555. "commit": [],
  556. "owner": ["pingou"],
  557. "ticket": [],
  558. },
  559. "close_status": [
  560. "Invalid",
  561. "Insufficient data",
  562. "Fixed",
  563. "Duplicate",
  564. ],
  565. "custom_keys": [],
  566. "date_created": "1436527638",
  567. "date_modified": "1436527638",
  568. "description": "namespaced test project",
  569. "fullname": "somenamespace/test3",
  570. "url_path": "somenamespace/test3",
  571. "id": 3,
  572. "milestones": {},
  573. "name": "test3",
  574. "namespace": "somenamespace",
  575. "parent": None,
  576. "priorities": {},
  577. "tags": [],
  578. "user": {"fullname": "PY C", "name": "pingou"},
  579. },
  580. ],
  581. "total_projects": 3,
  582. }
  583. self.assertDictEqual(data, expected_data)
  584. output = self.app.get("/api/0/projects?username=pingou")
  585. self.assertEqual(output.status_code, 200)
  586. data = json.loads(output.get_data(as_text=True))
  587. data["projects"][0]["date_created"] = "1436527638"
  588. data["projects"][0]["date_modified"] = "1436527638"
  589. data["projects"][1]["date_created"] = "1436527638"
  590. data["projects"][1]["date_modified"] = "1436527638"
  591. data["projects"][2]["date_created"] = "1436527638"
  592. data["projects"][2]["date_modified"] = "1436527638"
  593. del data["pagination"]
  594. expected_data = {
  595. "args": {
  596. "fork": None,
  597. "namespace": None,
  598. "owner": None,
  599. "page": 1,
  600. "pattern": None,
  601. "per_page": 20,
  602. "short": False,
  603. "tags": [],
  604. "username": "pingou",
  605. },
  606. "projects": [
  607. {
  608. "access_groups": {"admin": [], "commit": [], "ticket": []},
  609. "access_users": {
  610. "admin": [],
  611. "commit": [],
  612. "owner": ["pingou"],
  613. "ticket": [],
  614. },
  615. "close_status": [
  616. "Invalid",
  617. "Insufficient data",
  618. "Fixed",
  619. "Duplicate",
  620. ],
  621. "custom_keys": [],
  622. "date_created": "1436527638",
  623. "date_modified": "1436527638",
  624. "description": "test project #1",
  625. "fullname": "test",
  626. "url_path": "test",
  627. "id": 1,
  628. "milestones": {},
  629. "name": "test",
  630. "namespace": None,
  631. "parent": None,
  632. "priorities": {},
  633. "tags": ["infra"],
  634. "user": {"fullname": "PY C", "name": "pingou"},
  635. },
  636. {
  637. "access_groups": {"admin": [], "commit": [], "ticket": []},
  638. "access_users": {
  639. "admin": [],
  640. "commit": [],
  641. "owner": ["pingou"],
  642. "ticket": [],
  643. },
  644. "close_status": [
  645. "Invalid",
  646. "Insufficient data",
  647. "Fixed",
  648. "Duplicate",
  649. ],
  650. "custom_keys": [],
  651. "date_created": "1436527638",
  652. "date_modified": "1436527638",
  653. "description": "test project #2",
  654. "fullname": "test2",
  655. "url_path": "test2",
  656. "id": 2,
  657. "milestones": {},
  658. "name": "test2",
  659. "namespace": None,
  660. "parent": None,
  661. "priorities": {},
  662. "tags": [],
  663. "user": {"fullname": "PY C", "name": "pingou"},
  664. },
  665. {
  666. "access_groups": {"admin": [], "commit": [], "ticket": []},
  667. "access_users": {
  668. "admin": [],
  669. "commit": [],
  670. "owner": ["pingou"],
  671. "ticket": [],
  672. },
  673. "close_status": [
  674. "Invalid",
  675. "Insufficient data",
  676. "Fixed",
  677. "Duplicate",
  678. ],
  679. "custom_keys": [],
  680. "date_created": "1436527638",
  681. "date_modified": "1436527638",
  682. "description": "namespaced test project",
  683. "fullname": "somenamespace/test3",
  684. "url_path": "somenamespace/test3",
  685. "id": 3,
  686. "milestones": {},
  687. "name": "test3",
  688. "namespace": "somenamespace",
  689. "parent": None,
  690. "priorities": {},
  691. "tags": [],
  692. "user": {"fullname": "PY C", "name": "pingou"},
  693. },
  694. ],
  695. "total_projects": 3,
  696. }
  697. self.assertDictEqual(data, expected_data)
  698. output = self.app.get("/api/0/projects?username=pingou&tags=infra")
  699. self.assertEqual(output.status_code, 200)
  700. data = json.loads(output.get_data(as_text=True))
  701. data["projects"][0]["date_created"] = "1436527638"
  702. data["projects"][0]["date_modified"] = "1436527638"
  703. del data["pagination"]
  704. expected_data = {
  705. "args": {
  706. "fork": None,
  707. "namespace": None,
  708. "owner": None,
  709. "page": 1,
  710. "pattern": None,
  711. "per_page": 20,
  712. "short": False,
  713. "tags": ["infra"],
  714. "username": "pingou",
  715. },
  716. "projects": [
  717. {
  718. "access_groups": {"admin": [], "commit": [], "ticket": []},
  719. "access_users": {
  720. "admin": [],
  721. "commit": [],
  722. "owner": ["pingou"],
  723. "ticket": [],
  724. },
  725. "close_status": [
  726. "Invalid",
  727. "Insufficient data",
  728. "Fixed",
  729. "Duplicate",
  730. ],
  731. "custom_keys": [],
  732. "date_created": "1436527638",
  733. "date_modified": "1436527638",
  734. "description": "test project #1",
  735. "fullname": "test",
  736. "url_path": "test",
  737. "id": 1,
  738. "milestones": {},
  739. "name": "test",
  740. "namespace": None,
  741. "parent": None,
  742. "priorities": {},
  743. "tags": ["infra"],
  744. "user": {"fullname": "PY C", "name": "pingou"},
  745. }
  746. ],
  747. "total_projects": 1,
  748. }
  749. self.assertDictEqual(data, expected_data)
  750. output = self.app.get("/api/0/projects?namespace=somenamespace")
  751. self.assertEqual(output.status_code, 200)
  752. data = json.loads(output.get_data(as_text=True))
  753. data["projects"][0]["date_created"] = "1436527638"
  754. data["projects"][0]["date_modified"] = "1436527638"
  755. del data["pagination"]
  756. expected_data = {
  757. "args": {
  758. "fork": None,
  759. "owner": None,
  760. "page": 1,
  761. "namespace": "somenamespace",
  762. "per_page": 20,
  763. "pattern": None,
  764. "short": False,
  765. "tags": [],
  766. "username": None,
  767. },
  768. "projects": [
  769. {
  770. "access_groups": {"admin": [], "commit": [], "ticket": []},
  771. "access_users": {
  772. "admin": [],
  773. "commit": [],
  774. "owner": ["pingou"],
  775. "ticket": [],
  776. },
  777. "close_status": [
  778. "Invalid",
  779. "Insufficient data",
  780. "Fixed",
  781. "Duplicate",
  782. ],
  783. "custom_keys": [],
  784. "date_created": "1436527638",
  785. "date_modified": "1436527638",
  786. "description": "namespaced test project",
  787. "fullname": "somenamespace/test3",
  788. "url_path": "somenamespace/test3",
  789. "id": 3,
  790. "milestones": {},
  791. "name": "test3",
  792. "namespace": "somenamespace",
  793. "parent": None,
  794. "priorities": {},
  795. "tags": [],
  796. "user": {"fullname": "PY C", "name": "pingou"},
  797. }
  798. ],
  799. "total_projects": 1,
  800. }
  801. self.assertDictEqual(data, expected_data)
  802. def test_api_project(self):
  803. """ Test the api_project method of the flask api. """
  804. tests.create_projects(self.session)
  805. # Check before adding
  806. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  807. self.assertEqual(repo.tags, [])
  808. # Adding a tag
  809. output = pagure.lib.query.update_tags(
  810. self.session, repo, "infra", "pingou"
  811. )
  812. self.assertEqual(output, ["Project tagged with: infra"])
  813. # Check after adding
  814. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  815. self.assertEqual(len(repo.tags), 1)
  816. self.assertEqual(repo.tags_text, ["infra"])
  817. # Check the API
  818. # Non-existing project
  819. output = self.app.get("/api/0/random")
  820. self.assertEqual(output.status_code, 404)
  821. data = json.loads(output.get_data(as_text=True))
  822. self.assertDictEqual(
  823. data, {"error_code": "ENOPROJECT", "error": "Project not found"}
  824. )
  825. # Existing project
  826. output = self.app.get("/api/0/test")
  827. self.assertEqual(output.status_code, 200)
  828. data = json.loads(output.get_data(as_text=True))
  829. data["date_created"] = "1436527638"
  830. data["date_modified"] = "1436527638"
  831. expected_data = {
  832. "access_groups": {"admin": [], "commit": [], "ticket": []},
  833. "access_users": {
  834. "admin": [],
  835. "commit": [],
  836. "owner": ["pingou"],
  837. "ticket": [],
  838. },
  839. "close_status": [
  840. "Invalid",
  841. "Insufficient data",
  842. "Fixed",
  843. "Duplicate",
  844. ],
  845. "custom_keys": [],
  846. "date_created": "1436527638",
  847. "date_modified": "1436527638",
  848. "description": "test project #1",
  849. "fullname": "test",
  850. "url_path": "test",
  851. "id": 1,
  852. "milestones": {},
  853. "name": "test",
  854. "namespace": None,
  855. "parent": None,
  856. "priorities": {},
  857. "tags": ["infra"],
  858. "user": {"fullname": "PY C", "name": "pingou"},
  859. }
  860. self.assertDictEqual(data, expected_data)
  861. def test_api_project_group(self):
  862. """ Test the api_project method of the flask api. """
  863. tests.create_projects(self.session)
  864. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  865. # Adding a tag
  866. output = pagure.lib.query.update_tags(
  867. self.session, repo, "infra", "pingou"
  868. )
  869. self.assertEqual(output, ["Project tagged with: infra"])
  870. # Check after adding
  871. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  872. self.assertEqual(len(repo.tags), 1)
  873. self.assertEqual(repo.tags_text, ["infra"])
  874. # Add a group to the project
  875. msg = pagure.lib.query.add_group(
  876. self.session,
  877. group_name="some_group",
  878. display_name="Some Group",
  879. description=None,
  880. group_type="bar",
  881. user="foo",
  882. is_admin=False,
  883. blacklist=[],
  884. )
  885. self.session.commit()
  886. project = pagure.lib.query.get_authorized_project(self.session, "test")
  887. group = pagure.lib.query.search_groups(
  888. self.session, group_name="some_group"
  889. )
  890. pagure.lib.query.add_group_to_project(
  891. self.session,
  892. project,
  893. new_group="some_group",
  894. user="pingou",
  895. access="commit",
  896. create=False,
  897. is_admin=True,
  898. )
  899. self.session.commit()
  900. # Check the API
  901. # Existing project
  902. output = self.app.get("/api/0/test?expand_group=1")
  903. self.assertEqual(output.status_code, 200)
  904. data = json.loads(output.get_data(as_text=True))
  905. data["date_created"] = "1436527638"
  906. data["date_modified"] = "1436527638"
  907. expected_data = {
  908. "access_groups": {
  909. "admin": [],
  910. "commit": ["some_group"],
  911. "ticket": [],
  912. },
  913. "access_users": {
  914. "admin": [],
  915. "commit": [],
  916. "owner": ["pingou"],
  917. "ticket": [],
  918. },
  919. "close_status": [
  920. "Invalid",
  921. "Insufficient data",
  922. "Fixed",
  923. "Duplicate",
  924. ],
  925. "custom_keys": [],
  926. "date_created": "1436527638",
  927. "date_modified": "1436527638",
  928. "description": "test project #1",
  929. "fullname": "test",
  930. "url_path": "test",
  931. "group_details": {"some_group": ["foo"]},
  932. "id": 1,
  933. "milestones": {},
  934. "name": "test",
  935. "namespace": None,
  936. "parent": None,
  937. "priorities": {},
  938. "tags": ["infra"],
  939. "user": {"fullname": "PY C", "name": "pingou"},
  940. }
  941. self.assertDictEqual(data, expected_data)
  942. def test_api_project_group_but_no_group(self):
  943. """ Test the api_project method of the flask api when asking for
  944. group details while there are none associated.
  945. """
  946. tests.create_projects(self.session)
  947. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  948. # Adding a tag
  949. output = pagure.lib.query.update_tags(
  950. self.session, repo, "infra", "pingou"
  951. )
  952. self.assertEqual(output, ["Project tagged with: infra"])
  953. # Check after adding
  954. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  955. self.assertEqual(len(repo.tags), 1)
  956. self.assertEqual(repo.tags_text, ["infra"])
  957. # Check the API
  958. # Existing project
  959. output = self.app.get("/api/0/test?expand_group=0")
  960. self.assertEqual(output.status_code, 200)
  961. data = json.loads(output.get_data(as_text=True))
  962. data["date_created"] = "1436527638"
  963. data["date_modified"] = "1436527638"
  964. expected_data = {
  965. "access_groups": {"admin": [], "commit": [], "ticket": []},
  966. "access_users": {
  967. "admin": [],
  968. "commit": [],
  969. "owner": ["pingou"],
  970. "ticket": [],
  971. },
  972. "close_status": [
  973. "Invalid",
  974. "Insufficient data",
  975. "Fixed",
  976. "Duplicate",
  977. ],
  978. "custom_keys": [],
  979. "date_created": "1436527638",
  980. "date_modified": "1436527638",
  981. "description": "test project #1",
  982. "fullname": "test",
  983. "url_path": "test",
  984. "id": 1,
  985. "milestones": {},
  986. "name": "test",
  987. "namespace": None,
  988. "parent": None,
  989. "priorities": {},
  990. "tags": ["infra"],
  991. "user": {"fullname": "PY C", "name": "pingou"},
  992. }
  993. self.assertDictEqual(data, expected_data)
  994. def test_api_projects_pagination(self):
  995. """ Test the api_projects method of the flask api with pagination. """
  996. tests.create_projects(self.session)
  997. output = self.app.get("/api/0/projects?page=1")
  998. self.assertEqual(output.status_code, 200)
  999. data = json.loads(output.get_data(as_text=True))
  1000. for i in range(3):
  1001. data["projects"][i]["date_created"] = "1436527638"
  1002. data["projects"][i]["date_modified"] = "1436527638"
  1003. expected_data = {
  1004. "args": {
  1005. "fork": None,
  1006. "namespace": None,
  1007. "owner": None,
  1008. "page": 1,
  1009. "per_page": 20,
  1010. "pattern": None,
  1011. "short": False,
  1012. "tags": [],
  1013. "username": None,
  1014. },
  1015. "pagination": {
  1016. "next": None,
  1017. "page": 1,
  1018. "pages": 1,
  1019. "per_page": 20,
  1020. "prev": None,
  1021. },
  1022. "projects": [
  1023. {
  1024. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1025. "access_users": {
  1026. "admin": [],
  1027. "commit": [],
  1028. "owner": ["pingou"],
  1029. "ticket": [],
  1030. },
  1031. "close_status": [
  1032. "Invalid",
  1033. "Insufficient data",
  1034. "Fixed",
  1035. "Duplicate",
  1036. ],
  1037. "custom_keys": [],
  1038. "date_created": "1436527638",
  1039. "date_modified": "1436527638",
  1040. "description": "test project #1",
  1041. "fullname": "test",
  1042. "url_path": "test",
  1043. "id": 1,
  1044. "milestones": {},
  1045. "name": "test",
  1046. "namespace": None,
  1047. "parent": None,
  1048. "priorities": {},
  1049. "tags": [],
  1050. "user": {"fullname": "PY C", "name": "pingou"},
  1051. },
  1052. {
  1053. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1054. "access_users": {
  1055. "admin": [],
  1056. "commit": [],
  1057. "owner": ["pingou"],
  1058. "ticket": [],
  1059. },
  1060. "close_status": [
  1061. "Invalid",
  1062. "Insufficient data",
  1063. "Fixed",
  1064. "Duplicate",
  1065. ],
  1066. "custom_keys": [],
  1067. "date_created": "1436527638",
  1068. "date_modified": "1436527638",
  1069. "description": "test project #2",
  1070. "fullname": "test2",
  1071. "url_path": "test2",
  1072. "id": 2,
  1073. "milestones": {},
  1074. "name": "test2",
  1075. "namespace": None,
  1076. "parent": None,
  1077. "priorities": {},
  1078. "tags": [],
  1079. "user": {"fullname": "PY C", "name": "pingou"},
  1080. },
  1081. {
  1082. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1083. "access_users": {
  1084. "admin": [],
  1085. "commit": [],
  1086. "owner": ["pingou"],
  1087. "ticket": [],
  1088. },
  1089. "close_status": [
  1090. "Invalid",
  1091. "Insufficient data",
  1092. "Fixed",
  1093. "Duplicate",
  1094. ],
  1095. "custom_keys": [],
  1096. "date_created": "1436527638",
  1097. "date_modified": "1436527638",
  1098. "description": "namespaced test project",
  1099. "fullname": "somenamespace/test3",
  1100. "url_path": "somenamespace/test3",
  1101. "id": 3,
  1102. "milestones": {},
  1103. "name": "test3",
  1104. "namespace": "somenamespace",
  1105. "parent": None,
  1106. "priorities": {},
  1107. "tags": [],
  1108. "user": {"fullname": "PY C", "name": "pingou"},
  1109. },
  1110. ],
  1111. "total_projects": 3,
  1112. }
  1113. # Test URLs
  1114. self.assertURLEqual(
  1115. data["pagination"].pop("first"),
  1116. "http://localhost/api/0/projects?per_page=20&page=1",
  1117. )
  1118. self.assertURLEqual(
  1119. data["pagination"].pop("last"),
  1120. "http://localhost/api/0/projects?per_page=20&page=1",
  1121. )
  1122. self.assertDictEqual(data, expected_data)
  1123. def test_api_projects_pagination_per_page(self):
  1124. """ Test the api_projects method of the flask api with pagination and
  1125. the `per_page` argument set. """
  1126. tests.create_projects(self.session)
  1127. output = self.app.get("/api/0/projects?page=2&per_page=2")
  1128. self.assertEqual(output.status_code, 200)
  1129. data = json.loads(output.get_data(as_text=True))
  1130. data["projects"][0]["date_created"] = "1436527638"
  1131. data["projects"][0]["date_modified"] = "1436527638"
  1132. expected_data = {
  1133. "args": {
  1134. "fork": None,
  1135. "namespace": None,
  1136. "owner": None,
  1137. "page": 2,
  1138. "per_page": 2,
  1139. "pattern": None,
  1140. "short": False,
  1141. "tags": [],
  1142. "username": None,
  1143. },
  1144. "pagination": {"next": None, "page": 2, "pages": 2, "per_page": 2},
  1145. "projects": [
  1146. {
  1147. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1148. "access_users": {
  1149. "admin": [],
  1150. "commit": [],
  1151. "owner": ["pingou"],
  1152. "ticket": [],
  1153. },
  1154. "close_status": [
  1155. "Invalid",
  1156. "Insufficient data",
  1157. "Fixed",
  1158. "Duplicate",
  1159. ],
  1160. "custom_keys": [],
  1161. "date_created": "1436527638",
  1162. "date_modified": "1436527638",
  1163. "description": "namespaced test project",
  1164. "fullname": "somenamespace/test3",
  1165. "url_path": "somenamespace/test3",
  1166. "id": 3,
  1167. "milestones": {},
  1168. "name": "test3",
  1169. "namespace": "somenamespace",
  1170. "parent": None,
  1171. "priorities": {},
  1172. "tags": [],
  1173. "user": {"fullname": "PY C", "name": "pingou"},
  1174. }
  1175. ],
  1176. "total_projects": 3,
  1177. }
  1178. self.assertURLEqual(
  1179. data["pagination"].pop("first"),
  1180. "http://localhost/api/0/projects?per_page=2&page=1",
  1181. )
  1182. self.assertURLEqual(
  1183. data["pagination"].pop("prev"),
  1184. "http://localhost/api/0/projects?per_page=2&page=1",
  1185. )
  1186. self.assertURLEqual(
  1187. data["pagination"].pop("last"),
  1188. "http://localhost/api/0/projects?per_page=2&page=2",
  1189. )
  1190. self.assertDictEqual(data, expected_data)
  1191. def test_api_projects_pagination_invalid_page(self):
  1192. """ Test the api_projects method of the flask api when an invalid page
  1193. value is entered. """
  1194. tests.create_projects(self.session)
  1195. output = self.app.get("/api/0/projects?page=-3")
  1196. self.assertEqual(output.status_code, 400)
  1197. def test_api_projects_pagination_invalid_page_str(self):
  1198. """ Test the api_projects method of the flask api when an invalid type
  1199. for the page value is entered. """
  1200. tests.create_projects(self.session)
  1201. output = self.app.get("/api/0/projects?page=abcd")
  1202. self.assertEqual(output.status_code, 400)
  1203. def test_api_projects_pagination_invalid_per_page_too_low(self):
  1204. """ Test the api_projects method of the flask api when a per_page
  1205. value is below 1. """
  1206. tests.create_projects(self.session)
  1207. output = self.app.get("/api/0/projects?page=1&per_page=0")
  1208. self.assertEqual(output.status_code, 400)
  1209. error = json.loads(output.get_data(as_text=True))
  1210. self.assertEqual(
  1211. error["error"], "The per_page value must be between 1 and 100"
  1212. )
  1213. def test_api_projects_pagination_invalid_per_page_too_high(self):
  1214. """ Test the api_projects method of the flask api when a per_page
  1215. value is above 100. """
  1216. tests.create_projects(self.session)
  1217. output = self.app.get("/api/0/projects?page=1&per_page=101")
  1218. self.assertEqual(output.status_code, 400)
  1219. error = json.loads(output.get_data(as_text=True))
  1220. self.assertEqual(
  1221. error["error"], "The per_page value must be between 1 and 100"
  1222. )
  1223. def test_api_projects_pagination_invalid_per_page_str(self):
  1224. """ Test the api_projects method of the flask api when an invalid type
  1225. for the per_page value is entered. """
  1226. tests.create_projects(self.session)
  1227. output = self.app.get("/api/0/projects?page=1&per_page=abcd")
  1228. self.assertEqual(output.status_code, 400)
  1229. def test_api_projects_pagination_beyond_last_page(self):
  1230. """ Test the api_projects method of the flask api when a page value
  1231. that is larger than the last page is entered. """
  1232. tests.create_projects(self.session)
  1233. output = self.app.get("/api/0/projects?page=99999")
  1234. self.assertEqual(output.status_code, 200)
  1235. data = json.loads(output.get_data(as_text=True))
  1236. self.assertURLEqual(
  1237. data["pagination"].pop("first"),
  1238. "http://localhost/api/0/projects?per_page=20&page=1",
  1239. )
  1240. self.assertURLEqual(
  1241. data["pagination"].pop("last"),
  1242. "http://localhost/api/0/projects?per_page=20&page=1",
  1243. )
  1244. self.assertURLEqual(
  1245. data["pagination"].pop("prev"),
  1246. "http://localhost/api/0/projects?per_page=20&page=99998",
  1247. )
  1248. self.assertEqual(
  1249. data,
  1250. {
  1251. "args": {
  1252. "fork": None,
  1253. "namespace": None,
  1254. "owner": None,
  1255. "page": 99999,
  1256. "pattern": None,
  1257. "per_page": 20,
  1258. "short": False,
  1259. "tags": [],
  1260. "username": None,
  1261. },
  1262. "pagination": {
  1263. "next": None,
  1264. "page": 99999,
  1265. "pages": 1,
  1266. "per_page": 20,
  1267. },
  1268. "projects": [],
  1269. "total_projects": 3,
  1270. },
  1271. )
  1272. def test_api_modify_project_main_admin(self):
  1273. """ Test the api_modify_project method of the flask api when the
  1274. request is to change the main_admin of the project. """
  1275. tests.create_projects(self.session)
  1276. tests.create_tokens(self.session, project_id=None)
  1277. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1278. headers = {"Authorization": "token aaabbbcccddd"}
  1279. output = self.app.patch(
  1280. "/api/0/test", headers=headers, data={"main_admin": "foo"}
  1281. )
  1282. self.assertEqual(output.status_code, 200)
  1283. data = json.loads(output.get_data(as_text=True))
  1284. data["date_created"] = "1496338274"
  1285. data["date_modified"] = "1496338274"
  1286. expected_output = {
  1287. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1288. "access_users": {
  1289. "admin": [],
  1290. "commit": [],
  1291. "owner": ["foo"],
  1292. "ticket": [],
  1293. },
  1294. "close_status": [
  1295. "Invalid",
  1296. "Insufficient data",
  1297. "Fixed",
  1298. "Duplicate",
  1299. ],
  1300. "custom_keys": [],
  1301. "date_created": "1496338274",
  1302. "date_modified": "1496338274",
  1303. "description": "test project #1",
  1304. "fullname": "test",
  1305. "url_path": "test",
  1306. "id": 1,
  1307. "milestones": {},
  1308. "name": "test",
  1309. "namespace": None,
  1310. "parent": None,
  1311. "priorities": {},
  1312. "tags": [],
  1313. "user": {
  1314. "default_email": "foo@bar.com",
  1315. "emails": ["foo@bar.com"],
  1316. "fullname": "foo bar",
  1317. "name": "foo",
  1318. },
  1319. }
  1320. self.assertEqual(data, expected_output)
  1321. def test_api_modify_project_main_admin_retain_access(self):
  1322. """ Test the api_modify_project method of the flask api when the
  1323. request is to change the main_admin of the project and retain_access
  1324. is true. """
  1325. tests.create_projects(self.session)
  1326. tests.create_tokens(self.session, project_id=None)
  1327. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1328. headers = {"Authorization": "token aaabbbcccddd"}
  1329. output = self.app.patch(
  1330. "/api/0/test",
  1331. headers=headers,
  1332. data={"main_admin": "foo", "retain_access": True},
  1333. )
  1334. self.assertEqual(output.status_code, 200)
  1335. data = json.loads(output.get_data(as_text=True))
  1336. data["date_created"] = "1496338274"
  1337. data["date_modified"] = "1496338274"
  1338. expected_output = {
  1339. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1340. "access_users": {
  1341. "admin": ["pingou"],
  1342. "commit": [],
  1343. "owner": ["foo"],
  1344. "ticket": [],
  1345. },
  1346. "close_status": [
  1347. "Invalid",
  1348. "Insufficient data",
  1349. "Fixed",
  1350. "Duplicate",
  1351. ],
  1352. "custom_keys": [],
  1353. "date_created": "1496338274",
  1354. "date_modified": "1496338274",
  1355. "description": "test project #1",
  1356. "fullname": "test",
  1357. "url_path": "test",
  1358. "id": 1,
  1359. "milestones": {},
  1360. "name": "test",
  1361. "namespace": None,
  1362. "parent": None,
  1363. "priorities": {},
  1364. "tags": [],
  1365. "user": {
  1366. "default_email": "foo@bar.com",
  1367. "emails": ["foo@bar.com"],
  1368. "fullname": "foo bar",
  1369. "name": "foo",
  1370. },
  1371. }
  1372. self.assertEqual(data, expected_output)
  1373. def test_api_modify_project_main_admin_retain_access_already_user(self):
  1374. """ Test the api_modify_project method of the flask api when the
  1375. request is to change the main_admin of the project and retain_access
  1376. is true and the user becoming the main_admin already has access. """
  1377. tests.create_projects(self.session)
  1378. tests.create_tokens(self.session, project_id=None)
  1379. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1380. headers = {"Authorization": "token aaabbbcccddd"}
  1381. project = pagure.lib.query._get_project(self.session, "test")
  1382. pagure.lib.query.add_user_to_project(
  1383. self.session,
  1384. project,
  1385. new_user="foo",
  1386. user="pingou",
  1387. access="commit",
  1388. )
  1389. self.session.commit()
  1390. output = self.app.patch(
  1391. "/api/0/test",
  1392. headers=headers,
  1393. data={"main_admin": "foo", "retain_access": True},
  1394. )
  1395. self.assertEqual(output.status_code, 200)
  1396. data = json.loads(output.get_data(as_text=True))
  1397. data["date_created"] = "1496338274"
  1398. data["date_modified"] = "1496338274"
  1399. expected_output = {
  1400. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1401. "access_users": {
  1402. "admin": ["pingou"],
  1403. "commit": [],
  1404. "owner": ["foo"],
  1405. "ticket": [],
  1406. },
  1407. "close_status": [
  1408. "Invalid",
  1409. "Insufficient data",
  1410. "Fixed",
  1411. "Duplicate",
  1412. ],
  1413. "custom_keys": [],
  1414. "date_created": "1496338274",
  1415. "date_modified": "1496338274",
  1416. "description": "test project #1",
  1417. "fullname": "test",
  1418. "url_path": "test",
  1419. "id": 1,
  1420. "milestones": {},
  1421. "name": "test",
  1422. "namespace": None,
  1423. "parent": None,
  1424. "priorities": {},
  1425. "tags": [],
  1426. "user": {
  1427. "default_email": "foo@bar.com",
  1428. "emails": ["foo@bar.com"],
  1429. "fullname": "foo bar",
  1430. "name": "foo",
  1431. },
  1432. }
  1433. self.assertEqual(data, expected_output)
  1434. def test_api_modify_project_main_admin_json(self):
  1435. """ Test the api_modify_project method of the flask api when the
  1436. request is to change the main_admin of the project using JSON. """
  1437. tests.create_projects(self.session)
  1438. tests.create_tokens(self.session, project_id=None)
  1439. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1440. headers = {
  1441. "Authorization": "token aaabbbcccddd",
  1442. "Content-Type": "application/json",
  1443. }
  1444. output = self.app.patch(
  1445. "/api/0/test",
  1446. headers=headers,
  1447. data=json.dumps({"main_admin": "foo"}),
  1448. )
  1449. self.assertEqual(output.status_code, 200)
  1450. data = json.loads(output.get_data(as_text=True))
  1451. data["date_created"] = "1496338274"
  1452. data["date_modified"] = "1496338274"
  1453. expected_output = {
  1454. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1455. "access_users": {
  1456. "admin": [],
  1457. "commit": [],
  1458. "owner": ["foo"],
  1459. "ticket": [],
  1460. },
  1461. "close_status": [
  1462. "Invalid",
  1463. "Insufficient data",
  1464. "Fixed",
  1465. "Duplicate",
  1466. ],
  1467. "custom_keys": [],
  1468. "date_created": "1496338274",
  1469. "date_modified": "1496338274",
  1470. "description": "test project #1",
  1471. "fullname": "test",
  1472. "url_path": "test",
  1473. "id": 1,
  1474. "milestones": {},
  1475. "name": "test",
  1476. "namespace": None,
  1477. "parent": None,
  1478. "priorities": {},
  1479. "tags": [],
  1480. "user": {
  1481. "default_email": "foo@bar.com",
  1482. "emails": ["foo@bar.com"],
  1483. "fullname": "foo bar",
  1484. "name": "foo",
  1485. },
  1486. }
  1487. self.assertEqual(data, expected_output)
  1488. @patch.dict("pagure.config.config", {"PAGURE_ADMIN_USERS": "foo"})
  1489. def test_api_modify_project_main_admin_as_site_admin(self):
  1490. """ Test the api_modify_project method of the flask api when the
  1491. request is to change the main_admin of the project and the user is a
  1492. Pagure site admin. """
  1493. tests.create_projects(self.session)
  1494. tests.create_tokens(self.session, user_id=2, project_id=None)
  1495. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1496. headers = {"Authorization": "token aaabbbcccddd"}
  1497. # date before:
  1498. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1499. date_before = project.date_modified
  1500. self.assertIsNotNone(date_before)
  1501. output = self.app.patch(
  1502. "/api/0/test", headers=headers, data={"main_admin": "foo"}
  1503. )
  1504. self.assertEqual(output.status_code, 200)
  1505. data = json.loads(output.get_data(as_text=True))
  1506. data["date_created"] = "1496338274"
  1507. data["date_modified"] = "1496338274"
  1508. expected_output = {
  1509. "access_groups": {"admin": [], "commit": [], "ticket": []},
  1510. "access_users": {
  1511. "admin": [],
  1512. "commit": [],
  1513. "owner": ["foo"],
  1514. "ticket": [],
  1515. },
  1516. "close_status": [
  1517. "Invalid",
  1518. "Insufficient data",
  1519. "Fixed",
  1520. "Duplicate",
  1521. ],
  1522. "custom_keys": [],
  1523. "date_created": "1496338274",
  1524. "date_modified": "1496338274",
  1525. "description": "test project #1",
  1526. "fullname": "test",
  1527. "url_path": "test",
  1528. "id": 1,
  1529. "milestones": {},
  1530. "name": "test",
  1531. "namespace": None,
  1532. "parent": None,
  1533. "priorities": {},
  1534. "tags": [],
  1535. "user": {
  1536. "default_email": "foo@bar.com",
  1537. "emails": ["foo@bar.com"],
  1538. "fullname": "foo bar",
  1539. "name": "foo",
  1540. },
  1541. }
  1542. self.assertEqual(data, expected_output)
  1543. # date after:
  1544. self.session = pagure.lib.query.create_session(self.dbpath)
  1545. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1546. self.assertNotEqual(date_before, project.date_modified)
  1547. def test_api_modify_project_main_admin_not_main_admin(self):
  1548. """ Test the api_modify_project method of the flask api when the
  1549. requester is not the main_admin of the project and requests to change
  1550. the main_admin.
  1551. """
  1552. tests.create_projects(self.session)
  1553. project_user = pagure.lib.query.model.ProjectUser(
  1554. project_id=1, user_id=2, access="admin"
  1555. )
  1556. self.session.add(project_user)
  1557. self.session.commit()
  1558. tests.create_tokens(self.session, project_id=None, user_id=2)
  1559. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1560. headers = {"Authorization": "token aaabbbcccddd"}
  1561. output = self.app.patch(
  1562. "/api/0/test", headers=headers, data={"main_admin": "foo"}
  1563. )
  1564. self.assertEqual(output.status_code, 401)
  1565. expected_error = {
  1566. "error": (
  1567. "Only the main admin can set the main admin of a " "project"
  1568. ),
  1569. "error_code": "ENOTMAINADMIN",
  1570. }
  1571. self.assertEqual(
  1572. json.loads(output.get_data(as_text=True)), expected_error
  1573. )
  1574. def test_api_modify_project_not_admin(self):
  1575. """ Test the api_modify_project method of the flask api when the
  1576. requester is not an admin of the project.
  1577. """
  1578. tests.create_projects(self.session)
  1579. tests.create_tokens(self.session, project_id=None, user_id=2)
  1580. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1581. headers = {"Authorization": "token aaabbbcccddd"}
  1582. output = self.app.patch(
  1583. "/api/0/test", headers=headers, data={"main_admin": "foo"}
  1584. )
  1585. self.assertEqual(output.status_code, 401)
  1586. expected_error = {
  1587. "error": "You are not allowed to modify this project",
  1588. "error_code": "EMODIFYPROJECTNOTALLOWED",
  1589. }
  1590. self.assertEqual(
  1591. json.loads(output.get_data(as_text=True)), expected_error
  1592. )
  1593. def test_api_modify_project_invalid_request(self):
  1594. """ Test the api_modify_project method of the flask api when the
  1595. request data is invalid.
  1596. """
  1597. tests.create_projects(self.session)
  1598. tests.create_tokens(self.session, project_id=None)
  1599. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1600. headers = {"Authorization": "token aaabbbcccddd"}
  1601. output = self.app.patch("/api/0/test", headers=headers, data="invalid")
  1602. self.assertEqual(output.status_code, 400)
  1603. expected_error = {
  1604. "error": "Invalid or incomplete input submitted",
  1605. "error_code": "EINVALIDREQ",
  1606. }
  1607. self.assertEqual(
  1608. json.loads(output.get_data(as_text=True)), expected_error
  1609. )
  1610. def test_api_modify_project_invalid_keys(self):
  1611. """ Test the api_modify_project method of the flask api when the
  1612. request data contains an invalid key.
  1613. """
  1614. tests.create_projects(self.session)
  1615. tests.create_tokens(self.session, project_id=None)
  1616. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1617. headers = {"Authorization": "token aaabbbcccddd"}
  1618. output = self.app.patch(
  1619. "/api/0/test", headers=headers, data={"invalid": "invalid"}
  1620. )
  1621. self.assertEqual(output.status_code, 400)
  1622. expected_error = {
  1623. "error": "Invalid or incomplete input submitted",
  1624. "error_code": "EINVALIDREQ",
  1625. }
  1626. self.assertEqual(
  1627. json.loads(output.get_data(as_text=True)), expected_error
  1628. )
  1629. def test_api_modify_project_invalid_new_main_admin(self):
  1630. """ Test the api_modify_project method of the flask api when the
  1631. request is to change the main_admin of the project to a main_admin
  1632. that doesn't exist.
  1633. """
  1634. tests.create_projects(self.session)
  1635. tests.create_tokens(self.session, project_id=None)
  1636. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  1637. headers = {"Authorization": "token aaabbbcccddd"}
  1638. output = self.app.patch(
  1639. "/api/0/test", headers=headers, data={"main_admin": "tbrady"}
  1640. )
  1641. self.assertEqual(output.status_code, 400)
  1642. expected_error = {
  1643. "error": "No such user found",
  1644. "error_code": "ENOUSER",
  1645. }
  1646. self.assertEqual(
  1647. json.loads(output.get_data(as_text=True)), expected_error
  1648. )
  1649. def test_api_project_watchers(self):
  1650. """ Test the api_project_watchers method of the flask api. """
  1651. tests.create_projects(self.session)
  1652. # The user is not logged in and the owner is watching issues implicitly
  1653. output = self.app.get("/api/0/test/watchers")
  1654. self.assertEqual(output.status_code, 200)
  1655. expected_data = {
  1656. "total_watchers": 1,
  1657. "watchers": {"pingou": ["issues"]},
  1658. }
  1659. self.assertDictEqual(
  1660. json.loads(output.get_data(as_text=True)), expected_data
  1661. )
  1662. user = tests.FakeUser(username="pingou")
  1663. with tests.user_set(self.app.application, user):
  1664. # Non-existing project
  1665. output = self.app.get("/api/0/random/watchers")
  1666. self.assertEqual(output.status_code, 404)
  1667. data = json.loads(output.get_data(as_text=True))
  1668. self.assertDictEqual(
  1669. data,
  1670. {"error_code": "ENOPROJECT", "error": "Project not found"},
  1671. )
  1672. # The owner is watching issues implicitly
  1673. output = self.app.get("/api/0/test/watchers")
  1674. self.assertEqual(output.status_code, 200)
  1675. expected_data = {
  1676. "total_watchers": 1,
  1677. "watchers": {"pingou": ["issues"]},
  1678. }
  1679. self.assertDictEqual(
  1680. json.loads(output.get_data(as_text=True)), expected_data
  1681. )
  1682. project = pagure.lib.query.get_authorized_project(
  1683. self.session, "test"
  1684. )
  1685. # The owner is watching issues and commits explicitly
  1686. pagure.lib.query.update_watch_status(
  1687. self.session, project, "pingou", "3"
  1688. )
  1689. self.session.commit()
  1690. output = self.app.get("/api/0/test/watchers")
  1691. self.assertEqual(output.status_code, 200)
  1692. expected_data = {
  1693. "total_watchers": 1,
  1694. "watchers": {"pingou": ["issues", "commits"]},
  1695. }
  1696. self.assertDictEqual(
  1697. json.loads(output.get_data(as_text=True)), expected_data
  1698. )
  1699. # The owner is watching issues explicitly
  1700. pagure.lib.query.update_watch_status(
  1701. self.session, project, "pingou", "1"
  1702. )
  1703. self.session.commit()
  1704. output = self.app.get("/api/0/test/watchers")
  1705. self.assertEqual(output.status_code, 200)
  1706. expected_data = {
  1707. "total_watchers": 1,
  1708. "watchers": {"pingou": ["issues"]},
  1709. }
  1710. self.assertDictEqual(
  1711. json.loads(output.get_data(as_text=True)), expected_data
  1712. )
  1713. # The owner is watching commits explicitly
  1714. pagure.lib.query.update_watch_status(
  1715. self.session, project, "pingou", "2"
  1716. )
  1717. self.session.commit()
  1718. output = self.app.get("/api/0/test/watchers")
  1719. self.assertEqual(output.status_code, 200)
  1720. expected_data = {
  1721. "total_watchers": 1,
  1722. "watchers": {"pingou": ["commits"]},
  1723. }
  1724. self.assertDictEqual(
  1725. json.loads(output.get_data(as_text=True)), expected_data
  1726. )
  1727. # The owner is watching commits explicitly and foo is watching
  1728. # issues implicitly
  1729. project_user = pagure.lib.model.ProjectUser(
  1730. project_id=project.id, user_id=2, access="commit"
  1731. )
  1732. pagure.lib.query.update_watch_status(
  1733. self.session, project, "pingou", "2"
  1734. )
  1735. self.session.add(project_user)
  1736. self.session.commit()
  1737. output = self.app.get("/api/0/test/watchers")
  1738. self.assertEqual(output.status_code, 200)
  1739. expected_data = {
  1740. "total_watchers": 2,
  1741. "watchers": {"foo": ["issues"], "pingou": ["commits"]},
  1742. }
  1743. self.assertDictEqual(
  1744. json.loads(output.get_data(as_text=True)), expected_data
  1745. )
  1746. # The owner and foo are watching issues implicitly
  1747. pagure.lib.query.update_watch_status(
  1748. self.session, project, "pingou", "-1"
  1749. )
  1750. self.session.commit()
  1751. output = self.app.get("/api/0/test/watchers")
  1752. self.assertEqual(output.status_code, 200)
  1753. expected_data = {
  1754. "total_watchers": 2,
  1755. "watchers": {"foo": ["issues"], "pingou": ["issues"]},
  1756. }
  1757. self.assertDictEqual(
  1758. json.loads(output.get_data(as_text=True)), expected_data
  1759. )
  1760. # The owner and foo through group membership are watching issues
  1761. # implicitly
  1762. pagure.lib.query.update_watch_status(
  1763. self.session, project, "pingou", "-1"
  1764. )
  1765. project_membership = (
  1766. self.session.query(pagure.lib.model.ProjectUser)
  1767. .filter_by(user_id=2, project_id=project.id)
  1768. .one()
  1769. )
  1770. self.session.delete(project_membership)
  1771. self.session.commit()
  1772. msg = pagure.lib.query.add_group(
  1773. self.session,
  1774. group_name="some_group",
  1775. display_name="Some Group",
  1776. description=None,
  1777. group_type="bar",
  1778. user="pingou",
  1779. is_admin=False,
  1780. blacklist=[],
  1781. )
  1782. self.session.commit()
  1783. project = pagure.lib.query.get_authorized_project(
  1784. self.session, "test"
  1785. )
  1786. group = pagure.lib.query.search_groups(
  1787. self.session, group_name="some_group"
  1788. )
  1789. pagure.lib.query.add_user_to_group(
  1790. self.session, "foo", group, "pingou", False
  1791. )
  1792. pagure.lib.query.add_group_to_project(
  1793. self.session,
  1794. project,
  1795. new_group="some_group",
  1796. user="pingou",
  1797. access="commit",
  1798. create=False,
  1799. is_admin=True,
  1800. )
  1801. self.session.commit()
  1802. output = self.app.get("/api/0/test/watchers")
  1803. self.assertEqual(output.status_code, 200)
  1804. expected_data = {
  1805. "total_watchers": 2,
  1806. "watchers": {"@some_group": ["issues"], "pingou": ["issues"]},
  1807. }
  1808. self.assertDictEqual(
  1809. json.loads(output.get_data(as_text=True)), expected_data
  1810. )
  1811. # The owner is watching issues implicitly and foo will be watching
  1812. # commits explicitly but is in a group with commit access
  1813. pagure.lib.query.update_watch_status(
  1814. self.session, project, "pingou", "-1"
  1815. )
  1816. pagure.lib.query.update_watch_status(
  1817. self.session, project, "foo", "2"
  1818. )
  1819. self.session.commit()
  1820. output = self.app.get("/api/0/test/watchers")
  1821. self.assertEqual(output.status_code, 200)
  1822. expected_data = {
  1823. "total_watchers": 3,
  1824. "watchers": {
  1825. "@some_group": ["issues"],
  1826. "foo": ["commits"],
  1827. "pingou": ["issues"],
  1828. },
  1829. }
  1830. self.assertDictEqual(
  1831. json.loads(output.get_data(as_text=True)), expected_data
  1832. )
  1833. def test_api_new_project(self):
  1834. """ Test the api_new_project method of the flask api. """
  1835. tests.create_projects(self.session)
  1836. tests.create_projects_git(os.path.join(self.path, "tickets"))
  1837. tests.create_tokens(self.session)
  1838. tests.create_tokens_acl(self.session)
  1839. headers = {"Authorization": "token foo_token"}
  1840. # Invalid token
  1841. output = self.app.post("/api/0/new", headers=headers)
  1842. self.assertEqual(output.status_code, 401)
  1843. data = json.loads(output.get_data(as_text=True))
  1844. self.assertEqual(
  1845. sorted(data.keys()), ["error", "error_code", "errors"]
  1846. )
  1847. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"])
  1848. self.assertEqual(
  1849. pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"]
  1850. )
  1851. self.assertEqual(data["errors"], "Missing ACLs: create_project")
  1852. headers = {"Authorization": "token aaabbbcccddd"}
  1853. # No input
  1854. output = self.app.post("/api/0/new", headers=headers)
  1855. self.assertEqual(output.status_code, 400)
  1856. data = json.loads(output.get_data(as_text=True))
  1857. self.assertDictEqual(
  1858. data,
  1859. {
  1860. "error": "Invalid or incomplete input submitted",
  1861. "error_code": "EINVALIDREQ",
  1862. "errors": {
  1863. "name": ["This field is required."],
  1864. "description": ["This field is required."],
  1865. },
  1866. },
  1867. )
  1868. data = {"name": "test"}
  1869. # Incomplete request
  1870. output = self.app.post("/api/0/new", data=data, headers=headers)
  1871. self.assertEqual(output.status_code, 400)
  1872. data = json.loads(output.get_data(as_text=True))
  1873. self.assertDictEqual(
  1874. data,
  1875. {
  1876. "error": "Invalid or incomplete input submitted",
  1877. "error_code": "EINVALIDREQ",
  1878. "errors": {"description": ["This field is required."]},
  1879. },
  1880. )
  1881. data = {"name": "test", "description": "Just a small test project"}
  1882. # Valid request but repo already exists
  1883. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1884. self.assertEqual(output.status_code, 400)
  1885. data = json.loads(output.get_data(as_text=True))
  1886. self.assertDictEqual(
  1887. data,
  1888. {
  1889. "error": 'It is not possible to create the repo "test"',
  1890. "error_code": "ENOCODE",
  1891. },
  1892. )
  1893. data = {
  1894. "name": "api1",
  1895. "description": "Mighty mighty description",
  1896. "avatar_email": 123,
  1897. }
  1898. # invalid avatar_email - number
  1899. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1900. self.assertEqual(output.status_code, 400)
  1901. data = json.loads(output.get_data(as_text=True))
  1902. self.assertDictEqual(
  1903. data,
  1904. {
  1905. "error": "Invalid or incomplete input submitted",
  1906. "error_code": "EINVALIDREQ",
  1907. "errors": {"avatar_email": ["avatar_email must be an email"]},
  1908. },
  1909. )
  1910. data = {
  1911. "name": "api1",
  1912. "description": "Mighty mighty description",
  1913. "avatar_email": [1, 2, 3],
  1914. }
  1915. # invalid avatar_email - list
  1916. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1917. self.assertEqual(output.status_code, 400)
  1918. data = json.loads(output.get_data(as_text=True))
  1919. self.assertDictEqual(
  1920. data,
  1921. {
  1922. "error": "Invalid or incomplete input submitted",
  1923. "error_code": "EINVALIDREQ",
  1924. "errors": {"avatar_email": ["avatar_email must be an email"]},
  1925. },
  1926. )
  1927. data = {
  1928. "name": "api1",
  1929. "description": "Mighty mighty description",
  1930. "avatar_email": True,
  1931. }
  1932. # invalid avatar_email - boolean
  1933. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1934. self.assertEqual(output.status_code, 400)
  1935. data = json.loads(output.get_data(as_text=True))
  1936. self.assertDictEqual(
  1937. data,
  1938. {
  1939. "error": "Invalid or incomplete input submitted",
  1940. "error_code": "EINVALIDREQ",
  1941. "errors": {"avatar_email": ["avatar_email must be an email"]},
  1942. },
  1943. )
  1944. data = {
  1945. "name": "api1",
  1946. "description": "Mighty mighty description",
  1947. "avatar_email": "mighty@email.com",
  1948. }
  1949. # valid avatar_email
  1950. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1951. self.assertEqual(output.status_code, 200)
  1952. data = json.loads(output.get_data(as_text=True))
  1953. self.assertDictEqual(data, {"message": 'Project "api1" created'})
  1954. data = {
  1955. "name": "test_42",
  1956. "description": "Just another small test project",
  1957. }
  1958. # Valid request
  1959. output = self.app.post("/api/0/new/", data=data, headers=headers)
  1960. self.assertEqual(output.status_code, 200)
  1961. data = json.loads(output.get_data(as_text=True))
  1962. self.assertDictEqual(data, {"message": 'Project "test_42" created'})
  1963. @patch.dict(
  1964. "pagure.config.config",
  1965. {
  1966. "PAGURE_ADMIN_USERS": ["pingou"],
  1967. "ALLOW_ADMIN_IGNORE_EXISTING_REPOS": True,
  1968. },
  1969. )
  1970. def test_adopt_repos(self):
  1971. """ Test the new_project endpoint with existing git repo. """
  1972. # Before
  1973. projects = pagure.lib.query.search_projects(self.session)
  1974. self.assertEqual(len(projects), 0)
  1975. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1976. tests.add_content_git_repo(
  1977. os.path.join(self.path, "repos", "test.git")
  1978. )
  1979. item = pagure.lib.model.Token(
  1980. id="aaabbbcccddd",
  1981. user_id=1,
  1982. project_id=None,
  1983. expiration=datetime.datetime.utcnow()
  1984. + datetime.timedelta(days=10),
  1985. )
  1986. self.session.add(item)
  1987. self.session.commit()
  1988. tests.create_tokens_acl(self.session)
  1989. headers = {"Authorization": "token aaabbbcccddd"}
  1990. user = tests.FakeUser(username="pingou")
  1991. with tests.user_set(self.app.application, user):
  1992. input_data = {"name": "test", "description": "Project #1"}
  1993. # Valid request
  1994. output = self.app.post(
  1995. "/api/0/new/", data=input_data, headers=headers
  1996. )
  1997. self.assertEqual(output.status_code, 400)
  1998. data = json.loads(output.get_data(as_text=True))
  1999. self.assertDictEqual(
  2000. data,
  2001. {
  2002. "error": "The main repo test.git already exists",
  2003. "error_code": "ENOCODE",
  2004. },
  2005. )
  2006. input_data["ignore_existing_repos"] = "y"
  2007. # Valid request
  2008. output = self.app.post(
  2009. "/api/0/new/", data=input_data, headers=headers
  2010. )
  2011. self.assertEqual(output.status_code, 200)
  2012. data = json.loads(output.get_data(as_text=True))
  2013. self.assertDictEqual(data, {"message": 'Project "test" created'})
  2014. @patch.dict("pagure.config.config", {"PRIVATE_PROJECTS": True})
  2015. def test_api_new_project_private(self):
  2016. """ Test the api_new_project method of the flask api to create
  2017. a private project. """
  2018. tests.create_projects(self.session)
  2019. tests.create_projects_git(os.path.join(self.path, "tickets"))
  2020. tests.create_tokens(self.session)
  2021. tests.create_tokens_acl(self.session)
  2022. headers = {"Authorization": "token aaabbbcccddd"}
  2023. data = {
  2024. "name": "test",
  2025. "description": "Just a small test project",
  2026. "private": True,
  2027. }
  2028. # Valid request
  2029. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2030. self.assertEqual(output.status_code, 200)
  2031. data = json.loads(output.get_data(as_text=True))
  2032. self.assertDictEqual(
  2033. data, {"message": 'Project "pingou/test" created'}
  2034. )
  2035. def test_api_new_project_user_token(self):
  2036. """ Test the api_new_project method of the flask api. """
  2037. tests.create_projects(self.session)
  2038. tests.create_projects_git(os.path.join(self.path, "tickets"))
  2039. tests.create_tokens(self.session, project_id=None)
  2040. tests.create_tokens_acl(self.session)
  2041. headers = {"Authorization": "token foo_token"}
  2042. # Invalid token
  2043. output = self.app.post("/api/0/new", headers=headers)
  2044. self.assertEqual(output.status_code, 401)
  2045. data = json.loads(output.get_data(as_text=True))
  2046. self.assertEqual(
  2047. sorted(data.keys()), ["error", "error_code", "errors"]
  2048. )
  2049. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"])
  2050. self.assertEqual(
  2051. pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"]
  2052. )
  2053. self.assertEqual(data["errors"], "Missing ACLs: create_project")
  2054. headers = {"Authorization": "token aaabbbcccddd"}
  2055. # No input
  2056. output = self.app.post("/api/0/new", headers=headers)
  2057. self.assertEqual(output.status_code, 400)
  2058. data = json.loads(output.get_data(as_text=True))
  2059. self.assertDictEqual(
  2060. data,
  2061. {
  2062. "error": "Invalid or incomplete input submitted",
  2063. "error_code": "EINVALIDREQ",
  2064. "errors": {
  2065. "name": ["This field is required."],
  2066. "description": ["This field is required."],
  2067. },
  2068. },
  2069. )
  2070. data = {"name": "test"}
  2071. # Incomplete request
  2072. output = self.app.post("/api/0/new", data=data, headers=headers)
  2073. self.assertEqual(output.status_code, 400)
  2074. data = json.loads(output.get_data(as_text=True))
  2075. self.assertDictEqual(
  2076. data,
  2077. {
  2078. "error": "Invalid or incomplete input submitted",
  2079. "error_code": "EINVALIDREQ",
  2080. "errors": {"description": ["This field is required."]},
  2081. },
  2082. )
  2083. data = {"name": "test", "description": "Just a small test project"}
  2084. # Valid request but repo already exists
  2085. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2086. self.assertEqual(output.status_code, 400)
  2087. data = json.loads(output.get_data(as_text=True))
  2088. self.assertDictEqual(
  2089. data,
  2090. {
  2091. "error": 'It is not possible to create the repo "test"',
  2092. "error_code": "ENOCODE",
  2093. },
  2094. )
  2095. data = {
  2096. "name": "test_42",
  2097. "description": "Just another small test project",
  2098. }
  2099. # Valid request
  2100. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2101. self.assertEqual(output.status_code, 200)
  2102. data = json.loads(output.get_data(as_text=True))
  2103. self.assertDictEqual(data, {"message": 'Project "test_42" created'})
  2104. # Project with a namespace
  2105. pagure.config.config["ALLOWED_PREFIX"] = ["rpms"]
  2106. data = {
  2107. "name": "test_42",
  2108. "namespace": "pingou",
  2109. "description": "Just another small test project",
  2110. }
  2111. # Invalid namespace
  2112. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2113. self.assertEqual(output.status_code, 400)
  2114. data = json.loads(output.get_data(as_text=True))
  2115. self.assertDictEqual(
  2116. data,
  2117. {
  2118. "error": "Invalid or incomplete input submitted",
  2119. "error_code": "EINVALIDREQ",
  2120. "errors": {"namespace": ["Not a valid choice"]},
  2121. },
  2122. )
  2123. data = {
  2124. "name": "test_42",
  2125. "namespace": "rpms",
  2126. "description": "Just another small test project",
  2127. }
  2128. # All good
  2129. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2130. self.assertEqual(output.status_code, 200)
  2131. data = json.loads(output.get_data(as_text=True))
  2132. self.assertDictEqual(
  2133. data, {"message": 'Project "rpms/test_42" created'}
  2134. )
  2135. @patch.dict("pagure.config.config", {"USER_NAMESPACE": True})
  2136. def test_api_new_project_user_ns(self):
  2137. """ Test the api_new_project method of the flask api. """
  2138. tests.create_projects(self.session)
  2139. tests.create_projects_git(os.path.join(self.path, "tickets"))
  2140. tests.create_tokens(self.session)
  2141. tests.create_tokens_acl(self.session)
  2142. headers = {"Authorization": "token aaabbbcccddd"}
  2143. # Create a project with the user namespace feature on
  2144. data = {
  2145. "name": "testproject",
  2146. "description": "Just another small test project",
  2147. }
  2148. # Valid request
  2149. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2150. self.assertEqual(output.status_code, 200)
  2151. data = json.loads(output.get_data(as_text=True))
  2152. self.assertDictEqual(
  2153. data, {"message": 'Project "pingou/testproject" created'}
  2154. )
  2155. # Create a project with a namespace and the user namespace feature on
  2156. data = {
  2157. "name": "testproject2",
  2158. "namespace": "testns",
  2159. "description": "Just another small test project",
  2160. }
  2161. # Valid request
  2162. with patch.dict(
  2163. "pagure.config.config", {"ALLOWED_PREFIX": ["testns"]}
  2164. ):
  2165. output = self.app.post("/api/0/new/", data=data, headers=headers)
  2166. self.assertEqual(output.status_code, 200)
  2167. data = json.loads(output.get_data(as_text=True))
  2168. self.assertDictEqual(
  2169. data, {"message": 'Project "testns/testproject2" created'}
  2170. )
  2171. def test_api_fork_project(self):
  2172. """ Test the api_fork_project method of the flask api. """
  2173. tests.create_projects(self.session)
  2174. for folder in ["docs", "tickets", "requests", "repos"]:
  2175. tests.create_projects_git(
  2176. os.path.join(self.path, folder), bare=True
  2177. )
  2178. tests.create_tokens(self.session)
  2179. tests.create_tokens_acl(self.session)
  2180. headers = {"Authorization": "token foo_token"}
  2181. # Invalid token
  2182. output = self.app.post("/api/0/fork", headers=headers)
  2183. self.assertEqual(output.status_code, 401)
  2184. data = json.loads(output.get_data(as_text=True))
  2185. self.assertEqual(
  2186. sorted(data.keys()), ["error", "error_code", "errors"]
  2187. )
  2188. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"])
  2189. self.assertEqual(
  2190. pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"]
  2191. )
  2192. self.assertEqual(data["errors"], "Missing ACLs: fork_project")
  2193. headers = {"Authorization": "token aaabbbcccddd"}
  2194. # No input
  2195. output = self.app.post("/api/0/fork", headers=headers)
  2196. self.assertEqual(output.status_code, 400)
  2197. data = json.loads(output.get_data(as_text=True))
  2198. self.assertDictEqual(
  2199. data,
  2200. {
  2201. "error": "Invalid or incomplete input submitted",
  2202. "error_code": "EINVALIDREQ",
  2203. "errors": {"repo": ["This field is required."]},
  2204. },
  2205. )
  2206. data = {"name": "test"}
  2207. # Incomplete request
  2208. output = self.app.post("/api/0/fork", data=data, headers=headers)
  2209. self.assertEqual(output.status_code, 400)
  2210. data = json.loads(output.get_data(as_text=True))
  2211. self.assertDictEqual(
  2212. data,
  2213. {
  2214. "error": "Invalid or incomplete input submitted",
  2215. "error_code": "EINVALIDREQ",
  2216. "errors": {"repo": ["This field is required."]},
  2217. },
  2218. )
  2219. data = {"repo": "test"}
  2220. # Valid request
  2221. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2222. self.assertEqual(output.status_code, 200)
  2223. data = json.loads(output.get_data(as_text=True))
  2224. self.assertDictEqual(
  2225. data, {"message": 'Repo "test" cloned to "pingou/test"'}
  2226. )
  2227. data = {"repo": "test"}
  2228. # project already forked
  2229. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2230. self.assertEqual(output.status_code, 400)
  2231. data = json.loads(output.get_data(as_text=True))
  2232. self.assertDictEqual(
  2233. data,
  2234. {
  2235. "error": 'Repo "forks/pingou/test" already exists',
  2236. "error_code": "ENOCODE",
  2237. },
  2238. )
  2239. data = {"repo": "test", "username": "pingou"}
  2240. # Fork already exists
  2241. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2242. self.assertEqual(output.status_code, 400)
  2243. data = json.loads(output.get_data(as_text=True))
  2244. self.assertDictEqual(
  2245. data,
  2246. {
  2247. "error": 'Repo "forks/pingou/test" already exists',
  2248. "error_code": "ENOCODE",
  2249. },
  2250. )
  2251. data = {"repo": "test", "namespace": "pingou"}
  2252. # Repo does not exists
  2253. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2254. self.assertEqual(output.status_code, 404)
  2255. data = json.loads(output.get_data(as_text=True))
  2256. self.assertDictEqual(
  2257. data, {"error": "Project not found", "error_code": "ENOPROJECT"}
  2258. )
  2259. def test_api_fork_project_user_token(self):
  2260. """ Test the api_fork_project method of the flask api. """
  2261. tests.create_projects(self.session)
  2262. for folder in ["docs", "tickets", "requests", "repos"]:
  2263. tests.create_projects_git(
  2264. os.path.join(self.path, folder), bare=True
  2265. )
  2266. tests.create_tokens(self.session, project_id=None)
  2267. tests.create_tokens_acl(self.session)
  2268. headers = {"Authorization": "token foo_token"}
  2269. # Invalid token
  2270. output = self.app.post("/api/0/fork", headers=headers)
  2271. self.assertEqual(output.status_code, 401)
  2272. data = json.loads(output.get_data(as_text=True))
  2273. self.assertEqual(
  2274. sorted(data.keys()), ["error", "error_code", "errors"]
  2275. )
  2276. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"])
  2277. self.assertEqual(
  2278. pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"]
  2279. )
  2280. self.assertEqual(data["errors"], "Missing ACLs: fork_project")
  2281. headers = {"Authorization": "token aaabbbcccddd"}
  2282. # No input
  2283. output = self.app.post("/api/0/fork", headers=headers)
  2284. self.assertEqual(output.status_code, 400)
  2285. data = json.loads(output.get_data(as_text=True))
  2286. self.assertDictEqual(
  2287. data,
  2288. {
  2289. "error": "Invalid or incomplete input submitted",
  2290. "error_code": "EINVALIDREQ",
  2291. "errors": {"repo": ["This field is required."]},
  2292. },
  2293. )
  2294. data = {"name": "test"}
  2295. # Incomplete request
  2296. output = self.app.post("/api/0/fork", data=data, headers=headers)
  2297. self.assertEqual(output.status_code, 400)
  2298. data = json.loads(output.get_data(as_text=True))
  2299. self.assertDictEqual(
  2300. data,
  2301. {
  2302. "error": "Invalid or incomplete input submitted",
  2303. "error_code": "EINVALIDREQ",
  2304. "errors": {"repo": ["This field is required."]},
  2305. },
  2306. )
  2307. data = {"repo": "test"}
  2308. # Valid request
  2309. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2310. self.assertEqual(output.status_code, 200)
  2311. data = json.loads(output.get_data(as_text=True))
  2312. self.assertDictEqual(
  2313. data, {"message": 'Repo "test" cloned to "pingou/test"'}
  2314. )
  2315. data = {"repo": "test"}
  2316. # project already forked
  2317. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2318. self.assertEqual(output.status_code, 400)
  2319. data = json.loads(output.get_data(as_text=True))
  2320. self.assertDictEqual(
  2321. data,
  2322. {
  2323. "error": 'Repo "forks/pingou/test" already exists',
  2324. "error_code": "ENOCODE",
  2325. },
  2326. )
  2327. data = {"repo": "test", "username": "pingou"}
  2328. # Fork already exists
  2329. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2330. self.assertEqual(output.status_code, 400)
  2331. data = json.loads(output.get_data(as_text=True))
  2332. self.assertDictEqual(
  2333. data,
  2334. {
  2335. "error": 'Repo "forks/pingou/test" already exists',
  2336. "error_code": "ENOCODE",
  2337. },
  2338. )
  2339. data = {"repo": "test", "namespace": "pingou"}
  2340. # Repo does not exists
  2341. output = self.app.post("/api/0/fork/", data=data, headers=headers)
  2342. self.assertEqual(output.status_code, 404)
  2343. data = json.loads(output.get_data(as_text=True))
  2344. self.assertDictEqual(
  2345. data, {"error": "Project not found", "error_code": "ENOPROJECT"}
  2346. )
  2347. def test_api_generate_acls(self):
  2348. """ Test the api_generate_acls method of the flask api """
  2349. tests.create_projects(self.session)
  2350. tests.create_tokens(self.session, project_id=None)
  2351. tests.create_tokens_acl(
  2352. self.session, "aaabbbcccddd", "generate_acls_project"
  2353. )
  2354. headers = {"Authorization": "token aaabbbcccddd"}
  2355. user = pagure.lib.query.get_user(self.session, "pingou")
  2356. output = self.app.post(
  2357. "/api/0/test/git/generateacls",
  2358. headers=headers,
  2359. data={"wait": False},
  2360. )
  2361. self.assertEqual(output.status_code, 200)
  2362. data = json.loads(output.get_data(as_text=True))
  2363. expected_output = {
  2364. "message": "Project ACL generation queued",
  2365. "taskid": "abc-1234",
  2366. }
  2367. self.assertEqual(data, expected_output)
  2368. self.mock_gen_acls.assert_called_once_with(
  2369. name="test", namespace=None, user=None, group=None
  2370. )
  2371. def test_api_generate_acls_json(self):
  2372. """ Test the api_generate_acls method of the flask api using JSON """
  2373. tests.create_projects(self.session)
  2374. tests.create_tokens(self.session, project_id=None)
  2375. tests.create_tokens_acl(
  2376. self.session, "aaabbbcccddd", "generate_acls_project"
  2377. )
  2378. headers = {
  2379. "Authorization": "token aaabbbcccddd",
  2380. "Content-Type": "application/json",
  2381. }
  2382. user = pagure.lib.query.get_user(self.session, "pingou")
  2383. output = self.app.post(
  2384. "/api/0/test/git/generateacls",
  2385. headers=headers,
  2386. data=json.dumps({"wait": False}),
  2387. )
  2388. self.assertEqual(output.status_code, 200)
  2389. data = json.loads(output.get_data(as_text=True))
  2390. expected_output = {
  2391. "message": "Project ACL generation queued",
  2392. "taskid": "abc-1234",
  2393. }
  2394. self.assertEqual(data, expected_output)
  2395. self.mock_gen_acls.assert_called_once_with(
  2396. name="test", namespace=None, user=None, group=None
  2397. )
  2398. def test_api_generate_acls_wait_true(self):
  2399. """ Test the api_generate_acls method of the flask api when wait is
  2400. set to True """
  2401. tests.create_projects(self.session)
  2402. tests.create_tokens(self.session, project_id=None)
  2403. tests.create_tokens_acl(
  2404. self.session, "aaabbbcccddd", "generate_acls_project"
  2405. )
  2406. headers = {"Authorization": "token aaabbbcccddd"}
  2407. task_result = Mock()
  2408. task_result.id = "abc-1234"
  2409. self.mock_gen_acls.return_value = task_result
  2410. user = pagure.lib.query.get_user(self.session, "pingou")
  2411. output = self.app.post(
  2412. "/api/0/test/git/generateacls",
  2413. headers=headers,
  2414. data={"wait": True},
  2415. )
  2416. self.assertEqual(output.status_code, 200)
  2417. data = json.loads(output.get_data(as_text=True))
  2418. expected_output = {"message": "Project ACLs generated"}
  2419. self.assertEqual(data, expected_output)
  2420. self.mock_gen_acls.assert_called_once_with(
  2421. name="test", namespace=None, user=None, group=None
  2422. )
  2423. self.assertTrue(task_result.get.called)
  2424. def test_api_generate_acls_no_project(self):
  2425. """ Test the api_generate_acls method of the flask api when the project
  2426. doesn't exist """
  2427. tests.create_projects(self.session)
  2428. tests.create_tokens(self.session, project_id=None)
  2429. tests.create_tokens_acl(
  2430. self.session, "aaabbbcccddd", "generate_acls_project"
  2431. )
  2432. headers = {"Authorization": "token aaabbbcccddd"}
  2433. user = pagure.lib.query.get_user(self.session, "pingou")
  2434. output = self.app.post(
  2435. "/api/0/test12345123/git/generateacls",
  2436. headers=headers,
  2437. data={"wait": False},
  2438. )
  2439. self.assertEqual(output.status_code, 404)
  2440. data = json.loads(output.get_data(as_text=True))
  2441. expected_output = {
  2442. "error_code": "ENOPROJECT",
  2443. "error": "Project not found",
  2444. }
  2445. self.assertEqual(data, expected_output)
  2446. def test_api_new_git_branch(self):
  2447. """ Test the api_new_branch method of the flask api """
  2448. tests.create_projects(self.session)
  2449. repo_path = os.path.join(self.path, "repos")
  2450. tests.create_projects_git(repo_path, bare=True)
  2451. tests.add_content_git_repo(os.path.join(repo_path, "test.git"))
  2452. tests.create_tokens(self.session, project_id=None)
  2453. tests.create_tokens_acl(self.session, "aaabbbcccddd", "create_branch")
  2454. headers = {"Authorization": "token aaabbbcccddd"}
  2455. args = {"branch": "test123"}
  2456. output = self.app.post(
  2457. "/api/0/test/git/branch", headers=headers, data=args
  2458. )
  2459. self.assertEqual(output.status_code, 200)
  2460. data = json.loads(output.get_data(as_text=True))
  2461. expected_output = {"message": "Project branch was created"}
  2462. self.assertEqual(data, expected_output)
  2463. git_path = os.path.join(self.path, "repos", "test.git")
  2464. repo_obj = pygit2.Repository(git_path)
  2465. self.assertIn("test123", repo_obj.listall_branches())
  2466. def test_api_new_git_branch_json(self):
  2467. """ Test the api_new_branch method of the flask api """
  2468. tests.create_projects(self.session)
  2469. repo_path = os.path.join(self.path, "repos")
  2470. tests.create_projects_git(repo_path, bare=True)
  2471. tests.add_content_git_repo(os.path.join(repo_path, "test.git"))
  2472. tests.create_tokens(self.session, project_id=None)
  2473. tests.create_tokens_acl(self.session, "aaabbbcccddd", "create_branch")
  2474. headers = {
  2475. "Authorization": "token aaabbbcccddd",
  2476. "Content-Type": "application/json",
  2477. }
  2478. args = {"branch": "test123"}
  2479. output = self.app.post(
  2480. "/api/0/test/git/branch", headers=headers, data=json.dumps(args)
  2481. )
  2482. self.assertEqual(output.status_code, 200)
  2483. data = json.loads(output.get_data(as_text=True))
  2484. expected_output = {"message": "Project branch was created"}
  2485. self.assertEqual(data, expected_output)
  2486. git_path = os.path.join(self.path, "repos", "test.git")
  2487. repo_obj = pygit2.Repository(git_path)
  2488. self.assertIn("test123", repo_obj.listall_branches())
  2489. def test_api_new_git_branch_from_branch(self):
  2490. """ Test the api_new_branch method of the flask api """
  2491. tests.create_projects(self.session)
  2492. repo_path = os.path.join(self.path, "repos")
  2493. tests.create_projects_git(repo_path, bare=True)
  2494. tests.add_content_git_repo(os.path.join(repo_path, "test.git"))
  2495. tests.create_tokens(self.session, project_id=None)
  2496. tests.create_tokens_acl(self.session, "aaabbbcccddd", "create_branch")
  2497. git_path = os.path.join(self.path, "repos", "test.git")
  2498. repo_obj = pygit2.Repository(git_path)
  2499. parent = pagure.lib.git.get_branch_ref(repo_obj, "master").peel()
  2500. repo_obj.create_branch("dev123", parent)
  2501. headers = {"Authorization": "token aaabbbcccddd"}
  2502. args = {"branch": "test123", "from_branch": "dev123"}
  2503. output = self.app.post(
  2504. "/api/0/test/git/branch", headers=headers, data=args
  2505. )
  2506. self.assertEqual(output.status_code, 200)
  2507. data = json.loads(output.get_data(as_text=True))
  2508. expected_output = {"message": "Project branch was created"}
  2509. self.assertEqual(data, expected_output)
  2510. self.assertIn("test123", repo_obj.listall_branches())
  2511. def test_api_new_git_branch_already_exists(self):
  2512. """ Test the api_new_branch method of the flask api when branch already
  2513. exists """
  2514. tests.create_projects(self.session)
  2515. repo_path = os.path.join(self.path, "repos")
  2516. tests.create_projects_git(repo_path, bare=True)
  2517. tests.add_content_git_repo(os.path.join(repo_path, "test.git"))
  2518. tests.create_tokens(self.session, project_id=None)
  2519. tests.create_tokens_acl(self.session, "aaabbbcccddd", "create_branch")
  2520. headers = {"Authorization": "token aaabbbcccddd"}
  2521. args = {"branch": "master"}
  2522. output = self.app.post(
  2523. "/api/0/test/git/branch", headers=headers, data=args
  2524. )
  2525. self.assertEqual(output.status_code, 400)
  2526. data = json.loads(output.get_data(as_text=True))
  2527. expected_output = {
  2528. "error": 'The branch "master" already exists',
  2529. "error_code": "ENOCODE",
  2530. }
  2531. self.assertEqual(data, expected_output)
  2532. def test_api_new_git_branch_from_commit(self):
  2533. """ Test the api_new_branch method of the flask api """
  2534. tests.create_projects(self.session)
  2535. repos_path = os.path.join(self.path, "repos")
  2536. tests.create_projects_git(repos_path, bare=True)
  2537. git_path = os.path.join(repos_path, "test.git")
  2538. tests.add_content_git_repo(git_path)
  2539. tests.create_tokens(self.session, project_id=None)
  2540. tests.create_tokens_acl(self.session, "aaabbbcccddd", "create_branch")
  2541. repo_obj = pygit2.Repository(git_path)
  2542. from_commit = repo_obj.revparse_single("HEAD").oid.hex
  2543. headers = {"Authorization": "token aaabbbcccddd"}
  2544. args = {"branch": "test123", "from_commit": from_commit}
  2545. output = self.app.post(
  2546. "/api/0/test/git/branch", headers=headers, data=args
  2547. )
  2548. self.assertEqual(output.status_code, 200)
  2549. data = json.loads(output.get_data(as_text=True))
  2550. expected_output = {"message": "Project branch was created"}
  2551. self.assertEqual(data, expected_output)
  2552. self.assertIn("test123", repo_obj.listall_branches())
  2553. class PagureFlaskApiProjectFlagtests(tests.Modeltests):
  2554. """ Tests for the flask API of pagure for flagging commit in project
  2555. """
  2556. def setUp(self):
  2557. """ Set up the environnment, ran before every tests. """
  2558. super(PagureFlaskApiProjectFlagtests, self).setUp()
  2559. tests.create_projects(self.session)
  2560. repo_path = os.path.join(self.path, "repos")
  2561. self.git_path = os.path.join(repo_path, "test.git")
  2562. tests.create_projects_git(repo_path, bare=True)
  2563. tests.add_content_git_repo(self.git_path)
  2564. tests.create_tokens(self.session, project_id=None)
  2565. tests.create_tokens_acl(self.session, "aaabbbcccddd", "commit_flag")
  2566. def test_flag_commit_missing_status(self):
  2567. """ Test flagging a commit with missing precentage. """
  2568. repo_obj = pygit2.Repository(self.git_path)
  2569. commit = repo_obj.revparse_single("HEAD")
  2570. headers = {"Authorization": "token aaabbbcccddd"}
  2571. data = {
  2572. "username": "Jenkins",
  2573. "comment": "Tests passed",
  2574. "url": "http://jenkins.cloud.fedoraproject.org/",
  2575. "uid": "jenkins_build_pagure_100+seed",
  2576. }
  2577. output = self.app.post(
  2578. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2579. headers=headers,
  2580. data=data,
  2581. )
  2582. self.assertEqual(output.status_code, 400)
  2583. data = json.loads(output.get_data(as_text=True))
  2584. expected_output = {
  2585. "error": "Invalid or incomplete input submitted",
  2586. "error_code": "EINVALIDREQ",
  2587. "errors": {"status": ["Not a valid choice"]},
  2588. }
  2589. self.assertEqual(data, expected_output)
  2590. def test_flag_commit_missing_username(self):
  2591. """ Test flagging a commit with missing username. """
  2592. repo_obj = pygit2.Repository(self.git_path)
  2593. commit = repo_obj.revparse_single("HEAD")
  2594. headers = {"Authorization": "token aaabbbcccddd"}
  2595. data = {
  2596. "percent": 100,
  2597. "comment": "Tests passed",
  2598. "url": "http://jenkins.cloud.fedoraproject.org/",
  2599. "uid": "jenkins_build_pagure_100+seed",
  2600. "status": "success",
  2601. }
  2602. output = self.app.post(
  2603. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2604. headers=headers,
  2605. data=data,
  2606. )
  2607. self.assertEqual(output.status_code, 400)
  2608. data = json.loads(output.get_data(as_text=True))
  2609. expected_output = {
  2610. "error": "Invalid or incomplete input submitted",
  2611. "error_code": "EINVALIDREQ",
  2612. "errors": {"username": ["This field is required."]},
  2613. }
  2614. self.assertEqual(data, expected_output)
  2615. def test_flag_commit_missing_comment(self):
  2616. """ Test flagging a commit with missing comment. """
  2617. repo_obj = pygit2.Repository(self.git_path)
  2618. commit = repo_obj.revparse_single("HEAD")
  2619. headers = {"Authorization": "token aaabbbcccddd"}
  2620. data = {
  2621. "username": "Jenkins",
  2622. "percent": 100,
  2623. "url": "http://jenkins.cloud.fedoraproject.org/",
  2624. "uid": "jenkins_build_pagure_100+seed",
  2625. "status": "success",
  2626. }
  2627. output = self.app.post(
  2628. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2629. headers=headers,
  2630. data=data,
  2631. )
  2632. self.assertEqual(output.status_code, 400)
  2633. data = json.loads(output.get_data(as_text=True))
  2634. expected_output = {
  2635. "error": "Invalid or incomplete input submitted",
  2636. "error_code": "EINVALIDREQ",
  2637. "errors": {"comment": ["This field is required."]},
  2638. }
  2639. self.assertEqual(data, expected_output)
  2640. def test_flag_commit_missing_url(self):
  2641. """ Test flagging a commit with missing url. """
  2642. repo_obj = pygit2.Repository(self.git_path)
  2643. commit = repo_obj.revparse_single("HEAD")
  2644. headers = {"Authorization": "token aaabbbcccddd"}
  2645. data = {
  2646. "username": "Jenkins",
  2647. "percent": 100,
  2648. "comment": "Tests passed",
  2649. "uid": "jenkins_build_pagure_100+seed",
  2650. "status": "success",
  2651. }
  2652. output = self.app.post(
  2653. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2654. headers=headers,
  2655. data=data,
  2656. )
  2657. self.assertEqual(output.status_code, 400)
  2658. data = json.loads(output.get_data(as_text=True))
  2659. expected_output = {
  2660. "error": "Invalid or incomplete input submitted",
  2661. "error_code": "EINVALIDREQ",
  2662. "errors": {"url": ["This field is required."]},
  2663. }
  2664. self.assertEqual(data, expected_output)
  2665. def test_flag_commit_invalid_token(self):
  2666. """ Test flagging a commit with missing info. """
  2667. repo_obj = pygit2.Repository(self.git_path)
  2668. commit = repo_obj.revparse_single("HEAD")
  2669. headers = {"Authorization": "token 123"}
  2670. data = {
  2671. "username": "Jenkins",
  2672. "percent": 100,
  2673. "comment": "Tests passed",
  2674. "url": "http://jenkins.cloud.fedoraproject.org/",
  2675. "uid": "jenkins_build_pagure_100+seed",
  2676. }
  2677. output = self.app.post(
  2678. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2679. headers=headers,
  2680. data=data,
  2681. )
  2682. self.assertEqual(output.status_code, 401)
  2683. data = json.loads(output.get_data(as_text=True))
  2684. self.assertEqual(
  2685. sorted(data.keys()), ["error", "error_code", "errors"]
  2686. )
  2687. self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"])
  2688. self.assertEqual(
  2689. pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"]
  2690. )
  2691. self.assertEqual(data["errors"], "Invalid token")
  2692. def test_flag_commit_invalid_status(self):
  2693. """ Test flagging a commit with an invalid status. """
  2694. repo_obj = pygit2.Repository(self.git_path)
  2695. commit = repo_obj.revparse_single("HEAD")
  2696. headers = {"Authorization": "token aaabbbcccddd"}
  2697. data = {
  2698. "username": "Jenkins",
  2699. "percent": 100,
  2700. "comment": "Tests passed",
  2701. "url": "http://jenkins.cloud.fedoraproject.org/",
  2702. "status": "foobar",
  2703. }
  2704. output = self.app.post(
  2705. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2706. headers=headers,
  2707. data=data,
  2708. )
  2709. self.assertEqual(output.status_code, 400)
  2710. data = json.loads(output.get_data(as_text=True))
  2711. self.assertEqual(
  2712. data,
  2713. {
  2714. "errors": {"status": ["Not a valid choice"]},
  2715. "error_code": "EINVALIDREQ",
  2716. "error": "Invalid or incomplete input submitted",
  2717. },
  2718. )
  2719. def test_flag_commit_with_uid(self):
  2720. """ Test flagging a commit with provided uid. """
  2721. repo_obj = pygit2.Repository(self.git_path)
  2722. commit = repo_obj.revparse_single("HEAD")
  2723. headers = {"Authorization": "token aaabbbcccddd"}
  2724. data = {
  2725. "username": "Jenkins",
  2726. "percent": 100,
  2727. "comment": "Tests passed",
  2728. "url": "http://jenkins.cloud.fedoraproject.org/",
  2729. "uid": "jenkins_build_pagure_100+seed",
  2730. "status": "success",
  2731. }
  2732. output = self.app.post(
  2733. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2734. headers=headers,
  2735. data=data,
  2736. )
  2737. self.assertEqual(output.status_code, 200)
  2738. data = json.loads(output.get_data(as_text=True))
  2739. data["flag"]["date_created"] = "1510742565"
  2740. data["flag"]["date_updated"] = "1510742565"
  2741. data["flag"]["commit_hash"] = "62b49f00d489452994de5010565fab81"
  2742. expected_output = {
  2743. "flag": {
  2744. "comment": "Tests passed",
  2745. "commit_hash": "62b49f00d489452994de5010565fab81",
  2746. "date_created": "1510742565",
  2747. "date_updated": "1510742565",
  2748. "percent": 100,
  2749. "status": "success",
  2750. "url": "http://jenkins.cloud.fedoraproject.org/",
  2751. "user": {
  2752. "default_email": "bar@pingou.com",
  2753. "emails": ["bar@pingou.com", "foo@pingou.com"],
  2754. "fullname": "PY C",
  2755. "name": "pingou",
  2756. },
  2757. "username": "Jenkins",
  2758. },
  2759. "message": "Flag added",
  2760. "uid": "jenkins_build_pagure_100+seed",
  2761. }
  2762. self.assertEqual(data, expected_output)
  2763. @patch("pagure.lib.notify.send_email")
  2764. def test_flag_commit_without_uid(self, mock_email):
  2765. """ Test flagging a commit with missing info.
  2766. Also ensure notifications aren't sent when they are not asked for.
  2767. """
  2768. repo_obj = pygit2.Repository(self.git_path)
  2769. commit = repo_obj.revparse_single("HEAD")
  2770. headers = {"Authorization": "token aaabbbcccddd"}
  2771. data = {
  2772. "username": "Jenkins",
  2773. "percent": 100,
  2774. "comment": "Tests passed",
  2775. "url": "http://jenkins.cloud.fedoraproject.org/",
  2776. "status": "success",
  2777. }
  2778. output = self.app.post(
  2779. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2780. headers=headers,
  2781. data=data,
  2782. )
  2783. self.assertEqual(output.status_code, 200)
  2784. data = json.loads(output.get_data(as_text=True))
  2785. self.assertNotEqual(data["uid"], "jenkins_build_pagure_100+seed")
  2786. data["flag"]["date_created"] = "1510742565"
  2787. data["flag"]["date_updated"] = "1510742565"
  2788. data["uid"] = "b1de8f80defd4a81afe2e09f39678087"
  2789. expected_output = {
  2790. "flag": {
  2791. "comment": "Tests passed",
  2792. "commit_hash": commit.oid.hex,
  2793. "date_created": "1510742565",
  2794. "date_updated": "1510742565",
  2795. "percent": 100,
  2796. "status": "success",
  2797. "url": "http://jenkins.cloud.fedoraproject.org/",
  2798. "user": {
  2799. "default_email": "bar@pingou.com",
  2800. "emails": ["bar@pingou.com", "foo@pingou.com"],
  2801. "fullname": "PY C",
  2802. "name": "pingou",
  2803. },
  2804. "username": "Jenkins",
  2805. },
  2806. "message": "Flag added",
  2807. "uid": "b1de8f80defd4a81afe2e09f39678087",
  2808. }
  2809. self.assertEqual(data, expected_output)
  2810. mock_email.assert_not_called()
  2811. @patch("pagure.lib.notify.send_email")
  2812. def test_flag_commit_with_notification(self, mock_email):
  2813. """ Test flagging a commit with notification enabled. """
  2814. # Enable commit notifications
  2815. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2816. settings = repo.settings
  2817. settings["notify_on_commit_flag"] = True
  2818. repo.settings = settings
  2819. self.session.add(repo)
  2820. self.session.commit()
  2821. repo_obj = pygit2.Repository(self.git_path)
  2822. commit = repo_obj.revparse_single("HEAD")
  2823. headers = {"Authorization": "token aaabbbcccddd"}
  2824. data = {
  2825. "username": "Jenkins",
  2826. "percent": 100,
  2827. "comment": "Tests passed",
  2828. "url": "http://jenkins.cloud.fedoraproject.org/",
  2829. "status": "success",
  2830. }
  2831. output = self.app.post(
  2832. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2833. headers=headers,
  2834. data=data,
  2835. )
  2836. self.assertEqual(output.status_code, 200)
  2837. data = json.loads(output.get_data(as_text=True))
  2838. self.assertNotEqual(data["uid"], "jenkins_build_pagure_100+seed")
  2839. data["flag"]["date_created"] = "1510742565"
  2840. data["flag"]["date_updated"] = "1510742565"
  2841. data["uid"] = "b1de8f80defd4a81afe2e09f39678087"
  2842. expected_output = {
  2843. "flag": {
  2844. "comment": "Tests passed",
  2845. "commit_hash": commit.oid.hex,
  2846. "date_created": "1510742565",
  2847. "date_updated": "1510742565",
  2848. "percent": 100,
  2849. "status": "success",
  2850. "url": "http://jenkins.cloud.fedoraproject.org/",
  2851. "user": {
  2852. "default_email": "bar@pingou.com",
  2853. "emails": ["bar@pingou.com", "foo@pingou.com"],
  2854. "fullname": "PY C",
  2855. "name": "pingou",
  2856. },
  2857. "username": "Jenkins",
  2858. },
  2859. "message": "Flag added",
  2860. "uid": "b1de8f80defd4a81afe2e09f39678087",
  2861. }
  2862. self.assertEqual(data, expected_output)
  2863. mock_email.assert_called_once_with(
  2864. "\nJenkins flagged the commit "
  2865. "`" + commit.oid.hex + "` as success: "
  2866. "Tests passed\n\n"
  2867. "http://localhost.localdomain/test/c/" + commit.oid.hex + "\n",
  2868. "Commit #" + commit.oid.hex + " - Jenkins: success",
  2869. "bar@pingou.com",
  2870. in_reply_to="test-project-1",
  2871. mail_id="test-commit-1-1",
  2872. project_name="test",
  2873. user_from="Jenkins",
  2874. )
  2875. @patch.dict(
  2876. "pagure.config.config",
  2877. {
  2878. "FLAG_STATUSES_LABELS": {
  2879. "pend!": "label-info",
  2880. "succeed!": "label-success",
  2881. "fail!": "label-danger",
  2882. "what?": "label-warning",
  2883. },
  2884. "FLAG_PENDING": "pend!",
  2885. "FLAG_SUCCESS": "succeed!",
  2886. "FLAG_FAILURE": "fail!",
  2887. },
  2888. )
  2889. def test_flag_commit_with_custom_flags(self):
  2890. """ Test flagging when custom flags are set up
  2891. """
  2892. repo_obj = pygit2.Repository(self.git_path)
  2893. commit = repo_obj.revparse_single("HEAD")
  2894. headers = {"Authorization": "token aaabbbcccddd"}
  2895. send_data = {
  2896. "username": "Jenkins",
  2897. "percent": 100,
  2898. "comment": "Tests passed",
  2899. "url": "http://jenkins.cloud.fedoraproject.org/",
  2900. "status": "succeed!",
  2901. }
  2902. output = self.app.post(
  2903. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2904. headers=headers,
  2905. data=send_data,
  2906. )
  2907. self.assertEqual(output.status_code, 200)
  2908. data = json.loads(output.get_data(as_text=True))
  2909. self.assertEqual(data["flag"]["status"], "succeed!")
  2910. # Try invalid flag status
  2911. send_data["status"] = "nooooo...."
  2912. output = self.app.post(
  2913. "/api/0/test/c/%s/flag" % commit.oid.hex,
  2914. headers=headers,
  2915. data=send_data,
  2916. )
  2917. self.assertEqual(output.status_code, 400)
  2918. data = json.loads(output.get_data(as_text=True))
  2919. self.assertEqual(
  2920. data,
  2921. {
  2922. "errors": {"status": ["Not a valid choice"]},
  2923. "error_code": "EINVALIDREQ",
  2924. "error": "Invalid or incomplete input submitted",
  2925. },
  2926. )
  2927. def test_commit_flags(self):
  2928. """ Test retrieving commit flags. """
  2929. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2930. repo_obj = pygit2.Repository(self.git_path)
  2931. commit = repo_obj.revparse_single("HEAD")
  2932. # test with no flags
  2933. output = self.app.get("/api/0/test/c/%s/flag" % commit.oid.hex)
  2934. self.assertEqual(
  2935. json.loads(output.get_data(as_text=True)),
  2936. {"total_flags": 0, "flags": []},
  2937. )
  2938. self.assertEqual(output.status_code, 200)
  2939. # add some flags and retrieve them
  2940. pagure.lib.query.add_commit_flag(
  2941. session=self.session,
  2942. repo=repo,
  2943. commit_hash=commit.oid.hex,
  2944. username="simple-koji-ci",
  2945. status="pending",
  2946. percent=None,
  2947. comment="Build is running",
  2948. url="https://koji.fp.o/koji...",
  2949. uid="uid",
  2950. user="foo",
  2951. token="aaabbbcccddd",
  2952. )
  2953. pagure.lib.query.add_commit_flag(
  2954. session=self.session,
  2955. repo=repo,
  2956. commit_hash=commit.oid.hex,
  2957. username="complex-koji-ci",
  2958. status="success",
  2959. percent=None,
  2960. comment="Build succeeded",
  2961. url="https://koji.fp.o/koji...",
  2962. uid="uid2",
  2963. user="foo",
  2964. token="aaabbbcccddd",
  2965. )
  2966. self.session.commit()
  2967. output = self.app.get("/api/0/test/c/%s/flag" % commit.oid.hex)
  2968. data = json.loads(output.get_data(as_text=True))
  2969. for f in data["flags"]:
  2970. f["date_created"] = "1510742565"
  2971. f["date_updated"] = "1510742565"
  2972. f["commit_hash"] = "62b49f00d489452994de5010565fab81"
  2973. expected_output = {
  2974. "flags": [
  2975. {
  2976. "comment": "Build is running",
  2977. "commit_hash": "62b49f00d489452994de5010565fab81",
  2978. "date_created": "1510742565",
  2979. "date_updated": "1510742565",
  2980. "percent": None,
  2981. "status": "pending",
  2982. "url": "https://koji.fp.o/koji...",
  2983. "user": {"fullname": "foo bar", "name": "foo"},
  2984. "username": "simple-koji-ci",
  2985. },
  2986. {
  2987. "comment": "Build succeeded",
  2988. "commit_hash": "62b49f00d489452994de5010565fab81",
  2989. "date_created": "1510742565",
  2990. "date_updated": "1510742565",
  2991. "percent": None,
  2992. "status": "success",
  2993. "url": "https://koji.fp.o/koji...",
  2994. "user": {"fullname": "foo bar", "name": "foo"},
  2995. "username": "complex-koji-ci",
  2996. },
  2997. ],
  2998. "total_flags": 2,
  2999. }
  3000. self.assertEqual(data, expected_output)
  3001. class PagureFlaskApiProjectModifyAclTests(tests.Modeltests):
  3002. """ Tests for the flask API of pagure for modifying ACLs in a project
  3003. """
  3004. maxDiff = None
  3005. def setUp(self):
  3006. """ Set up the environnment, ran before every tests. """
  3007. super(PagureFlaskApiProjectModifyAclTests, self).setUp()
  3008. tests.create_projects(self.session)
  3009. tests.create_tokens(self.session, project_id=None)
  3010. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  3011. project = pagure.lib.query._get_project(self.session, "test")
  3012. self.assertEquals(
  3013. project.access_users, {"admin": [], "commit": [], "ticket": []}
  3014. )
  3015. def test_api_modify_acls_no_project(self):
  3016. """ Test the api_modify_acls method of the flask api when the project
  3017. doesn't exist """
  3018. headers = {"Authorization": "token aaabbbcccddd"}
  3019. data = {"user_type": "user", "name": "bar", "acl": "commit"}
  3020. output = self.app.post(
  3021. "/api/0/test12345123/git/modifyacls", headers=headers, data=data
  3022. )
  3023. self.assertEqual(output.status_code, 404)
  3024. data = json.loads(output.get_data(as_text=True))
  3025. expected_output = {
  3026. "error_code": "ENOPROJECT",
  3027. "error": "Project not found",
  3028. }
  3029. self.assertEqual(data, expected_output)
  3030. def test_api_modify_acls_no_user(self):
  3031. """ Test the api_modify_acls method of the flask api when the user
  3032. doesn't exist """
  3033. headers = {"Authorization": "token aaabbbcccddd"}
  3034. data = {"user_type": "user", "name": "nosuchuser", "acl": "commit"}
  3035. output = self.app.post(
  3036. "/api/0/test/git/modifyacls", headers=headers, data=data
  3037. )
  3038. self.assertEqual(output.status_code, 404)
  3039. data = json.loads(output.get_data(as_text=True))
  3040. expected_output = {
  3041. "error": "No such user found",
  3042. "error_code": "ENOUSER",
  3043. }
  3044. self.assertEqual(data, expected_output)
  3045. def test_api_modify_acls_no_group(self):
  3046. """ Test the api_modify_acls method of the flask api when the group
  3047. doesn't exist """
  3048. headers = {"Authorization": "token aaabbbcccddd"}
  3049. data = {"user_type": "group", "name": "nosuchgroup", "acl": "commit"}
  3050. output = self.app.post(
  3051. "/api/0/test/git/modifyacls", headers=headers, data=data
  3052. )
  3053. self.assertEqual(output.status_code, 404)
  3054. data = json.loads(output.get_data(as_text=True))
  3055. expected_output = {
  3056. "error": "Group not found",
  3057. "error_code": "ENOGROUP",
  3058. }
  3059. self.assertEqual(data, expected_output)
  3060. def test_api_modify_acls_no_permission(self):
  3061. """ Test the api_modify_acls method of the flask api when the user
  3062. doesn't have permissions """
  3063. item = pagure.lib.model.Token(
  3064. id="foo_token2",
  3065. user_id=2,
  3066. project_id=None,
  3067. expiration=datetime.datetime.utcnow()
  3068. + datetime.timedelta(days=30),
  3069. )
  3070. self.session.add(item)
  3071. self.session.commit()
  3072. tests.create_tokens_acl(self.session, "foo_token2", "modify_project")
  3073. headers = {"Authorization": "token foo_token2"}
  3074. data = {"user_type": "user", "name": "foo", "acl": "commit"}
  3075. output = self.app.post(
  3076. "/api/0/test/git/modifyacls", headers=headers, data=data
  3077. )
  3078. self.assertEqual(output.status_code, 401)
  3079. data = json.loads(output.get_data(as_text=True))
  3080. expected_output = {
  3081. "error": "You are not allowed to modify this project",
  3082. "error_code": "EMODIFYPROJECTNOTALLOWED",
  3083. }
  3084. self.assertEqual(data, expected_output)
  3085. def test_api_modify_acls_neither_user_nor_group(self):
  3086. """ Test the api_modify_acls method of the flask api when neither
  3087. user nor group was set """
  3088. headers = {"Authorization": "token aaabbbcccddd"}
  3089. data = {"acl": "commit"}
  3090. output = self.app.post(
  3091. "/api/0/test/git/modifyacls", headers=headers, data=data
  3092. )
  3093. self.assertEqual(output.status_code, 400)
  3094. data = json.loads(output.get_data(as_text=True))
  3095. expected_output = {
  3096. "error": "Invalid or incomplete input submitted",
  3097. "error_code": "EINVALIDREQ",
  3098. "errors": {
  3099. "name": ["This field is required."],
  3100. "user_type": ["Not a valid choice"],
  3101. },
  3102. }
  3103. self.assertEqual(data, expected_output)
  3104. def test_api_modify_acls_invalid_acl(self):
  3105. """ Test the api_modify_acls method of the flask api when the ACL
  3106. doesn't exist. Must be one of ticket, commit or admin. """
  3107. headers = {"Authorization": "token aaabbbcccddd"}
  3108. data = {"user_type": "user", "name": "bar", "acl": "invalidacl"}
  3109. output = self.app.post(
  3110. "/api/0/test/git/modifyacls", headers=headers, data=data
  3111. )
  3112. self.assertEqual(output.status_code, 400)
  3113. data = json.loads(output.get_data(as_text=True))
  3114. expected_output = {
  3115. "error": "Invalid or incomplete input submitted",
  3116. "error_code": "EINVALIDREQ",
  3117. "errors": {"acl": ["Not a valid choice"]},
  3118. }
  3119. self.assertEqual(data, expected_output)
  3120. def test_api_modify_acls_user(self):
  3121. """ Test the api_modify_acls method of the flask api for
  3122. setting an ACL for a user. """
  3123. headers = {"Authorization": "token aaabbbcccddd"}
  3124. data = {"user_type": "user", "name": "foo", "acl": "commit"}
  3125. output = self.app.post(
  3126. "/api/0/test/git/modifyacls", headers=headers, data=data
  3127. )
  3128. self.assertEqual(output.status_code, 200)
  3129. data = json.loads(output.get_data(as_text=True))
  3130. data["date_created"] = "1510742565"
  3131. data["date_modified"] = "1510742566"
  3132. expected_output = {
  3133. "access_groups": {"admin": [], "commit": [], "ticket": []},
  3134. "access_users": {
  3135. "admin": [],
  3136. "commit": ["foo"],
  3137. "owner": ["pingou"],
  3138. "ticket": [],
  3139. },
  3140. "close_status": [
  3141. "Invalid",
  3142. "Insufficient data",
  3143. "Fixed",
  3144. "Duplicate",
  3145. ],
  3146. "custom_keys": [],
  3147. "date_created": "1510742565",
  3148. "date_modified": "1510742566",
  3149. "description": "test project #1",
  3150. "fullname": "test",
  3151. "id": 1,
  3152. "milestones": {},
  3153. "name": "test",
  3154. "namespace": None,
  3155. "parent": None,
  3156. "priorities": {},
  3157. "tags": [],
  3158. "url_path": "test",
  3159. "user": {"fullname": "PY C", "name": "pingou"},
  3160. }
  3161. self.assertEqual(data, expected_output)
  3162. def test_api_modify_acls_group(self):
  3163. """ Test the api_modify_acls method of the flask api for
  3164. setting an ACL for a group. """
  3165. headers = {"Authorization": "token aaabbbcccddd"}
  3166. # Create a group
  3167. msg = pagure.lib.query.add_group(
  3168. self.session,
  3169. group_name="baz",
  3170. display_name="baz group",
  3171. description=None,
  3172. group_type="bar",
  3173. user="foo",
  3174. is_admin=False,
  3175. blacklist=[],
  3176. )
  3177. self.session.commit()
  3178. self.assertEqual(msg, "User `foo` added to the group `baz`.")
  3179. data = {"user_type": "group", "name": "baz", "acl": "ticket"}
  3180. output = self.app.post(
  3181. "/api/0/test/git/modifyacls", headers=headers, data=data
  3182. )
  3183. self.assertEqual(output.status_code, 200)
  3184. data = json.loads(output.get_data(as_text=True))
  3185. data["date_created"] = "1510742565"
  3186. data["date_modified"] = "1510742566"
  3187. expected_output = {
  3188. "access_groups": {"admin": [], "commit": [], "ticket": ["baz"]},
  3189. "access_users": {
  3190. "admin": [],
  3191. "commit": [],
  3192. "owner": ["pingou"],
  3193. "ticket": [],
  3194. },
  3195. "close_status": [
  3196. "Invalid",
  3197. "Insufficient data",
  3198. "Fixed",
  3199. "Duplicate",
  3200. ],
  3201. "custom_keys": [],
  3202. "date_created": "1510742565",
  3203. "date_modified": "1510742566",
  3204. "description": "test project #1",
  3205. "fullname": "test",
  3206. "id": 1,
  3207. "milestones": {},
  3208. "name": "test",
  3209. "namespace": None,
  3210. "parent": None,
  3211. "priorities": {},
  3212. "tags": [],
  3213. "url_path": "test",
  3214. "user": {"fullname": "PY C", "name": "pingou"},
  3215. }
  3216. self.assertEqual(data, expected_output)
  3217. def test_api_modify_acls_no_acl(self):
  3218. """ Test the api_modify_acls method of the flask api when no ACL
  3219. are specified. """
  3220. headers = {"Authorization": "token aaabbbcccddd"}
  3221. project = pagure.lib.query._get_project(self.session, "test")
  3222. self.assertEquals(
  3223. project.access_users, {"admin": [], "commit": [], "ticket": []}
  3224. )
  3225. data = {"user_type": "user", "name": "foo"}
  3226. output = self.app.post(
  3227. "/api/0/test/git/modifyacls", headers=headers, data=data
  3228. )
  3229. self.assertEqual(output.status_code, 400)
  3230. data = json.loads(output.get_data(as_text=True))
  3231. expected_output = {
  3232. "error": "Invalid or incomplete input submitted",
  3233. "error_code": "EINVALIDREQ",
  3234. "errors": "User does not have any access on the repo",
  3235. }
  3236. self.assertEqual(data, expected_output)
  3237. def test_api_modify_acls_remove_own_acl_no_access(self):
  3238. """ Test the api_modify_acls method of the flask api when no ACL
  3239. are specified, so the user tries to remove their own access but the
  3240. user is the project owner. """
  3241. headers = {"Authorization": "token aaabbbcccddd"}
  3242. data = {"user_type": "user", "name": "pingou"}
  3243. output = self.app.post(
  3244. "/api/0/test/git/modifyacls", headers=headers, data=data
  3245. )
  3246. self.assertEqual(output.status_code, 400)
  3247. data = json.loads(output.get_data(as_text=True))
  3248. expected_output = {
  3249. "error": "Invalid or incomplete input submitted",
  3250. "error_code": "EINVALIDREQ",
  3251. "errors": "User does not have any access on the repo",
  3252. }
  3253. self.assertEqual(data, expected_output)
  3254. def test_api_modify_acls_remove_own_acl_(self):
  3255. """ Test the api_modify_acls method of the flask api when no ACL
  3256. are specified, so the user tries to remove their own access but the
  3257. user is the project owner. """
  3258. # Add the user `foo` to the project
  3259. self.test_api_modify_acls_user()
  3260. # Ensure `foo` was properly added:
  3261. project = pagure.lib.query._get_project(self.session, "test")
  3262. user_foo = pagure.lib.query.search_user(self.session, username="foo")
  3263. self.assertEquals(
  3264. project.access_users,
  3265. {"admin": [], "commit": [user_foo], "ticket": []},
  3266. )
  3267. # Create an API token for `foo` for the project `test`
  3268. item = pagure.lib.model.Token(
  3269. id="foo_test_token",
  3270. user_id=2, # foo
  3271. project_id=1, # test
  3272. expiration=datetime.datetime.utcnow()
  3273. + datetime.timedelta(days=10),
  3274. )
  3275. self.session.add(item)
  3276. self.session.commit()
  3277. tests.create_tokens_acl(
  3278. self.session, "foo_test_token", "modify_project"
  3279. )
  3280. headers = {"Authorization": "token foo_test_token"}
  3281. data = {"user_type": "user", "name": "foo"}
  3282. output = self.app.post(
  3283. "/api/0/test/git/modifyacls", headers=headers, data=data
  3284. )
  3285. self.assertEqual(output.status_code, 200)
  3286. data = json.loads(output.get_data(as_text=True))
  3287. data["date_created"] = "1510742565"
  3288. data["date_modified"] = "1510742566"
  3289. expected_output = {
  3290. "access_groups": {"admin": [], "commit": [], "ticket": []},
  3291. "access_users": {
  3292. "admin": [],
  3293. "commit": [],
  3294. "owner": ["pingou"],
  3295. "ticket": [],
  3296. },
  3297. "close_status": [
  3298. "Invalid",
  3299. "Insufficient data",
  3300. "Fixed",
  3301. "Duplicate",
  3302. ],
  3303. "custom_keys": [],
  3304. "date_created": "1510742565",
  3305. "date_modified": "1510742566",
  3306. "description": "test project #1",
  3307. "fullname": "test",
  3308. "id": 1,
  3309. "milestones": {},
  3310. "name": "test",
  3311. "namespace": None,
  3312. "parent": None,
  3313. "priorities": {},
  3314. "tags": [],
  3315. "url_path": "test",
  3316. "user": {"fullname": "PY C", "name": "pingou"},
  3317. }
  3318. self.assertEqual(data, expected_output)
  3319. # Ensure `foo` was properly removed
  3320. self.session = pagure.lib.query.create_session(self.dbpath)
  3321. project = pagure.lib.query._get_project(self.session, "test")
  3322. self.assertEquals(
  3323. project.access_users, {"admin": [], "commit": [], "ticket": []}
  3324. )
  3325. def test_api_modify_acls_remove_someone_else_acl(self):
  3326. """ Test the api_modify_acls method of the flask api an admin tries
  3327. to remove access from someone else. """
  3328. # Add the user `foo` to the project
  3329. self.test_api_modify_acls_user()
  3330. # Ensure `foo` was properly added:
  3331. project = pagure.lib.query._get_project(self.session, "test")
  3332. user_foo = pagure.lib.query.search_user(self.session, username="foo")
  3333. self.assertEquals(
  3334. project.access_users,
  3335. {"admin": [], "commit": [user_foo], "ticket": []},
  3336. )
  3337. headers = {"Authorization": "token aaabbbcccddd"}
  3338. data = {"user_type": "user", "name": "foo"}
  3339. output = self.app.post(
  3340. "/api/0/test/git/modifyacls", headers=headers, data=data
  3341. )
  3342. self.assertEqual(output.status_code, 200)
  3343. data = json.loads(output.get_data(as_text=True))
  3344. data["date_created"] = "1510742565"
  3345. data["date_modified"] = "1510742566"
  3346. expected_output = {
  3347. "access_groups": {"admin": [], "commit": [], "ticket": []},
  3348. "access_users": {
  3349. "admin": [],
  3350. "commit": [],
  3351. "owner": ["pingou"],
  3352. "ticket": [],
  3353. },
  3354. "close_status": [
  3355. "Invalid",
  3356. "Insufficient data",
  3357. "Fixed",
  3358. "Duplicate",
  3359. ],
  3360. "custom_keys": [],
  3361. "date_created": "1510742565",
  3362. "date_modified": "1510742566",
  3363. "description": "test project #1",
  3364. "fullname": "test",
  3365. "id": 1,
  3366. "milestones": {},
  3367. "name": "test",
  3368. "namespace": None,
  3369. "parent": None,
  3370. "priorities": {},
  3371. "tags": [],
  3372. "url_path": "test",
  3373. "user": {"fullname": "PY C", "name": "pingou"},
  3374. }
  3375. self.assertEqual(data, expected_output)
  3376. # Ensure `foo` was properly removed
  3377. self.session = pagure.lib.query.create_session(self.dbpath)
  3378. project = pagure.lib.query._get_project(self.session, "test")
  3379. self.assertEquals(
  3380. project.access_users, {"admin": [], "commit": [], "ticket": []}
  3381. )
  3382. class PagureFlaskApiProjectOptionsTests(tests.Modeltests):
  3383. """ Tests for the flask API of pagure for modifying options ofs a project
  3384. """
  3385. maxDiff = None
  3386. def setUp(self):
  3387. """ Set up the environnment, ran before every tests. """
  3388. super(PagureFlaskApiProjectOptionsTests, self).setUp()
  3389. tests.create_projects(self.session)
  3390. tests.create_tokens(self.session, project_id=None)
  3391. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  3392. project = pagure.lib.query._get_project(self.session, "test")
  3393. self.assertEquals(
  3394. project.access_users, {"admin": [], "commit": [], "ticket": []}
  3395. )
  3396. def test_api_get_project_options_wrong_project(self):
  3397. """ Test accessing api_get_project_options w/o auth header. """
  3398. headers = {"Authorization": "token aaabbbcccddd"}
  3399. output = self.app.get("/api/0/unknown/options", headers=headers)
  3400. self.assertEqual(output.status_code, 404)
  3401. data = json.loads(output.get_data(as_text=True))
  3402. self.assertEqual(
  3403. data, {"error": "Project not found", "error_code": "ENOPROJECT"}
  3404. )
  3405. def test_api_get_project_options_wo_header(self):
  3406. """ Test accessing api_get_project_options w/o auth header. """
  3407. output = self.app.get("/api/0/test/options")
  3408. self.assertEqual(output.status_code, 401)
  3409. data = json.loads(output.get_data(as_text=True))
  3410. self.assertEqual(
  3411. data,
  3412. {
  3413. "error": "Invalid or expired token. Please visit "
  3414. "http://localhost.localdomain/settings#nav-api-tab to get "
  3415. "or renew your API token.",
  3416. "error_code": "EINVALIDTOK",
  3417. "errors": "Invalid token",
  3418. },
  3419. )
  3420. def test_api_get_project_options_w_header(self):
  3421. """ Test accessing api_get_project_options w/ auth header. """
  3422. headers = {"Authorization": "token aaabbbcccddd"}
  3423. output = self.app.get("/api/0/test/options", headers=headers)
  3424. self.assertEqual(output.status_code, 200)
  3425. data = json.loads(output.get_data(as_text=True))
  3426. self.assertEqual(
  3427. data,
  3428. {
  3429. "settings": {
  3430. "Enforce_signed-off_commits_in_pull-request": False,
  3431. "Minimum_score_to_merge_pull-request": -1,
  3432. "Only_assignee_can_merge_pull-request": False,
  3433. "Web-hooks": None,
  3434. "always_merge": False,
  3435. "disable_non_fast-forward_merges": False,
  3436. "fedmsg_notifications": True,
  3437. "issue_tracker": True,
  3438. "issue_tracker_read_only": False,
  3439. "issues_default_to_private": False,
  3440. "mqtt_notifications": True,
  3441. "notify_on_commit_flag": False,
  3442. "notify_on_pull-request_flag": False,
  3443. "open_metadata_access_to_all": False,
  3444. "project_documentation": False,
  3445. "pull_request_access_only": False,
  3446. "pull_requests": True,
  3447. "stomp_notifications": True,
  3448. },
  3449. "status": "ok",
  3450. },
  3451. )
  3452. def test_api_modify_project_options_wrong_project(self):
  3453. """ Test accessing api_modify_project_options w/ an invalid project.
  3454. """
  3455. headers = {"Authorization": "token aaabbbcccddd"}
  3456. output = self.app.post(
  3457. "/api/0/unknown/options/update", headers=headers
  3458. )
  3459. self.assertEqual(output.status_code, 404)
  3460. data = json.loads(output.get_data(as_text=True))
  3461. self.assertEqual(
  3462. data, {"error": "Project not found", "error_code": "ENOPROJECT"}
  3463. )
  3464. def test_api_modify_project_options_wo_header(self):
  3465. """ Test accessing api_modify_project_options w/o auth header. """
  3466. output = self.app.post("/api/0/test/options/update")
  3467. self.assertEqual(output.status_code, 401)
  3468. data = json.loads(output.get_data(as_text=True))
  3469. self.assertEqual(
  3470. data,
  3471. {
  3472. "error": "Invalid or expired token. Please visit "
  3473. "http://localhost.localdomain/settings#nav-api-tab to get "
  3474. "or renew your API token.",
  3475. "error_code": "EINVALIDTOK",
  3476. "errors": "Invalid token",
  3477. },
  3478. )
  3479. def test_api_modify_project_options_no_data(self):
  3480. """ Test accessing api_modify_project_options w/ auth header. """
  3481. # check before
  3482. headers = {"Authorization": "token aaabbbcccddd"}
  3483. output = self.app.get("/api/0/test/options", headers=headers)
  3484. self.assertEqual(output.status_code, 200)
  3485. before = json.loads(output.get_data(as_text=True))
  3486. self.assertEqual(
  3487. before,
  3488. {
  3489. "settings": {
  3490. "Enforce_signed-off_commits_in_pull-request": False,
  3491. "Minimum_score_to_merge_pull-request": -1,
  3492. "Only_assignee_can_merge_pull-request": False,
  3493. "Web-hooks": None,
  3494. "always_merge": False,
  3495. "disable_non_fast-forward_merges": False,
  3496. "fedmsg_notifications": True,
  3497. "issue_tracker": True,
  3498. "issue_tracker_read_only": False,
  3499. "issues_default_to_private": False,
  3500. "mqtt_notifications": True,
  3501. "notify_on_commit_flag": False,
  3502. "notify_on_pull-request_flag": False,
  3503. "open_metadata_access_to_all": False,
  3504. "project_documentation": False,
  3505. "pull_request_access_only": False,
  3506. "pull_requests": True,
  3507. "stomp_notifications": True,
  3508. },
  3509. "status": "ok",
  3510. },
  3511. )
  3512. # Do not update anything
  3513. data = {}
  3514. output = self.app.post(
  3515. "/api/0/test/options/update", headers=headers, data=data
  3516. )
  3517. self.assertEqual(output.status_code, 200)
  3518. data = json.loads(output.get_data(as_text=True))
  3519. self.assertEqual(
  3520. data, {"message": "No settings to change", "status": "ok"}
  3521. )
  3522. # check after
  3523. headers = {"Authorization": "token aaabbbcccddd"}
  3524. output = self.app.get("/api/0/test/options", headers=headers)
  3525. self.assertEqual(output.status_code, 200)
  3526. after = json.loads(output.get_data(as_text=True))
  3527. self.assertEqual(after, before)
  3528. def test_api_modify_project_options(self):
  3529. """ Test accessing api_modify_project_options w/ auth header. """
  3530. # check before
  3531. headers = {"Authorization": "token aaabbbcccddd"}
  3532. output = self.app.get("/api/0/test/options", headers=headers)
  3533. self.assertEqual(output.status_code, 200)
  3534. before = json.loads(output.get_data(as_text=True))
  3535. self.assertEqual(
  3536. before,
  3537. {
  3538. "settings": {
  3539. "Enforce_signed-off_commits_in_pull-request": False,
  3540. "Minimum_score_to_merge_pull-request": -1,
  3541. "Only_assignee_can_merge_pull-request": False,
  3542. "Web-hooks": None,
  3543. "always_merge": False,
  3544. "disable_non_fast-forward_merges": False,
  3545. "fedmsg_notifications": True,
  3546. "issue_tracker": True,
  3547. "issue_tracker_read_only": False,
  3548. "issues_default_to_private": False,
  3549. "mqtt_notifications": True,
  3550. "notify_on_commit_flag": False,
  3551. "notify_on_pull-request_flag": False,
  3552. "open_metadata_access_to_all": False,
  3553. "project_documentation": False,
  3554. "pull_request_access_only": False,
  3555. "pull_requests": True,
  3556. "stomp_notifications": True,
  3557. },
  3558. "status": "ok",
  3559. },
  3560. )
  3561. # Update: `issues_default_to_private`.
  3562. data = {"issues_default_to_private": True}
  3563. output = self.app.post(
  3564. "/api/0/test/options/update", headers=headers, data=data
  3565. )
  3566. self.assertEqual(output.status_code, 200)
  3567. data = json.loads(output.get_data(as_text=True))
  3568. self.assertEqual(
  3569. data,
  3570. {
  3571. "message": "Edited successfully settings of repo: test",
  3572. "status": "ok",
  3573. },
  3574. )
  3575. # check after
  3576. headers = {"Authorization": "token aaabbbcccddd"}
  3577. output = self.app.get("/api/0/test/options", headers=headers)
  3578. self.assertEqual(output.status_code, 200)
  3579. after = json.loads(output.get_data(as_text=True))
  3580. self.assertNotEqual(before, after)
  3581. before["settings"]["issues_default_to_private"] = True
  3582. self.assertEqual(after, before)
  3583. class PagureFlaskApiProjectCreateAPITokenTests(tests.Modeltests):
  3584. """ Tests for the flask API of pagure for creating user project API token
  3585. """
  3586. maxDiff = None
  3587. def setUp(self):
  3588. """ Set up the environnment, ran before every tests. """
  3589. super(PagureFlaskApiProjectCreateAPITokenTests, self).setUp()
  3590. tests.create_projects(self.session)
  3591. tests.create_tokens(self.session, project_id=None)
  3592. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  3593. def test_api_createapitoken_as_owner(self):
  3594. """ Test accessing api_project_create_token as owner. """
  3595. headers = {"Authorization": "token aaabbbcccddd"}
  3596. project = pagure.lib.query._get_project(self.session, "test")
  3597. tdescription = "my new token"
  3598. # Call the api with pingou user token and verify content
  3599. data = {
  3600. "description": tdescription,
  3601. "acls": ["pull_request_merge", "pull_request_comment"],
  3602. }
  3603. output = self.app.post(
  3604. "/api/0/test/token/new", headers=headers, data=data
  3605. )
  3606. self.assertEqual(output.status_code, 200)
  3607. data = json.loads(output.get_data(as_text=True))
  3608. tid = pagure.lib.query.search_token(
  3609. self.session, None, description=tdescription
  3610. )[0].id
  3611. self.assertEqual(
  3612. data, {"token": {"description": tdescription, "id": tid}}
  3613. )
  3614. # Create a second token but with faulty acl
  3615. # Call the api with pingou user token and error code
  3616. data = {"description": tdescription, "acl": ["foo", "bar"]}
  3617. output = self.app.post(
  3618. "/api/0/test/token/new", headers=headers, data=data
  3619. )
  3620. self.assertEqual(output.status_code, 400)
  3621. def test_api_createapitoken_as_admin(self):
  3622. """ Test accessing api_project_create_token as admin. """
  3623. project = pagure.lib.query._get_project(self.session, "test")
  3624. # Set the foo user as test project admin
  3625. pagure.lib.query.add_user_to_project(
  3626. self.session,
  3627. project,
  3628. new_user="foo",
  3629. user="pingou",
  3630. access="admin",
  3631. )
  3632. self.session.commit()
  3633. # Create modify_project token for foo user
  3634. token = pagure.lib.query.add_token_to_user(
  3635. self.session, project=None, acls=["modify_project"], username="foo"
  3636. )
  3637. # Call the connector with foo user token and verify content
  3638. headers = {"Authorization": "token %s" % token.id}
  3639. tdescription = "my new token"
  3640. # Call the api with pingou user token and verify content
  3641. data = {
  3642. "description": tdescription,
  3643. "acls": ["pull_request_merge", "pull_request_comment"],
  3644. }
  3645. output = self.app.post(
  3646. "/api/0/test/token/new", headers=headers, data=data
  3647. )
  3648. self.assertEqual(output.status_code, 200)
  3649. data = json.loads(output.get_data(as_text=True))
  3650. tid = pagure.lib.query.search_token(
  3651. self.session, None, user="foo", description=tdescription
  3652. )[0].id
  3653. self.assertEqual(
  3654. data, {"token": {"description": tdescription, "id": tid}}
  3655. )
  3656. def test_api_createapitoken_as_unauthorized(self):
  3657. """ Test accessing api_project_create_token as project admin
  3658. but with unauthorized token ACL.
  3659. """
  3660. project = pagure.lib.query._get_project(self.session, "test")
  3661. # Set the foo user as test project admin
  3662. pagure.lib.query.add_user_to_project(
  3663. self.session,
  3664. project,
  3665. new_user="foo",
  3666. user="pingou",
  3667. access="admin",
  3668. )
  3669. self.session.commit()
  3670. # Create modify_project token for foo user
  3671. pagure.lib.query.add_token_to_user(
  3672. self.session, project=None, acls=["create_branch"], username="foo"
  3673. )
  3674. mtoken = pagure.lib.query.search_token(
  3675. self.session, ["create_branch"], user="foo"
  3676. )[0]
  3677. # Call the connector with foo user token and verify content
  3678. headers = {"Authorization": "token %s" % mtoken.id}
  3679. tdescription = "my new token"
  3680. # Call the api with pingou user token and verify content
  3681. data = {
  3682. "description": tdescription,
  3683. "acls": ["pull_request_merge", "pull_request_comment"],
  3684. }
  3685. output = self.app.post(
  3686. "/api/0/test/token/new", headers=headers, data=data
  3687. )
  3688. self.assertEqual(output.status_code, 401)
  3689. def test_api_createapitoken_as_unauthorized_2(self):
  3690. """ Test accessing api_project_create_token as project user
  3691. with unauthorized token ACL.
  3692. """
  3693. project = pagure.lib.query._get_project(self.session, "test")
  3694. # Set the foo user as test project admin
  3695. pagure.lib.query.add_user_to_project(
  3696. self.session,
  3697. project,
  3698. new_user="foo",
  3699. user="pingou",
  3700. access="commit",
  3701. )
  3702. self.session.commit()
  3703. # Create modify_project token for foo user
  3704. pagure.lib.query.add_token_to_user(
  3705. self.session, project=None, acls=["modify_project"], username="foo"
  3706. )
  3707. mtoken = pagure.lib.query.search_token(
  3708. self.session, ["modify_project"], user="foo"
  3709. )[0]
  3710. # Call the connector with foo user token and verify content
  3711. headers = {"Authorization": "token %s" % mtoken.id}
  3712. tdescription = "my new token"
  3713. # Call the api with pingou user token and verify content
  3714. data = {
  3715. "description": tdescription,
  3716. "acls": ["pull_request_merge", "pull_request_comment"],
  3717. }
  3718. output = self.app.post(
  3719. "/api/0/test/token/new", headers=headers, data=data
  3720. )
  3721. self.assertEqual(output.status_code, 401)
  3722. class PagureFlaskApiProjectConnectorTests(tests.Modeltests):
  3723. """ Tests for the flask API of pagure for getting connector of a project
  3724. """
  3725. maxDiff = None
  3726. def setUp(self):
  3727. """ Set up the environnment, ran before every tests. """
  3728. super(PagureFlaskApiProjectConnectorTests, self).setUp()
  3729. tests.create_projects(self.session)
  3730. tests.create_tokens(self.session, project_id=None)
  3731. tests.create_tokens_acl(self.session, "aaabbbcccddd", "modify_project")
  3732. def test_api_get_project_connector_as_owner(self):
  3733. """ Test accessing api_get_project_connector as project owner. """
  3734. project = pagure.lib.query._get_project(self.session, "test")
  3735. # Create witness project Token for pingou user
  3736. pagure.lib.query.add_token_to_user(
  3737. self.session,
  3738. project=project,
  3739. acls=["pull_request_merge"],
  3740. username="pingou",
  3741. )
  3742. ctokens = pagure.lib.query.search_token(
  3743. self.session, ["pull_request_merge"], user="pingou"
  3744. )
  3745. self.assertEqual(len(ctokens), 1)
  3746. # Call the connector with pingou user token and verify content
  3747. headers = {"Authorization": "token aaabbbcccddd"}
  3748. output = self.app.get("/api/0/test/connector", headers=headers)
  3749. self.assertEqual(output.status_code, 200)
  3750. data = json.loads(output.get_data(as_text=True))
  3751. self.assertEqual(
  3752. data,
  3753. {
  3754. "connector": {
  3755. "hook_token": project.hook_token,
  3756. "api_tokens": [
  3757. {
  3758. "description": t.description,
  3759. "id": t.id,
  3760. "expired": False,
  3761. }
  3762. for t in ctokens
  3763. ],
  3764. },
  3765. "status": "ok",
  3766. },
  3767. )
  3768. def test_api_get_project_connector_as_admin(self):
  3769. """ Test accessing api_get_project_connector as project admin """
  3770. project = pagure.lib.query._get_project(self.session, "test")
  3771. # Set the foo user as test project admin
  3772. pagure.lib.query.add_user_to_project(
  3773. self.session,
  3774. project,
  3775. new_user="foo",
  3776. user="pingou",
  3777. access="admin",
  3778. )
  3779. self.session.commit()
  3780. # Create modify_project token for foo user
  3781. pagure.lib.query.add_token_to_user(
  3782. self.session, project=None, acls=["modify_project"], username="foo"
  3783. )
  3784. mtoken = pagure.lib.query.search_token(
  3785. self.session, ["modify_project"], user="foo"
  3786. )[0]
  3787. # Create witness project Token for foo user
  3788. pagure.lib.query.add_token_to_user(
  3789. self.session,
  3790. project=project,
  3791. acls=["pull_request_merge"],
  3792. username="foo",
  3793. )
  3794. ctokens = pagure.lib.query.search_token(
  3795. self.session, ["pull_request_merge"], user="foo"
  3796. )
  3797. self.assertEqual(len(ctokens), 1)
  3798. # Call the connector with foo user token and verify content
  3799. headers = {"Authorization": "token %s" % mtoken.id}
  3800. output = self.app.get("/api/0/test/connector", headers=headers)
  3801. self.assertEqual(output.status_code, 200)
  3802. data = json.loads(output.get_data(as_text=True))
  3803. self.assertEqual(
  3804. data,
  3805. {
  3806. "connector": {
  3807. "hook_token": project.hook_token,
  3808. "api_tokens": [
  3809. {
  3810. "description": t.description,
  3811. "id": t.id,
  3812. "expired": False,
  3813. }
  3814. for t in ctokens
  3815. ],
  3816. },
  3817. "status": "ok",
  3818. },
  3819. )
  3820. def test_api_get_project_connector_as_unauthorized(self):
  3821. """ Test accessing api_get_project_connector as project admin
  3822. but with unauthorized token ACL
  3823. """
  3824. project = pagure.lib.query._get_project(self.session, "test")
  3825. # Set the foo user as test project admin
  3826. pagure.lib.query.add_user_to_project(
  3827. self.session,
  3828. project,
  3829. new_user="foo",
  3830. user="pingou",
  3831. access="admin",
  3832. )
  3833. self.session.commit()
  3834. # Create modify_project token for foo user
  3835. pagure.lib.query.add_token_to_user(
  3836. self.session, project=None, acls=["create_project"], username="foo"
  3837. )
  3838. mtoken = pagure.lib.query.search_token(
  3839. self.session, ["create_project"], user="foo"
  3840. )[0]
  3841. # Call the connector with foo user token and verify unauthorized
  3842. headers = {"Authorization": "token %s" % mtoken.id}
  3843. output = self.app.get("/api/0/test/connector", headers=headers)
  3844. self.assertEqual(output.status_code, 401)
  3845. def test_api_get_project_connector_as_unauthorized_2(self):
  3846. """ Test accessing api_get_project_connector as project
  3847. but with unauthorized token ACL
  3848. """
  3849. project = pagure.lib.query._get_project(self.session, "test")
  3850. # Set the foo user as test project admin
  3851. pagure.lib.query.add_user_to_project(
  3852. self.session,
  3853. project,
  3854. new_user="foo",
  3855. user="pingou",
  3856. access="commit",
  3857. )
  3858. self.session.commit()
  3859. # Create modify_project token for foo user
  3860. pagure.lib.query.add_token_to_user(
  3861. self.session, project=None, acls=["modify_project"], username="foo"
  3862. )
  3863. mtoken = pagure.lib.query.search_token(
  3864. self.session, ["modify_project"], user="foo"
  3865. )[0]
  3866. # Call the connector with foo user token and verify unauthorized
  3867. headers = {"Authorization": "token %s" % mtoken.id}
  3868. output = self.app.get("/api/0/test/connector", headers=headers)
  3869. self.assertEqual(output.status_code, 401)
  3870. if __name__ == "__main__":
  3871. unittest.main(verbosity=2)