test_pagure_flask_ui_issues.py 144 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.8']
  8. import pkg_resources
  9. from unittest.case import SkipTest
  10. import json
  11. import unittest
  12. import urlparse
  13. import shutil
  14. import sys
  15. import os
  16. try:
  17. import pyclamd
  18. except ImportError:
  19. pyclamd = None
  20. import tempfile
  21. import re
  22. from datetime import datetime, timedelta
  23. import pygit2
  24. from bs4 import BeautifulSoup
  25. from mock import patch, MagicMock
  26. sys.path.insert(0, os.path.join(os.path.dirname(
  27. os.path.abspath(__file__)), '..'))
  28. import pagure
  29. import pagure.lib
  30. import tests
  31. class PagureFlaskIssuestests(tests.Modeltests):
  32. """ Tests for flask issues controller of pagure """
  33. @patch('pagure.lib.git.update_git')
  34. @patch('pagure.lib.notify.send_email')
  35. def test_new_issue(self, p_send_email, p_ugt):
  36. """ Test the new_issue endpoint. """
  37. p_send_email.return_value = True
  38. p_ugt.return_value = True
  39. # No Git repo
  40. output = self.app.get('/foo/new_issue')
  41. self.assertEqual(output.status_code, 404)
  42. user = tests.FakeUser()
  43. with tests.user_set(self.app.application, user):
  44. output = self.app.get('/foo/new_issue')
  45. self.assertEqual(output.status_code, 404)
  46. tests.create_projects(self.session)
  47. tests.create_projects_git(
  48. os.path.join(self.path, 'repos'), bare=True)
  49. output = self.app.get('/test/new_issue')
  50. self.assertEqual(output.status_code, 200)
  51. self.assertTrue(
  52. '<div class="card-header">\n New issue'
  53. in output.data)
  54. csrf_token = self.get_csrf(output=output)
  55. data = {
  56. }
  57. # Insufficient input
  58. output = self.app.post('/test/new_issue', data=data)
  59. self.assertEqual(output.status_code, 200)
  60. self.assertTrue(
  61. '<div class="card-header">\n New issue'
  62. in output.data)
  63. self.assertEqual(output.data.count(
  64. 'This field is required.'), 2)
  65. data['title'] = 'Test issue'
  66. output = self.app.post('/test/new_issue', data=data)
  67. self.assertEqual(output.status_code, 200)
  68. self.assertTrue(
  69. '<div class="card-header">\n New issue'
  70. in output.data)
  71. self.assertEqual(output.data.count(
  72. 'This field is required.'), 1)
  73. data['issue_content'] = 'We really should improve on this issue'
  74. data['status'] = 'Open'
  75. output = self.app.post('/test/new_issue', data=data)
  76. self.assertEqual(output.status_code, 200)
  77. self.assertTrue(
  78. '<div class="card-header">\n New issue'
  79. in output.data)
  80. self.assertEqual(output.data.count(
  81. '</button>\n This field is required.'),
  82. 0)
  83. # Invalid user
  84. data['csrf_token'] = csrf_token
  85. output = self.app.post('/test/new_issue', data=data)
  86. self.assertEqual(output.status_code, 404)
  87. self.assertIn(
  88. '<p>No such user found in the database: username</p>',
  89. output.data)
  90. # User not logged in
  91. output = self.app.get('/test/new_issue')
  92. self.assertEqual(output.status_code, 302)
  93. user.username = 'pingou'
  94. with tests.user_set(self.app.application, user):
  95. output = self.app.post(
  96. '/test/new_issue', data=data, follow_redirects=True)
  97. self.assertEqual(output.status_code, 200)
  98. self.assertIn(
  99. '<title>Issue #1: Test issue - test - Pagure</title>',
  100. output.data)
  101. self.assertIn(
  102. '<a class="btn btn-primary btn-sm" '
  103. 'href="/test/issue/1/edit" title="Edit this issue">',
  104. output.data)
  105. # Project w/o issue tracker
  106. repo = pagure.lib.get_authorized_project(self.session, 'test')
  107. repo.settings = {'issue_tracker': False}
  108. self.session.add(repo)
  109. self.session.commit()
  110. user.username = 'pingou'
  111. with tests.user_set(self.app.application, user):
  112. output = self.app.post(
  113. '/test/new_issue', data=data, follow_redirects=True)
  114. self.assertEqual(output.status_code, 404)
  115. @patch('pagure.lib.git.update_git')
  116. @patch('pagure.lib.notify.send_email')
  117. def test_new_issue_w_file(self, p_send_email, p_ugt):
  118. """ Test the new_issue endpoint with a file. """
  119. p_send_email.return_value = True
  120. p_ugt.return_value = True
  121. tests.create_projects(self.session)
  122. tests.create_projects_git(
  123. os.path.join(self.path, 'repos'), bare=True)
  124. tests.create_projects_git(
  125. os.path.join(self.path, 'tickets'), bare=True)
  126. user = tests.FakeUser()
  127. user.username = 'pingou'
  128. with tests.user_set(self.app.application, user):
  129. output = self.app.get('/test/new_issue')
  130. self.assertEqual(output.status_code, 200)
  131. self.assertTrue(
  132. '<div class="card-header">\n New issue'
  133. in output.data)
  134. csrf_token = self.get_csrf()
  135. with open(os.path.join(tests.HERE, 'placebo.png'), 'r') as stream:
  136. data = {
  137. 'title': 'Test issue',
  138. 'issue_content': 'We really should improve on this issue\n'
  139. '<!!image>',
  140. 'status': 'Open',
  141. 'filestream': stream,
  142. 'enctype': 'multipart/form-data',
  143. 'csrf_token': csrf_token,
  144. }
  145. output = self.app.post(
  146. '/test/new_issue', data=data, follow_redirects=True)
  147. self.assertEqual(output.status_code, 200)
  148. self.assertIn(
  149. '<title>Issue #1: Test issue - test - Pagure</title>',
  150. output.data)
  151. self.assertIn(
  152. '<a class="btn btn-primary btn-sm" '
  153. 'href="/test/issue/1/edit" title="Edit this issue">',
  154. output.data)
  155. # Check the image was uploaded
  156. self.assertIn(
  157. 'href="/test/issue/raw/'
  158. '8a06845923010b27bfd8e7e75acff7badc40d1021b4'
  159. '994e01f5e11ca40bc3abe',
  160. output.data)
  161. @patch('pagure.lib.git.update_git')
  162. @patch('pagure.lib.notify.send_email')
  163. def test_new_issue_w_file_no_issue_tracker(self, p_send_email, p_ugt):
  164. """ Test the new_issue endpoint with a file. """
  165. p_send_email.return_value = True
  166. p_ugt.return_value = True
  167. tests.create_projects(self.session)
  168. tests.create_projects_git(
  169. os.path.join(self.path, 'repos'), bare=True)
  170. tests.create_projects_git(
  171. os.path.join(self.path, 'tickets'), bare=True)
  172. # Project w/o issue tracker
  173. repo = pagure.lib.get_authorized_project(self.session, 'test')
  174. repo.settings = {'issue_tracker': False}
  175. self.session.add(repo)
  176. self.session.commit()
  177. user = tests.FakeUser()
  178. user.username = 'pingou'
  179. with tests.user_set(self.app.application, user):
  180. with open(os.path.join(tests.HERE, 'placebo.png'), 'r') as stream:
  181. data = {
  182. 'title': 'Test issue',
  183. 'issue_content': 'We really should improve on this issue',
  184. 'status': 'Open',
  185. 'filestream': stream,
  186. 'enctype': 'multipart/form-data',
  187. 'csrf_token': self.get_csrf(),
  188. }
  189. output = self.app.post(
  190. '/test/new_issue', data=data, follow_redirects=True)
  191. self.assertEqual(output.status_code, 404)
  192. @patch('pagure.lib.git.update_git')
  193. @patch('pagure.lib.notify.send_email')
  194. def test_new_issue_w_file_namespace(self, p_send_email, p_ugt):
  195. """ Test the new_issue endpoint with a file. """
  196. p_send_email.return_value = True
  197. p_ugt.return_value = True
  198. tests.create_projects(self.session)
  199. tests.create_projects_git(
  200. os.path.join(self.path, 'repos'), bare=True)
  201. tests.create_projects_git(
  202. os.path.join(self.path, 'tickets'), bare=True)
  203. # Project with a namespace
  204. user = tests.FakeUser()
  205. user.username = 'pingou'
  206. with tests.user_set(self.app.application, user):
  207. output = self.app.get('/somenamespace/test3/new_issue')
  208. self.assertEqual(output.status_code, 200)
  209. self.assertTrue(
  210. '<div class="card-header">\n New issue'
  211. in output.data)
  212. csrf_token = self.get_csrf()
  213. with open(os.path.join(tests.HERE, 'placebo.png'), 'r') as stream:
  214. data = {
  215. 'title': 'Test issue3',
  216. 'issue_content': 'We really should improve on this issue\n'
  217. '<!!image>',
  218. 'status': 'Open',
  219. 'filestream': stream,
  220. 'enctype': 'multipart/form-data',
  221. 'csrf_token': csrf_token,
  222. }
  223. output = self.app.post(
  224. '/somenamespace/test3/new_issue', data=data, follow_redirects=True)
  225. self.assertEqual(output.status_code, 200)
  226. self.assertIn(
  227. '<title>Issue #1: Test issue3 - test3 - Pagure</title>',
  228. output.data)
  229. self.assertIn(
  230. '<a class="btn btn-primary btn-sm" '
  231. 'href="/somenamespace/test3/issue/1/edit" '
  232. 'title="Edit this issue">',
  233. output.data)
  234. # Check the image was uploaded
  235. self.assertIn(
  236. 'href="/somenamespace/test3/issue/raw/'
  237. '8a06845923010b27bfd8e7e75acff7badc40d1021b4'
  238. '994e01f5e11ca40bc3abe',
  239. output.data)
  240. @patch('pagure.lib.git.update_git')
  241. @patch('pagure.lib.notify.send_email')
  242. def test_new_issue_w_files(self, p_send_email, p_ugt):
  243. """ Test the new_issue endpoint with two files. """
  244. p_send_email.return_value = True
  245. p_ugt.return_value = True
  246. tests.create_projects(self.session)
  247. tests.create_projects_git(
  248. os.path.join(self.path, 'repos'), bare=True)
  249. tests.create_projects_git(
  250. os.path.join(self.path, 'tickets'), bare=True)
  251. user = tests.FakeUser()
  252. user.username = 'pingou'
  253. with tests.user_set(self.app.application, user):
  254. output = self.app.get('/test/new_issue')
  255. self.assertEqual(output.status_code, 200)
  256. self.assertTrue(
  257. '<div class="card-header">\n New issue'
  258. in output.data)
  259. csrf_token = self.get_csrf()
  260. with open(
  261. os.path.join(tests.HERE, 'placebo.png'), 'r'
  262. ) as stream:
  263. with open(
  264. os.path.join(tests.HERE, 'pagure.png'), 'r'
  265. ) as stream2:
  266. data = {
  267. 'title': 'Test issue',
  268. 'issue_content': 'We really should improve on this issue\n'
  269. '<!!image>\n<!!image>',
  270. 'status': 'Open',
  271. 'filestream': [stream, stream2],
  272. 'enctype': 'multipart/form-data',
  273. 'csrf_token': csrf_token,
  274. }
  275. output = self.app.post(
  276. '/test/new_issue', data=data, follow_redirects=True)
  277. self.assertEqual(output.status_code, 200)
  278. self.assertIn(
  279. '<title>Issue #1: Test issue - test - Pagure</title>',
  280. output.data)
  281. self.assertIn(
  282. '<a class="btn btn-primary btn-sm" '
  283. 'href="/test/issue/1/edit" title="Edit this issue">',
  284. output.data)
  285. # Check the image was uploaded
  286. self.assertIn(
  287. 'href="/test/issue/raw/'
  288. '8a06845923010b27bfd8e7e75acff7badc40d1021b4'
  289. '994e01f5e11ca40bc3abe',
  290. output.data)
  291. self.assertIn(
  292. 'href="/test/issue/raw/'
  293. '6498a2de405546200b6144da56fc25d0a3976ae688d'
  294. 'bfccaca609c8b4480523e',
  295. output.data)
  296. @patch('pagure.lib.git.update_git')
  297. @patch('pagure.lib.notify.send_email')
  298. def test_new_issue_w_files_namespace(self, p_send_email, p_ugt):
  299. """ Test the new_issue endpoint with two files. """
  300. p_send_email.return_value = True
  301. p_ugt.return_value = True
  302. tests.create_projects(self.session)
  303. tests.create_projects_git(
  304. os.path.join(self.path, 'repos'), bare=True)
  305. tests.create_projects_git(
  306. os.path.join(self.path, 'tickets'), bare=True)
  307. # Project with a namespace
  308. user = tests.FakeUser()
  309. user.username = 'pingou'
  310. with tests.user_set(self.app.application, user):
  311. output = self.app.get('/somenamespace/test3/new_issue')
  312. self.assertEqual(output.status_code, 200)
  313. self.assertTrue(
  314. '<div class="card-header">\n New issue'
  315. in output.data)
  316. csrf_token = self.get_csrf()
  317. with open(
  318. os.path.join(tests.HERE, 'placebo.png'), 'r'
  319. ) as stream:
  320. with open(
  321. os.path.join(tests.HERE, 'pagure.png'), 'r'
  322. ) as stream2:
  323. data = {
  324. 'title': 'Test issue3',
  325. 'issue_content': 'We really should improve on this issue\n'
  326. '<!!image>\n<!!image>',
  327. 'status': 'Open',
  328. 'filestream': [stream, stream2],
  329. 'enctype': 'multipart/form-data',
  330. 'csrf_token': csrf_token,
  331. }
  332. output = self.app.post(
  333. '/somenamespace/test3/new_issue',
  334. data=data, follow_redirects=True)
  335. self.assertEqual(output.status_code, 200)
  336. self.assertIn(
  337. '<title>Issue #1: Test issue3 - test3 - Pagure</title>',
  338. output.data)
  339. self.assertIn(
  340. '<a class="btn btn-primary btn-sm" '
  341. 'href="/somenamespace/test3/issue/1/edit" '
  342. 'title="Edit this issue">',
  343. output.data)
  344. # Check the image was uploaded
  345. self.assertIn(
  346. 'href="/somenamespace/test3/issue/raw/'
  347. '8a06845923010b27bfd8e7e75acff7badc40d1021b4'
  348. '994e01f5e11ca40bc3abe',
  349. output.data)
  350. self.assertIn(
  351. 'href="/somenamespace/test3/issue/raw/'
  352. '6498a2de405546200b6144da56fc25d0a3976ae688d'
  353. 'bfccaca609c8b4480523e',
  354. output.data)
  355. def test_new_issue_metadata_user(self):
  356. """ Test the new_issue endpoint when the user has access to the
  357. project. """
  358. tests.create_projects(self.session)
  359. tests.create_projects_git(
  360. os.path.join(self.path, 'repos'), bare=True)
  361. tests.create_projects_git(
  362. os.path.join(self.path, 'tickets'), bare=True)
  363. user = tests.FakeUser()
  364. user.username = 'pingou'
  365. with tests.user_set(self.app.application, user):
  366. output = self.app.get('/test/new_issue')
  367. self.assertEqual(output.status_code, 200)
  368. self.assertIn(
  369. '<div class="card-header">\n New issue',
  370. output.data)
  371. self.assertIn(
  372. '<label for="tag"><strong>Tags</strong></label>',
  373. output.data)
  374. self.assertIn(
  375. '<label for="assignee"><strong>Assignee</strong></label>',
  376. output.data)
  377. def test_new_issue_metadata_not_user(self):
  378. """ Test the new_issue endpoint when the user does not have access
  379. to the project. """
  380. tests.create_projects(self.session)
  381. tests.create_projects_git(
  382. os.path.join(self.path, 'repos'), bare=True)
  383. tests.create_projects_git(
  384. os.path.join(self.path, 'tickets'), bare=True)
  385. user = tests.FakeUser()
  386. user.username = 'foo'
  387. with tests.user_set(self.app.application, user):
  388. output = self.app.get('/test/new_issue')
  389. self.assertEqual(output.status_code, 200)
  390. self.assertIn(
  391. '<div class="card-header">\n New issue',
  392. output.data)
  393. self.assertNotIn(
  394. '<label for="tag"><strong>Tags</strong></label>',
  395. output.data)
  396. self.assertNotIn(
  397. '<label for="assignee"><strong>Assignee</strong></label>',
  398. output.data)
  399. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  400. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  401. def test_new_issue_with_metadata(self):
  402. """ Test the new_issue endpoint when the user has access to the
  403. project. """
  404. tests.create_projects(self.session)
  405. tests.create_projects_git(
  406. os.path.join(self.path, 'repos'), bare=True)
  407. tests.create_projects_git(
  408. os.path.join(self.path, 'tickets'), bare=True)
  409. # Set some milestone
  410. repo = pagure.lib.get_authorized_project(self.session, 'test')
  411. repo.milestones = {'v1.0': '', 'v2.0': 'Tomorrow!'}
  412. self.session.add(repo)
  413. self.session.commit()
  414. user = tests.FakeUser()
  415. user.username = 'pingou'
  416. with tests.user_set(self.app.application, user):
  417. output = self.app.get('/test/new_issue')
  418. self.assertEqual(output.status_code, 200)
  419. self.assertIn(
  420. '<div class="card-header">\n New issue',
  421. output.data)
  422. self.assertIn(
  423. '<label for="tag"><strong>Tags</strong></label>',
  424. output.data)
  425. self.assertIn(
  426. '<label for="assignee"><strong>Assignee</strong></label>',
  427. output.data)
  428. csrf_token = self.get_csrf(output=output)
  429. data = {
  430. 'title': 'Test issue3',
  431. 'issue_content': 'We really should improve on this issue\n',
  432. 'status': 'Open',
  433. 'assignee': 'foo',
  434. 'milestone': 'v2.0',
  435. 'tag': 'tag2',
  436. 'csrf_token': csrf_token,
  437. }
  438. output = self.app.post(
  439. '/test/new_issue', data=data, follow_redirects=True)
  440. self.assertEqual(output.status_code, 200)
  441. self.assertIn(
  442. '<title>Issue #1: Test issue3 - test - Pagure</title>',
  443. output.data)
  444. self.assertIn(
  445. '<a class="btn btn-primary btn-sm" '
  446. 'href="/test/issue/1/edit" '
  447. 'title="Edit this issue">',
  448. output.data)
  449. # Check the metadata
  450. self.assertIn(
  451. 'title="comma separated list of tags"\n '
  452. 'value="tag2" />', output.data)
  453. self.assertIn(
  454. 'placeholder="username"\n value="foo" />',
  455. output.data)
  456. self.assertIn(
  457. '<div id="milestone_plain">\n <span>'
  458. '\n <a href="/test/roadmap?milestone=v2.0">'
  459. '\n v2.0\n', output.data)
  460. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  461. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  462. def test_new_issue_with_metadata_not_user(self):
  463. """ Test the new_issue endpoint when the user does not have access
  464. to the project but still tries to.
  465. """
  466. tests.create_projects(self.session)
  467. tests.create_projects_git(
  468. os.path.join(self.path, 'repos'), bare=True)
  469. tests.create_projects_git(
  470. os.path.join(self.path, 'tickets'), bare=True)
  471. # Set some milestone
  472. repo = pagure.lib.get_authorized_project(self.session, 'test')
  473. repo.milestones = {'v1.0': '', 'v2.0': 'Tomorrow!'}
  474. self.session.add(repo)
  475. self.session.commit()
  476. user = tests.FakeUser()
  477. user.username = 'foo'
  478. with tests.user_set(self.app.application, user):
  479. output = self.app.get('/test/new_issue')
  480. self.assertEqual(output.status_code, 200)
  481. self.assertIn(
  482. '<div class="card-header">\n New issue',
  483. output.data)
  484. self.assertNotIn(
  485. '<label for="tag"><strong>Tags</strong></label>',
  486. output.data)
  487. self.assertNotIn(
  488. '<label for="assignee"><strong>Assignee</strong></label>',
  489. output.data)
  490. csrf_token = self.get_csrf(output=output)
  491. data = {
  492. 'title': 'Test issue3',
  493. 'issue_content': 'We really should improve on this issue\n',
  494. 'status': 'Open',
  495. 'assignee': 'foo',
  496. 'milestone': 'v2.0',
  497. 'tag': 'tag2',
  498. 'csrf_token': csrf_token,
  499. }
  500. output = self.app.post(
  501. '/test/new_issue', data=data, follow_redirects=True)
  502. self.assertEqual(output.status_code, 200)
  503. self.assertIn(
  504. '<title>Issue #1: Test issue3 - test - Pagure</title>',
  505. output.data)
  506. self.assertIn(
  507. '<a class="btn btn-primary btn-sm" '
  508. 'href="/test/issue/1/edit" '
  509. 'title="Edit this issue">',
  510. output.data)
  511. # Check the metadata
  512. self.assertNotIn(
  513. 'title="comma separated list of tags"\n '
  514. 'value="tag2" />', output.data)
  515. self.assertNotIn(
  516. 'placeholder="username"\n value="foo" />',
  517. output.data)
  518. self.assertNotIn(
  519. '<div id="milestone_plain">\n <span>'
  520. '\n <a href="/test/roadmap?milestone=v2.0">'
  521. '\n v2.0\n', output.data)
  522. @patch('pagure.lib.git.update_git')
  523. @patch('pagure.lib.notify.send_email')
  524. def test_view_issues_roadmap_view(self, p_send_email, p_ugt):
  525. """ Test the view_issues endpoint when view is set as roadmap view """
  526. p_send_email.return_value = True
  527. p_ugt.return_value = True
  528. tests.create_projects(self.session)
  529. tests.create_projects_git(
  530. os.path.join(self.path, 'repos'), bare=True)
  531. # Change settings to show roadmap on issue page
  532. repo = pagure.lib.get_authorized_project(self.session, 'test')
  533. old_settings = repo.settings
  534. old_settings['roadmap_on_issues_page'] = True
  535. repo.settings = old_settings
  536. self.session.add(repo)
  537. self.session.commit()
  538. # check on landing page of project for the URL that on the Issues tab
  539. output = self.app.get('/test/')
  540. self.assertEqual(output.status_code, 200)
  541. self.assertIn('<a class="nav-link" href="/test/roadmap"', output.data)
  542. # Revert and check
  543. old_settings = repo.settings
  544. old_settings['roadmap_on_issues_page'] = False
  545. repo.settings = old_settings
  546. self.session.add(repo)
  547. self.session.commit()
  548. output = self.app.get('/test/')
  549. self.assertEqual(output.status_code, 200)
  550. self.assertIn('<a class="nav-link" href="/test/issues"', output.data)
  551. @patch('pagure.lib.git.update_git')
  552. @patch('pagure.lib.notify.send_email')
  553. def test_view_issues(self, p_send_email, p_ugt):
  554. """ Test the view_issues endpoint. """
  555. p_send_email.return_value = True
  556. p_ugt.return_value = True
  557. output = self.app.get('/foo/issues')
  558. self.assertEqual(output.status_code, 404)
  559. tests.create_projects(self.session)
  560. tests.create_projects_git(
  561. os.path.join(self.path, 'repos'), bare=True)
  562. output = self.app.get('/test/issues')
  563. self.assertEqual(output.status_code, 200)
  564. self.assertIn(
  565. 'div class="projectinfo m-t-1 m-b-1">\ntest project #1 '
  566. '</div>', output.data)
  567. self.assertIn(
  568. '<h2>\n 0 Open Issues', output.data)
  569. repo = pagure.lib.get_authorized_project(self.session, 'test')
  570. # Create some custom fields to play with
  571. msg = pagure.lib.set_custom_key_fields(
  572. session=self.session,
  573. project=repo,
  574. fields=['test1'],
  575. types=['text'],
  576. data=[None],
  577. notify=[None]
  578. )
  579. self.session.commit()
  580. self.assertEqual(msg, 'List of custom fields updated')
  581. cfield = pagure.lib.get_custom_key(
  582. session=self.session,
  583. project=repo,
  584. keyname='test1')
  585. # Create issues to play with
  586. msg = pagure.lib.new_issue(
  587. session=self.session,
  588. repo=repo,
  589. title=u'tést íssüé',
  590. content='We should work on this',
  591. user='pingou',
  592. ticketfolder=None
  593. )
  594. self.session.commit()
  595. self.assertEqual(msg.title, u'tést íssüé')
  596. msg = pagure.lib.set_custom_key_value(
  597. session=self.session,
  598. issue=msg,
  599. key=cfield,
  600. value='firstissue')
  601. self.session.commit()
  602. self.assertEqual(msg, 'Custom field test1 adjusted to firstissue')
  603. msg = pagure.lib.new_issue(
  604. session=self.session,
  605. repo=repo,
  606. title=u'Tést íssüé with milestone',
  607. content='Testing search',
  608. user='pingou',
  609. milestone='1.1',
  610. ticketfolder=None
  611. )
  612. self.session.commit()
  613. self.assertEqual(msg.title, u'Tést íssüé with milestone')
  614. msg = pagure.lib.new_issue(
  615. session=self.session,
  616. repo=repo,
  617. title='Test invalid issue',
  618. content='This really is not related',
  619. user='pingou',
  620. status='Closed',
  621. close_status='Invalid',
  622. ticketfolder=None
  623. )
  624. self.session.commit()
  625. self.assertEqual(msg.title, 'Test invalid issue')
  626. msg = pagure.lib.set_custom_key_value(
  627. session=self.session,
  628. issue=msg,
  629. key=cfield,
  630. value='second issue')
  631. self.session.commit()
  632. self.assertEqual(msg, 'Custom field test1 adjusted to second issue')
  633. # Whole list
  634. output = self.app.get('/test/issues')
  635. self.assertEqual(output.status_code, 200)
  636. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  637. self.assertTrue(
  638. '<h2>\n 2 Open Issues' in output.data)
  639. self.assertIn(
  640. '<div class="addrem_bar issues_pbar m-b-1 " title="33% of '
  641. 'closed issues of total 3 issues">', output.data)
  642. self.assertIn(
  643. '<span style="width: 67%" title="67% of open issues of total '
  644. '3 issues">', output.data)
  645. # Verify that the sorting links are correct and the arrow is pointing
  646. # down next to the Opened column
  647. th_elements = re.findall(r'<th (?:id|class)=".*?">(.*?)</th>',
  648. output.data, re.M | re.S)
  649. self.assertDictEqual(
  650. {'status': ['Open'], 'order_key': ['title'], 'order': ['desc']},
  651. urlparse.parse_qs(urlparse.urlparse(
  652. th_elements[0].split('"')[1]).query)
  653. )
  654. self.assertDictEqual(
  655. {'status': ['Open'], 'order_key': ['date_created'], 'order': ['asc']},
  656. urlparse.parse_qs(urlparse.urlparse(
  657. th_elements[1].split('"')[1]).query)
  658. )
  659. arrow = '<span class="oi" data-glyph="arrow-thick-bottom"></span>'
  660. self.assertIn(arrow, th_elements[1])
  661. self.assertDictEqual(
  662. {'status': ['Open'], 'order_key': ['last_updated'], 'order': ['desc']},
  663. urlparse.parse_qs(urlparse.urlparse(
  664. th_elements[2].split('"')[1]).query)
  665. )
  666. self.assertDictEqual(
  667. {'status': ['Open'], 'order_key': ['priority'], 'order': ['desc']},
  668. urlparse.parse_qs(urlparse.urlparse(
  669. th_elements[3].split('"')[1]).query)
  670. )
  671. self.assertDictEqual(
  672. {'status': ['Open'], 'order_key': ['user'], 'order': ['desc']},
  673. urlparse.parse_qs(urlparse.urlparse(
  674. th_elements[4].split('"')[1]).query)
  675. )
  676. self.assertDictEqual(
  677. {'status': ['Open'], 'order_key': ['assignee'], 'order': ['desc']},
  678. urlparse.parse_qs(urlparse.urlparse(
  679. th_elements[5].split('"')[1]).query)
  680. )
  681. # Status = closed (all but open)
  682. output = self.app.get('/test/issues?status=cloSED')
  683. self.assertEqual(output.status_code, 200)
  684. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  685. self.assertIn(
  686. '<h2>\n 1 Closed Issues', output.data)
  687. self.assertIn(
  688. '<div class="addrem_bar issues_pbar m-b-1 closed" '
  689. 'title="67% of open issues of total 3 issues">', output.data)
  690. self.assertIn(
  691. '<span style="width: 33%" title="33% of closed issues '
  692. 'of total 3 issues">', output.data)
  693. # Status = fixed
  694. output = self.app.get('/test/issues?status=fixed')
  695. self.assertEqual(output.status_code, 200)
  696. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  697. self.assertTrue(
  698. '<h2>\n 0 Closed Issues' in output.data)
  699. # Status = Invalid
  700. output = self.app.get('/test/issues?status=Invalid')
  701. self.assertEqual(output.status_code, 200)
  702. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  703. self.assertTrue(
  704. '<h2>\n 1 Closed Issues' in output.data)
  705. # All tickets
  706. output = self.app.get('/test/issues?status=all')
  707. self.assertEqual(output.status_code, 200)
  708. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  709. self.assertTrue(
  710. '<h2>\n 3 Issues' in output.data)
  711. # Unicode search pattern
  712. output = self.app.get(
  713. '/test/issues?status=all&search_pattern=گروه')
  714. self.assertEqual(output.status_code, 200)
  715. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  716. self.assertIn('0 Issues', output.data)
  717. # Custom key searching
  718. output = self.app.get(
  719. '/test/issues?status=all&search_pattern=test1:firstissue')
  720. self.assertEqual(output.status_code, 200)
  721. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  722. self.assertIn('1 Issues', output.data)
  723. # Custom key searching with space
  724. output = self.app.get(
  725. '/test/issues?status=all&search_pattern=test1:"second issue"')
  726. self.assertEqual(output.status_code, 200)
  727. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  728. self.assertIn('1 Issues', output.data)
  729. # All tickets - different pagination
  730. before = pagure.config.config['ITEM_PER_PAGE']
  731. pagure.config.config['ITEM_PER_PAGE'] = 1
  732. output = self.app.get('/test/issues?status=all')
  733. self.assertEqual(output.status_code, 200)
  734. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  735. self.assertIn('<h2>\n 1 Issues (of 3)', output.data)
  736. self.assertIn(
  737. '<li class="active">page 1 of 3</li>', output.data)
  738. # All tickets - filtered for 1 - checking the pagination
  739. output = self.app.get(
  740. '/test/issues?status=all&search_pattern=invalid')
  741. self.assertEqual(output.status_code, 200)
  742. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  743. self.assertIn('<h2>\n 1 Issues (of 1)', output.data)
  744. self.assertIn(
  745. '<li class="active">page 1 of 1</li>', output.data)
  746. pagure.config.config['ITEM_PER_PAGE'] = before
  747. # Search for issues with no milestone MARK
  748. output = self.app.get(
  749. '/test/issues?milestone=none')
  750. self.assertEqual(output.status_code, 200)
  751. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  752. self.assertIn('1 Open Issues (of 1)', output.data)
  753. # Search for issues with no milestone and milestone 1.1
  754. output = self.app.get(
  755. '/test/issues?milestone=none&milestone=1.1')
  756. self.assertEqual(output.status_code, 200)
  757. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  758. self.assertIn('2 Open Issues (of 2)', output.data)
  759. # Add another issue to test sorting
  760. msg = pagure.lib.new_issue(
  761. session=self.session,
  762. repo=repo,
  763. title=u'Big problÈm!',
  764. content='I need help ASAP',
  765. user='foo',
  766. ticketfolder=None
  767. )
  768. self.session.commit()
  769. self.assertEqual(msg.title, u'Big problÈm!')
  770. # Sort by last_updated
  771. output = self.app.get('/test/issues?order_key=last_updated')
  772. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  773. self.assertEqual(output.status_code, 200)
  774. arrowed_th = ('Modified</a>\n <span class="oi" data-glyph='
  775. '"arrow-thick-bottom"></span>')
  776. # First table row is the header
  777. self.assertIn(arrowed_th, tr_elements[0])
  778. # Make sure that issue four is first since it was modified last
  779. self.assertIn('href="/test/issue/4"', tr_elements[1])
  780. # Make sure that issue two is second since it was modified second
  781. self.assertIn('href="/test/issue/2"', tr_elements[2])
  782. # Make sure that issue one is last since it was modified first
  783. self.assertIn('href="/test/issue/1"', tr_elements[3])
  784. # Modify the date of the first issue and try again
  785. issue_one = pagure.lib.search_issues(self.session, repo, 1)
  786. issue_one.last_updated = datetime.utcnow() + timedelta(seconds=2)
  787. self.session.add(issue_one)
  788. self.session.commit()
  789. output = self.app.get('/test/issues?order_key=last_updated')
  790. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  791. self.assertEqual(output.status_code, 200)
  792. # Make sure that issue one is first since it was modified last
  793. self.assertIn('href="/test/issue/1"', tr_elements[1])
  794. # Make sure that issue four is second since it was modified before
  795. # last
  796. self.assertIn('href="/test/issue/4"', tr_elements[2])
  797. # Make sure that issue two is last since it was modified before issue
  798. # one and four
  799. self.assertIn('href="/test/issue/2"', tr_elements[3])
  800. # Now query so that the results are ascending
  801. output = self.app.get('/test/issues?order_key=last_updated&order=asc')
  802. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  803. arrowed_th = ('Modified</a>\n <span class="oi" data-glyph='
  804. '"arrow-thick-top"></span>')
  805. # First table row is the header
  806. self.assertIn(arrowed_th, tr_elements[0])
  807. self.assertIn('href="/test/issue/2"', tr_elements[1])
  808. self.assertIn('href="/test/issue/4"', tr_elements[2])
  809. self.assertIn('href="/test/issue/1"', tr_elements[3])
  810. # Sort by title descending
  811. output = self.app.get('/test/issues?order_key=title')
  812. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  813. self.assertEqual(output.status_code, 200)
  814. arrowed_th = ('Issue</a>\n <span class="oi" data-glyph='
  815. '"arrow-thick-bottom"></span>')
  816. # First table row is the header
  817. self.assertIn(arrowed_th, tr_elements[0])
  818. self.assertIn('href="/test/issue/2"', tr_elements[1])
  819. self.assertIn('href="/test/issue/1"', tr_elements[2])
  820. self.assertIn('href="/test/issue/4"', tr_elements[3])
  821. # Sort by title ascending
  822. output = self.app.get('/test/issues?order_key=title&order=asc')
  823. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  824. self.assertEqual(output.status_code, 200)
  825. arrowed_th = ('Issue</a>\n <span class="oi" data-glyph='
  826. '"arrow-thick-top"></span>')
  827. # First table row is the header
  828. self.assertIn(arrowed_th, tr_elements[0])
  829. self.assertIn('href="/test/issue/4"', tr_elements[1])
  830. self.assertIn('href="/test/issue/1"', tr_elements[2])
  831. self.assertIn('href="/test/issue/2"', tr_elements[3])
  832. # Sort by user (reporter/author) descending
  833. output = self.app.get('/test/issues?order_key=user&order=desc')
  834. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  835. self.assertEqual(output.status_code, 200)
  836. arrowed_th = ('Reporter</a>\n <span class="oi" data-glyph='
  837. '"arrow-thick-bottom"></span>')
  838. # First table row is the header
  839. self.assertIn(arrowed_th, tr_elements[0])
  840. # Check for the name after the avatar
  841. self.assertIn('>\n pingou', tr_elements[1])
  842. # We check that they are unassigned, otherwise our previous check is
  843. # not specific enough as it can catch an assignee of "pingou"
  844. self.assertIn('unassigned', tr_elements[1])
  845. self.assertIn('>\n pingou', tr_elements[2])
  846. self.assertIn('unassigned', tr_elements[2])
  847. self.assertIn('>\n foo', tr_elements[3])
  848. self.assertIn('unassigned', tr_elements[3])
  849. # Sort by user (reporter/author) ascending
  850. output = self.app.get('/test/issues?order_key=user&order=asc')
  851. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  852. self.assertEqual(output.status_code, 200)
  853. arrowed_th = ('Reporter</a>\n <span class="oi" data-glyph='
  854. '"arrow-thick-top"></span>')
  855. # First table row is the header
  856. self.assertIn(arrowed_th, tr_elements[0])
  857. # Check for the name after the avatar
  858. self.assertIn('>\n foo', tr_elements[1])
  859. # We check that they are unassigned, otherwise our previous check is
  860. # not specific enough as it can catch an assignee of "foo"
  861. self.assertIn('unassigned', tr_elements[1])
  862. self.assertIn('>\n pingou', tr_elements[2])
  863. self.assertIn('unassigned', tr_elements[2])
  864. self.assertIn('>\n pingou', tr_elements[3])
  865. self.assertIn('unassigned', tr_elements[3])
  866. # Set some assignees
  867. issues = self.session.query(pagure.lib.model.Issue).filter_by(
  868. status='Open').order_by(pagure.lib.model.Issue.id).all()
  869. issues[0].assignee_id = 1
  870. issues[1].assignee_id = 2
  871. issues[2].assignee_id = 1
  872. self.session.commit()
  873. # This detects the assignee but keying on if a certain link is present
  874. def _check_assignee_link(html, expected_links):
  875. soup = BeautifulSoup(html, "html.parser")
  876. for index, expected_link in enumerate(expected_links):
  877. link = soup.find_all("tr")[index + 1].find(
  878. "a", title="Filter issues by assignee")
  879. self.assertIsNotNone(link, "Link %s was not found" % expected_link)
  880. self.assertURLEqual(link["href"], expected_link)
  881. # Sort by assignee descending
  882. output = self.app.get('/test/issues?order_key=assignee&order=desc')
  883. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  884. self.assertEqual(output.status_code, 200)
  885. arrowed_th = ('Assignee</a>\n <span class="oi" data-glyph='
  886. '"arrow-thick-bottom"></span>')
  887. # First table row is the header
  888. self.assertIn(arrowed_th, tr_elements[0])
  889. _check_assignee_link(output.data, [
  890. '/test/issues?status=Open&assignee=pingou',
  891. '/test/issues?status=Open&assignee=pingou',
  892. '/test/issues?status=Open&assignee=foo',
  893. ])
  894. # Sort by assignee ascending
  895. output = self.app.get('/test/issues?order_key=assignee&order=asc')
  896. tr_elements = re.findall(r'<tr>(.*?)</tr>', output.data, re.M | re.S)
  897. self.assertEqual(output.status_code, 200)
  898. arrowed_th = ('Assignee</a>\n <span class="oi" data-glyph='
  899. '"arrow-thick-top"></span>')
  900. # First table row is the header
  901. self.assertIn(arrowed_th, tr_elements[0])
  902. _check_assignee_link(output.data, [
  903. '/test/issues?status=Open&assignee=foo',
  904. '/test/issues?status=Open&assignee=pingou',
  905. '/test/issues?status=Open&assignee=pingou',
  906. ])
  907. # New issue button is shown
  908. user = tests.FakeUser()
  909. with tests.user_set(self.app.application, user):
  910. output = self.app.get('/test')
  911. self.assertEqual(output.status_code, 200)
  912. self.assertIn(
  913. 'class="btn btn-success btn-sm">New Issue</a>',
  914. output.data)
  915. # Project w/o issue tracker
  916. repo = pagure.lib.get_authorized_project(self.session, 'test')
  917. repo.settings = {'issue_tracker': False}
  918. self.session.add(repo)
  919. self.session.commit()
  920. output = self.app.get('/test/issues')
  921. self.assertEqual(output.status_code, 404)
  922. # New issue button is hidden
  923. user = tests.FakeUser()
  924. with tests.user_set(self.app.application, user):
  925. output = self.app.get('/test')
  926. self.assertEqual(output.status_code, 200)
  927. self.assertNotIn(
  928. 'class="btn btn-success btn-sm">New Issue</a>',
  929. output.data)
  930. @patch('pagure.lib.git.update_git')
  931. @patch('pagure.lib.notify.send_email')
  932. def test_search_issues_unicode(self, p_send_email, p_ugt):
  933. """ Test the view_issues endpoint filtering for an unicode char. """
  934. p_send_email.return_value = True
  935. p_ugt.return_value = True
  936. tests.create_projects(self.session)
  937. tests.create_projects_git(
  938. os.path.join(self.path, 'repos'), bare=True)
  939. repo = pagure.lib.get_authorized_project(self.session, 'test')
  940. # Create 2 issues to play with
  941. msg = pagure.lib.new_issue(
  942. session=self.session,
  943. repo=repo,
  944. title=u'Test issue ☃',
  945. content=u'We should work on this ❤',
  946. user='pingou',
  947. ticketfolder=None
  948. )
  949. self.session.commit()
  950. self.assertEqual(msg.title, u'Test issue ☃')
  951. msg = pagure.lib.new_issue(
  952. session=self.session,
  953. repo=repo,
  954. title='Test issue with milestone',
  955. content='Testing search',
  956. user='pingou',
  957. milestone='1.1',
  958. ticketfolder=None
  959. )
  960. self.session.commit()
  961. self.assertEqual(msg.title, 'Test issue with milestone')
  962. # Whole list
  963. output = self.app.get('/test/issues')
  964. self.assertEqual(output.status_code, 200)
  965. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  966. self.assertTrue(
  967. '<h2>\n 2 Open Issues' in output.data)
  968. # Unicode search pattern
  969. output = self.app.get(
  970. '/test/issues?status=all&search_pattern=☃')
  971. self.assertEqual(output.status_code, 200)
  972. self.assertIn('<title>Issues - test - Pagure</title>', output.data)
  973. self.assertIn('1 Issues', output.data)
  974. @patch('pagure.lib.git.update_git')
  975. @patch('pagure.lib.notify.send_email')
  976. def test_view_issue(self, p_send_email, p_ugt):
  977. """ Test the view_issue endpoint. """
  978. p_send_email.return_value = True
  979. p_ugt.return_value = True
  980. output = self.app.get('/foo/issue/1')
  981. self.assertEqual(output.status_code, 404)
  982. tests.create_projects(self.session)
  983. tests.create_projects_git(
  984. os.path.join(self.path, 'repos'), bare=True)
  985. output = self.app.get('/test/issue/1')
  986. self.assertEqual(output.status_code, 404)
  987. # Create issues to play with
  988. repo = pagure.lib.get_authorized_project(self.session, 'test')
  989. msg = pagure.lib.new_issue(
  990. session=self.session,
  991. repo=repo,
  992. title='Test issue',
  993. content='We should work on this',
  994. user='pingou',
  995. ticketfolder=None
  996. )
  997. self.session.commit()
  998. self.assertEqual(msg.title, 'Test issue')
  999. output = self.app.get('/test/issue/1')
  1000. self.assertEqual(output.status_code, 200)
  1001. # Not authentified = No edit
  1002. self.assertNotIn(
  1003. '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
  1004. 'title="Edit this issue">',
  1005. output.data)
  1006. self.assertIn(
  1007. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  1008. 'Login</a>\n to comment on this ticket.',
  1009. output.data)
  1010. user = tests.FakeUser()
  1011. with tests.user_set(self.app.application, user):
  1012. output = self.app.get('/test/issue/1')
  1013. self.assertEqual(output.status_code, 200)
  1014. # Not author nor admin = No edit
  1015. self.assertNotIn(
  1016. '<a class="btn btn-primary btn-sm" '
  1017. 'href="/test/issue/1/edit" title="Edit this issue">',
  1018. output.data)
  1019. self.assertNotIn(
  1020. '<button class="btn btn-danger btn-sm" type="submit"',
  1021. output.data)
  1022. self.assertNotIn('title="Delete this ticket">', output.data)
  1023. self.assertFalse(
  1024. '<a href="/login/">Login</a> to comment on this ticket.'
  1025. in output.data)
  1026. # Not author nor admin = No take
  1027. self.assertNotIn('function take_issue(){', output.data)
  1028. self.assertNotIn('function drop_issue(){', output.data)
  1029. self.assertNotIn(
  1030. '<button class="btn btn-sm pull-xs-right" id="take-btn"',
  1031. output.data)
  1032. user.username = 'pingou'
  1033. with tests.user_set(self.app.application, user):
  1034. output = self.app.get('/test/issue/1')
  1035. self.assertEqual(output.status_code, 200)
  1036. self.assertIn(
  1037. '<a class="btn btn-primary btn-sm" '
  1038. 'href="/test/issue/1/edit" title="Edit this issue">',
  1039. output.data)
  1040. self.assertIn(
  1041. '<button class="btn btn-danger btn-sm" type="submit"',
  1042. output.data)
  1043. self.assertIn('title="Delete this ticket">', output.data)
  1044. csrf_token = self.get_csrf(output=output)
  1045. # Create private issue
  1046. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1047. msg = pagure.lib.new_issue(
  1048. session=self.session,
  1049. repo=repo,
  1050. title='Test issue',
  1051. content='We should work on this',
  1052. user='pingou',
  1053. ticketfolder=None,
  1054. private=True,
  1055. )
  1056. self.session.commit()
  1057. self.assertEqual(msg.title, 'Test issue')
  1058. # Not logged in
  1059. output = self.app.get('/test/issue/2')
  1060. self.assertEqual(output.status_code, 404)
  1061. # Wrong user
  1062. user = tests.FakeUser()
  1063. with tests.user_set(self.app.application, user):
  1064. output = self.app.get('/test/issue/2')
  1065. self.assertEqual(output.status_code, 404)
  1066. # reporter
  1067. user.username = 'pingou'
  1068. with tests.user_set(self.app.application, user):
  1069. output = self.app.get('/test/issue/2')
  1070. self.assertEqual(output.status_code, 200)
  1071. self.assertIn(
  1072. '<title>Issue #2: Test issue - test - Pagure</title>',
  1073. output.data)
  1074. self.assertIn(
  1075. '<span class="oi red-icon" data-glyph="lock-locked" '
  1076. 'title="Private issue"></span>', output.data)
  1077. self.assertIn(
  1078. '<a class="btn btn-primary btn-sm" '
  1079. 'href="/test/issue/2/edit" title="Edit this issue">',
  1080. output.data)
  1081. # Project w/o issue tracker
  1082. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1083. repo.settings = {'issue_tracker': False}
  1084. self.session.add(repo)
  1085. self.session.commit()
  1086. output = self.app.get('/test/issue/1')
  1087. self.assertEqual(output.status_code, 404)
  1088. @patch('pagure.lib.git.update_git')
  1089. @patch('pagure.lib.notify.send_email')
  1090. def test_view_issue_user_ticket(self, p_send_email, p_ugt):
  1091. """ Test the view_issue endpoint. """
  1092. p_send_email.return_value = True
  1093. p_ugt.return_value = True
  1094. output = self.app.get('/foo/issue/1')
  1095. self.assertEqual(output.status_code, 404)
  1096. tests.create_projects(self.session)
  1097. tests.create_projects_git(
  1098. os.path.join(self.path, 'repos'), bare=True)
  1099. output = self.app.get('/test/issue/1')
  1100. self.assertEqual(output.status_code, 404)
  1101. # Create issues to play with
  1102. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1103. msg = pagure.lib.new_issue(
  1104. session=self.session,
  1105. repo=repo,
  1106. title='Test issue',
  1107. content='We should work on this',
  1108. user='pingou',
  1109. ticketfolder=None
  1110. )
  1111. self.session.commit()
  1112. self.assertEqual(msg.title, 'Test issue')
  1113. output = self.app.get('/test/issue/1')
  1114. self.assertEqual(output.status_code, 200)
  1115. # Not authentified = No edit
  1116. self.assertNotIn(
  1117. '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
  1118. 'title="Edit this issue">',
  1119. output.data)
  1120. self.assertTrue(
  1121. '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
  1122. 'Login</a>\n to comment on this ticket.'
  1123. in output.data)
  1124. # Create issues to play with
  1125. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1126. # Add user 'foo' with ticket access on repo
  1127. msg = pagure.lib.add_user_to_project(
  1128. self.session,
  1129. repo,
  1130. new_user='foo',
  1131. user='pingou',
  1132. access='ticket',
  1133. )
  1134. self.assertEqual(msg, 'User added')
  1135. self.session.commit()
  1136. user = tests.FakeUser(username='foo')
  1137. with tests.user_set(self.app.application, user):
  1138. output = self.app.get('/test/issue/1')
  1139. self.assertEqual(output.status_code, 200)
  1140. # Not author nor admin = No edit
  1141. self.assertNotIn(
  1142. '<a class="btn btn-primary btn-sm" '
  1143. 'href="/test/issue/1/edit" title="Edit this issue">',
  1144. output.data)
  1145. self.assertNotIn(
  1146. '<button class="btn btn-danger btn-sm" type="submit"',
  1147. output.data)
  1148. self.assertNotIn('title="Delete this ticket">', output.data)
  1149. self.assertFalse(
  1150. '<a href="/login/">Login</a> to comment on this ticket.'
  1151. in output.data)
  1152. # user has ticket = take ok
  1153. self.assertIn('function take_issue(){', output.data)
  1154. self.assertIn('function drop_issue(){', output.data)
  1155. self.assertIn(
  1156. '<button class="btn btn-sm pull-xs-right" id="take-btn"',
  1157. output.data)
  1158. @patch('pagure.lib.git.update_git')
  1159. @patch('pagure.lib.notify.send_email')
  1160. def test_view_issue_custom_field_user_ticket(self, p_send_email, p_ugt):
  1161. """ Test the view_issue endpoint. """
  1162. p_send_email.return_value = True
  1163. p_ugt.return_value = True
  1164. output = self.app.get('/foo/issue/1')
  1165. self.assertEqual(output.status_code, 404)
  1166. tests.create_projects(self.session)
  1167. tests.create_projects_git(
  1168. os.path.join(self.path, 'repos'), bare=True)
  1169. output = self.app.get('/test/issue/1')
  1170. self.assertEqual(output.status_code, 404)
  1171. # Create issues to play with
  1172. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1173. msg = pagure.lib.new_issue(
  1174. session=self.session,
  1175. repo=repo,
  1176. title='Test issue',
  1177. content='We should work on this',
  1178. user='pingou',
  1179. ticketfolder=None
  1180. )
  1181. self.session.commit()
  1182. self.assertEqual(msg.title, 'Test issue')
  1183. # Add user 'foo' with ticket access on repo
  1184. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1185. msg = pagure.lib.add_user_to_project(
  1186. self.session,
  1187. repo,
  1188. new_user='foo',
  1189. user='pingou',
  1190. access='ticket',
  1191. )
  1192. self.assertEqual(msg, 'User added')
  1193. self.session.commit()
  1194. # Set some custom fields
  1195. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1196. msg = pagure.lib.set_custom_key_fields(
  1197. self.session,
  1198. repo,
  1199. ['bugzilla', 'upstream', 'reviewstatus'],
  1200. ['link', 'boolean', 'list'],
  1201. ['unused data for non-list type', '', 'ack, nack , needs review'],
  1202. [None, None, None])
  1203. self.session.commit()
  1204. self.assertEqual(msg, 'List of custom fields updated')
  1205. # User with no rights
  1206. user = tests.FakeUser()
  1207. with tests.user_set(self.app.application, user):
  1208. output = self.app.get('/test/issue/1')
  1209. self.assertEqual(output.status_code, 200)
  1210. self.assertNotIn(
  1211. '<a class="btn btn-primary btn-sm" '
  1212. 'href="/test/issue/1/edit" title="Edit this issue">',
  1213. output.data)
  1214. self.assertNotIn(
  1215. '<button class="btn btn-danger btn-sm" type="submit"',
  1216. output.data)
  1217. self.assertNotIn('title="Delete this ticket">', output.data)
  1218. # user no ACLs = no take action/button
  1219. self.assertNotIn('function take_issue(){',output.data)
  1220. self.assertNotIn('function drop_issue(){',output.data)
  1221. self.assertNotIn(
  1222. '<button class="btn btn-sm pull-xs-right" id="take-btn"',
  1223. output.data)
  1224. # user no ACLs = no metadata form
  1225. self.assertNotIn(
  1226. '<input class="form-control" '
  1227. 'name="bugzilla" id="bugzilla"/>',output.data)
  1228. self.assertNotIn(
  1229. '<select class="form-control" name="reviewstatus" '
  1230. 'id="reviewstatus>',output.data)
  1231. self.assertNotIn(
  1232. '<input type="checkbox" '
  1233. 'class="form-control" name="upstream" id="upstream"/>',
  1234. output.data)
  1235. user = tests.FakeUser(username='foo')
  1236. with tests.user_set(self.app.application, user):
  1237. output = self.app.get('/test/issue/1')
  1238. self.assertEqual(output.status_code, 200)
  1239. self.assertNotIn(
  1240. '<a class="btn btn-primary btn-sm" '
  1241. 'href="/test/issue/1/edit" title="Edit this issue">',
  1242. output.data)
  1243. self.assertNotIn(
  1244. '<button class="btn btn-danger btn-sm" type="submit"',
  1245. output.data)
  1246. self.assertNotIn('title="Delete this ticket">', output.data)
  1247. self.assertFalse(
  1248. '<a href="/login/">Login</a> to comment on this ticket.'
  1249. in output.data)
  1250. # user has ticket = take ok
  1251. self.assertIn('function take_issue(){',output.data)
  1252. self.assertIn('function drop_issue(){',output.data)
  1253. self.assertIn(
  1254. '<button class="btn btn-sm pull-xs-right" id="take-btn"',
  1255. output.data)
  1256. # user has ticket == Sees the metadata
  1257. self.assertIn(
  1258. '<input class="form-control" '
  1259. 'name="bugzilla" id="bugzilla"/>',output.data)
  1260. self.assertIn(
  1261. '<select class="form-control"\n'
  1262. ' name="reviewstatus"\n'
  1263. ' id="reviewstatus">\n',
  1264. output.data)
  1265. self.assertIn(
  1266. '<input type="checkbox" '
  1267. 'class="form-control" name="upstream" id="upstream"/>',
  1268. output.data)
  1269. @patch('pagure.lib.git.update_git')
  1270. @patch('pagure.lib.notify.send_email')
  1271. def test_view_issue_non_ascii_milestone(self, p_send_email, p_ugt):
  1272. """ Test the view_issue endpoint with non-ascii milestone. """
  1273. p_send_email.return_value = True
  1274. p_ugt.return_value = True
  1275. output = self.app.get('/foo/issue/1')
  1276. self.assertEqual(output.status_code, 404)
  1277. tests.create_projects(self.session)
  1278. tests.create_projects_git(
  1279. os.path.join(self.path, 'repos'), bare=True)
  1280. output = self.app.get('/test/issue/1')
  1281. self.assertEqual(output.status_code, 404)
  1282. # Create issues to play with
  1283. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1284. msg = pagure.lib.new_issue(
  1285. session=self.session,
  1286. repo=repo,
  1287. title='Test issue',
  1288. content='We should work on this',
  1289. user='pingou',
  1290. ticketfolder=None
  1291. )
  1292. self.session.commit()
  1293. self.assertEqual(msg.title, 'Test issue')
  1294. # Add a non-ascii milestone to the issue but project has no milestone
  1295. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1296. message = pagure.lib.edit_issue(
  1297. self.session,
  1298. issue=issue,
  1299. milestone=b'käpy'.decode('utf-8'),
  1300. private=False,
  1301. user='pingou',
  1302. ticketfolder=None
  1303. )
  1304. self.assertEqual(
  1305. message,
  1306. [
  1307. u'Issue set to the milestone: k\xe4py'
  1308. ]
  1309. )
  1310. self.session.commit()
  1311. output = self.app.get('/test/issue/1')
  1312. self.assertEqual(output.status_code, 200)
  1313. self.assertIn(
  1314. '<title>Issue #1: Test issue - test - Pagure</title>',
  1315. output.data)
  1316. self.assertNotIn(b'käpy'.decode('utf-8'), output.data)
  1317. # Add a non-ascii milestone to the project
  1318. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1319. repo.milestones = {b'käpy'.decode('utf-8'): None}
  1320. self.session.add(repo)
  1321. self.session.commit()
  1322. # View the issue
  1323. output = self.app.get('/test/issue/1')
  1324. self.assertEqual(output.status_code, 200)
  1325. self.assertIn(
  1326. '<title>Issue #1: Test issue - test - Pagure</title>',
  1327. output.data)
  1328. self.assertIn(b'käpy'.decode('utf-8'), output.data.decode('utf-8'))
  1329. @patch('pagure.lib.git.update_git')
  1330. @patch('pagure.lib.notify.send_email')
  1331. def test_view_issue_list_no_data(self, p_send_email, p_ugt):
  1332. """ Test the view_issue endpoint when the issue has a custom field
  1333. of type list with no data attached. """
  1334. p_send_email.return_value = True
  1335. p_ugt.return_value = True
  1336. tests.create_projects(self.session)
  1337. tests.create_projects_git(
  1338. os.path.join(self.path, 'repos'), bare=True)
  1339. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1340. # Add custom fields to the project
  1341. msg = pagure.lib.set_custom_key_fields(
  1342. session=self.session,
  1343. project=repo,
  1344. fields=['test1'],
  1345. types=['list'],
  1346. data=[None],
  1347. notify=[None]
  1348. )
  1349. self.session.commit()
  1350. self.assertEqual(msg, 'List of custom fields updated')
  1351. # Create issues to play with
  1352. msg = pagure.lib.new_issue(
  1353. session=self.session,
  1354. repo=repo,
  1355. title=u'Big problÈm!',
  1356. content='We should work on this',
  1357. user='pingou',
  1358. ticketfolder=None
  1359. )
  1360. self.session.commit()
  1361. self.assertEqual(msg.title, u'Big problÈm!')
  1362. # Assign a value to the custom key on that ticket
  1363. cfield = pagure.lib.get_custom_key(
  1364. session=self.session,
  1365. project=repo,
  1366. keyname='test1')
  1367. msg = pagure.lib.set_custom_key_value(
  1368. session=self.session,
  1369. issue=msg,
  1370. key=cfield,
  1371. value='item')
  1372. self.session.commit()
  1373. self.assertEqual(msg, 'Custom field test1 adjusted to item')
  1374. user = tests.FakeUser()
  1375. user.username = 'pingou'
  1376. with tests.user_set(self.app.application, user):
  1377. output = self.app.get('/test/issue/1')
  1378. self.assertEqual(output.status_code, 200)
  1379. @patch('pagure.lib.git.update_git')
  1380. @patch('pagure.lib.notify.send_email')
  1381. def test_update_issue(self, p_send_email, p_ugt):
  1382. """ Test the update_issue endpoint. """
  1383. p_send_email.return_value = True
  1384. p_ugt.return_value = True
  1385. # No Git repo
  1386. output = self.app.get('/foo/issue/1/update')
  1387. self.assertEqual(output.status_code, 404)
  1388. tests.create_projects(self.session)
  1389. tests.create_projects_git(
  1390. os.path.join(self.path, 'repos'), bare=True)
  1391. output = self.app.get('/test/issue/1/update')
  1392. self.assertEqual(output.status_code, 302)
  1393. # Create issues to play with
  1394. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1395. msg = pagure.lib.new_issue(
  1396. session=self.session,
  1397. repo=repo,
  1398. title='Test issue',
  1399. content='We should work on this',
  1400. user='pingou',
  1401. ticketfolder=None
  1402. )
  1403. self.session.commit()
  1404. self.assertEqual(msg.title, 'Test issue')
  1405. user = tests.FakeUser()
  1406. user.username = 'pingou'
  1407. with tests.user_set(self.app.application, user):
  1408. output = self.app.get('/test/issue/1')
  1409. self.assertEqual(output.status_code, 200)
  1410. self.assertIn(
  1411. '<title>Issue #1: Test issue - test - Pagure</title>',
  1412. output.data)
  1413. self.assertIn(
  1414. '<a class="btn btn-primary btn-sm" '
  1415. 'href="/test/issue/1/edit" title="Edit this issue">',
  1416. output.data)
  1417. self.assertEqual(output.data.count('title="PY C (pingou)"'), 1)
  1418. csrf_token = self.get_csrf(output=output)
  1419. data = {
  1420. 'status': 'Closed',
  1421. 'close_status': 'fixed'
  1422. }
  1423. # Invalid repo
  1424. output = self.app.post('/bar/issue/1/update', data=data)
  1425. self.assertEqual(output.status_code, 404)
  1426. # Non-existing issue
  1427. output = self.app.post('/test/issue/100/update', data=data)
  1428. self.assertEqual(output.status_code, 404)
  1429. output = self.app.post(
  1430. '/test/issue/1/update', data=data, follow_redirects=True)
  1431. self.assertEqual(output.status_code, 200)
  1432. self.assertIn(
  1433. '<title>Issue #1: Test issue - test - Pagure</title>',
  1434. output.data)
  1435. self.assertIn(
  1436. '<a class="btn btn-primary btn-sm" '
  1437. 'href="/test/issue/1/edit" title="Edit this issue">',
  1438. output.data)
  1439. self.assertFalse(
  1440. '<option selected value="Fixed">Fixed</option>'
  1441. in output.data)
  1442. # Right status, wrong csrf
  1443. data['close_status'] = 'Fixed'
  1444. output = self.app.post(
  1445. '/test/issue/1/update', data=data, follow_redirects=True)
  1446. self.assertEqual(output.status_code, 200)
  1447. self.assertIn(
  1448. '<title>Issue #1: Test issue - test - Pagure</title>',
  1449. output.data)
  1450. self.assertIn(
  1451. '<a class="btn btn-primary btn-sm" '
  1452. 'href="/test/issue/1/edit" title="Edit this issue">',
  1453. output.data)
  1454. self.assertFalse(
  1455. '<option selected value="Fixed">Fixed</option>'
  1456. in output.data)
  1457. # working status update
  1458. data['csrf_token'] = csrf_token
  1459. output = self.app.post(
  1460. '/test/issue/1/update', data=data, follow_redirects=True)
  1461. self.assertEqual(output.status_code, 200)
  1462. self.assertIn(
  1463. '<title>Issue #1: Test issue - test - Pagure</title>',
  1464. output.data)
  1465. self.assertIn(
  1466. '<a class="btn btn-primary btn-sm" '
  1467. 'href="/test/issue/1/edit" title="Edit this issue">',
  1468. output.data)
  1469. self.assertIn(
  1470. '</button>\n '
  1471. 'Issue close_status updated to: Fixed\n',
  1472. output.data)
  1473. self.assertIn(
  1474. '</button>\n '
  1475. 'Issue status updated to: Closed (was: Open)\n',
  1476. output.data)
  1477. self.assertTrue(
  1478. '<option selected value="Fixed">Fixed</option>'
  1479. in output.data)
  1480. # FIXME: There is likely something going wrong in the html
  1481. # below
  1482. self.assertIn(
  1483. '<small><p><strong>Metadata Update from '\
  1484. '<a href="https://pagure.org/user/pingou"></a>'\
  1485. '''<a href="https://pagure.org/user/pingou">@pingou</a></strong>:<br>
  1486. - Issue close_status updated to: Fixed<br>
  1487. - Issue status updated to: Closed (was: Open)</p></small>''',
  1488. output.data)
  1489. # Add new comment
  1490. data = {
  1491. 'csrf_token': csrf_token,
  1492. 'status': 'Closed',
  1493. 'close_status': 'Fixed',
  1494. 'comment': 'Woohoo a second comment!',
  1495. }
  1496. output = self.app.post(
  1497. '/test/issue/1/update', data=data, follow_redirects=True)
  1498. self.assertEqual(output.status_code, 200)
  1499. self.assertIn(
  1500. '<title>Issue #1: Test issue - test - Pagure</title>',
  1501. output.data)
  1502. self.assertIn(
  1503. '<a class="btn btn-primary btn-sm" '
  1504. 'href="/test/issue/1/edit" title="Edit this issue">',
  1505. output.data)
  1506. self.assertIn(
  1507. '</button>\n Comment added',
  1508. output.data)
  1509. self.assertNotIn(
  1510. '</button>\n No changes to edit',
  1511. output.data)
  1512. self.assertTrue(
  1513. '<p>Woohoo a second comment!</p>' in output.data)
  1514. self.assertEqual(output.data.count('comment_body">'), 2)
  1515. self.assertTrue(
  1516. '<option selected value="Fixed">Fixed</option>'
  1517. in output.data)
  1518. # 2: one for the original comment, one for the new comment
  1519. self.assertEqual(output.data.count('title="PY C (pingou)"'), 2)
  1520. # Add new tag
  1521. data = {
  1522. 'csrf_token': csrf_token,
  1523. 'status': 'Closed',
  1524. 'close_status': 'Fixed',
  1525. 'tag': 'tag2',
  1526. }
  1527. output = self.app.post(
  1528. '/test/issue/1/update', data=data, follow_redirects=True)
  1529. self.assertEqual(output.status_code, 200)
  1530. self.assertIn(
  1531. '<title>Issue #1: Test issue - test - Pagure</title>',
  1532. output.data)
  1533. self.assertIn(
  1534. '<a class="btn btn-primary btn-sm" '
  1535. 'href="/test/issue/1/edit" title="Edit this issue">',
  1536. output.data)
  1537. self.assertTrue(
  1538. '<p>Woohoo a second comment!</p>' in output.data)
  1539. self.assertEqual(output.data.count('comment_body">'), 2)
  1540. self.assertTrue(
  1541. '<option selected value="Fixed">Fixed</option>'
  1542. in output.data)
  1543. # Assign issue to an non-existent user
  1544. data = {
  1545. 'csrf_token': csrf_token,
  1546. 'status': 'Closed',
  1547. 'close_status': 'Fixed',
  1548. 'assignee': 'ralph',
  1549. }
  1550. output = self.app.post(
  1551. '/test/issue/1/update', data=data, follow_redirects=True)
  1552. self.assertEqual(output.status_code, 200)
  1553. self.assertIn(
  1554. '<title>Issue #1: Test issue - test - Pagure</title>',
  1555. output.data)
  1556. self.assertIn(
  1557. '<a class="btn btn-primary btn-sm" '
  1558. 'href="/test/issue/1/edit" title="Edit this issue">',
  1559. output.data)
  1560. self.assertIn(
  1561. '</button>\n No user &#34;ralph&#34; found',
  1562. output.data)
  1563. self.assertTrue(
  1564. '<p>Woohoo a second comment!</p>' in output.data)
  1565. self.assertEqual(output.data.count('comment_body">'), 2)
  1566. self.assertTrue(
  1567. '<option selected value="Fixed">Fixed</option>'
  1568. in output.data)
  1569. # Assign issue properly
  1570. data = {
  1571. 'csrf_token': csrf_token,
  1572. 'status': 'Closed',
  1573. 'close_status': 'Fixed',
  1574. 'assignee': 'pingou',
  1575. }
  1576. output = self.app.post(
  1577. '/test/issue/1/update', data=data, follow_redirects=True)
  1578. self.assertEqual(output.status_code, 200)
  1579. self.assertIn(
  1580. '<title>Issue #1: Test issue - test - Pagure</title>',
  1581. output.data)
  1582. self.assertIn(
  1583. '<a class="btn btn-primary btn-sm" '
  1584. 'href="/test/issue/1/edit" title="Edit this issue">',
  1585. output.data)
  1586. self.assertIn(
  1587. '</button>\n Issue assigned to pingou\n',
  1588. output.data)
  1589. self.assertTrue(
  1590. '<a href="/test/issues?assignee=pingou" title="PY C (pingou)"' in output.data)
  1591. self.assertTrue(
  1592. '<p>Woohoo a second comment!</p>' in output.data)
  1593. self.assertEqual(output.data.count('comment_body">'), 2)
  1594. self.assertTrue(
  1595. '<option selected value="Fixed">Fixed</option>'
  1596. in output.data)
  1597. # Create another issue with a dependency
  1598. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1599. msg = pagure.lib.new_issue(
  1600. session=self.session,
  1601. repo=repo,
  1602. title='Test issue',
  1603. content='We should work on this',
  1604. user='pingou',
  1605. ticketfolder=None
  1606. )
  1607. self.session.commit()
  1608. self.assertEqual(msg.title, 'Test issue')
  1609. # Reset the status of the first issue
  1610. parent_issue = pagure.lib.search_issues(
  1611. self.session, repo, issueid=1)
  1612. parent_issue.status = 'Open'
  1613. self.session.add(parent_issue)
  1614. # Add the dependency relationship
  1615. self.session.add(parent_issue)
  1616. issue = pagure.lib.search_issues(self.session, repo, issueid=2)
  1617. issue.parents.append(parent_issue)
  1618. self.session.add(issue)
  1619. self.session.commit()
  1620. with tests.user_set(self.app.application, user):
  1621. data['csrf_token'] = csrf_token
  1622. output = self.app.post(
  1623. '/test/issue/2/update', data=data, follow_redirects=True)
  1624. self.assertEqual(output.status_code, 200)
  1625. self.assertIn(
  1626. '<title>Issue #2: Test issue - test - Pagure</title>',
  1627. output.data)
  1628. self.assertIn(
  1629. '<a class="btn btn-primary btn-sm" '
  1630. 'href="/test/issue/2/edit" title="Edit this issue">',
  1631. output.data)
  1632. self.assertIn(
  1633. '</button>\n You cannot close a ticket '
  1634. 'that has ticket depending that are still open.',
  1635. output.data)
  1636. self.assertTrue(
  1637. '<option selected value="Open">Open</option>'
  1638. in output.data)
  1639. # Create private issue
  1640. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1641. msg = pagure.lib.new_issue(
  1642. session=self.session,
  1643. repo=repo,
  1644. title='Test issue',
  1645. content='We should work on this',
  1646. user='pingou',
  1647. ticketfolder=None,
  1648. private=True,
  1649. )
  1650. self.session.commit()
  1651. self.assertEqual(msg.title, 'Test issue')
  1652. # Wrong user
  1653. user = tests.FakeUser()
  1654. with tests.user_set(self.app.application, user):
  1655. output = self.app.post(
  1656. '/test/issue/3/update', data=data, follow_redirects=True)
  1657. self.assertEqual(output.status_code, 403)
  1658. # Project w/o issue tracker
  1659. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1660. repo.settings = {'issue_tracker': False}
  1661. self.session.add(repo)
  1662. self.session.commit()
  1663. with tests.user_set(self.app.application, user):
  1664. # Repo not set-up for issue tracker
  1665. output = self.app.post('/test/issue/1/update', data=data)
  1666. self.assertEqual(output.status_code, 404)
  1667. @patch('pagure.lib.git.update_git')
  1668. @patch('pagure.lib.notify.send_email')
  1669. def test_update_issue_drop_comment(self, p_send_email, p_ugt):
  1670. """ Test droping comment via the update_issue endpoint. """
  1671. p_send_email.return_value = True
  1672. p_ugt.return_value = True
  1673. tests.create_projects(self.session)
  1674. tests.create_projects_git(
  1675. os.path.join(self.path, 'repos'), bare=True)
  1676. # Create issues to play with
  1677. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1678. msg = pagure.lib.new_issue(
  1679. session=self.session,
  1680. repo=repo,
  1681. title='Test issue',
  1682. content='We should work on this',
  1683. user='pingou',
  1684. ticketfolder=None
  1685. )
  1686. self.session.commit()
  1687. self.assertEqual(msg.title, 'Test issue')
  1688. user = tests.FakeUser()
  1689. user.username = 'pingou'
  1690. with tests.user_set(self.app.application, user):
  1691. output = self.app.get('/test/issue/1')
  1692. self.assertEqual(output.status_code, 200)
  1693. self.assertIn(
  1694. '<title>Issue #1: Test issue - test - Pagure</title>',
  1695. output.data)
  1696. self.assertIn(
  1697. '<a class="btn btn-primary btn-sm" '
  1698. 'href="/test/issue/1/edit" title="Edit this issue">',
  1699. output.data)
  1700. csrf_token = self.get_csrf(output=output)
  1701. # Add new comment
  1702. data = {
  1703. 'csrf_token': csrf_token,
  1704. 'comment': 'Woohoo a second comment!',
  1705. }
  1706. output = self.app.post(
  1707. '/test/issue/1/update', data=data, follow_redirects=True)
  1708. self.assertEqual(output.status_code, 200)
  1709. self.assertIn(
  1710. '<title>Issue #1: Test issue - test - Pagure</title>',
  1711. output.data)
  1712. self.assertIn(
  1713. '<a class="btn btn-primary btn-sm" '
  1714. 'href="/test/issue/1/edit" title="Edit this issue">',
  1715. output.data)
  1716. self.assertIn(
  1717. '</button>\n Comment added',
  1718. output.data)
  1719. self.assertTrue(
  1720. '<p>Woohoo a second comment!</p>' in output.data)
  1721. self.assertEqual(output.data.count('comment_body">'), 2)
  1722. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1723. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1724. self.assertEqual(len(issue.comments), 1)
  1725. data = {
  1726. 'csrf_token': csrf_token,
  1727. 'drop_comment': 1,
  1728. }
  1729. user = tests.FakeUser()
  1730. with tests.user_set(self.app.application, user):
  1731. # Wrong issue id
  1732. output = self.app.post(
  1733. '/test/issue/3/update', data=data, follow_redirects=True)
  1734. self.assertEqual(output.status_code, 404)
  1735. # Wrong user
  1736. output = self.app.post(
  1737. '/test/issue/1/update', data=data, follow_redirects=True)
  1738. self.assertEqual(output.status_code, 403)
  1739. user = tests.FakeUser()
  1740. user.username = 'pingou'
  1741. with tests.user_set(self.app.application, user):
  1742. # Drop the new comment
  1743. output = self.app.post(
  1744. '/test/issue/1/update', data=data, follow_redirects=True)
  1745. self.assertEqual(output.status_code, 200)
  1746. self.assertIn(
  1747. '<title>Issue #1: Test issue - test - Pagure</title>',
  1748. output.data)
  1749. self.assertIn(
  1750. '<a class="btn btn-primary btn-sm" '
  1751. 'href="/test/issue/1/edit" title="Edit this issue">',
  1752. output.data)
  1753. self.assertIn(
  1754. '</button>\n Comment removed',
  1755. output.data)
  1756. # Drop non-existant comment
  1757. output = self.app.post(
  1758. '/test/issue/1/update', data=data, follow_redirects=True)
  1759. self.assertEqual(output.status_code, 404)
  1760. self.session.commit()
  1761. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1762. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1763. self.assertEqual(len(issue.comments), 0)
  1764. @patch('pagure.lib.git.update_git')
  1765. @patch('pagure.lib.notify.send_email')
  1766. def test_update_issue_depend(self, p_send_email, p_ugt):
  1767. """ Test adding dependency via the update_issue endpoint. """
  1768. p_send_email.return_value = True
  1769. p_ugt.return_value = True
  1770. tests.create_projects(self.session)
  1771. tests.create_projects_git(
  1772. os.path.join(self.path, 'repos'), bare=True)
  1773. # Create issues to play with
  1774. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1775. msg = pagure.lib.new_issue(
  1776. session=self.session,
  1777. repo=repo,
  1778. title='Test issue',
  1779. content='We should work on this',
  1780. user='pingou',
  1781. ticketfolder=None
  1782. )
  1783. self.session.commit()
  1784. self.assertEqual(msg.title, 'Test issue')
  1785. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1786. msg = pagure.lib.new_issue(
  1787. session=self.session,
  1788. repo=repo,
  1789. title='Test issue #2',
  1790. content='We should work on this again',
  1791. user='foo',
  1792. ticketfolder=None
  1793. )
  1794. self.session.commit()
  1795. self.assertEqual(msg.title, 'Test issue #2')
  1796. user = tests.FakeUser()
  1797. user.username = 'pingou'
  1798. with tests.user_set(self.app.application, user):
  1799. output = self.app.get('/test/issue/1')
  1800. self.assertEqual(output.status_code, 200)
  1801. self.assertIn(
  1802. '<title>Issue #1: Test issue - test - Pagure</title>',
  1803. output.data)
  1804. self.assertIn(
  1805. '<a class="btn btn-primary btn-sm" '
  1806. 'href="/test/issue/1/edit" title="Edit this issue">',
  1807. output.data)
  1808. csrf_token = self.get_csrf(output=output)
  1809. # Add a dependent ticket
  1810. data = {
  1811. 'csrf_token': csrf_token,
  1812. 'depending': '2',
  1813. }
  1814. output = self.app.post(
  1815. '/test/issue/1/update', data=data, follow_redirects=True)
  1816. self.assertEqual(output.status_code, 200)
  1817. self.assertIn(
  1818. '<title>Issue #1: Test issue - test - Pagure</title>',
  1819. output.data)
  1820. self.assertIn(
  1821. '<a class="btn btn-primary btn-sm" '
  1822. 'href="/test/issue/1/edit" title="Edit this issue">',
  1823. output.data)
  1824. # Add an invalid dependent ticket
  1825. data = {
  1826. 'csrf_token': csrf_token,
  1827. 'depending': '2,abc',
  1828. }
  1829. output = self.app.post(
  1830. '/test/issue/1/update', data=data, follow_redirects=True)
  1831. self.assertEqual(output.status_code, 200)
  1832. self.assertIn(
  1833. '<title>Issue #1: Test issue - test - Pagure</title>',
  1834. output.data)
  1835. self.assertIn(
  1836. '<a class="btn btn-primary btn-sm" '
  1837. 'href="/test/issue/1/edit" title="Edit this issue">',
  1838. output.data)
  1839. self.assertNotIn(
  1840. '</button>\n '
  1841. 'Successfully edited issue #1',
  1842. output.data)
  1843. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1844. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1845. self.assertEqual(issue.depending_text, [2])
  1846. self.assertEqual(issue.blocking_text, [])
  1847. # Check the icons showing if the issues are blocking/blocked
  1848. output = self.app.get('/test/issues/')
  1849. self.assertEqual(
  1850. output.data.count(
  1851. '<span class="oi" data-glyph="lock-unlocked" title="Issue '
  1852. 'blocking one or more issue(s)"></span>'),
  1853. 1)
  1854. self.assertEqual(
  1855. output.data.count(
  1856. '<span class="oi" data-glyph="ban" title="Issue blocked '
  1857. 'by one or more issue(s)"></span>'),
  1858. 1)
  1859. @patch('pagure.lib.git.update_git')
  1860. @patch('pagure.lib.notify.send_email')
  1861. def test_update_issue_block(self, p_send_email, p_ugt):
  1862. """ Test adding blocked issue via the update_issue endpoint. """
  1863. p_send_email.return_value = True
  1864. p_ugt.return_value = True
  1865. tests.create_projects(self.session)
  1866. tests.create_projects_git(
  1867. os.path.join(self.path, 'repos'), bare=True)
  1868. # Create issues to play with
  1869. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1870. msg = pagure.lib.new_issue(
  1871. session=self.session,
  1872. repo=repo,
  1873. title='Test issue',
  1874. content='We should work on this',
  1875. user='pingou',
  1876. ticketfolder=None
  1877. )
  1878. self.session.commit()
  1879. self.assertEqual(msg.title, 'Test issue')
  1880. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1881. msg = pagure.lib.new_issue(
  1882. session=self.session,
  1883. repo=repo,
  1884. title='Test issue #2',
  1885. content='We should work on this again',
  1886. user='foo',
  1887. ticketfolder=None
  1888. )
  1889. self.session.commit()
  1890. self.assertEqual(msg.title, 'Test issue #2')
  1891. # User is not an admin of the project
  1892. user = tests.FakeUser(username='foo')
  1893. with tests.user_set(self.app.application, user):
  1894. output = self.app.get('/test/issue/1')
  1895. self.assertEqual(output.status_code, 200)
  1896. self.assertIn(
  1897. '<title>Issue #1: Test issue - test - Pagure</title>',
  1898. output.data)
  1899. csrf_token = self.get_csrf(output=output)
  1900. # Add a dependent ticket
  1901. data = {
  1902. 'csrf_token': csrf_token,
  1903. 'blocking': '2',
  1904. }
  1905. output = self.app.post(
  1906. '/test/issue/1/update', data=data, follow_redirects=True)
  1907. self.assertEqual(output.status_code, 200)
  1908. self.assertIn(
  1909. '<title>Issue #1: Test issue - test - Pagure</title>',
  1910. output.data)
  1911. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1912. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1913. self.assertEqual(issue.depending_text, [])
  1914. self.assertEqual(issue.blocking_text, [])
  1915. user = tests.FakeUser()
  1916. user.username = 'pingou'
  1917. with tests.user_set(self.app.application, user):
  1918. output = self.app.get('/test/issue/1')
  1919. self.assertEqual(output.status_code, 200)
  1920. self.assertIn(
  1921. '<title>Issue #1: Test issue - test - Pagure</title>',
  1922. output.data)
  1923. self.assertIn(
  1924. '<a class="btn btn-primary btn-sm" '
  1925. 'href="/test/issue/1/edit" title="Edit this issue">',
  1926. output.data)
  1927. csrf_token = self.get_csrf(output=output)
  1928. # Add a dependent ticket
  1929. data = {
  1930. 'csrf_token': csrf_token,
  1931. 'blocking': '2',
  1932. }
  1933. output = self.app.post(
  1934. '/test/issue/1/update', data=data, follow_redirects=True)
  1935. self.assertEqual(output.status_code, 200)
  1936. self.assertIn(
  1937. '<title>Issue #1: Test issue - test - Pagure</title>',
  1938. output.data)
  1939. self.assertIn(
  1940. '<a class="btn btn-primary btn-sm" '
  1941. 'href="/test/issue/1/edit" title="Edit this issue">',
  1942. output.data)
  1943. # Add an invalid dependent ticket
  1944. data = {
  1945. 'csrf_token': csrf_token,
  1946. 'blocking': '2,abc',
  1947. }
  1948. output = self.app.post(
  1949. '/test/issue/1/update', data=data, follow_redirects=True)
  1950. self.assertEqual(output.status_code, 200)
  1951. self.assertIn(
  1952. '<title>Issue #1: Test issue - test - Pagure</title>',
  1953. output.data)
  1954. self.assertIn(
  1955. '<a class="btn btn-primary btn-sm" '
  1956. 'href="/test/issue/1/edit" title="Edit this issue">',
  1957. output.data)
  1958. self.assertNotIn(
  1959. '</button>\n '
  1960. 'Successfully edited issue #1',
  1961. output.data)
  1962. self.session.commit()
  1963. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1964. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  1965. self.assertEqual(issue.depending_text, [])
  1966. self.assertEqual(issue.blocking_text, [2])
  1967. @patch('pagure.lib.git.update_git')
  1968. @patch('pagure.lib.notify.send_email')
  1969. def test_upload_issue(self, p_send_email, p_ugt):
  1970. """ Test the upload_issue endpoint. """
  1971. p_send_email.return_value = True
  1972. p_ugt.return_value = True
  1973. tests.create_projects(self.session)
  1974. tests.create_projects_git(
  1975. os.path.join(self.path, 'repos'), bare=True)
  1976. tests.create_projects_git(
  1977. os.path.join(self.path, 'repos', 'tickets'), bare=True)
  1978. # Create issues to play with
  1979. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1980. msg = pagure.lib.new_issue(
  1981. session=self.session,
  1982. repo=repo,
  1983. title='Test issue',
  1984. content='We should work on this',
  1985. user='pingou',
  1986. ticketfolder=None
  1987. )
  1988. self.session.commit()
  1989. self.assertEqual(msg.title, 'Test issue')
  1990. user = tests.FakeUser()
  1991. user.username = 'pingou'
  1992. with tests.user_set(self.app.application, user):
  1993. output = self.app.get('/test/issue/1')
  1994. self.assertEqual(output.status_code, 200)
  1995. self.assertIn(
  1996. '<title>Issue #1: Test issue - test - Pagure</title>',
  1997. output.data)
  1998. self.assertIn(
  1999. '<a class="btn btn-primary btn-sm" '
  2000. 'href="/test/issue/1/edit" title="Edit this issue">',
  2001. output.data)
  2002. csrf_token = self.get_csrf(output=output)
  2003. output = self.app.post('/foo/issue/1/upload')
  2004. self.assertEqual(output.status_code, 404)
  2005. output = self.app.post('/test/issue/100/upload')
  2006. self.assertEqual(output.status_code, 404)
  2007. # Invalid upload
  2008. data = {
  2009. 'enctype': 'multipart/form-data',
  2010. }
  2011. output = self.app.post(
  2012. '/test/issue/1/upload', data=data, follow_redirects=True)
  2013. self.assertEqual(output.status_code, 200)
  2014. json_data = json.loads(output.data)
  2015. exp = {'output': 'notok'}
  2016. self.assertDictEqual(json_data, exp)
  2017. # Attach a file to a ticket
  2018. with open(os.path.join(tests.HERE, 'placebo.png'), 'rb') as stream:
  2019. data = {
  2020. 'csrf_token': csrf_token,
  2021. 'filestream': stream,
  2022. 'enctype': 'multipart/form-data',
  2023. }
  2024. output = self.app.post(
  2025. '/test/issue/1/upload', data=data, follow_redirects=True)
  2026. self.assertEqual(output.status_code, 200)
  2027. json_data = json.loads(output.data)
  2028. folder = os.path.dirname(
  2029. os.path.abspath(__file__))[1:].replace('/', '_')
  2030. exp = {
  2031. 'filelocations': [
  2032. '/test/issue/raw/files/8a06845923010b27bfd8'
  2033. 'e7e75acff7badc40d1021b4994e01f5e11ca40bc3a'
  2034. 'be-%s_placebo.png' % folder
  2035. ],
  2036. 'filenames': ['%s_placebo.png' % folder],
  2037. 'output': 'ok'
  2038. }
  2039. self.assertDictEqual(json_data, exp)
  2040. # Project w/o issue tracker
  2041. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2042. repo.settings = {'issue_tracker': False}
  2043. self.session.add(repo)
  2044. self.session.commit()
  2045. with tests.user_set(self.app.application, user):
  2046. output = self.app.post('/test/issue/1/upload')
  2047. self.assertEqual(output.status_code, 404)
  2048. @patch.dict('pagure.config.config', {'PR_ONLY': True})
  2049. @patch('pagure.lib.git.update_git')
  2050. @patch('pagure.lib.notify.send_email')
  2051. def test_upload_issue_virus(self, p_send_email, p_ugt):
  2052. """ Test the upload_issue endpoint. """
  2053. if not pyclamd:
  2054. raise SkipTest()
  2055. p_send_email.return_value = True
  2056. p_ugt.return_value = True
  2057. tests.create_projects(self.session)
  2058. tests.create_projects_git(
  2059. os.path.join(self.path, 'repos'), bare=True)
  2060. tests.create_projects_git(
  2061. os.path.join(self.path, 'tickets'), bare=True)
  2062. # Create issues to play with
  2063. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2064. msg = pagure.lib.new_issue(
  2065. session=self.session,
  2066. repo=repo,
  2067. title='Test issue',
  2068. content='We should work on this',
  2069. user='pingou',
  2070. ticketfolder=None
  2071. )
  2072. self.session.commit()
  2073. self.assertEqual(msg.title, 'Test issue')
  2074. user = tests.FakeUser()
  2075. user.username = 'pingou'
  2076. with tests.user_set(self.app.application, user):
  2077. csrf_token = self.get_csrf()
  2078. # TODO: Figure a way to enable this test on jenkins
  2079. # Try to attach a virus
  2080. if not os.environ.get('BUILD_ID'):
  2081. with tempfile.NamedTemporaryFile() as eicarfile:
  2082. eicarfile.write(pyclamd.ClamdUnixSocket().EICAR())
  2083. eicarfile.flush()
  2084. with open(eicarfile.name, 'rb') as stream:
  2085. data = {
  2086. 'csrf_token': csrf_token,
  2087. 'filestream': stream,
  2088. 'enctype': 'multipart/form-data',
  2089. }
  2090. output = self.app.post(
  2091. '/test/issue/1/upload', data=data, follow_redirects=True)
  2092. self.assertEqual(output.status_code, 200)
  2093. json_data = json.loads(output.data)
  2094. exp = {
  2095. 'output': 'notok',
  2096. }
  2097. self.assertDictEqual(json_data, exp)
  2098. @patch('pagure.lib.git.update_git')
  2099. @patch('pagure.lib.notify.send_email')
  2100. def test_upload_issue_two_files(self, p_send_email, p_ugt):
  2101. """ Test the upload_issue endpoint with two files. """
  2102. p_send_email.return_value = True
  2103. p_ugt.return_value = True
  2104. tests.create_projects(self.session)
  2105. tests.create_projects_git(
  2106. os.path.join(self.path, 'repos'), bare=True)
  2107. tests.create_projects_git(
  2108. os.path.join(self.path, 'tickets'), bare=True)
  2109. # Create issues to play with
  2110. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2111. msg = pagure.lib.new_issue(
  2112. session=self.session,
  2113. repo=repo,
  2114. title='Test issue',
  2115. content='We should work on this',
  2116. user='pingou',
  2117. ticketfolder=None
  2118. )
  2119. self.session.commit()
  2120. self.assertEqual(msg.title, 'Test issue')
  2121. user = tests.FakeUser()
  2122. user.username = 'pingou'
  2123. with tests.user_set(self.app.application, user):
  2124. csrf_token = self.get_csrf()
  2125. # Attach two files to a ticket
  2126. with open(os.path.join(tests.HERE, 'placebo.png'), 'rb') as stream:
  2127. with open(os.path.join(tests.HERE, 'placebo.png'), 'rb') as stream2:
  2128. data = {
  2129. 'csrf_token': csrf_token,
  2130. 'filestream': [stream, stream2],
  2131. 'enctype': 'multipart/form-data',
  2132. }
  2133. output = self.app.post(
  2134. '/test/issue/1/upload', data=data, follow_redirects=True)
  2135. self.assertEqual(output.status_code, 200)
  2136. json_data = json.loads(output.data)
  2137. folder = os.path.dirname(
  2138. os.path.abspath(__file__))[1:].replace('/', '_')
  2139. exp = {
  2140. 'output': 'ok',
  2141. 'filelocations': [
  2142. '/test/issue/raw/files/8a06845923010b27bfd8'
  2143. 'e7e75acff7badc40d1021b4994e01f5e11ca40bc3a'
  2144. 'be-%s_placebo.png' % folder,
  2145. '/test/issue/raw/files/8a06845923010b27bfd8'
  2146. 'e7e75acff7badc40d1021b4994e01f5e11ca40bc3a'
  2147. 'be-%s_placebo.png' % folder,
  2148. ],
  2149. 'filenames': [
  2150. '%s_placebo.png' % folder,
  2151. '%s_placebo.png' % folder
  2152. ],
  2153. }
  2154. self.assertDictEqual(json_data, exp)
  2155. def test_view_issue_raw_file_empty(self):
  2156. """ Test the view_issue_raw_file endpoint. """
  2157. # Create the project and git repos
  2158. tests.create_projects(self.session)
  2159. tests.create_projects_git(
  2160. os.path.join(self.path, 'tickets'), bare=True)
  2161. # Create issues to play with
  2162. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2163. msg = pagure.lib.new_issue(
  2164. session=self.session,
  2165. repo=repo,
  2166. title='Test issue',
  2167. content='We should work on this',
  2168. user='pingou',
  2169. ticketfolder=None
  2170. )
  2171. self.session.commit()
  2172. self.assertEqual(msg.title, 'Test issue')
  2173. url = '/issue/raw/8a06845923010b27bfd8'\
  2174. 'e7e75acff7badc40d1021b4994e01f5e11ca40bc3a'\
  2175. 'be-home_pierrey_repos_gitrepo_pagure_tests'\
  2176. '_placebo.png'
  2177. output = self.app.get('/foo' + url)
  2178. self.assertEqual(output.status_code, 404)
  2179. output = self.app.get('/test' + url)
  2180. self.assertEqual(output.status_code, 404)
  2181. # Project w/o issue tracker
  2182. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2183. repo.settings = {'issue_tracker': False}
  2184. self.session.add(repo)
  2185. self.session.commit()
  2186. output = self.app.get('/test' + url)
  2187. self.assertEqual(output.status_code, 404)
  2188. def test_view_issue_raw_file(self):
  2189. """ Test the view_issue_raw_file endpoint. """
  2190. # Create the issue and upload to it
  2191. self.test_upload_issue()
  2192. # Project w/ issue tracker
  2193. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2194. repo.settings = {'issue_tracker': True}
  2195. self.session.add(repo)
  2196. self.session.commit()
  2197. url = '/issue/raw/8a06845923010b27bfd8'\
  2198. 'e7e75acff7badc40d1021b4994e01f5e11ca40bc3a'\
  2199. 'be-%s_placebo.png' % os.path.dirname(
  2200. os.path.abspath(__file__))[1:].replace('/', '_')
  2201. output = self.app.get('/foo' + url)
  2202. self.assertEqual(output.status_code, 404)
  2203. output = self.app.get('/test/issue/raw/test.png')
  2204. self.assertEqual(output.status_code, 404)
  2205. # Access file by name
  2206. output = self.app.get('/test' + url)
  2207. self.assertEqual(output.status_code, 200)
  2208. # Project w/o issue tracker
  2209. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2210. repo.settings = {'issue_tracker': False}
  2211. self.session.add(repo)
  2212. self.session.commit()
  2213. output = self.app.get('/test' + url)
  2214. self.assertEqual(output.status_code, 404)
  2215. @patch('pagure.lib.git.update_git')
  2216. @patch('pagure.lib.notify.send_email')
  2217. def test_edit_issue(self, p_send_email, p_ugt):
  2218. """ Test the edit_issue endpoint. """
  2219. p_send_email.return_value = True
  2220. p_ugt.return_value = True
  2221. # No Git repo
  2222. output = self.app.get('/foo/issue/1/edit')
  2223. self.assertEqual(output.status_code, 404)
  2224. user = tests.FakeUser()
  2225. with tests.user_set(self.app.application, user):
  2226. output = self.app.get('/foo/issue/1/edit')
  2227. self.assertEqual(output.status_code, 404)
  2228. tests.create_projects(self.session)
  2229. tests.create_projects_git(
  2230. os.path.join(self.path, 'repos'), bare=True)
  2231. output = self.app.get('/test/issue/1/edit')
  2232. self.assertEqual(output.status_code, 404)
  2233. # User not logged in
  2234. output = self.app.get('/foo/issue/1/edit')
  2235. self.assertEqual(output.status_code, 404)
  2236. user.username = 'pingou'
  2237. with tests.user_set(self.app.application, user):
  2238. output = self.app.get('/test/issue/1/edit')
  2239. self.assertEqual(output.status_code, 404)
  2240. # Create issues to play with
  2241. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2242. msg = pagure.lib.new_issue(
  2243. session=self.session,
  2244. repo=repo,
  2245. title='Test issue',
  2246. content='We should work on this',
  2247. user='pingou',
  2248. ticketfolder=None
  2249. )
  2250. self.session.commit()
  2251. self.assertEqual(msg.title, 'Test issue')
  2252. user = tests.FakeUser()
  2253. with tests.user_set(self.app.application, user):
  2254. output = self.app.get('/test/issue/1/edit')
  2255. self.assertEqual(output.status_code, 403)
  2256. user.username = 'pingou'
  2257. with tests.user_set(self.app.application, user):
  2258. output = self.app.get('/test/issue/1/edit')
  2259. self.assertEqual(output.status_code, 200)
  2260. self.assertTrue(
  2261. '<div class="card-header">\n Edit '
  2262. 'issue #1\n </div>' in output.data)
  2263. csrf_token = self.get_csrf(output=output)
  2264. data = {
  2265. 'issue_content': 'We should work on this!'
  2266. }
  2267. output = self.app.post('/test/issue/1/edit', data=data)
  2268. self.assertEqual(output.status_code, 200)
  2269. self.assertTrue(
  2270. '<div class="card-header">\n Edit '
  2271. 'issue #1\n </div>' in output.data)
  2272. self.assertEqual(output.data.count(
  2273. '<small>\n This field is required.&nbsp;\n'
  2274. ' </small>'), 1)
  2275. self.assertEqual(output.data.count(
  2276. '<small>\n Not a valid choice&nbsp;'
  2277. '\n </small>'), 1)
  2278. data['status'] = 'Open'
  2279. data['title'] = 'Test issue #1'
  2280. output = self.app.post('/test/issue/1/edit', data=data)
  2281. self.assertEqual(output.status_code, 200)
  2282. self.assertTrue(
  2283. '<div class="card-header">\n Edit '
  2284. 'issue #1\n </div>' in output.data)
  2285. self.assertEqual(output.data.count(
  2286. '<small>\n This field is required.&nbsp;\n'
  2287. ' </small>'), 0)
  2288. self.assertEqual(output.data.count(
  2289. '<small>\n Not a valid choice&nbsp;'
  2290. '\n </small>'), 0)
  2291. data['csrf_token'] = csrf_token
  2292. output = self.app.post(
  2293. '/test/issue/1/edit', data=data, follow_redirects=True)
  2294. self.assertEqual(output.status_code, 200)
  2295. self.assertIn(
  2296. '<span class="issueid label label-default">#1</span>\n'
  2297. ' <span id="issuetitle">Test issue #1</span>',
  2298. output.data)
  2299. self.assertEqual(output.data.count(
  2300. '<option selected value="Open">Open</option>'), 1)
  2301. self.assertEqual(output.data.count('comment_body">'), 1)
  2302. self.assertEqual(output.data.count(
  2303. '<p>We should work on this!</p>'), 1)
  2304. # Project w/o issue tracker
  2305. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2306. repo.settings = {'issue_tracker': False}
  2307. self.session.add(repo)
  2308. self.session.commit()
  2309. user.username = 'pingou'
  2310. with tests.user_set(self.app.application, user):
  2311. output = self.app.post('/test/issue/1/edit', data=data)
  2312. self.assertEqual(output.status_code, 404)
  2313. @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
  2314. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2315. def test_edit_issue_no_change(self):
  2316. """ Test the edit_issue endpoint. """
  2317. tests.create_projects(self.session)
  2318. tests.create_projects_git(
  2319. os.path.join(self.path, 'repos'), bare=True)
  2320. # Create an issue to play with
  2321. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2322. msg = pagure.lib.new_issue(
  2323. session=self.session,
  2324. repo=repo,
  2325. title='Test issue',
  2326. content='We should work on this',
  2327. user='pingou',
  2328. ticketfolder=None
  2329. )
  2330. self.session.commit()
  2331. self.assertEqual(msg.title, 'Test issue')
  2332. user = tests.FakeUser(username = 'pingou')
  2333. with tests.user_set(self.app.application, user):
  2334. output = self.app.get('/test/issue/1/edit')
  2335. self.assertEqual(output.status_code, 200)
  2336. self.assertTrue(
  2337. '<div class="card-header">\n Edit '
  2338. 'issue #1\n </div>' in output.data)
  2339. csrf_token = self.get_csrf(output=output)
  2340. # Change nothing in the issue
  2341. data = {
  2342. 'issue_content': 'We should work on this',
  2343. 'status': 'Open',
  2344. 'title': 'Test issue',
  2345. 'csrf_token': csrf_token
  2346. }
  2347. output = self.app.post(
  2348. '/test/issue/1/edit', data=data, follow_redirects=True)
  2349. self.assertEqual(output.status_code, 200)
  2350. self.assertIn(
  2351. '<span class="issueid label label-default">#1</span>\n'
  2352. ' <span id="issuetitle">Test issue</span>',
  2353. output.data)
  2354. self.assertEqual(output.data.count(
  2355. '<option selected value="Open">Open</option>'), 1)
  2356. self.assertEqual(output.data.count('comment_body">'), 1)
  2357. self.assertEqual(output.data.count(
  2358. '<p>We should work on this</p>'), 1)
  2359. @patch('pagure.lib.git.update_git')
  2360. @patch('pagure.lib.notify.send_email')
  2361. def test_edit_tag(self, p_send_email, p_ugt):
  2362. """ Test the edit_tag endpoint. """
  2363. p_send_email.return_value = True
  2364. p_ugt.return_value = True
  2365. # No Git repo
  2366. output = self.app.get('/foo/tag/foo/edit')
  2367. self.assertEqual(output.status_code, 404)
  2368. user = tests.FakeUser()
  2369. with tests.user_set(self.app.application, user):
  2370. output = self.app.get('/foo/tag/foo/edit')
  2371. self.assertEqual(output.status_code, 404)
  2372. tests.create_projects(self.session)
  2373. tests.create_projects_git(os.path.join(self.path, 'repos'))
  2374. output = self.app.get('/test/tag/foo/edit')
  2375. self.assertEqual(output.status_code, 403)
  2376. # User not logged in
  2377. output = self.app.get('/test/tag/foo/edit')
  2378. self.assertEqual(output.status_code, 302)
  2379. # Create issues to play with
  2380. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2381. msg = pagure.lib.new_issue(
  2382. session=self.session,
  2383. repo=repo,
  2384. title='Test issue',
  2385. content='We should work on this',
  2386. user='pingou',
  2387. ticketfolder=None
  2388. )
  2389. self.session.commit()
  2390. self.assertEqual(msg.title, 'Test issue')
  2391. # Add a tag to the issue
  2392. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2393. msg = pagure.lib.add_tag_obj(
  2394. session=self.session,
  2395. obj=issue,
  2396. tags='tag1',
  2397. user='pingou',
  2398. gitfolder=None)
  2399. self.session.commit()
  2400. self.assertEqual(msg, 'Issue tagged with: tag1')
  2401. # Before edit, list tags
  2402. tags = pagure.lib.get_tags_of_project(self.session, repo)
  2403. self.assertEqual([tag.tag for tag in tags], ['tag1'])
  2404. # Edit tag
  2405. user.username = 'pingou'
  2406. with tests.user_set(self.app.application, user):
  2407. #Edit a tag that doesn't exit
  2408. output = self.app.get('/test/tag/does_not_exist/edit')
  2409. self.assertEqual(output.status_code, 404)
  2410. output = self.app.get('/test/tag/tag1/edit')
  2411. self.assertEqual(output.status_code, 200)
  2412. self.assertTrue('<strong>Edit tag: tag1</strong>' in output.data)
  2413. csrf_token = self.get_csrf(output=output)
  2414. data = {'tag': 'tag2',
  2415. 'tag_description': 'lorem ipsum',
  2416. 'tag_color': 'DeepSkyBlue'}
  2417. output = self.app.post('/test/tag/tag1/edit', data=data)
  2418. self.assertEqual(output.status_code, 200)
  2419. self.assertTrue('<strong>Edit tag: tag1</strong>' in output.data)
  2420. data['csrf_token'] = csrf_token
  2421. output = self.app.post(
  2422. '/test/tag/tag1/edit', data=data, follow_redirects=True)
  2423. self.assertEqual(output.status_code, 200)
  2424. self.assertIn(
  2425. 'Settings - test - Pagure', output.data)
  2426. self.assertIn(
  2427. '</button>\n '
  2428. 'Edited tag: tag1()[DeepSkyBlue] to tag2(lorem ipsum)[DeepSkyBlue]',
  2429. output.data)
  2430. # update tag with empty description
  2431. data['tag_description'] = ''
  2432. output = self.app.post(
  2433. '/test/tag/tag2/edit', data=data, follow_redirects=True)
  2434. self.assertEqual(output.status_code, 200)
  2435. self.assertIn(
  2436. 'Settings - test - Pagure', output.data)
  2437. self.assertIn(
  2438. '</button>\n '
  2439. 'Edited tag: tag2(lorem ipsum)[DeepSkyBlue] to tag2()[DeepSkyBlue]',
  2440. output.data)
  2441. # After edit, list tags
  2442. self.session.commit()
  2443. tags = pagure.lib.get_tags_of_project(self.session, repo)
  2444. self.assertEqual([tag.tag for tag in tags], ['tag2'])
  2445. @patch('pagure.lib.git.update_git')
  2446. @patch('pagure.lib.notify.send_email')
  2447. def test_remove_tag(self, p_send_email, p_ugt):
  2448. """ Test the remove_tag endpoint. """
  2449. p_send_email.return_value = True
  2450. p_ugt.return_value = True
  2451. # No Git repo
  2452. output = self.app.post('/foo/droptag/')
  2453. self.assertEqual(output.status_code, 404)
  2454. user = tests.FakeUser()
  2455. with tests.user_set(self.app.application, user):
  2456. output = self.app.post('/foo/droptag/')
  2457. self.assertEqual(output.status_code, 404)
  2458. tests.create_projects(self.session)
  2459. tests.create_projects_git(os.path.join(self.path, 'repos'))
  2460. output = self.app.post('/test/droptag/')
  2461. self.assertEqual(output.status_code, 403)
  2462. # User not logged in
  2463. output = self.app.post('/test/droptag/')
  2464. self.assertEqual(output.status_code, 302)
  2465. # Create issues to play with
  2466. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2467. msg = pagure.lib.new_issue(
  2468. session=self.session,
  2469. repo=repo,
  2470. title='Test issue',
  2471. content='We should work on this',
  2472. user='pingou',
  2473. ticketfolder=None
  2474. )
  2475. self.session.commit()
  2476. self.assertEqual(msg.title, 'Test issue')
  2477. # Add a tag to the issue
  2478. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2479. msg = pagure.lib.add_tag_obj(
  2480. session=self.session,
  2481. obj=issue,
  2482. tags='tag1',
  2483. user='pingou',
  2484. gitfolder=None)
  2485. self.session.commit()
  2486. self.assertEqual(msg, 'Issue tagged with: tag1')
  2487. # Before edit, list tags
  2488. tags = pagure.lib.get_tags_of_project(self.session, repo)
  2489. self.assertEqual([tag.tag for tag in tags], ['tag1'])
  2490. # Edit tag
  2491. user.username = 'pingou'
  2492. with tests.user_set(self.app.application, user):
  2493. output = self.app.post(
  2494. '/test/droptag/', data={}, follow_redirects=True)
  2495. self.assertEqual(output.status_code, 200)
  2496. self.assertTrue(
  2497. '<title>Settings - test - Pagure</title>' in output.data)
  2498. self.assertTrue("<h3>Settings for test</h3>" in output.data)
  2499. csrf_token = self.get_csrf(output=output)
  2500. data = {'tag': 'tag1'}
  2501. output = self.app.post(
  2502. '/test/droptag/', data=data, follow_redirects=True)
  2503. self.assertEqual(output.status_code, 200)
  2504. self.assertTrue("<h3>Settings for test</h3>" in output.data)
  2505. data['csrf_token'] = csrf_token
  2506. output = self.app.post(
  2507. '/test/droptag/', data=data, follow_redirects=True)
  2508. self.assertEqual(output.status_code, 200)
  2509. self.assertTrue("<h3>Settings for test</h3>" in output.data)
  2510. self.assertIn(
  2511. '</button>\n '
  2512. 'Tag: tag1 has been deleted', output.data)
  2513. @patch('pagure.lib.git.update_git')
  2514. @patch('pagure.lib.notify.send_email')
  2515. def test_delete_issue(self, p_send_email, p_ugt):
  2516. """ Test the delete_issue endpoint. """
  2517. p_send_email.return_value = True
  2518. p_ugt.return_value = True
  2519. tests.create_projects(self.session)
  2520. tests.create_projects_git(os.path.join(self.path, 'repos'))
  2521. tests.create_projects_git(os.path.join(self.path, 'tickets'))
  2522. # Create issues to play with
  2523. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2524. msg = pagure.lib.new_issue(
  2525. session=self.session,
  2526. repo=repo,
  2527. title='Test issue',
  2528. content='We should work on this',
  2529. user='pingou',
  2530. ticketfolder=None
  2531. )
  2532. self.session.commit()
  2533. self.assertEqual(msg.title, 'Test issue')
  2534. user = tests.FakeUser()
  2535. with tests.user_set(self.app.application, user):
  2536. output = self.app.post(
  2537. '/foo/issue/1/drop', follow_redirects=True)
  2538. self.assertEqual(output.status_code, 404)
  2539. output = self.app.post(
  2540. '/test/issue/100/drop', follow_redirects=True)
  2541. self.assertEqual(output.status_code, 404)
  2542. output = self.app.post(
  2543. '/test/issue/1/drop', follow_redirects=True)
  2544. self.assertEqual(output.status_code, 403)
  2545. user.username = 'pingou'
  2546. with tests.user_set(self.app.application, user):
  2547. output = self.app.post(
  2548. '/test/issue/1/drop', follow_redirects=True)
  2549. self.assertEqual(output.status_code, 200)
  2550. self.assertIn(
  2551. '<title>Issue #1: Test issue - test - Pagure</title>',
  2552. output.data)
  2553. csrf_token = self.get_csrf(output=output)
  2554. data = {
  2555. }
  2556. # No CSRF token
  2557. output = self.app.post(
  2558. '/test/issue/1/drop', data=data, follow_redirects=True)
  2559. self.assertEqual(output.status_code, 200)
  2560. self.assertIn(
  2561. '<title>Issue #1: Test issue - test - Pagure</title>',
  2562. output.data)
  2563. data['csrf_token'] = csrf_token
  2564. output = self.app.post(
  2565. '/test/issue/1/drop', data=data, follow_redirects=True)
  2566. self.assertEqual(output.status_code, 200)
  2567. self.assertIn(
  2568. '<title>Issues - test - Pagure</title>', output.data)
  2569. self.assertIn(
  2570. '</button>\n Issue deleted',
  2571. output.data)
  2572. # Project w/o issue tracker
  2573. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2574. repo.settings = {'issue_tracker': False}
  2575. self.session.add(repo)
  2576. self.session.commit()
  2577. user.username = 'pingou'
  2578. with tests.user_set(self.app.application, user):
  2579. output = self.app.post('/test/issue/1/drop', data=data)
  2580. self.assertEqual(output.status_code, 404)
  2581. @patch('pagure.lib.git.update_git')
  2582. @patch('pagure.lib.notify.send_email')
  2583. def test_update_issue_edit_comment(self, p_send_email, p_ugt):
  2584. """ Test the issues edit comment endpoint """
  2585. p_send_email.return_value = True
  2586. p_ugt.return_value = True
  2587. tests.create_projects(self.session)
  2588. tests.create_projects_git(
  2589. os.path.join(self.path, 'repos'), bare=True)
  2590. # Create issues to play with
  2591. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2592. msg = pagure.lib.new_issue(
  2593. session=self.session,
  2594. repo=repo,
  2595. title='Test issue',
  2596. content='We should work on this',
  2597. user='pingou',
  2598. ticketfolder=None
  2599. )
  2600. self.session.commit()
  2601. self.assertEqual(msg.title, 'Test issue')
  2602. user = tests.FakeUser()
  2603. user.username = 'pingou'
  2604. with tests.user_set(self.app.application, user):
  2605. output = self.app.get('/test/issue/1')
  2606. self.assertEqual(output.status_code, 200)
  2607. self.assertIn(
  2608. '<title>Issue #1: Test issue - test - Pagure</title>',
  2609. output.data)
  2610. self.assertIn(
  2611. '<a class="btn btn-primary btn-sm" '
  2612. 'href="/test/issue/1/edit" title="Edit this issue">',
  2613. output.data)
  2614. csrf_token = self.get_csrf(output=output)
  2615. # Add new comment
  2616. data = {
  2617. 'csrf_token': csrf_token,
  2618. 'comment': 'Woohoo a second comment!',
  2619. }
  2620. output = self.app.post(
  2621. '/test/issue/1/update', data=data, follow_redirects=True)
  2622. self.assertEqual(output.status_code, 200)
  2623. self.assertIn(
  2624. '<title>Issue #1: Test issue - test - Pagure</title>',
  2625. output.data)
  2626. self.assertIn(
  2627. '<a class="btn btn-primary btn-sm" '
  2628. 'href="/test/issue/1/edit" title="Edit this issue">',
  2629. output.data)
  2630. self.assertIn(
  2631. '</button>\n Comment added',
  2632. output.data)
  2633. self.assertTrue(
  2634. '<p>Woohoo a second comment!</p>' in output.data)
  2635. self.assertEqual(output.data.count('comment_body">'), 2)
  2636. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2637. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2638. self.assertEqual(len(issue.comments), 1)
  2639. self.assertEqual(
  2640. issue.comments[0].comment,
  2641. 'Woohoo a second comment!')
  2642. data = {
  2643. 'csrf_token': csrf_token,
  2644. 'edit_comment': 1,
  2645. 'update_comment': 'Updated comment',
  2646. }
  2647. user = tests.FakeUser()
  2648. with tests.user_set(self.app.application, user):
  2649. # Wrong issue id
  2650. output = self.app.post(
  2651. '/test/issue/3/update', data=data, follow_redirects=True)
  2652. self.assertEqual(output.status_code, 404)
  2653. # Wrong user
  2654. output = self.app.post(
  2655. '/test/issue/1/update', data=data, follow_redirects=True)
  2656. self.assertEqual(output.status_code, 403)
  2657. user = tests.FakeUser()
  2658. user.username = 'pingou'
  2659. with tests.user_set(self.app.application, user):
  2660. # Edit comment
  2661. output = self.app.post(
  2662. '/test/issue/1/update', data=data, follow_redirects=True)
  2663. self.assertEqual(output.status_code, 200)
  2664. self.assertIn(
  2665. '<title>Issue #1: Test issue - test - Pagure</title>',
  2666. output.data)
  2667. self.assertIn(
  2668. '<a class="btn btn-primary btn-sm" '
  2669. 'href="/test/issue/1/edit" title="Edit this issue">',
  2670. output.data)
  2671. self.assertIn(
  2672. '</button>\n Comment updated',
  2673. output.data)
  2674. self.session.commit()
  2675. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2676. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2677. self.assertEqual(len(issue.comments), 1)
  2678. self.assertEqual(issue.comments[0].comment, 'Updated comment')
  2679. with tests.user_set(self.app.application, user):
  2680. output = self.app.get('/test/issue/1/comment/1/edit')
  2681. self.assertIn(
  2682. '<title>test - Pagure</title>', output.data)
  2683. self.assertTrue('<div id="edit">' in output.data)
  2684. self.assertTrue('<section class="edit_comment">' in output.data)
  2685. self.assertTrue(
  2686. '<textarea class="form-control" id="update_comment"'
  2687. in output.data)
  2688. csrf_token = self.get_csrf(output=output)
  2689. data['csrf_token'] = csrf_token
  2690. data['update_comment'] = 'Second update'
  2691. # Edit the comment with the other endpoint
  2692. output = self.app.post(
  2693. '/test/issue/1/comment/1/edit',
  2694. data=data,
  2695. follow_redirects=True)
  2696. self.assertEqual(output.status_code, 200)
  2697. self.assertIn(
  2698. '<title>Issue #1: Test issue - test - Pagure</title>',
  2699. output.data)
  2700. self.assertIn(
  2701. '<a class="btn btn-primary btn-sm" '
  2702. 'href="/test/issue/1/edit" title="Edit this issue">',
  2703. output.data)
  2704. self.assertIn(
  2705. '</button>\n Comment updated',
  2706. output.data)
  2707. self.session.commit()
  2708. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2709. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2710. self.assertEqual(len(issue.comments), 1)
  2711. self.assertEqual(issue.comments[0].comment, 'Second update')
  2712. # Create another issue from someone else
  2713. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2714. msg = pagure.lib.new_issue(
  2715. session=self.session,
  2716. repo=repo,
  2717. title='Test issue',
  2718. content='We should work on this',
  2719. user='foo',
  2720. ticketfolder=None
  2721. )
  2722. self.session.commit()
  2723. self.assertEqual(msg.title, 'Test issue')
  2724. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2725. self.assertEqual(len(issue.comments), 1)
  2726. self.assertEqual(issue.status, 'Open')
  2727. issue = pagure.lib.search_issues(self.session, repo, issueid=2)
  2728. self.assertEqual(len(issue.comments), 0)
  2729. self.assertEqual(issue.status, 'Open')
  2730. user = tests.FakeUser(username='foo')
  2731. with tests.user_set(self.app.application, user):
  2732. data = {
  2733. 'csrf_token': csrf_token,
  2734. 'comment': 'Nevermind figured it out',
  2735. 'status': 'Closed',
  2736. 'close_status': 'Invalid'
  2737. }
  2738. # Add a comment and close the ticket #1
  2739. output = self.app.post(
  2740. '/test/issue/1/update', data=data, follow_redirects=True)
  2741. self.assertEqual(output.status_code, 200)
  2742. self.assertNotIn(
  2743. '</button>\n '
  2744. 'Successfully edited issue #1\n',
  2745. output.data
  2746. )
  2747. self.assertIn(
  2748. '</button>\n Comment added\n',
  2749. output.data
  2750. )
  2751. self.assertNotIn(
  2752. 'editmetadatatoggle">\n Edit Metadata',
  2753. output.data
  2754. )
  2755. data = {
  2756. 'csrf_token': csrf_token,
  2757. 'comment': 'Nevermind figured it out',
  2758. 'status': 'Closed',
  2759. 'close_status': 'Invalid'
  2760. }
  2761. # Add a comment and close the ticket #2
  2762. output = self.app.post(
  2763. '/test/issue/2/update', data=data, follow_redirects=True)
  2764. self.assertEqual(output.status_code, 200)
  2765. self.assertIn(
  2766. '</button>\n '
  2767. 'Issue close_status updated to: Invalid\n',
  2768. output.data
  2769. )
  2770. self.assertIn(
  2771. '</button>\n Comment added\n',
  2772. output.data
  2773. )
  2774. self.assertIn(
  2775. '</button>\n '
  2776. 'Issue status updated to: Closed (was: Open)\n',
  2777. output.data
  2778. )
  2779. self.assertIn(
  2780. 'editmetadatatoggle">\n Edit Metadata',
  2781. output.data
  2782. )
  2783. # Ticket #1 has one more comment and is still open
  2784. self.session.commit()
  2785. issue = pagure.lib.search_issues(self.session, repo, issueid=1)
  2786. self.assertEqual(len(issue.comments), 2)
  2787. self.assertEqual(issue.status, 'Open')
  2788. # Ticket #2 has one less comment and is closed
  2789. issue = pagure.lib.search_issues(self.session, repo, issueid=2)
  2790. self.assertEqual(len(issue.comments), 2)
  2791. self.assertEqual(
  2792. issue.comments[0].comment,
  2793. 'Nevermind figured it out')
  2794. self.assertEqual(
  2795. issue.comments[1].comment,
  2796. '**Metadata Update from @foo**:\n'
  2797. '- Issue close_status updated to: Invalid\n'
  2798. '- Issue status updated to: Closed (was: Open)')
  2799. self.assertEqual(issue.status, 'Closed')
  2800. @patch('pagure.lib.git.update_git')
  2801. @patch('pagure.lib.notify.send_email')
  2802. def test_git_urls(self, p_send_email, p_ugt):
  2803. """ Check that the url to the git repo for issues is present/absent when
  2804. it should.
  2805. """
  2806. p_send_email.return_value = True
  2807. p_ugt.return_value = True
  2808. self.test_view_issues()
  2809. user = tests.FakeUser()
  2810. user.username = 'pingou'
  2811. with tests.user_set(self.app.application, user):
  2812. # Check that the git issue URL is present
  2813. output = self.app.get('/test')
  2814. self.assertNotIn(
  2815. '<h5><strong>Issues GIT URLs</strong></h5>', output.data)
  2816. # Project w/o issue tracker
  2817. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2818. repo.settings = {'issue_tracker': True}
  2819. self.session.add(repo)
  2820. self.session.commit()
  2821. # Check that the git issue URL is gone
  2822. output = self.app.get('/test')
  2823. self.assertIn(
  2824. '<h5><strong>Issues GIT URLs</strong></h5>', output.data)
  2825. @patch('pagure.lib.git.update_git')
  2826. @patch('pagure.lib.notify.send_email')
  2827. def test_update_tags(self, p_send_email, p_ugt):
  2828. """ Test the update_tags endpoint. """
  2829. p_send_email.return_value = True
  2830. p_ugt.return_value = True
  2831. # No Git repo
  2832. output = self.app.post('/foo/update/tags')
  2833. self.assertEqual(output.status_code, 404)
  2834. user = tests.FakeUser()
  2835. with tests.user_set(self.app.application, user):
  2836. output = self.app.post('/foo/update/tags')
  2837. self.assertEqual(output.status_code, 404)
  2838. tests.create_projects(self.session)
  2839. tests.create_projects_git(os.path.join(self.path, 'repos'))
  2840. output = self.app.post('/test/update/tags')
  2841. self.assertEqual(output.status_code, 403)
  2842. # User not logged in
  2843. output = self.app.post('/test/update/tags')
  2844. self.assertEqual(output.status_code, 302)
  2845. # Create issues to play with
  2846. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2847. msg = pagure.lib.new_issue(
  2848. session=self.session,
  2849. repo=repo,
  2850. title='Test issue',
  2851. content='We should work on this',
  2852. user='pingou',
  2853. ticketfolder=None
  2854. )
  2855. self.session.commit()
  2856. self.assertEqual(msg.title, 'Test issue')
  2857. # Before update, list tags
  2858. tags = pagure.lib.get_tags_of_project(self.session, repo)
  2859. self.assertEqual([tag.tag for tag in tags], [])
  2860. user.username = 'pingou'
  2861. with tests.user_set(self.app.application, user):
  2862. # No CSRF
  2863. data = {
  2864. 'tag': 'red',
  2865. 'tag_description': 'lorem ipsum',
  2866. 'tag_color': '#ff0000'
  2867. }
  2868. output = self.app.post(
  2869. '/test/update/tags', data=data, follow_redirects=True)
  2870. self.assertEqual(output.status_code, 200)
  2871. self.assertIn(
  2872. '<title>Settings - test - Pagure</title>', output.data)
  2873. self.assertIn(
  2874. ' <ul class="list-group list-group-flush">'
  2875. '\n </ul>', output.data)
  2876. csrf_token = self.get_csrf(output=output)
  2877. # Invalid color
  2878. data = {
  2879. 'tag': 'red',
  2880. 'tag_description': 'lorem ipsum',
  2881. 'tag_color': 'red',
  2882. 'csrf_token': csrf_token,
  2883. }
  2884. output = self.app.post(
  2885. '/test/update/tags', data=data, follow_redirects=True)
  2886. self.assertEqual(output.status_code, 200)
  2887. self.assertIn(
  2888. '<title>Settings - test - Pagure</title>', output.data)
  2889. self.assertIn(
  2890. '</button>\n '
  2891. 'Color: red does not match the expected pattern',
  2892. output.data)
  2893. self.assertIn(
  2894. ' <ul class="list-group list-group-flush">'
  2895. '\n </ul>', output.data)
  2896. # Invalid tag name
  2897. data = {
  2898. 'tag': 'red/green',
  2899. 'tag_description': 'lorem ipsum',
  2900. 'tag_color': '#fff',
  2901. 'csrf_token': csrf_token,
  2902. }
  2903. output = self.app.post(
  2904. '/test/update/tags', data=data, follow_redirects=True)
  2905. self.assertEqual(output.status_code, 200)
  2906. self.assertIn(
  2907. '<title>Settings - test - Pagure</title>', output.data)
  2908. self.assertIn(
  2909. '</button>\n '
  2910. 'Tag: red/green contains an invalid character: &#34;/&#34;',
  2911. output.data)
  2912. self.assertIn(
  2913. ' <ul class="list-group list-group-flush">'
  2914. '\n </ul>', output.data)
  2915. # Inconsistent length tags (missing tag field)
  2916. data = {
  2917. 'tag': 'red',
  2918. 'tag_description': ['lorem ipsum', 'foo bar'],
  2919. 'tag_color': ['#ff0000', '#003cff'],
  2920. 'csrf_token': csrf_token,
  2921. }
  2922. output = self.app.post(
  2923. '/test/update/tags', data=data, follow_redirects=True)
  2924. self.assertEqual(output.status_code, 200)
  2925. self.assertIn(
  2926. '<title>Settings - test - Pagure</title>', output.data)
  2927. self.assertIn(
  2928. '</button>\n Error: Incomplete request. '
  2929. 'One or more tag fields missing.', output.data)
  2930. self.assertIn(
  2931. ' <ul class="list-group list-group-flush">'
  2932. '\n </ul>', output.data)
  2933. # Inconsistent length color
  2934. data = {
  2935. 'tag': ['red', 'blue'],
  2936. 'tag_description': ['lorem ipsum', 'foo bar'],
  2937. 'tag_color': 'red',
  2938. 'csrf_token': csrf_token,
  2939. }
  2940. output = self.app.post(
  2941. '/test/update/tags', data=data, follow_redirects=True)
  2942. self.assertEqual(output.status_code, 200)
  2943. self.assertIn(
  2944. '<title>Settings - test - Pagure</title>', output.data)
  2945. self.assertIn(
  2946. '</button>\n '
  2947. 'Color: red does not match the expected pattern',
  2948. output.data)
  2949. self.assertIn(
  2950. '</button>\n Error: Incomplete request. '
  2951. 'One or more tag color fields missing.', output.data)
  2952. self.assertIn(
  2953. ' <ul class="list-group list-group-flush">'
  2954. '\n </ul>', output.data)
  2955. # Inconsistent length description
  2956. data = {
  2957. 'tag': ['red', 'blue'],
  2958. 'tag_description': 'lorem ipsum',
  2959. 'tag_color': ['#ff0000', '#003cff'],
  2960. 'csrf_token': csrf_token,
  2961. }
  2962. output = self.app.post(
  2963. '/test/update/tags', data=data, follow_redirects=True)
  2964. self.assertEqual(output.status_code, 200)
  2965. self.assertIn(
  2966. '<title>Settings - test - Pagure</title>', output.data)
  2967. self.assertIn(
  2968. '</button>\n Error: Incomplete request. '
  2969. 'One or more tag description fields missing.', output.data)
  2970. self.assertIn(
  2971. ' <ul class="list-group list-group-flush">'
  2972. '\n </ul>', output.data)
  2973. # consistent length, but empty description
  2974. data = {
  2975. 'tag': ['red', 'blue'],
  2976. 'tag_description': ['lorem ipsum', ''],
  2977. 'tag_color': ['#ff0000', '#003cff'],
  2978. 'csrf_token': csrf_token,
  2979. }
  2980. output = self.app.post(
  2981. '/test/update/tags', data=data, follow_redirects=True)
  2982. self.assertEqual(output.status_code, 200)
  2983. self.assertIn(
  2984. '<title>Settings - test - Pagure</title>', output.data)
  2985. self.assertIn(
  2986. '<span class="label label-info" style="background-color:'
  2987. '#003cff">blue</span>\n'
  2988. ' &nbsp;<span class="text-muted"></span>',
  2989. output.data)
  2990. self.assertIn(
  2991. '<input type="hidden" value="blue" name="tag" />',
  2992. output.data)
  2993. self.assertIn(
  2994. '<span class="label label-info" style="background-color:'
  2995. '#ff0000">red</span>\n'
  2996. ' &nbsp;<span class="text-muted">lorem ipsum'
  2997. '</span>', output.data)
  2998. self.assertIn(
  2999. '<input type="hidden" value="red" name="tag" />',
  3000. output.data)
  3001. # Valid query
  3002. data = {
  3003. 'tag': ['red1', 'green'],
  3004. 'tag_description': ['lorem ipsum', 'sample description'],
  3005. 'tag_color': ['#ff0000', '#00ff00'],
  3006. 'csrf_token': csrf_token,
  3007. }
  3008. output = self.app.post(
  3009. '/test/update/tags', data=data, follow_redirects=True)
  3010. self.assertEqual(output.status_code, 200)
  3011. self.assertIn(
  3012. '<title>Settings - test - Pagure</title>', output.data)
  3013. self.assertIn(
  3014. '<span class="label label-info" style="background-color:'
  3015. '#00ff00">green</span>\n'
  3016. ' &nbsp;<span class="text-muted">sample description'
  3017. '</span>', output.data)
  3018. self.assertIn(
  3019. '<input type="hidden" value="green" name="tag" />',
  3020. output.data)
  3021. self.assertIn(
  3022. '<span class="label label-info" style="background-color:'
  3023. '#ff0000">red</span>\n'
  3024. ' &nbsp;<span class="text-muted">lorem ipsum'
  3025. '</span>', output.data)
  3026. # '<span class="badge badge-info" '
  3027. # 'style="background-color:#ff0000">red1</span>\n'
  3028. # ' &nbsp;'
  3029. # '<span class="text-muted">lorem ipsum</span>', output.data)
  3030. self.assertIn(
  3031. '<input type="hidden" value="red" name="tag" />',
  3032. output.data)
  3033. # Valid query - Two tags of the same color
  3034. data = {
  3035. 'tag': ['red2', 'red3'],
  3036. 'tag_color': ['#ff0000', '#ff0000'],
  3037. 'tag_description': ['', ''],
  3038. 'csrf_token': csrf_token,
  3039. }
  3040. output = self.app.post(
  3041. '/test/update/tags', data=data, follow_redirects=True)
  3042. self.assertEqual(output.status_code, 200)
  3043. self.assertIn(
  3044. '<title>Settings - test - Pagure</title>', output.data)
  3045. self.assertIn(
  3046. '<span class="label label-info" style="background-color:'
  3047. '#ff0000">red2</span>\n'
  3048. ' &nbsp;<span class="text-muted"></span>',
  3049. output.data)
  3050. self.assertIn(
  3051. '<input type="hidden" value="green" name="tag" />',
  3052. output.data)
  3053. self.assertIn(
  3054. '<span class="label label-info" style="background-color:'
  3055. '#ff0000">red3</span>\n'
  3056. ' &nbsp;<span class="text-muted"></span>',
  3057. output.data)
  3058. self.assertIn(
  3059. '<input type="hidden" value="red" name="tag" />',
  3060. output.data)
  3061. # Invalid query - Tag already known
  3062. data = {
  3063. 'tag': ['red2'],
  3064. 'tag_color': ['#000'],
  3065. 'tag_description': [''],
  3066. 'csrf_token': csrf_token,
  3067. }
  3068. output = self.app.post(
  3069. '/test/update/tags', data=data, follow_redirects=True)
  3070. self.assertEqual(output.status_code, 200)
  3071. output_text = output.get_data(as_text=True)
  3072. self.assertIn(
  3073. '<title>Settings - test - Pagure</title>', output_text)
  3074. self.assertIn(
  3075. '<span class="label label-info" style="background-color:'
  3076. '#ff0000">red2</span>\n'
  3077. ' &nbsp;<span class="text-muted"></span>',
  3078. output.data)
  3079. # '<span class="badge badge-info" '
  3080. # 'style="background-color:#ff0000">red2</span>\n'
  3081. # ' &nbsp;'
  3082. # '<span class="text-muted"></span>', output_text)
  3083. self.assertIn(
  3084. '<input type="hidden" value="green" name="tag" />',
  3085. output_text)
  3086. self.assertIn(
  3087. '<span class="label label-info" style="background-color:'
  3088. '#ff0000">red3</span>\n'
  3089. ' &nbsp;<span class="text-muted"></span>',
  3090. output.data)
  3091. # '<span class="badge badge-info" '
  3092. # 'style="background-color:#ff0000">red3</span>\n'
  3093. # ' &nbsp;'
  3094. # '<span class="text-muted"></span>', output_text)
  3095. self.assertIn(
  3096. '<input type="hidden" value="red" name="tag" />',
  3097. output_text)
  3098. self.assertIn(
  3099. '</button>\n Duplicated tag: red2',
  3100. output_text)
  3101. # After update, list tags
  3102. tags = pagure.lib.get_tags_of_project(self.session, repo)
  3103. self.assertEqual(
  3104. sorted([tag.tag for tag in tags]),
  3105. ['blue', 'green', 'red', 'red1', 'red2', 'red3'])
  3106. @patch('pagure.lib.git.update_git')
  3107. @patch('pagure.lib.notify.send_email')
  3108. def test_view_issue_namespace_comment(self, p_send_email, p_ugt):
  3109. """ Test comment on the view_issue endpoint on namespaced project.
  3110. """
  3111. # Create the project ns/test
  3112. item = pagure.lib.model.Project(
  3113. user_id=1, # pingou
  3114. name='test3',
  3115. namespace='ns',
  3116. description='test project #3',
  3117. hook_token='aaabbbcccdd',
  3118. )
  3119. self.session.add(item)
  3120. self.session.commit()
  3121. self.assertEqual(item.fullname, 'ns/test3')
  3122. pygit2.init_repository(
  3123. os.path.join(self.path, 'repos', 'ns', 'test3.git'),
  3124. bare=True)
  3125. # Create 2 issues
  3126. iss = pagure.lib.new_issue(
  3127. issue_id=1,
  3128. session=self.session,
  3129. repo=item,
  3130. title=u'test issue',
  3131. content='content test issue',
  3132. user='pingou',
  3133. ticketfolder=None,
  3134. )
  3135. self.session.commit()
  3136. self.assertEqual(iss.id, 1)
  3137. self.assertEqual(iss.title, u'test issue')
  3138. self.assertEqual(iss.project.fullname, 'ns/test3')
  3139. iss = pagure.lib.new_issue(
  3140. issue_id=2,
  3141. session=self.session,
  3142. repo=item,
  3143. title='test issue2',
  3144. content='content test issue2',
  3145. user='pingou',
  3146. ticketfolder=None,
  3147. )
  3148. self.session.commit()
  3149. self.assertEqual(iss.id, 2)
  3150. self.assertEqual(iss.title, 'test issue2')
  3151. self.assertEqual(iss.project.fullname, 'ns/test3')
  3152. # Add a comment on the second issue pointing to the first one
  3153. issue_comment = pagure.lib.model.IssueComment(
  3154. issue_uid=iss.uid,
  3155. comment='foo bar #1 see?',
  3156. user_id=1, # pingou
  3157. notification=False,
  3158. )
  3159. self.session.add(issue_comment)
  3160. self.session.commit()
  3161. output = self.app.get('/ns/test3/issue/2')
  3162. self.assertEqual(output.status_code, 200)
  3163. self.assertIn(
  3164. '<span class="comment_text comment_body">'
  3165. '<p>foo bar <a href="/ns/test3/issue/1" '
  3166. 'title="[Open] test issue">#1</a> see?</p></span>', output.data)
  3167. @patch('pagure.lib.git.update_git')
  3168. @patch('pagure.lib.notify.send_email')
  3169. def test_view_issue_forked_namespace_comment(self, p_send_email, p_ugt):
  3170. """ Test comment on the view_issue endpoint on namespaced project.
  3171. """
  3172. # Create the project ns/test
  3173. item = pagure.lib.model.Project(
  3174. user_id=1, # pingou
  3175. name='test3',
  3176. namespace='ns',
  3177. description='test project #3',
  3178. hook_token='aaabbbcccdd',
  3179. )
  3180. self.session.add(item)
  3181. self.session.commit()
  3182. self.assertEqual(item.fullname, 'ns/test3')
  3183. # Fork the project ns/test
  3184. item = pagure.lib.model.Project(
  3185. user_id=1, # pingou
  3186. parent_id=1, # ns/test
  3187. is_fork=True,
  3188. name='test3',
  3189. namespace='ns',
  3190. description='test project #3',
  3191. hook_token='aaabbbcccddff',
  3192. )
  3193. self.session.add(item)
  3194. self.session.commit()
  3195. self.assertEqual(item.fullname, 'forks/pingou/ns/test3')
  3196. pygit2.init_repository(
  3197. os.path.join(
  3198. self.path, 'repos', 'forks', 'pingou', 'ns', 'test3.git'),
  3199. bare=True)
  3200. # Create 2 issues
  3201. iss = pagure.lib.new_issue(
  3202. issue_id=1,
  3203. session=self.session,
  3204. repo=item,
  3205. title=u'test issue',
  3206. content='content test issue',
  3207. user='pingou',
  3208. ticketfolder=None,
  3209. )
  3210. self.session.commit()
  3211. self.assertEqual(iss.id, 1)
  3212. self.assertEqual(iss.title, 'test issue')
  3213. self.assertEqual(iss.project.fullname, 'forks/pingou/ns/test3')
  3214. iss = pagure.lib.new_issue(
  3215. issue_id=2,
  3216. session=self.session,
  3217. repo=item,
  3218. title='test issue2',
  3219. content='content test issue2',
  3220. user='pingou',
  3221. ticketfolder=None,
  3222. )
  3223. self.session.commit()
  3224. self.assertEqual(iss.id, 2)
  3225. self.assertEqual(iss.title, 'test issue2')
  3226. self.assertEqual(iss.project.fullname, 'forks/pingou/ns/test3')
  3227. # Add a comment on the second issue pointing to the first one
  3228. issue_comment = pagure.lib.model.IssueComment(
  3229. issue_uid=iss.uid,
  3230. comment='foo bar #1 see?',
  3231. user_id=1, # pingou
  3232. notification=False,
  3233. )
  3234. self.session.add(issue_comment)
  3235. self.session.commit()
  3236. output = self.app.get('/fork/pingou/ns/test3/issue/2')
  3237. self.assertEqual(output.status_code, 200)
  3238. self.assertIn(
  3239. '<span class="comment_text comment_body">'
  3240. '<p>foo bar <a href="/fork/pingou/ns/test3/issue/1" '
  3241. 'title="[Open] test issue">#1</a> see?</p></span>', output.data)
  3242. @patch('pagure.lib.git.update_git')
  3243. @patch('pagure.lib.notify.send_email')
  3244. def test_view_issue_closed(self, p_send_email, p_ugt):
  3245. """ Test viewing a closed issue. """
  3246. p_send_email.return_value = True
  3247. p_ugt.return_value = True
  3248. tests.create_projects(self.session)
  3249. tests.create_projects_git(
  3250. os.path.join(self.path, 'repos'), bare=True)
  3251. # Create issues to play with
  3252. repo = pagure.lib.get_authorized_project(self.session, 'test')
  3253. msg = pagure.lib.new_issue(
  3254. session=self.session,
  3255. repo=repo,
  3256. title='Test issue',
  3257. content='We should work on this',
  3258. user='pingou',
  3259. ticketfolder=None
  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. self.assertIn(
  3269. '<title>Issue #1: Test issue - test - Pagure</title>',
  3270. output.data)
  3271. self.assertIn(
  3272. '<a class="btn btn-primary btn-sm" '
  3273. 'href="/test/issue/1/edit" title="Edit this issue">',
  3274. output.data)
  3275. csrf_token = self.get_csrf(output=output)
  3276. # Add new comment
  3277. data = {
  3278. 'csrf_token': csrf_token,
  3279. 'status': 'Closed',
  3280. 'close_status': 'Fixed',
  3281. 'comment': 'Woohoo a second comment!',
  3282. }
  3283. output = self.app.post(
  3284. '/test/issue/1/update', data=data, follow_redirects=True)
  3285. self.assertEqual(output.status_code, 200)
  3286. self.assertIn(
  3287. '<title>Issue #1: Test issue - test - Pagure</title>',
  3288. output.data)
  3289. self.assertIn(
  3290. '<a class="btn btn-primary btn-sm" '
  3291. 'href="/test/issue/1/edit" title="Edit this issue">',
  3292. output.data)
  3293. self.assertIn(
  3294. '</button>\n Comment added',
  3295. output.data)
  3296. self.assertTrue(
  3297. '<p>Woohoo a second comment!</p>' in output.data)
  3298. self.assertEqual(output.data.count('comment_body">'), 2)
  3299. self.assertTrue(
  3300. '<option selected value="Fixed">Fixed</option>'
  3301. in output.data)
  3302. self.assertEqual(
  3303. output.data.count(
  3304. 'title="Reply to this comment - lose formatting">',
  3305. ), 1)
  3306. if __name__ == '__main__':
  3307. unittest.main(verbosity=2)