test_pagure_flask_api_issue.py 148 KB

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