Ticket #1749: ticketdelete-trac0.11-v3.patch
| File ticketdelete-trac0.11-v3.patch, 12.6 kB (added by hkaimio, 1 year ago) |
|---|
-
ticketdelete/web_ui.py
old new 5 5 from trac.core import * 6 6 from trac.web.api import IRequestFilter 7 7 from trac.web.chrome import ITemplateProvider, add_script, add_stylesheet 8 from webadmin.web_ui import IAdminPageProvider8 from trac.admin.api import IAdminPanelProvider 9 9 import re, traceback, pprint 10 10 from time import strftime, localtime 11 from trac.ticket.model import Ticket 11 12 12 13 __all__ = ['TicketDeletePlugin'] 13 14 14 15 class TicketDeletePlugin(Component): 15 16 """A small ticket deletion plugin.""" 16 17 17 implements(ITemplateProvider, IAdminPa geProvider, IRequestFilter)18 implements(ITemplateProvider, IAdminPanelProvider, IRequestFilter) 18 19 19 20 # IRequestFilter methods 20 21 def pre_process_request(self, req, handler): … … 27 28 add_stylesheet(req, 'ticketdelete/ticketdelete.css') 28 29 return template, content_type 29 30 30 # IAdminPa geProvider methods31 def get_admin_pa ges(self, req):31 # IAdminPanelProvider methods 32 def get_admin_panels(self, req): 32 33 if req.perm.has_permission('TICKET_ADMIN'): 33 34 yield ('ticket', 'Ticket System', 'delete', 'Delete') 34 35 yield ('ticket', 'Ticket System', 'comments', 'Delete Changes') 35 36 36 def process_admin_request(self, req, cat, page, path_info):37 def render_admin_panel(self, req, cat, page, path_info): 37 38 req.perm.assert_permission('TICKET_ADMIN') 38 39 39 40 data = {} 41 ticketdelete = {} 40 42 41 data['ticketdelete.href'] = req.href('admin', cat, page) 42 data['ticketdelete.page'] = page 43 data['ticketdelete.redir'] = 1 43 ticketdelete['href'] = req.href('admin', cat, page) 44 ticketdelete['page'] = page 45 ticketdelete['redir'] = 1 46 data['ticketdelete'] = ticketdelete 44 47 45 48 if req.method == 'POST': 46 49 if page == 'delete': 47 50 if 'ticketid' in req.args and 'ticketid2' in req.args: 48 51 if req.args.get('ticketid') == req.args.get('ticketid2'): 49 t = self._validate(req, req.args.get('ticketid'))52 t, ticketdelete = self._validate(req, req.args.get('ticketid'), ticketdelete) 50 53 if t: 51 54 self._delete_ticket(t.id) 52 data['ticketdelete.message'] = "Ticket #%s has been deleted." % t.id55 ticketdelete['message'] = "Ticket #%s has been deleted." % t.id 53 56 54 57 else: 55 data['ticketdelete.message'] = "The two IDs did not match. Please try again."58 ticketdelete['message'] = "The two IDs did not match. Please try again." 56 59 elif page == 'comments': 57 60 if 'ticketid' in req.args: 58 61 req.redirect(req.href.admin(cat, page, req.args.get('ticketid'))) 59 62 else: 60 t = self._validate(req, path_info)63 t, ticketdelete = self._validate(req, path_info, ticketdelete) 61 64 if t: 62 data['ticketdelete.href'] = req.href('admin', cat, page, path_info)65 ticketdelete['href'] = req.href('admin', cat, page, path_info) 63 66 try: 64 67 deletions = None 65 68 if "multidelete" in req.args: … … 74 77 ts = int(ts) 75 78 self.log.debug('TicketDelete: Deleting change to ticket %s at %s (%s)'%(t.id,ts,field)) 76 79 self._delete_change(t.id, ts, field) 77 data['ticketdelete.message'] = "Change to ticket #%s at %s has been modified" % (t.id, strftime('%a, %d %b %Y %H:%M:%S',localtime(ts)))78 data['ticketdelete.redir'] = 080 ticketdelete['message'] = "Change to ticket #%s at %s has been modified" % (t.id, strftime('%a, %d %b %Y %H:%M:%S',localtime(ts))) 81 ticketdelete['redir'] = 0 79 82 except ValueError, e: 80 83 self.log.debug("TicketDelete: Error is %s"%e) 81 84 self.log.debug("TicketDelete: args = '%s'"%req.args.items()) 82 data['ticketdelete.message'] = "Timestamp '%s' not valid" % req.args.get('ts')85 ticketdelete['message'] = "Timestamp '%s' not valid" % req.args.get('ts') 83 86 84 87 85 88 if path_info: 86 t = self._validate(req, path_info)89 t, ticketdelete = self._validate(req, path_info, ticketdelete) 87 90 if t: 88 91 if page == 'comments': 89 92 try: … … 96 99 data = ticket_data.setdefault(str(time), {}) 97 100 data.setdefault('fields', {})[field] = {'old': oldvalue, 'new': newvalue} 98 101 data['author'] = author 99 data['prettytime'] = strftime('%a, %d %b %Y %H:%M:%S',localtime(time))102 #data['prettytime'] = strftime('%a, %d %b %Y %H:%M:%S',localtime(0.10)) 100 103 101 104 # Remove all attachment changes 102 105 for k, v in ticket_data.items(): … … 107 110 time_list = list(sorted(ticket_data.iterkeys())) 108 111 if selected is not None and selected < len(time_list): 109 112 ticket_data[time_list[selected]]['checked'] = True 110 data['ticketdelete.changes'] = ticket_data 113 ticketdelete['changes'] = [] 114 for time in time_list: 115 ticketdelete['changes'].append(ticket_data[time]) 111 116 elif page == 'delete': 112 data['ticketdelete.id'] = t.id117 ticketdelete['id'] = t.id 113 118 114 return 'ticketdelete_admin.html', data , None119 return 'ticketdelete_admin.html', data 115 120 116 121 # ITemplateProvider methods 117 122 def get_templates_dirs(self): … … 145 150 else: 146 151 return (0,0) 147 152 148 def _validate(self, req, arg ):153 def _validate(self, req, arg, ticketdelete): 149 154 """Validate that arg is a string containing a valid ticket ID.""" 150 155 try: 151 156 id = int(arg) 152 157 t = Ticket(self.env, id) 153 return t 158 return t, ticketdelete 154 159 except TracError: 155 data['ticketdelete.message'] = "Ticket #%s not found. Please try again." % id160 ticketdelete['message'] = "Ticket #%s not found. Please try again." % id 156 161 except ValueError: 157 data['ticketdelete.message'] = "Ticket ID '%s' is not valid. Please try again." % arg158 return False 162 ticketdelete['message'] = "Ticket ID '%s' is not valid. Please try again." % arg 163 return False, ticketdelete 159 164 160 165 161 166 def _delete_ticket(self, id): -
ticketdelete/htdocs/ticketdelete.js
old new 7 7 } else { 8 8 $('#ticket table.properties').after('<div class="description"><h3><span class="inlinebuttons">'+delete_link+'</span> </h3></div>'); 9 9 } 10 $('#changelog h3').each(function() { 10 $('#changelog form').each(function() { 11 if (!/#comment$/.test(this.action)) { 12 return; 13 } 11 14 var comment = $('input[@name=replyto]', this)[0]; 12 15 if (comment) { 13 16 comment = comment.value; -
ticketdelete/templates/ticketdelete_admin.html
old new 1 <div xmlns="http://www.w3.org/1999/xhtml" 2 xmlns:py="http://genshi.edgewall.org/" 3 id="page"> 4 <h2>Delete Ticket<py:if ticketdelete.page="comments"> Changes</py:if></h2> 1 <!DOCTYPE html 2 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 4 <html xmlns="http://www.w3.org/1999/xhtml" 5 xmlns:xi="http://www.w3.org/2001/XInclude" 6 xmlns:py="http://genshi.edgewall.org/"> 7 <xi:include href="admin.html" /> 8 <head> 9 <title>Delete</title> 10 </head> 11 <body> 5 12 13 <h2>Delete Ticket<py:if test="ticketdelete.page == 'comments'"> Changes</py:if></h2> 14 6 15 <py:choose> 7 16 <py:when test="ticketdelete.message and ticketdelete.redir"> 8 17 <b>${ticketdelete.message}</b><br /> … … 22 31 </form> 23 32 </py:when> 24 33 <py:when test="ticketdelete.page == 'comments'"> 25 <py:choose has_tickets="len(ticketdelete.changes)">26 <py:when has_tickets="True">34 <py:choose test="len(ticketdelete.changes)"> 35 <py:when test="True"> 27 36 <py:if test="ticketdelete.message"> 28 37 <p><b>${ticketdelete.message}</b></p> 29 38 </py:if> … … 34 43 <tbody> 35 44 <py:for each="change in ticketdelete.changes"> 36 45 <tr> 37 <td><input type="checkbox" name="dontcare" value="dontcare" id="checkbox_${change}" checked="${change.checked or None}" /></td>46 <td><input type="checkbox" name="dontcare" value="dontcare" id="checkbox_${change}" checked="${change.checked or None}" onchange="syncchecks(this)" /></td> 38 47 <td colspan="3"><b>Change at ${change.prettytime} by ${change.author}</b></td> 39 48 <td><input type="submit" name="delete_${change}" value="Delete change" /></td> 40 49 <tr> 41 50 <py:for each="field in change.fields"> 42 51 <tr> 43 <td><input type="checkbox" id="checkbox${field}_${change}" name="mdelete" value="${field}_${change}" checked="${change.checked or None}" /></td> 52 <td><input type="checkbox" id="checkbox_${change}_${field}" name="mdelete" value="${field}_${change}" checked="${change.checked or None}" onchange="if(this.checked) { $('#checkbox_${change}').checked = 0; }" /></td> 53 44 54 <td>${field}</td> 45 <py:choose test=" name(field)">55 <py:choose test="str(field)"> 46 56 <td py:when="comment" colspan="2">${field.new}</td> 47 57 48 58 <py:otherwise> … … 61 71 62 72 <script type="text/javascript"> 63 73 <!-- 64 function toggleboxen(me, boxen)74 function syncchecks(me) 65 75 { 66 status = document.getElementById("checkbox_" + me).checked; 67 boxen.pop() // Remove the last (blank) entry. 68 for (box in boxen) { 69 //alert("Changing checkbox"+boxen[box]+"_"+me); 70 document.getElementById("checkbox"+boxen[box]+"_"+me).checked = status; 76 var checked = me.checked; 77 var checks = document.getElementsByTagName("input"); 78 var re = new RegExp("^" + me.id + "_"); 79 for (var i = 0, l = checks.length; i < l; i ++) { 80 var check = checks[i]; 81 if (check.type == "checkbox" && re.test(check.id)) { 82 check.checked = checked; 83 } 71 84 } 72 85 } 73 74 <py:for each="change in ticketdelete.changes">75 addEvent(document.getElementById("checkbox_${change}"), "change", function() {76 var boxen = Array(${py:for each="field in change.fields"${field}",</py:for>"");77 toggleboxen("${change}", boxen); //Array(<py:for each="field in change.fields">"${field}",</py:for>));78 });79 <py:for each="field in change.fields">80 addEvent(document.getElementById("checkbox${field}_${change}"),"change", function() {81 if(!document.getElementById("checkbox${field}_${change}").checked) {82 document.getElementById("checkbox${change}").checked = 0;83 }84 });85 </py:for>86 </py:for>87 88 89 86 //--> 90 87 </script> 91 88 … … 104 101 </py:choose> 105 102 </py:when> 106 103 </py:choose> 107 </div> 104 </body> 105 106 </html>
