test_pagure_flask_api_issue.py 183 KB

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