test_pagure_flask_api_issue.py 142 KB

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