def _process_attachment(self, req, config, build): resource_id = req.args['member'] == 'config' \ and build.config or build.resource.id upload = req.args['file'] if not upload.file: send_error(req, message="Attachment not received.") self.log.debug('Received attachment %s for attaching to build:%s', upload.filename, resource_id) # Determine size of file upload.file.seek(0, 2) # to the end size = upload.file.tell() upload.file.seek(0) # beginning again # Delete attachment if it already exists try: old_attach = Attachment(self.env, 'build', parent_id=resource_id, filename=upload.filename) old_attach.delete() except ResourceNotFound: pass # Save new attachment attachment = Attachment(self.env, 'build', parent_id=resource_id) attachment.description = req.args.get('description', '') attachment.author = req.authname attachment.insert(upload.filename, upload.file, size) self._send_response(req, 201, 'Attachment created', headers={ 'Content-Type': 'text/plain', 'Content-Length': str(len('Attachment created'))})
def putAttachmentEx(self, req, pagename, filename, description, data, replace=True): """ Attach a file to a Wiki page. Returns the (possibly transformed) filename of the attachment. Use this method if you don't care about WikiRPC compatibility. """ if not WikiPage(self.env, pagename).exists: raise ResourceNotFound, 'Wiki page "%s" does not exist' % pagename if replace: try: attachment = Attachment(self.env, 'wiki', pagename, filename) req.perm(attachment.resource).require('ATTACHMENT_DELETE') attachment.delete() except TracError: pass attachment = Attachment(self.env, 'wiki', pagename) req.perm(attachment.resource).require('ATTACHMENT_CREATE') attachment.author = req.authname attachment.description = description attachment.insert(filename, StringIO(data.data), len(data.data)) return attachment.filename
def deleteAttachment(self, req, ticket, filename): """ Delete an attachment. """ if not model.Ticket(self.env, ticket).exists: raise TracError('Ticket "%s" does not exists' % ticket) attachment = Attachment(self.env, 'ticket', ticket, filename) attachment.delete() return True
def remove(self, req, realm, objid, filename): """ Delete an attachment. """ resource = Resource(realm, objid).child('attachment', filename) attachment = Attachment(self.env, resource) req.perm(attachment.resource).require('ATTACHMENT_DELETE') attachment.delete() return True
def deleteAttachment(self, req, path): """ Delete an attachment. """ pagename, filename = posixpath.split(path) if not WikiPage(self.env, pagename).exists: raise TracError, 'Wiki page "%s" does not exist' % pagename attachment = Attachment(self.env, 'wiki', pagename, filename) attachment.delete() return True
def deleteAttachment(self, req, ticket, filename): """ Delete an attachment. """ if not model.Ticket(self.env, ticket).exists: raise ResourceNotFound('Ticket "%s" does not exists' % ticket) attachment = Attachment(self.env, 'ticket', ticket, filename) req.perm(attachment.resource).require('ATTACHMENT_DELETE') attachment.delete() return True
def deleteAttachment(self, req, path): """ Delete an attachment. """ pagename, filename = os.path.split(path) if not WikiPage(self.env, pagename).exists: raise ResourceNotFound, 'Wiki page "%s" does not exist' % pagename attachment = Attachment(self.env, 'wiki', pagename, filename) req.perm(attachment.resource).require('ATTACHMENT_DELETE') attachment.delete() return True
def deleteAttachment(self, req, path): """ Delete an attachment. """ pagename, filename = os.path.split(path) if not WikiPage(self.env, pagename).exists: raise ResourceNotFound, 'Wiki page "%s" does not exist' % pagename attachment = Attachment(self.env, "wiki", pagename, filename) req.perm(attachment.resource).require("ATTACHMENT_DELETE") attachment.delete() return True
def test_delete_file_gone(self): """ Verify that deleting an attachment works even if the referenced file doesn't exist for some reason. """ attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', StringIO(''), 0) os.unlink(attachment.path) attachment.delete()
def test_delete_file_gone(self): """ Verify that deleting an attachment works even if the referenced file doesn't exist for some reason. """ attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', tempfile.TemporaryFile(), 0) os.unlink(attachment.path) attachment.delete()
def putAttachment(self, req, ticket, filename, description, data, replace=True): """ Add an attachment, optionally (and defaulting to) overwriting an existing one. Returns filename.""" if not model.Ticket(self.env, ticket).exists: raise TracError, 'Ticket "%s" does not exist' % ticket if replace: try: attachment = Attachment(self.env, 'ticket', ticket, filename) attachment.delete() except TracError: pass attachment = Attachment(self.env, 'ticket', ticket) attachment.author = req.authname or 'anonymous' attachment.description = description attachment.insert(filename, StringIO(data.data), len(data.data)) return attachment.filename
def test_delete(self): attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', StringIO(''), 0) attachment2 = Attachment(self.env, 'wiki', 'SomePage') attachment2.insert('bar.jpg', StringIO(''), 0) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(2, len(list(attachments))) attachment1.delete() attachment2.delete() assert not os.path.exists(attachment1.path) assert not os.path.exists(attachment2.path) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(0, len(list(attachments)))
def test_attachment_change_listeners_called(self): """The move method calls attachment change listeners""" attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', io.BytesIO(), 0) attachment.move(new_realm='ticket', new_id=42) attachment.delete() modern_listener = self.attachment_change_listeners[0](self.env) self.assertEqual(1, modern_listener.added_call_count) self.assertEqual(1, modern_listener.deleted_call_count) self.assertEqual(1, modern_listener.moved_call_count) self.assertEqual('wiki', modern_listener.moved_old_parent_realm) self.assertEqual('SomePage', modern_listener.moved_old_parent_id) self.assertEqual('foo.txt', modern_listener.moved_old_filename) legacy_listener = self.attachment_change_listeners[0](self.env) self.assertEqual(1, legacy_listener.added_call_count) self.assertEqual(1, legacy_listener.deleted_call_count)
def test_delete(self): attachment1 = Attachment(self.env, "wiki", "SomePage") attachment1.insert("foo.txt", StringIO(""), 0) attachment2 = Attachment(self.env, "wiki", "SomePage") attachment2.insert("bar.jpg", StringIO(""), 0) attachments = Attachment.select(self.env, "wiki", "SomePage") self.assertEqual(2, len(list(attachments))) attachment1.delete() attachment2.delete() assert not os.path.exists(attachment1.path) assert not os.path.exists(attachment2.path) attachments = Attachment.select(self.env, "wiki", "SomePage") self.assertEqual(0, len(list(attachments)))
def test_delete(self): attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', tempfile.TemporaryFile(), 0) attachment2 = Attachment(self.env, 'wiki', 'SomePage') attachment2.insert('bar.jpg', tempfile.TemporaryFile(), 0) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(2, len(list(attachments))) attachment1.delete() attachment2.delete() assert not os.path.exists(attachment1.path) assert not os.path.exists(attachment2.path) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(0, len(list(attachments)))
def test_delete(self): attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', StringIO(''), 0) attachment2 = Attachment(self.env, 'wiki', 'SomePage') attachment2.insert('bar.jpg', StringIO(''), 0) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(2, len(list(attachments))) attachment1.delete() attachment2.delete() self.assertFalse(os.path.exists(attachment1.path)) self.assertFalse(os.path.exists(attachment2.path)) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(0, len(list(attachments)))
def putAttachmentEx(self, req, pagename, filename, description, data, replace=True): """ Attach a file to a Wiki page. Returns the (possibly transformed) filename of the attachment. Use this method if you don't care about WikiRPC compatibility. """ if not WikiPage(self.env, pagename).exists: raise TracError, 'Wiki page "%s" does not exist' % pagename if replace: try: attachment = Attachment(self.env, 'wiki', pagename, filename) attachment.delete() except TracError: pass attachment = Attachment(self.env, 'wiki', pagename) attachment.author = req.authname or 'anonymous' attachment.description = description attachment.insert(filename, StringIO(data.data), len(data.data)) return attachment.filename
def putAttachment(self, req, ticket, filename, description, data, replace=True): """ Add an attachment, optionally (and defaulting to) overwriting an existing one. Returns filename.""" if not model.Ticket(self.env, ticket).exists: raise ResourceNotFound('Ticket "%s" does not exist' % ticket) if replace: try: attachment = Attachment(self.env, 'ticket', ticket, filename) req.perm(attachment.resource).require('ATTACHMENT_DELETE') attachment.delete() except TracError: pass attachment = Attachment(self.env, 'ticket', ticket) req.perm(attachment.resource).require('ATTACHMENT_CREATE') attachment.author = req.authname attachment.description = description attachment.insert(filename, StringIO(data.data), len(data.data)) return attachment.filename
def putAttachmentEx(self, req, pagename, filename, description, data, replace=True): """ Attach a file to a Wiki page. Returns the (possibly transformed) filename of the attachment. Use this method if you don't care about WikiRPC compatibility. """ if not WikiPage(self.env, pagename).exists: raise ResourceNotFound, 'Wiki page "%s" does not exist' % pagename if replace: try: attachment = Attachment(self.env, "wiki", pagename, filename) req.perm(attachment.resource).require("ATTACHMENT_DELETE") attachment.delete() except TracError: pass attachment = Attachment(self.env, "wiki", pagename) req.perm(attachment.resource).require("ATTACHMENT_CREATE") attachment.author = req.authname attachment.description = description attachment.insert(filename, StringIO(data.data), len(data.data)) return attachment.filename
def copy_attachment(source_env, dest_env, parent_type, parent_id, filename, dest_db=None): # In case a string gets passed in if not isinstance(source_env, Environment): source_env = _open_environment(source_env) if not isinstance(dest_env, Environment): dest_env = _open_environment(dest_env) # Log message source_env.log.info('DatamoverPlugin: Moving attachment (%s,%s,%s) to the environment at %s', parent_type, parent_id, filename, dest_env.path) dest_env.log.info('DatamoverPlugin: Moving attachment (%s,%s,%s) from the environment at %s', parent_type, parent_id, filename, source_env.path) # Open databases source_db = source_env.get_db_cnx() source_cursor = source_db.cursor() handle_commit = True if not dest_db: dest_db, handle_commit = dest_env.get_db_cnx(), False dest_cursor = dest_db.cursor() # Remove the attachment from the destination try: dest_attachment = Attachment(dest_env, parent_type, parent_id, filename, db=dest_db) dest_attachment.delete(db=dest_db) except TracError: pass # Copy each entry in the attachments table source_cursor.execute('SELECT * FROM attachment WHERE type=%s AND id=%s AND filename=%s',(parent_type, parent_id, filename)) for row in source_cursor: att_data = dict(zip([d[0] for d in source_cursor.description], row)) q = make_query(att_data, 'attachment') dest_cursor.execute(*q) # now copy the file itself old_att = Attachment(source_env, parent_type, parent_id, filename, db=source_db) new_att = Attachment(dest_env, parent_type, parent_id, filename, db=dest_db) if not os.path.isdir(os.path.dirname(new_att.path)): os.makedirs(os.path.dirname(new_att.path)) copyfile(old_att.path, new_att.path) if handle_commit: dest_db.commit()
def _process_attachment(self, req, config, build): resource_id = req.args['member'] == 'config' \ and build.config or build.resource.id upload = req.args['file'] if not upload.file: send_error(req, message="Attachment not received.") self.log.debug('Received attachment %s for attaching to build:%s', upload.filename, resource_id) # Determine size of file upload.file.seek(0, 2) # to the end size = upload.file.tell() upload.file.seek(0) # beginning again # Delete attachment if it already exists try: old_attach = Attachment(self.env, 'build', parent_id=resource_id, filename=upload.filename) old_attach.delete() except ResourceNotFound: pass # Save new attachment attachment = Attachment(self.env, 'build', parent_id=resource_id) attachment.description = req.args.get('description', '') attachment.author = req.authname attachment.insert(upload.filename, upload.file, size) self._send_response(req, 201, 'Attachment created', headers={ 'Content-Type': 'text/plain', 'Content-Length': str(len('Attachment created')) })
def copy_attachment(source_env, dest_env, parent_type, parent_id, filename, dest_db=None): # In case a string gets passed in if not isinstance(source_env, Environment): source_env = _open_environment(source_env) if not isinstance(dest_env, Environment): dest_env = _open_environment(dest_env) # Log message source_env.log.info( 'DatamoverPlugin: Moving attachment (%s,%s,%s) to the environment at %s', parent_type, parent_id, filename, dest_env.path) dest_env.log.info( 'DatamoverPlugin: Moving attachment (%s,%s,%s) from the environment at %s', parent_type, parent_id, filename, source_env.path) # Open databases source_db = source_env.get_db_cnx() source_cursor = source_db.cursor() handle_commit = True if not dest_db: dest_db, handle_commit = dest_env.get_db_cnx(), False dest_cursor = dest_db.cursor() # Remove the attachment from the destination try: dest_attachment = Attachment(dest_env, parent_type, parent_id, filename, db=dest_db) dest_attachment.delete(db=dest_db) except TracError: pass # Copy each entry in the attachments table source_cursor.execute( 'SELECT * FROM attachment WHERE type=%s AND id=%s AND filename=%s', (parent_type, parent_id, filename)) for row in source_cursor: att_data = dict(zip([d[0] for d in source_cursor.description], row)) q = make_query(att_data, 'attachment') dest_cursor.execute(*q) # now copy the file itself old_att = Attachment(source_env, parent_type, parent_id, filename, db=source_db) new_att = Attachment(dest_env, parent_type, parent_id, filename, db=dest_db) if not os.path.isdir(os.path.dirname(new_att.path)): os.makedirs(os.path.dirname(new_att.path)) copyfile(old_att.path, new_att.path) if handle_commit: dest_db.commit()
item.update(item_elem.attr) for child_elem in item_elem.children(): item[child_elem.name] = child_elem.gettext() report.items.append(item) report.insert(db=db) # Collect attachments from the request body for attach_elem in elem.children(Recipe.ATTACH): attach_elem = list(attach_elem.children('file'))[0] # One file only filename = attach_elem.attr.get('filename') resource_id = attach_elem.attr.get('resource') == 'config' \ and build.config or build.resource.id try: # Delete attachment if it already exists old_attach = Attachment(self.env, 'build', parent_id=resource_id, filename=filename) old_attach.delete() except ResourceNotFound: pass attachment = Attachment(self.env, 'build', parent_id=resource_id) attachment.description = attach_elem.attr.get('description') attachment.author = req.authname fileobj = StringIO(attach_elem.gettext().decode('base64')) attachment.insert(filename, fileobj, fileobj.len, db=db) # If this was the last step in the recipe we mark the build as # completed if last_step: self.log.info('Slave %s completed build %d ("%s" as of [%s])', build.slave, build.id, build.config, build.rev) build.stopped = step.stopped
report.items.append(item) report.insert(db=db) # Collect attachments from the request body for attach_elem in elem.children(Recipe.ATTACH): attach_elem = list( attach_elem.children('file'))[0] # One file only filename = attach_elem.attr.get('filename') resource_id = attach_elem.attr.get('resource') == 'config' \ and build.config or build.resource.id try: # Delete attachment if it already exists old_attach = Attachment(self.env, 'build', parent_id=resource_id, filename=filename) old_attach.delete() except ResourceNotFound: pass attachment = Attachment(self.env, 'build', parent_id=resource_id) attachment.description = attach_elem.attr.get('description') attachment.author = req.authname fileobj = StringIO(attach_elem.gettext().decode('base64')) attachment.insert(filename, fileobj, fileobj.len, db=db) # If this was the last step in the recipe we mark the build as # completed if last_step: self.log.info('Slave %s completed build %d ("%s" as of [%s])', build.slave, build.id, build.config, build.rev) build.stopped = step.stopped
def _save_attachement(self, req, attachment): from trac.web import RequestDone from trac.attachment import AttachmentModule, InvalidAttachment from trac.resource import get_resource_url from trac.timeline.web_ui import TimelineModule import os import unicodedata from trac.util.datefmt import pretty_timedelta response = None try: upload = req.args["attachment"] if not hasattr(upload, "filename") or not upload.filename: raise TracError(_("No file uploaded")) if hasattr(upload.file, "fileno"): size = os.fstat(upload.file.fileno())[6] else: upload.file.seek(0, 2) # seek to end of file size = upload.file.tell() upload.file.seek(0) if size == 0: raise TracError(_("Can't upload empty file")) # Maximum attachment size (in bytes) max_size = AttachmentModule(self.env).max_size if max_size >= 0 and size > max_size: raise TracError(_("Maximum attachment size: %(num)s bytes", num=max_size), _("Upload failed")) # We try to normalize the filename to unicode NFC if we can. # Files uploaded from OS X might be in NFD. filename = unicodedata.normalize("NFC", unicode(upload.filename, "utf-8")) filename = filename.replace("\\", "/").replace(":", "/") filename = os.path.basename(filename) if not filename: raise TracError(_("No file uploaded")) # Now the filename is known, update the attachment resource # attachment.filename = filename attachment.description = req.args.get("description", "") attachment.author = get_reporter_id(req, "author") attachment.ipnr = req.remote_addr # Validate attachment for manipulator in AttachmentModule(self.env).manipulators: for field, message in manipulator.validate_attachment(req, attachment): if field: raise InvalidAttachment( _("Attachment field %(field)s is " "invalid: %(message)s", field=field, message=message) ) else: raise InvalidAttachment(_("Invalid attachment: %(message)s", message=message)) if req.args.get("replace"): try: old_attachment = Attachment(self.env, attachment.resource(id=filename)) if not (old_attachment.author and req.authname and old_attachment.author == req.authname): req.perm(attachment.resource).require("ATTACHMENT_DELETE") if not attachment.description.strip() and old_attachment.description: attachment.description = old_attachment.description old_attachment.delete() except TracError: pass # don't worry if there's nothing to replace attachment.filename = None attachment.insert(filename, upload.file, size) timeline = TimelineModule(self.env).get_timeline_link( req, attachment.date, pretty_timedelta(attachment.date), precision="second" ) response = { "attachment": { "href": get_resource_url(self.env, attachment.resource, req.href), "realm": attachment.resource.parent.realm, "objid": attachment.resource.parent.id, "filename": filename, "size": size, "author": attachment.author, "description": attachment.description, "timeline": timeline.generate().render().replace("<", "<").replace(">", ">"), } } except (TracError, InvalidAttachment), e: response = {"error": e.message}
def _save_attachement(self, req, attachment): from trac.web import RequestDone from trac.attachment import AttachmentModule, InvalidAttachment from trac.resource import get_resource_url from trac.timeline.web_ui import TimelineModule import os import unicodedata from trac.util.datefmt import pretty_timedelta response = None try: upload = req.args['attachment'] if not hasattr(upload, 'filename') or not upload.filename: raise TracError(_('No file uploaded')) if hasattr(upload.file, 'fileno'): size = os.fstat(upload.file.fileno())[6] else: upload.file.seek(0, 2) # seek to end of file size = upload.file.tell() upload.file.seek(0) if size == 0: raise TracError(_("Can't upload empty file")) # Maximum attachment size (in bytes) max_size = AttachmentModule(self.env).max_size if max_size >= 0 and size > max_size: raise TracError( _('Maximum attachment size: %(num)s bytes', num=max_size), _('Upload failed')) # We try to normalize the filename to unicode NFC if we can. # Files uploaded from OS X might be in NFD. filename = unicodedata.normalize('NFC', unicode(upload.filename, 'utf-8')) filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) if not filename: raise TracError(_('No file uploaded')) # Now the filename is known, update the attachment resource # attachment.filename = filename attachment.description = req.args.get('description', '') attachment.author = get_reporter_id(req, 'author') attachment.ipnr = req.remote_addr # Validate attachment for manipulator in AttachmentModule(self.env).manipulators: for field, message in manipulator.validate_attachment( req, attachment): if field: raise InvalidAttachment( _( 'Attachment field %(field)s is ' 'invalid: %(message)s', field=field, message=message)) else: raise InvalidAttachment( _('Invalid attachment: %(message)s', message=message)) if req.args.get('replace'): try: old_attachment = Attachment( self.env, attachment.resource(id=filename)) if not (old_attachment.author and req.authname \ and old_attachment.author == req.authname): req.perm( attachment.resource).require('ATTACHMENT_DELETE') if (not attachment.description.strip() and old_attachment.description): attachment.description = old_attachment.description old_attachment.delete() except TracError: pass # don't worry if there's nothing to replace attachment.filename = None attachment.insert(filename, upload.file, size) timeline = TimelineModule(self.env).get_timeline_link( req, attachment.date, pretty_timedelta(attachment.date), precision='second') response = { 'attachment': { 'href': get_resource_url(self.env, attachment.resource, req.href), 'realm': attachment.resource.parent.realm, 'objid': attachment.resource.parent.id, 'filename': filename, 'size': size, 'author': attachment.author, 'description': attachment.description, 'timeline': timeline.generate().render().replace('<', '<').replace( '>', '>') } } except (TracError, InvalidAttachment), e: response = {'error': e.message}