test_pagure_flask_api_issue.py 161 KB

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