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 _migrate_attachments(self, attachments, to_product=None, copy=False): for type, id, filename in attachments: old_path = Attachment._get_path(self.env.path, type, id, filename) new_path = self.env.path if to_product: new_path = os.path.join(new_path, 'products', to_product) new_path = Attachment._get_path(new_path, type, id, filename) dirname = os.path.dirname(new_path) if not os.path.exists(old_path): self.log.warning( "Missing attachment files for %s:%s/%s", type, id, filename) continue if os.path.exists(new_path): # TODO: Do we want to overwrite? continue try: if not os.path.exists(dirname): os.makedirs(dirname) if copy: if hasattr(os, 'link'): # TODO: It this safe? os.link(old_path, new_path) else: shutil.copy(old_path, new_path) else: os.rename(old_path, new_path) except OSError as err: self.log.warning( "Could not move attachment %s from %s %s to" "product @ (%s)", filename, type, id, str(err) )
def source(self, req, args): arg = re.compile(":").split(args) if (len(arg) != 2): raise TracError('Usage: BibAdd(attachment:[path/to/]file)') realm = 'wiki' page = None file = arg[1] path_info = arg[1].split('/', 1) # greedy! split wikipath and filename if len(path_info) > 2: raise TracError('Usage: BibAdd(attachment:[path/to/]file)') elif len(path_info) == 1: file = path_info[0] page = req.args.get('page') if page is None: # TODO: clean solution page = 'WikiStart' bib = Attachment(self.env, realm, page, file) elif len(path_info) == 2: page = path_info[0] file = path_info[1] bib = Attachment(self.env, realm, page, file) file = bib.open() text = file.read() file.close() return _extract(text)
def convert(moindir, tracdir = None, mapfile = None): pagemap = None if mapfile: pagemap = {} for line in open(mapfile): if line[0] == '#': continue (page, wikidir) = line.split() pagemap[page] = wikidir pages = os.listdir(moindir) for page in pages: wikidir = tracdir if pagemap: if not pagemap.has_key(page): continue wikidir = pagemap[page] admin = TracAdmin() admin.env_set (wikidir) revdir = moindir + '/' + page + '/revisions' if os.access(revdir, os.F_OK): revisions = os.listdir(revdir) for rev in revisions: cmd='wiki import %s %s' % ( recodeName(page), revdir +'/'+rev) print cmd, "->", wikidir admin.onecmd(cmd) # Process attachments attdir = moindir + '/' + page + '/attachments' if os.access(attdir, os.F_OK): attachments = os.listdir(attdir) for att in attachments: attachment = Attachment(admin.env_open(), 'wiki', page) size = os.stat(attdir + '/'+ att)[6] print "attaching " + att + ' = ' + str(size) attfile = open (attdir + '/'+ att) attachment.insert (att, attfile, size)
def image_setup(tc): add_pages(tc, ['page:fr']) from trac.attachment import Attachment tc.env.path = tempfile.mkdtemp(prefix='trac-tempenv-') attachment = Attachment(tc.env, 'wiki', 'page:fr') attachment.description = "image in page:fr" attachment.insert('img.png', StringIO(''), 0, 2)
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 update(self, author=None): """Update the milestone. """ self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid milestone name.")) old = self._old.copy() with self.env.db_transaction as db: if self.name != old['name']: # Update milestone field in tickets self.move_tickets(self.name, author, "Milestone renamed") # Reparent attachments Attachment.reparent_all(self.env, self.realm, old['name'], self.realm, self.name) self.env.log.info("Updating milestone '%s'", old['name']) db("""UPDATE milestone SET name=%s, due=%s, completed=%s, description=%s WHERE name=%s """, (self.name, to_utimestamp(self.due), to_utimestamp(self.completed), self.description, old['name'])) self.checkin() # Fields need reset if renamed or completed/due changed TicketSystem(self.env).reset_ticket_fields() old_values = dict((k, v) for k, v in old.iteritems() if getattr(self, k) != v) for listener in TicketSystem(self.env).milestone_change_listeners: listener.milestone_changed(self, old_values)
def test_get_path_encoded(self): attachment = Attachment(self.env, "ticket", 42) attachment.filename = "Teh foo.txt" self.assertEqual(os.path.join(self.attachments_dir, "ticket", "42", "Teh%20foo.txt"), attachment.path) attachment = Attachment(self.env, "wiki", u"ÜberSicht") attachment.filename = "Teh bar.jpg" self.assertEqual(os.path.join(self.attachments_dir, "wiki", "%C3%9CberSicht", "Teh%20bar.jpg"), attachment.path)
def test_get_path(self): attachment = Attachment(self.env, "ticket", 42) attachment.filename = "foo.txt" self.assertEqual(os.path.join(self.attachments_dir, "ticket", "42", "foo.txt"), attachment.path) attachment = Attachment(self.env, "wiki", "SomePage") attachment.filename = "bar.jpg" self.assertEqual(os.path.join(self.attachments_dir, "wiki", "SomePage", "bar.jpg"), attachment.path)
def delete(self, db=None): """Remove a build configuration and all dependent objects from the database.""" assert self.exists, "Cannot delete non-existing configuration" if not db: db = self.env.get_db_cnx() handle_ta = True else: handle_ta = False for platform in list(TargetPlatform.select(self.env, self.name, db=db)): platform.delete(db=db) for build in list(Build.select(self.env, config=self.name, db=db)): build.delete(db=db) # Delete attachments Attachment.delete_all(self.env, "build", self.resource.id, db) cursor = db.cursor() cursor.execute("DELETE FROM bitten_config WHERE name=%s", (self.name,)) if handle_ta: db.commit() self._old_name = None
def rename(self, new_name): """Rename wiki page in-place, keeping the history intact. Renaming a page this way will eventually leave dangling references to the old page - which litterally doesn't exist anymore. """ assert self.exists, "Cannot rename non-existent page" if not validate_page_name(new_name): raise TracError(_("Invalid Wiki page name '%(name)s'", name=new_name)) old_name = self.name with self.env.db_transaction as db: new_page = WikiPage(self.env, new_name) if new_page.exists: raise TracError(_("Can't rename to existing %(name)s page.", name=new_name)) db("UPDATE wiki SET name=%s WHERE name=%s", (new_name, old_name)) # Invalidate page name cache del WikiSystem(self.env).pages # Reparent attachments from trac.attachment import Attachment Attachment.reparent_all(self.env, 'wiki', old_name, 'wiki', new_name) self.name = new_name self.env.log.info('Renamed page %s to %s', old_name, new_name) for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_renamed'): listener.wiki_page_renamed(self, old_name)
def import_wiki_attachments(self, template_path): """Imports wiki attachments from template using the Attachment API.""" # check that there are attachments to import template_attachment_path = os.path.join(template_path, 'attachments', 'wiki') if os.path.isdir(template_attachment_path): # clear the wiki attachment table @self.env.with_transaction() def clear_attachments(db): """Clears any wiki attachments from the current attachment table.""" cursor = db.cursor() cursor.execute("DELETE FROM attachment WHERE type='wiki'") # move attachment file into the env and insert database row filepath = os.path.join(template_path, 'attachment.xml') tree = ET.ElementTree(file=filepath) for att in tree.getroot(): attachment = Attachment(self.env, 'wiki', att.attrib['parent_id']) attachment.description = att.text try: fileobj = open(os.path.join(template_attachment_path, att.attrib['parent_id'], unicode_quote(att.attrib['name']))) attachment.insert(att.attrib['name'], fileobj, att.attrib['size']) except IOError: self.log.info("Unable to import attachment %s", att.attrib['name'])
def _do_uploadPicture(self, req, userProfile, teamRosterData, req_arg_picture = 'tr_userProfile_picture' ): upload = req.args.get(req_arg_picture, None) if upload == None or not hasattr(upload, 'filename') or not upload.filename: return userProfile.picture_href 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")) filename = upload.filename filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) if not filename: raise TracError(_('No file uploaded')) page = WikiPage(self.env, self.teamRoster_wikiPage) if not page.exists: page.text="= Team Roster Pictures =" page.save( 'trac', 'Page created by tracteamroster component', req.remote_addr) attachment = Attachment(self.env, 'wiki', self.teamRoster_wikiPage) attachment.author = get_reporter_id(req, 'author') attachment.ipnr = req.remote_addr attachment.insert('_'.join([userProfile.id, filename]), upload.file, size) return req.href('/'.join(['raw-attachment', 'wiki',self.teamRoster_wikiPage,attachment.filename]))
def process_request(self, req): """Process the request. For ClearSilver, return a (template_name, content_type) tuple, where `template` is the ClearSilver template to use (either a `neo_cs.CS` object, or the file name of the template), and `content_type` is the MIME type of the content. For Genshi, return a (template_name, data, content_type) tuple, where `data` is a dictionary of substitutions for the template. For both templating systems, "text/html" is assumed if `content_type` is `None`. Note that if template processing should not occur, this method can simply send the response itself and not return anything. """ # handle image setting if req.method == 'POST': self.set_default_image(req) req.redirect(req.get_header('referer') or req.href(req.path_info)) # GET default image ticket_id, size = self.ticket_id_and_size(req.path_info) image = DefaultTicketImage(self.env).default_image(ticket_id, size) assert image is not None # TODO better images = ImageTrac(self.env).images(ticket_id) attachment = Attachment(self.env, 'ticket', ticket_id, images[image][size]) mimeview = Mimeview(self.env) mimetype = mimeview.get_mimetype(attachment.filename) req.send(attachment.open().read(), mimetype)
def do_delete(db): cursor = db.cursor() Attachment.delete_all(self.env, self.resource.realm, self.resource.id, db) cursor.execute(""" DELETE FROM mailinglistraw WHERE id IN (SELECT raw FROM mailinglistmessages WHERE id = %s)""", (self.id,)) cursor.execute('DELETE FROM mailinglistmessages WHERE id = %s', (self.id,))
def delete(self, version=0): """ Deletes a specific version, or if none is provided then all versions will be deleted. If all (or just one version exists) it will also delete all comments and any attachments attached to the post. """ if version: sql = "DELETE FROM fullblog_posts WHERE name=%s AND version=%s" args = (self.name, version) else: sql = "DELETE FROM fullblog_posts WHERE name=%s" args = (self.name,) if hasattr(self.env, 'db_transaction'): self.env.db_transaction(sql, args) db = None else: db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(sql, args) db.commit() if not len(self.get_versions()): # Delete comments for comment in self.get_comments(): comment.delete() # Delete attachments if db is not None: Attachment.delete_all(self.env, 'blog', self.name, db) else: Attachment.delete_all(self.env, 'blog', self.name) return True
def addAttachment(self, ticket_id, filename, datafile, filesize, author, description, upload_time): # copied from bugzilla2trac attachment = Attachment(self.env, 'ticket', ticket_id) attachment.author = author attachment.description = description attachment.insert(filename, datafile, filesize, upload_time) del attachment
def do_delete(db): Attachment.delete_all(self.env, 'ticket', self.id, db) cursor = db.cursor() cursor.execute("DELETE FROM ticket WHERE id=%s", (self.id,)) cursor.execute("DELETE FROM ticket_change WHERE ticket=%s", (self.id,)) cursor.execute("DELETE FROM ticket_custom WHERE ticket=%s", (self.id,))
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 get_file(self, filespec, req): # parse filespec argument to get module and id if contained. parts = filespec.split(':') url = None if len(parts) == 3: # module:id:attachment if parts[0] in ['wiki', 'ticket']: module, id, file = parts else: return None elif len(parts) == 2: from trac.versioncontrol.web_ui import BrowserModule try: browser_links = [link for link,_ in BrowserModule(self.env).get_link_resolvers()] except Exception: browser_links = [] if parts[0] in browser_links: # source:path module, file = parts rev = None if '@' in file: file, rev = file.split('@') url = req.href.browser(file, rev=rev) raw_url = req.href.browser(file, rev=rev, format='raw') else: # #ticket:attachment or WikiPage:attachment # FIXME: do something generic about shorthand forms... id, file = parts if id and id[0] == '#': module = 'ticket' id = id[1:] elif id == 'htdocs': raw_url = url = req.href.chrome('site', file) elif id in ('http', 'https', 'ftp'): # external URLs raw_url = url = id+':'+file else: module = 'wiki' elif len(parts) == 1: # attachment # determine current object # FIXME: should be retrieved from the formatter... # ...and the formatter should be provided to the macro file = filespec module, id = 'wiki', 'WikiStart' path_info = req.path_info.split('/',2) if len(path_info) > 1: module = path_info[1] if len(path_info) > 2: id = path_info[2] if module not in ['wiki', 'ticket']: raise Exception('Cannot reference local attachment from here') else: raise Exception('No filespec given') if not url: # this is an attachment from trac.attachment import Attachment attachment = Attachment(self.env, module, id, file) url = attachment.href(req) raw_url = attachment.href(req, format='raw') return url
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 image_setup(tc): add_pages(tc, ['page:fr']) from trac.attachment import Attachment tc.env.path = tempfile.mkdtemp(prefix='trac-tempenv-') attachment = Attachment(tc.env, 'wiki', 'page:fr') attachment.description = "image in page:fr" attachment.insert('img.png', StringIO(''), 0, 2) htdocs_location = 'http://assets.example.org/common' tc.context.req.chrome['htdocs_location'] = htdocs_location tc.env.config.set('trac', 'htdocs_location', htdocs_location)
def test_format_name_attachment(self): attachment = Attachment(self.env, 'wiki', 'WikiStart') attachment.insert('foo.txt', StringIO(''), 1) data = self.bmsys._format_name(self.req, '/attachment/wiki/WikiStart/foo.txt') self.assertEquals('attachment', data['class_']) self.assertEquals('/trac.cgi/attachment/wiki/WikiStart/foo.txt', data['href']) self.assertEquals("Attachment 'foo.txt' in WikiStart", data['linkname']) self.assertEquals('', data['name'])
def test_get_path(self): attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'foo.txt' self.assertEqual(os.path.join(self.attachments_dir, 'ticket', '42', 'foo.txt'), attachment.path) attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.filename = 'bar.jpg' self.assertEqual(os.path.join(self.attachments_dir, 'wiki', 'SomePage', 'bar.jpg'), attachment.path)
def delete(self): """Delete the ticket. """ with self.env.db_transaction as db: Attachment.delete_all(self.env, self.realm, self.id) db("DELETE FROM ticket WHERE id=%s", (self.id,)) db("DELETE FROM ticket_change WHERE ticket=%s", (self.id,)) db("DELETE FROM ticket_custom WHERE ticket=%s", (self.id,)) for listener in TicketSystem(self.env).change_listeners: listener.ticket_deleted(self)
def test_get_path_encoded(self): attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'Teh foo.txt' self.assertEqual(os.path.join(self.attachments_dir, 'ticket', '42', 'Teh%20foo.txt'), attachment.path) attachment = Attachment(self.env, 'wiki', u'ÜberSicht') attachment.filename = 'Teh bar.jpg' self.assertEqual(os.path.join(self.attachments_dir, 'wiki', '%C3%9CberSicht', 'Teh%20bar.jpg'), attachment.path)
def delete(self, db=None): db, handle_ta = self._get_db_for_write(db) Attachment.delete_all(self.env, 'ticket', self.id, db) cursor = db.cursor() cursor.execute("DELETE FROM ticket WHERE id=%s", (self.id,)) cursor.execute("DELETE FROM ticket_change WHERE ticket=%s", (self.id,)) cursor.execute("DELETE FROM ticket_custom WHERE ticket=%s", (self.id,)) if handle_ta: db.commit() for listener in TicketSystem(self.env).change_listeners: listener.ticket_deleted(self)
def do_rename(db): cursor = db.cursor() new_page = WikiPage(self.env, new_name, db=db) if new_page.exists: raise TracError(_("Can't rename to existing %(name)s page.", name=new_name)) cursor.execute("UPDATE wiki SET name=%s WHERE name=%s", (new_name, old_name)) # Invalidate page name cache del WikiSystem(self.env).pages # Reparent attachments from trac.attachment import Attachment Attachment.reparent_all(self.env, "wiki", old_name, "wiki", new_name)
def test_get_path_encoded(self): attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'Teh foo.txt' self.assertEqual( os.path.join(self.env.attachments_dir, 'ticket', hashes['42'][0:3], hashes['42'], hashes['Teh foo.txt'] + '.txt'), attachment.path) attachment = Attachment(self.env, 'wiki', u'ÜberSicht') attachment.filename = 'Teh bar.jpg' self.assertEqual( os.path.join(self.env.attachments_dir, 'wiki', hashes[u'ÜberSicht'][0:3], hashes[u'ÜberSicht'], hashes['Teh bar.jpg'] + '.jpg'), attachment.path)
def test_get_path(self): attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'foo.txt' self.assertEqual( os.path.join(self.env.attachments_dir, 'ticket', hashes['42'][0:3], hashes['42'], hashes['foo.txt'] + '.txt'), attachment.path) attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.filename = 'bar.jpg' self.assertEqual( os.path.join(self.env.attachments_dir, 'wiki', hashes['SomePage'][0:3], hashes['SomePage'], hashes['bar.jpg'] + '.jpg'), attachment.path)
def addTicket(self, ticket, source): '''Add a ticket from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute( 'select count(*) as count from ticket where id = %s', (ticket['id'], )) idCount = idCountRes.fetchone()[0] assert idCount == 0, 'Ticket %s found in %s' % (ticket['id'], self.name) insertMainTicketQuery = 'insert into ticket (id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords) \ values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)' insertMainTicketValues = (ticket['id'], ticket['type'], ticket['time'], ticket['changetime'], ticket['component'], \ ticket['severity'], ticket['priority'], ticket['owner'], ticket['reporter'], ticket['cc'], ticket['version'], \ ticket['milestone'], ticket['status'], ticket['resolution'], ticket['summary'], ticket['description'], ticket['keywords']) insertMainTicketRes = cursor.execute(insertMainTicketQuery, insertMainTicketValues) #so we know where the ticket came from insertTicketSourceQuery = 'insert into ticket_custom (ticket, name, value) values (%s, %s, %s)' insertTicketSourceValues = (ticket['id'], 'project', source) insertTicketSourceRes = cursor.execute(insertTicketSourceQuery, insertTicketSourceValues) insertTicketChangeQuery = 'insert into ticket_change (ticket, time, author, field, oldvalue, newvalue) values (%s, %s, %s, %s, %s, %s)' for ticket_change in ticket['ticket_change']: insertTicketChangeValues = (ticket['id'], ticket_change['time'], ticket_change['author'], ticket_change['field'], ticket_change['oldvalue'], ticket_change['newvalue']) insertTicketChangeRes = cursor.execute(insertTicketChangeQuery, insertTicketChangeValues) for a in ticket['attachment']: ticketAttach = Attachment(self._env, 'ticket', ticket['id']) ticketAttach.description = a['description'] ticketAttach.author = a['author'] ticketAttach.ipnr = a['ipnr'] ticketAttach.insert(a['filename'], a['fileobj'], a['size'], t=a['time']) db.commit()
def test_convert_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db(self.src_env, 'sqlite:db/trac.db', self.dst_path) self.dst_env = Environment(self.dst_path) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path))
def _render_attachments(self, req): realm = req.args['realm'] db = self.env.get_db_cnx() attachments = Attachment.select(self.env, realm, req.args['path'], db=db) data = {} data['alist'] = { 'can_create': False, 'attachments': attachments, } if 'compact' in req.args: data['compact'] = req.args['compact'] != '0' else: data['compact'] = realm != 'ticket' data['foldable'] = True data['fragment'] = self._is_xhr(req) return 'tracdragdrop.html', data, None
def get_template(self, req): """ return path of standard auto report template """ print("get_template:") print(req) page_path = get_base_url(req) + 'wiki/' + TEMPLATE_PAGE # self.envs[TEMPLATE_INSTANCE].project_url +\ # '/wiki/' + TEMPLATE_PAGE print("page_path", page_path) for attachment in Attachment.select(self.env, 'wiki', TEMPLATE_PAGE): if attachment.filename == TEMPLATE_NAME: return attachment.path self.errorlog.append( ("Attachment {} could not be found at {}.".\ format(TEMPLATE_NAME, TEMPLATE_PAGE), page_path))
def move_attachment_file(env, parent_realm, parent_id, filename): old_path = os.path.join(env.path, 'attachments', parent_realm, unicode_quote(parent_id)) if filename: old_path = os.path.join(old_path, unicode_quote(filename)) old_path = os.path.normpath(old_path) if os.path.isfile(old_path): new_path = Attachment._get_path(env.path, parent_realm, parent_id, filename) try: os.renames(old_path, new_path) except OSError: printerr(_("Unable to move attachment from:\n\n" " %(old_path)s\n\nto:\n\n %(new_path)s\n", old_path=old_path, new_path=new_path)) raise else: env.log.warning("Can't find file for 'attachment:%s:%s:%s', ignoring", filename, parent_realm, parent_id)
def get_image_file(self, filename, page, req): """ return path of image attachment """ page_path = req.args.get('get_wiki_link') if page.exists: for attachment in Attachment.select(page.env, page.realm, page.resource.id): if attachment.filename == filename: # path = str(attachment.path) return attachment.path self.errorlog.append( ("Attachment {} could not be found at {}".\ format(filename, page.resource.id), page_path)) else: self.errorlog.append( ("Page for the spec " +\ "{} could not be found!".format(page.name), page_path))
def addAttachment(self, author, a): description = a['description'].encode('utf-8') id = a['bug_id'] filename = a['filename'].encode('utf-8') filedata = StringIO.StringIO(a['thedata'].tostring()) filesize = len(filedata.getvalue()) time = a['creation_ts'] print " ->inserting attachment '%s' for ticket %s -- %s" % \ (filename, id, description) attachment = Attachment(self.env, 'ticket', id) attachment.author = author attachment.description = description attachment.insert(filename, filedata, filesize, time.strftime('%s')) del attachment
def attach(self, ticket, image): attachment = Attachment(self.env, 'ticket', ticket.id) attachment.author = ticket['reporter'] attachment.description = ticket['summary'] image.file.seek(0, 2) # seek to end of file size = image.file.tell() filename = image.filename image.file.seek(0) attachment.insert(filename, image.file, size) # XXX shouldn't this only be called for, like, the # first image or whenever you really want to set the default? from imagetrac.default_image import DefaultTicketImage if self.env.is_component_enabled(DefaultTicketImage): DefaultTicketImage(self.env).set_default(ticket.id, filename)
def get_uploaded_file_href(self, req, user, field, req_field): """Returns uploaded file's url @param req: trac.web.req @param user: tracusermanager.api.User @param field: str @param req_field: str @return: str """ # validate request field upload = req.args.get(req_field, None) if upload == None or not hasattr(upload, 'filename') or not upload.filename: return user[field] 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")) filename = upload.filename filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) if not filename: raise TracError(_('No file uploaded')) page = WikiPage(self.env, self.attachments_wikiPage) if not page.exists: page.text="= UserManager's Attachments =" page.save( 'trac', 'Page created by tracusermanager.profile component', req.remote_addr) attachment = Attachment(self.env, 'wiki', self.attachments_wikiPage) attachment.author = get_reporter_id(req, 'author') attachment.ipnr = req.remote_addr attachment.description = (_("%s\'s Avatar") % (user.username)) attachment.insert('_'.join([user.username, filename]), upload.file, size) return req.href('/'.join(['raw-attachment', 'wiki',self.attachments_wikiPage, attachment.filename]))
def addAttachment(self, author, a): if a['filename'] != '': description = a['description'] id = a['bug_id'] filename = a['filename'] filedata = io.BytesIO(a['thedata']) filesize = len(filedata.getvalue()) time = a['creation_ts'] print(" ->inserting attachment '%s' for ticket %s -- %s" % (filename, id, description)) attachment = Attachment(self.env, 'ticket', id) attachment.author = author attachment.description = description attachment.insert(filename, filedata, filesize, datetime2epoch(time)) del attachment
def delete(self, version=None, db=None): assert self.exists, 'Cannot delete non-existent page' if not db: db = self.env.get_db_cnx() handle_ta = True else: handle_ta = False page_deleted = False cursor = db.cursor() if version is None: # Delete a wiki page completely cursor.execute("DELETE FROM wiki WHERE name=%s", (self.name, )) self.env.log.info('Deleted page %s' % self.name) page_deleted = True else: # Delete only a specific page version cursor.execute("DELETE FROM wiki WHERE name=%s and version=%s", (self.name, version)) self.env.log.info('Deleted version %d of page %s' % (version, self.name)) cursor.execute("SELECT COUNT(*) FROM wiki WHERE name=%s", (self.name, )) if cursor.fetchone()[0] == 0: page_deleted = True if page_deleted: from trac.attachment import Attachment # Delete orphaned attachments for attachment in Attachment.select(self.env, 'wiki', self.name, db): attachment.delete(db) # Let change listeners know about the deletion for listener in WikiSystem(self.env).change_listeners: listener.wiki_page_deleted(self) if handle_ta: db.commit() self.version = 0
def _render_view(self, req, db, page): req.perm.assert_permission('WIKI_VIEW') if page.name == 'WikiStart': req.hdf['title'] = '' else: req.hdf['title'] = escape(page.name) version = req.args.get('version') if version: # Ask web spiders to not index old versions req.hdf['html.norobots'] = 1 txt_href = self.env.href.wiki(page.name, version=version, format='txt') add_link(req, 'alternate', txt_href, 'Plain Text', 'text/plain') req.hdf['wiki'] = { 'page_name': page.name, 'exists': page.exists, 'version': page.version, 'readonly': page.readonly } if page.exists: req.hdf['wiki.page_html'] = wiki_to_html(page.text, self.env, req) history_href = self.env.href.wiki(page.name, action='history') req.hdf['wiki.history_href'] = escape(history_href) else: if not req.perm.has_permission('WIKI_CREATE'): raise TracError('Page %s not found' % page.name) req.hdf['wiki.page_html'] = '<p>Describe "%s" here</p>' % page.name # Show attachments attachments = [] for attachment in Attachment.select(self.env, 'wiki', page.name, db): attachments.append(attachment_to_hdf(self.env, db, req, attachment)) req.hdf['wiki.attachments'] = attachments if req.perm.has_permission('WIKI_MODIFY'): attach_href = self.env.href.attachment('wiki', page.name) req.hdf['wiki.attach_href'] = attach_href
def _render_confirm_delete(self, req, page): req.perm(page.resource).require('WIKI_DELETE') version = None if 'delete_version' in req.args: version = req.args.getint('version', 0) old_version = req.args.getint('old_version', version) what = 'multiple' if version and old_version \ and version - old_version > 1 \ else 'single' if version else 'page' num_versions = 0 new_date = None old_date = None for v, t, author, comment in page.get_history(): if (v <= version or what == 'page') and new_date is None: new_date = t if (v <= old_version and what == 'multiple' or num_versions > 1 and what == 'single'): break num_versions += 1 old_date = t data = self._page_data(req, page, 'delete') attachments = Attachment.select(self.env, self.realm, page.name) data.update({ 'what': what, 'new_version': None, 'old_version': None, 'num_versions': num_versions, 'new_date': new_date, 'old_date': old_date, 'attachments': list(attachments), }) if version is not None: data.update({'new_version': version, 'old_version': old_version}) self._wiki_ctxtnav(req, page) return 'wiki_delete.html', data
def _render_confirm(self, req, milestone): req.perm(milestone.resource).require('MILESTONE_DELETE') milestones = [ m for m in Milestone.select(self.env) if m.name != milestone.name and 'MILESTONE_VIEW' in req.perm(m.resource) ] attachments = Attachment.select(self.env, self.realm, milestone.name) data = { 'milestone': milestone, 'milestone_groups': group_milestones(milestones, 'TICKET_ADMIN' in req.perm), 'num_tickets': get_num_tickets_for_milestone(self.env, milestone), 'retarget_to': self.default_retarget_to, 'attachments': list(attachments) } add_stylesheet(req, 'common/css/roadmap.css') return 'milestone_delete.html', data
def _render_attachments(self, req): realm = req.args['realm'] path = req.args['path'] db = self.env.get_read_db() attachments = [ attachment for attachment in Attachment.select(self.env, realm, path, db=db)] data = {} data['alist'] = { 'can_create': False, 'attachments': attachments, } if 'compact' in req.args: data['compact'] = req.args['compact'] != '0' else: data['compact'] = realm != 'ticket' data['foldable'] = True if self._is_xhr(req): template = 'list_of_attachments.html' else: template = 'tracdragdrop.html' return template, data, None
def expand_macro(self, formatter, name, content, args=None): parent = formatter.resource this_page = Attachment(self.env, parent.realm, parent.id) path = this_page.path path = path[len(os.path.join(self.env.path, 'attachments/')):] path = os.path.join(self.env.path, _inbox, path) path = os.path.realpath(path) # follow symbolic link if needed if not os.path.exists(path) and not os.path.isdir(path): return newfiles = os.listdir(path) for attachment in Attachment.select(self.env, parent.realm, parent.id): if attachment.filename in newfiles: newfiles.remove(attachment.filename) # avoid overwrite if len(newfiles) == 0: return for filename in newfiles: fullpath = os.path.join(path, filename) if not os.path.isfile(fullpath): continue # skip it stat = os.stat(fullpath) this_page = Attachment(self.env, parent.realm, parent.id) this_page.author = __package__ # attacher name this_page.insert(filename, file(fullpath), stat.st_size) self.log.debug('ATTACHED NEW FILE: %s' % filename)
def test_attachment(self): attachment = Attachment(self.env, 'ticket', 42) attachment.description = 'Summary line' attachment.author = 'Santa' attachment.ipnr = 'northpole.example.com' attachment.insert('foo.txt', StringIO('Lorem ipsum dolor sit amet'), 0) so = self._get_so() self.assertEquals('%s:attachment:ticket:42:foo.txt' % self.basename, so.doc_id) self.assertEquals('attachment', so.realm) self.assertEquals('foo.txt', so.id) self.assertEquals('ticket', so.parent_realm) self.assertEquals(42, so.parent_id) self.assertTrue('foo.txt' in so.title) self.assertEquals('Santa', so.author) self.assertEquals(attachment.date, so.created) self.assertEquals(attachment.date, so.changed) self.assertTrue('Santa' in so.involved) #self.assertTrue('Lorem ipsum' in so.oneline) # TODO self.assertTrue('Lorem ipsum' in so.body.read()) self.assertTrue('Summary line' in so.comments)
def test_upgrade_moves_tickets_and_related_objects_to_default_prod(self): self._add_custom_field('custom_field') with self.env.db_direct_transaction as db: db("""INSERT INTO ticket (id) VALUES (1)""") db("""INSERT INTO attachment (type, id, filename) VALUES ('ticket', '1', '')""") db("""INSERT INTO ticket_custom (ticket, name, value) VALUES (1, 'custom_field', '42')""") db("""INSERT INTO ticket_change (ticket, time, field) VALUES (1, 42, 'summary')""") self._enable_multiproduct() self.env.upgrade() with self.product('@'): ticket = Ticket(self.env, 1) attachments = list( Attachment.select(self.env, ticket.resource.realm, ticket.resource.id)) self.assertEqual(len(attachments), 1) self.assertEqual(ticket['custom_field'], '42') changes = ticket.get_changelog() self.assertEqual(len(changes), 3)
def getWikiPageCurrent(self, page): '''Get the current version of a wiki page as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute( 'select count(*) as count from wiki where name = %s', (page, )) pageCount = pageCountRes.fetchone()[0] assert pageCount >= 1, 'Page %s not found in %s' % (page, self.name) pageQuery = 'select name, version, time, author, ipnr, text, comment, readonly from wiki where name = %s and version = (select max(version) from wiki where name = %s)' pageRes = cursor.execute(pageQuery, (page, page)) wikiPage = dict( zip([d[0] for d in pageRes.description], pageRes.fetchone())) wikiPage['attachment'] = [] pageAttachmentQuery = "select type, id, filename, size, time, description, author, ipnr from attachment where type = 'wiki' and id = %s" pageAttachmentRes = cursor.execute(pageAttachmentQuery, (page, )) for attachment in pageAttachmentRes: thisAttachment = dict( zip([d[0] for d in pageAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment( self._env, 'wiki', page, thisAttachment['filename']).open() wikiPage['attachment'].append(thisAttachment) return wikiPage
def _test_convert_with_plugin_to_sqlite_env(self): self.src_env = Environment(self.src_path) self.assertTrue(self.src_env.needs_upgrade()) self.src_env.upgrade() self.assertFalse(self.src_env.needs_upgrade()) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db(self.src_env, 'sqlite:db/trac.db', self.dst_path) self.dst_env = Environment(self.dst_path) self.assertFalse(self.dst_env.needs_upgrade()) self.assertFalse(os.path.exists(os.path.join(self.dst_env.log_dir, 'created'))) self.assertTrue(os.path.exists(os.path.join(self.dst_env.log_dir, 'upgraded'))) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path))
def getTicket(self, id): '''Get a ticket id as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute( 'select count(*) as count from ticket where id = %s', (id, )) idCount = idCountRes.fetchone()[0] assert idCount >= 1, 'Page %s not found in %s' % (id, self.id) mainTicketQuery = 'select id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords from ticket where id = %s' mainTicketRes = cursor.execute(mainTicketQuery, (id, )) ticket = dict( zip([d[0] for d in mainTicketRes.description], mainTicketRes.fetchone())) ticket['ticket_change'] = [] ticketChangeQuery = 'select time, author, field, oldvalue, newvalue from ticket_change where ticket = %s' ticketChangeRes = cursor.execute(ticketChangeQuery, (id, )) for ticket_change in ticketChangeRes: ticket['ticket_change'].append( dict( zip([d[0] for d in ticketChangeRes.description], ticket_change))) ticket['attachment'] = [] ticketAttachmentQuery = 'select type, id, filename, size, time, description, author, ipnr from attachment where type = \'ticket\' and id = %s' ticketAttachmentRes = cursor.execute(ticketAttachmentQuery, (id, )) for attachment in ticketAttachmentRes: thisAttachment = dict( zip([d[0] for d in ticketAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment( self._env, 'ticket', id, thisAttachment['filename']).open() ticket['attachment'].append(thisAttachment) return ticket
def add_attachments(env, ticket, attachments): """add attachments to the ticket""" ctr = 1 for msg in attachments: attachment = Attachment(env, 'ticket', ticket.id) attachment.author = ticket['reporter'] attachment.description = ticket['summary'] payload = msg.get_payload() if msg.get('Content-Transfer-Encoding') == 'base64': payload = base64.b64decode(payload) size = len(payload) filename = msg.get_filename() or message.get('Subject') if not filename: filename = 'attachment-%d' % ctr extensions = KNOWN_MIME_TYPES.get(message.get_content_type()) if extensions: filename += '.%s' % extensions[0] ctr += 1 buffer = StringIO() print >> buffer, payload buffer.seek(0) attachment.insert(filename, buffer, size) os.chmod(attachment._get_path(), 0666)
def test_rename_page(self): data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) self.env.db_transaction( "INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", ('TestPage', ) + data) attachment = Attachment(self.env, 'wiki', 'TestPage') attachment.insert('foo.txt', StringIO(), 0, 1) page = WikiPage(self.env, 'TestPage') page.rename('PageRenamed') self.assertEqual('PageRenamed', page.name) self.assertEqual('PageRenamed', page.resource.id) self.assertEqual([data], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('PageRenamed', ))) attachments = Attachment.select(self.env, 'wiki', 'PageRenamed') self.assertEqual('foo.txt', attachments.next().filename) self.assertRaises(StopIteration, attachments.next) Attachment.delete_all(self.env, 'wiki', 'PageRenamed') old_page = WikiPage(self.env, 'TestPage') self.assertFalse(old_page.exists) self.assertEqual([], self.env.db_query( """ SELECT version, time, author, ipnr, text, comment, readonly FROM wiki WHERE name=%s """, ('TestPage', ))) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0])
def test_rename_milestone(self): milestone = Milestone(self.env) milestone.name = 'OldName' milestone.insert() attachment = Attachment(self.env, 'milestone', 'OldName') attachment.insert('foo.txt', StringIO(), 0, 1) milestone = Milestone(self.env, 'OldName') milestone.name = 'NewName' milestone.update() self.assertRaises(ResourceNotFound, Milestone, self.env, 'OldName') self.assertEqual('NewName', Milestone(self.env, 'NewName').name) attachments = Attachment.select(self.env, 'milestone', 'OldName') self.assertRaises(StopIteration, attachments.next) attachments = Attachment.select(self.env, 'milestone', 'NewName') self.assertEqual('foo.txt', attachments.next().filename) self.assertRaises(StopIteration, attachments.next)
def create_sizes(self, ticket, attachment): """create the sizes for a ticket image""" filename = attachment.filename # add the specified sizes as attachments sizes = self.sizes() for name, size in sizes.items(): # crop the image image = Image.open(attachment.path) i = crop_resize(image, size) buffer = StringIO() i.save(buffer, image.format) buffer.seek(0, 2) # seek to end of file filesize = buffer.tell() buffer.seek(0) a = Attachment(self.env, 'ticket', ticket.id) a.author = ticket['reporter'] a.description = ticket['summary'] f = ('.%sx%s.' % (size[0] or '', size[1] or '')).join( filename.rsplit('.', 1)) # XXX assumes the file has an extension a.insert(f, buffer, filesize)
def attachment_setup(tc): import trac.ticket.api import trac.wiki.api tc.env.path = mkdtemp() with tc.env.db_transaction as db: db("INSERT INTO wiki (name,version) VALUES ('SomePage/SubPage',1)") db("INSERT INTO ticket (id) VALUES (123)") attachment = Attachment(tc.env, 'ticket', 123) attachment.insert('file.txt', io.BytesIO(b''), 0) attachment = Attachment(tc.env, 'wiki', 'WikiStart') attachment.insert('file.txt', io.BytesIO(b''), 0) attachment = Attachment(tc.env, 'wiki', 'SomePage/SubPage') attachment.insert('foo.txt', io.BytesIO(b''), 0)
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_insert_outside_attachments_dir(self): attachment = Attachment(self.env, '../../../../../sth/private', 42) self.assertRaises(AssertionError, attachment.insert, 'foo.txt', tempfile.TemporaryFile(), 0)