test_pagure_flask_api_project.py 188 KB

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