Edgewall Software

Ticket #2141: 0001-Multi-file-Attachment-Facility.patch

File 0001-Multi-file-Attachment-Facility.patch, 8.9 KB (added by support@…, 20 months ago)

Working multiple-attachments based on r9099

  • 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): 
    606606 
    607607    # Internal methods 
    608608 
    609     def _do_save(self, req, attachment): 
     609    def _do_save_one(self, req, attachment, upload, description): 
    610610        req.perm(attachment.resource).require('ATTACHMENT_CREATE') 
    611611        parent_resource = attachment.resource.parent 
    612612        if not resource_exists(self.env, parent_resource): 
    class AttachmentModule(Component): 
    614614                _("%(parent)s doesn't exist, can't create attachment", 
    615615                  parent=get_resource_name(self.env, parent_resource))) 
    616616 
    617         if 'cancel' in req.args: 
    618             req.redirect(get_resource_url(self.env, parent_resource, req.href)) 
    619  
    620         upload = req.args['attachment'] 
    621617        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)')) 
    623619        if hasattr(upload.file, 'fileno'): 
    624620            size = os.fstat(upload.file.fileno())[6] 
    625621        else: 
    class AttachmentModule(Component): 
    642638        filename = filename.replace('\\', '/').replace(':', '/') 
    643639        filename = os.path.basename(filename) 
    644640        if not filename: 
    645             raise TracError(_('No file uploaded')) 
     641            raise TracError(_('No file uploaded (cannot normalize filename)')) 
    646642        # Now the filename is known, update the attachment resource 
    647643        # attachment.filename = filename 
    648         attachment.description = req.args.get('description', '') 
     644        attachment.description = description 
    649645        attachment.author = get_reporter_id(req, 'author') 
    650646        attachment.ipnr = req.remote_addr 
    651647 
    class AttachmentModule(Component): 
    683679            attachment.filename = None 
    684680        attachment.insert(filename, upload.file, size) 
    685681 
    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)) 
    688706 
    689707    def _do_delete(self, req, attachment): 
    690708        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  
    131131  } 
    132132 
    133133})(jQuery); 
     134 
     135var ATTACHFILE_COUNTER=0; 
     136function 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  
    2424  </head> 
    2525 
    2626  <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'"> 
    3134          <div class="field"> 
    32             <label>File<py:if test="max_size >= 0"> 
    33               <i18n: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> 
    3538          </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 
    3664          <fieldset> 
    3765            <legend>Attachment Info</legend> 
    3866            <py:if test="authname == 'anonymous'"> 
     
    4270                </label> 
    4371              </div> 
    4472              </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 /> 
    5073            <py:if test="authname and authname != 'anonymous'"> 
    5174              <div class="options"> 
    5275                <label><input type="checkbox" name="replace" /> 
    53                   Replace existing attachment of the same name</label> 
     76                  Replace existing attachments of the same name</label> 
    5477              </div> 
    5578              <br /> 
    5679            </py:if> 
    5780          </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()} 
    5889          <div class="buttons"> 
    5990            <input type="hidden" name="action" value="new" /> 
    6091            <input type="hidden" name="realm" value="$parent.realm" />