test_pagure_flask_ui_issues.py 185 KB

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