test_pagure_flask_api_issue.py 163 KB

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