test_pagure_flask_api_project.py 208 KB

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