test_pagure_flask_api_issue.py 158 KB

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