Ticket #948: attachment_del_replace.1077.diff
| File attachment_del_replace.1077.diff, 10.3 kB (added by cboos@…, 4 years ago) |
|---|
-
templates/attachment.cs
=== templates/attachment.cs ==================================================================
14 14 <label for="file">File:</label> 15 15 <input type="file" id="file" name="attachment" /> 16 16 </div> 17 <div class="field"> 18 <input type="checkbox" id="replace" name="replace" checked="1" /> 19 <label for="replace">Replace Existing File</label> 20 </div> 17 21 <fieldset> 18 22 <legend>Attachment Info</legend> 19 23 <div class="field"> -
templates/file.cs
=== templates/file.cs ==================================================================
13 13 <?cs if file.attachment_parent ?> 14 14 <h1><a href="<?cs var:file.attachment_parent_href ?>"><?cs 15 15 var:file.attachment_parent ?></a>: <?cs var:file.filename ?></h1> 16 <table id="info" summary="Attachment info"> 17 <tr> 18 <th scope="row"> 19 File <a href="<?cs var:attachment.href ?>"><?cs var:attachment.name ?></a>, <?cs var:attachment.size ?> 20 (attached by <?cs var:attachment.author ?>, <?cs var:attachment.time ?>) 21 </th> 22 <td class="message"><?cs var:attachment.descr ?></td> 23 </tr> 24 </table> 16 25 17 26 <?cs else ?> 18 27 <?cs call:browser_path_links(file.path, file) ?> -
trac/Environment.py
=== trac/Environment.py ==================================================================
214 214 def get_attachments_dir(self): 215 215 return os.path.join(self.path, 'attachments') 216 216 217 def get_attachment(self, cnx, type, id, filename): 218 cursor = cnx.cursor() 219 cursor.execute('SELECT filename,description,type,size,time,author,ipnr ' 220 'FROM attachment ' 221 'WHERE type=%s AND id=%s AND filename=%s ORDER BY time', type, id, filename) 222 return cursor.fetchone() 223 217 224 def get_attachments(self, cnx, type, id): 218 225 cursor = cnx.cursor() 219 226 cursor.execute('SELECT filename,description,type,size,time,author,ipnr ' … … 221 228 'WHERE type=%s AND id=%s ORDER BY time', type, id) 222 229 return cursor.fetchall() 223 230 231 def get_attachment_hdf(self, cnx, type, id, hdf, prefix, file, idx=None): 232 from Wiki import wiki_to_oneliner 233 if idx: 234 p = '%s.%d' % (prefix, idx) 235 else: 236 p = prefix 237 hdf.setValue(p + '.name', file['filename']) 238 hdf.setValue(p + '.descr', 239 wiki_to_oneliner(file['description'], hdf, self, cnx)) 240 hdf.setValue(p + '.author', util.escape(file['author'])) 241 hdf.setValue(p + '.ipnr', file['ipnr']) 242 hdf.setValue(p + '.size', util.pretty_size(file['size'])) 243 hdf.setValue(p + '.time', 244 time.strftime('%c', time.localtime(file['time']))) 245 hdf.setValue(p + '.href', 246 self.href.attachment(type, id, file['filename'])) 247 248 224 249 def get_attachments_hdf(self, cnx, type, id, hdf, prefix): 225 250 from Wiki import wiki_to_oneliner 226 251 files = self.get_attachments(cnx, type, id) 227 252 idx = 0 228 253 for file in files: 229 p = '%s.%d' % (prefix, idx) 230 hdf.setValue(p + '.name', file['filename']) 231 hdf.setValue(p + '.descr', 232 wiki_to_oneliner(file['description'], hdf, self, cnx)) 233 hdf.setValue(p + '.author', util.escape(file['author'])) 234 hdf.setValue(p + '.ipnr', file['ipnr']) 235 hdf.setValue(p + '.size', util.pretty_size(file['size'])) 236 hdf.setValue(p + '.time', 237 time.strftime('%c', time.localtime(file['time']))) 238 hdf.setValue(p + '.href', 239 self.href.attachment(type, id, file['filename'])) 254 self.get_attachment_hdf(cnx, type, id, hdf, prefix, file, idx) 240 255 idx += 1 241 256 242 257 def create_attachment(self, cnx, type, id, attachment, 243 description, author, ipnr ):258 description, author, ipnr, replace=0): 244 259 # Maximum attachment size (in bytes) 245 260 max_size = int(self.get_config('attachment', 'max_size', '262144')) 246 261 if hasattr(attachment.file, 'fileno'): … … 258 273 filename = attachment.filename.replace('\\', '/').replace(':', '/') 259 274 filename = os.path.basename(filename) 260 275 276 cursor = cnx.cursor() 277 cursor.execute('SELECT author FROM attachment WHERE ' 278 'type=%s AND id=%s AND filename=%s', 279 type, id, filename) 280 row = cursor.fetchone() 281 if row and author != row['author']: 282 replace = 0 283 261 284 # We try to normalize the filename to utf-8 NFC if we can. 262 285 # Files uploaded from OS X might be in NFD. 263 286 if sys.version_info[0] > 2 or \ … … 265 288 filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 266 289 267 290 filename = urllib.quote(filename) 268 path, fd = util.create_unique_file(os.path.join(dir, filename) )291 path, fd = util.create_unique_file(os.path.join(dir, filename), replace) 269 292 filename = os.path.basename(path) 270 293 filename = urllib.unquote(filename) 271 cursor = cnx.cursor() 272 cursor.execute('INSERT INTO attachment VALUES(%s,%s,%s,%s,%s,%s,%s,%s)', 294 295 if replace: 296 action = "REPLACE" 297 else: 298 action = "INSERT" 299 cursor.execute(action + ' INTO attachment VALUES(%s,%s,%s,%s,%s,%s,%s,%s)', 273 300 type, id, filename, length, int(time.time()), 274 301 description, author, ipnr) 275 302 shutil.copyfileobj(attachment.file, fd) -
trac/File.py
=== trac/File.py ==================================================================
104 104 self.env.href.wiki(self.attachment_id)) 105 105 assert 0 106 106 107 def can_delete(self, do_assert=None): 108 print 'author', self.file['author'], 'authname', self.req.authname 109 if self.file and self.file['author'] and self.req.authname: 110 if self.file['author'] == self.req.authname: 111 return 1 112 perm_map = {'ticket': perm.TICKET_ADMIN, 'wiki': perm.WIKI_DELETE} 113 if do_assert: 114 self.perm.assert_permission(perm_map[self.attachment_type]) 115 else: 116 return self.perm.has_permission(perm_map[self.attachment_type]) 117 107 118 def render(self): 108 119 FileCommon.render(self) 109 120 self.view_form = 0 110 121 self.attachment_type = self.args.get('type', None) 111 122 self.attachment_id = self.args.get('id', None) 112 123 self.filename = self.args.get('filename', None) 113 if self.filename:114 self.filename = os.path.basename(self.filename)115 124 116 125 if not self.attachment_type or not self.attachment_id: 117 126 raise util.TracError('Unknown request') 118 127 128 if self.filename: 129 self.filename = os.path.basename(self.filename) 130 self.file = self.env.get_attachment(self.db, self.attachment_type, 131 self.attachment_id, self.filename) 132 if self.file: 133 self.env.get_attachment_hdf(self.db, self.attachment_type, 134 self.attachment_id, self.req.hdf, 135 'attachment', self.file) 136 119 137 if self.filename and len(self.filename) > 0 and \ 120 138 self.args.has_key('delete'): 121 perm_map = {'ticket': perm.TICKET_ADMIN, 'wiki': perm.WIKI_DELETE} 122 self.perm.assert_permission(perm_map[self.attachment_type]) 139 self.can_delete(do_assert=1) 123 140 self.env.delete_attachment(self.db, 124 141 self.attachment_type, 125 142 self.attachment_id, … … 160 177 self.filename, 'raw'), 161 178 'Original Format', self.mime_type) 162 179 163 perm_map = {'ticket': perm.TICKET_ADMIN, 'wiki': perm.WIKI_DELETE} 164 if self.perm.has_permission(perm_map[self.attachment_type]): 180 if self.can_delete(): 165 181 self.req.hdf.setValue('attachment.delete_href', '?delete=yes') 166 182 167 183 return … … 187 203 self.args['attachment'], 188 204 self.args.get('description'), 189 205 self.args.get('author'), 190 self.req.remote_addr) 206 self.req.remote_addr, 207 self.args.get('replace')) 208 191 209 # Redirect the user to the newly created attachment 192 210 self.req.redirect(self.env.href.attachment(self.attachment_type, 193 211 self.attachment_id, … … 210 228 self.req.hdf.setValue('attachment.author', util.get_reporter_id(self.req)) 211 229 self.req.display('attachment.cs') 212 230 return 231 213 232 self.req.hdf.setValue('file.filename', urllib.unquote(self.filename)) 214 233 self.req.hdf.setValue('trac.active_module', self.attachment_type) # Kludge 215 234 FileCommon.display(self) -
trac/util.py
=== trac/util.py ==================================================================
235 235 return '%i %s' % (r, r == 1 and unit or unit_plural) 236 236 return '' 237 237 238 def create_unique_file(path ):238 def create_unique_file(path,replace=0): 239 239 """Create a new file. An index is added if the path exists""" 240 240 parts = os.path.splitext(path) 241 241 idx = 1 242 242 while 1: 243 243 try: 244 flags = os.O_CREAT + os.O_WRONLY + os.O_EXCL 244 flags = os.O_CREAT + os.O_WRONLY 245 if not replace: 246 flags += os.O_EXCL 245 247 if hasattr(os, 'O_BINARY'): 246 248 flags += os.O_BINARY 247 249 return path, os.fdopen(os.open(path, flags), 'w') 248 except OSError: 250 except OSError, e: 251 if replace: 252 raise e # propagate failure 249 253 idx += 1 250 254 # A sanity check 251 255 if idx > 100:
