test_pagure_flask_ui_issues.py 156 KB

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