test_pagure_flask_api_project.py 204 KB

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