Ticket #2141: 0001-Multi-file-Attachment-Facility.patch
| File 0001-Multi-file-Attachment-Facility.patch, 8.9 KB (added by support@…, 20 months ago) |
|---|
-
trac/attachment.py
From 5c4c0b03d6b40de91b800753c5da375fbc5bfc69 Mon Sep 17 00:00:00 2001 From: TJ <tj@tjworld.net> Date: Sun, 20 Jun 2010 23:43:56 +0100 Subject: [PATCH] Multi-file Attachment Facility --- trac/attachment.py | 38 +++++++++++++++++++------- trac/htdocs/js/trac.js | 33 +++++++++++++++++++++++ trac/templates/attachment.html | 57 ++++++++++++++++++++++++++++++--------- 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/trac/attachment.py b/trac/attachment.py index 8002c16..d042390 100644
a b class AttachmentModule(Component): 606 606 607 607 # Internal methods 608 608 609 def _do_save (self, req, attachment):609 def _do_save_one(self, req, attachment, upload, description): 610 610 req.perm(attachment.resource).require('ATTACHMENT_CREATE') 611 611 parent_resource = attachment.resource.parent 612 612 if not resource_exists(self.env, parent_resource): … … class AttachmentModule(Component): 614 614 _("%(parent)s doesn't exist, can't create attachment", 615 615 parent=get_resource_name(self.env, parent_resource))) 616 616 617 if 'cancel' in req.args:618 req.redirect(get_resource_url(self.env, parent_resource, req.href))619 620 upload = req.args['attachment']621 617 if not hasattr(upload, 'filename') or not upload.filename: 622 raise TracError(_('No file uploaded '))618 raise TracError(_('No file uploaded (no filename attribute in request)')) 623 619 if hasattr(upload.file, 'fileno'): 624 620 size = os.fstat(upload.file.fileno())[6] 625 621 else: … … class AttachmentModule(Component): 642 638 filename = filename.replace('\\', '/').replace(':', '/') 643 639 filename = os.path.basename(filename) 644 640 if not filename: 645 raise TracError(_('No file uploaded '))641 raise TracError(_('No file uploaded (cannot normalize filename)')) 646 642 # Now the filename is known, update the attachment resource 647 643 # attachment.filename = filename 648 attachment.description = req.args.get('description', '')644 attachment.description = description 649 645 attachment.author = get_reporter_id(req, 'author') 650 646 attachment.ipnr = req.remote_addr 651 647 … … class AttachmentModule(Component): 683 679 attachment.filename = None 684 680 attachment.insert(filename, upload.file, size) 685 681 686 req.redirect(get_resource_url(self.env, attachment.resource(id=None), 687 req.href)) 682 def _do_save_many(self, req, attachment): 683 curr_attach = 0 684 while curr_attach < int(req.args['multiple_attachments']): 685 upload=req.args['attachment-%d' % curr_attach] 686 if hasattr(upload, 'filename') and upload.filename: 687 attachment.filename = None 688 if hasattr(upload, 'filename') and upload.filename and len(upload.filename) > 0: 689 self._do_save_one(req, attachment, upload, req.args.get('description-%d' % curr_attach, '')) 690 691 curr_attach=curr_attach+1 692 693 def _do_save(self, req, attachment): 694 req.perm(attachment.resource).require('ATTACHMENT_CREATE') 695 696 if 'cancel' in req.args: 697 req.redirect(get_resource_url(self.env, attachment.resource.parent, req.href)) 698 699 if 'multiple_attachments' in req.args: 700 self._do_save_many(req, attachment) 701 req.redirect(get_resource_url(self.env, attachment.resource(id=None), req.href)) 702 else: 703 self._do_save_one(req, attachment, req.args['attachment'], req.args.get('description', '')) 704 # Redirect the user to list of attachments (must add a trailing '/') 705 req.redirect(get_resource_url(self.env, attachment.resource(id=None), req.href)) 688 706 689 707 def _do_delete(self, req, attachment): 690 708 req.perm(attachment.resource).require('ATTACHMENT_DELETE') -
trac/htdocs/js/trac.js
diff --git a/trac/htdocs/js/trac.js b/trac/htdocs/js/trac.js index 9c3c717..f842fa9 100644
a b 131 131 } 132 132 133 133 })(jQuery); 134 135 var ATTACHFILE_COUNTER=0; 136 function manageMultipleAttachFields(_obj){ 137 if (_obj.value == '') { 138 if($("#multiAttach_tbody").get(0).rows.length == 1) return; 139 $("#multiAttach_tbody").get(0).deleteRow($(_obj).attr("attachnum")*1); 140 ATTACHFILE_COUNTER=0; 141 $("#multiAttach_tbody tr").each(function(index, element){ 142 $("input", $("td", element).get(0)) 143 .attr("attachnum",ATTACHFILE_COUNTER) 144 .get(0).name = "attachment-"+ATTACHFILE_COUNTER; 145 $("input", $("td", element).get(1)) 146 .get(0).name = "description-"+ATTACHFILE_COUNTER; 147 ATTACHFILE_COUNTER++; 148 }); 149 $("#multiAttach_count").get(0).value = $("#multiAttach_count").val()*1-1; 150 } else { 151 if ($(_obj).attr("attachnum") != $("#multiAttach_count").val()-1) return; 152 var tr = $("#multiAttach_tbody").get(0).insertRow(-1); 153 var td = tr.insertCell(-1); 154 $('<input type="file" onchange="manageMultipleAttachFields(this)">') 155 .attr("attachnum",$("#multiAttach_count").val()) 156 .appendTo(td) 157 .get(0).name = "attachment-"+$("#multiAttach_count").val(); 158 159 td = tr.insertCell(-1); 160 $('<input type="text">') 161 .attr("size",60) 162 .appendTo(td) 163 .get(0).name = "description-"+$("#multiAttach_count").val(); 164 $("#multiAttach_count").get(0).value = $("#multiAttach_count").val()*1+1; 165 } 166 } -
trac/templates/attachment.html
diff --git a/trac/templates/attachment.html b/trac/templates/attachment.html index 55cb544..38d19d1 100644
a b 24 24 </head> 25 25 26 26 <body> 27 <div py:choose="mode" id="content" class="attachment"> 28 <py:when test="'new'"> 29 <h1 i18n:msg="parent">Add Attachment to <a href="${url_of(parent)}">${name_of(parent)}</a></h1> 30 <form id="attachment" method="post" enctype="multipart/form-data" action=""> 27 <py:def function="attach_oneFile()"> 28 <div class="field"> 29 <label>File:<br /><input type="file" name="attachment" /></label> 30 </div> 31 <fieldset> 32 <legend>Attachment Info</legend> 33 <py:if test="authname == 'anonymous'"> 31 34 <div class="field"> 32 <label> File<py:if test="max_size >= 0">33 <i 18n:msg params="value">(size limit ${pretty_size(max_size)})</i18n:msg></py:if>:<br/>34 <input type="file" name="attachment" /></label>35 <label>Your email or username:<br /> 36 <input type="text" name="author" size="30" value="$author" /> 37 </label> 35 38 </div> 39 </py:if> 40 <div class="field"> 41 <label>Description of the file (optional):<br /> 42 <input type="text" name="description" size="60" /></label> 43 </div> 44 <br /> 45 <div class="options"> 46 <label><input type="checkbox" name="replace" /> 47 Replace existing attachment of the same name</label> 48 </div> 49 <br /> 50 </fieldset> 51 </py:def> 52 <py:def function="attach_multiFile()"> 53 <table><thead> 54 <tr><th align="left">File</th><th align="left">Description</th></tr> 55 </thead> 56 <tbody id="multiAttach_tbody"> 57 <tr> 58 <td><input type="file" attachnum="0" name="attachment-0" onchange="manageMultipleAttachFields(this);"/></td> 59 <td><input type="text" name="description-0" size="60" /></td> 60 </tr> 61 </tbody></table> 62 <input type="hidden" id="multiAttach_count" name="multiple_attachments" value="1" /> 63 36 64 <fieldset> 37 65 <legend>Attachment Info</legend> 38 66 <py:if test="authname == 'anonymous'"> … … 42 70 </label> 43 71 </div> 44 72 </py:if> 45 <div class="field">46 <label>Description of the file (optional):<br />47 <input type="text" name="description" size="60" /></label>48 </div>49 <br />50 73 <py:if test="authname and authname != 'anonymous'"> 51 74 <div class="options"> 52 75 <label><input type="checkbox" name="replace" /> 53 Replace existing attachment of the same name</label>76 Replace existing attachments of the same name</label> 54 77 </div> 55 78 <br /> 56 79 </py:if> 57 80 </fieldset> 81 </py:def> 82 83 <div py:choose="mode" id="content" class="attachment"> 84 <py:when test="'new'"> 85 <h1>Add Attachment to <a href="${url_of(parent)}">${name_of(parent)}</a></h1> 86 <form id="attachment" method="post" enctype="multipart/form-data" action=""> 87 88 ${attach_multiFile()} 58 89 <div class="buttons"> 59 90 <input type="hidden" name="action" value="new" /> 60 91 <input type="hidden" name="realm" value="$parent.realm" />
