def test_preview_valid_xhtml(self): chrome = Chrome(self.env) module = AttachmentModule(self.env) def render(attachment): path_info = '/attachment/%s/%s/%s' % (attachment.parent_realm, attachment.parent_id, attachment.filename) req = MockRequest(self.env, path_info=path_info) self.assertTrue(module.match_request(req)) template, data = module.process_request(req) return chrome.render_template(req, template, data, {'fragment': True}) # empty file attachment = Attachment(self.env, 'parent_realm', 'parent_id') attachment.insert('empty', io.BytesIO(), 0, 1) result = render(attachment) self.assertIn(b'<strong>(The file is empty)</strong>', result) xml = minidom.parseString(result) # text file attachment = Attachment(self.env, 'parent_realm', 'parent_id') attachment.insert('foo.txt', io.BytesIO(b'text'), 4, 1) result = render(attachment) self.assertIn( b'<tr><th id="L1"><a href="#L1">1</a></th>' b'<td>text</td></tr>', result) xml = minidom.parseString(result) # preview unavailable attachment = Attachment(self.env, 'parent_realm', 'parent_id') attachment.insert('foo.dat', io.BytesIO(b'\x00\x00\x01\xb3'), 4, 1) result = render(attachment) self.assertIn(b'<strong>HTML preview not available</strong>', result) xml = minidom.parseString(result)
def test_attachment_rename(self): """Rename attachment.""" attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', io.BytesIO(), 0) rv, output = self.execute('attachment move wiki:SomePage foo.txt ' 'wiki:SomePage bar.txt') self.assertEqual(0, rv, output) self.assertEqual('', output) rv, output = self.execute('attachment list wiki:SomePage') self.assertEqual(0, rv, output) self.assertExpectedResult(output, { 'date': format_datetime(attachment.date, console_datetime_format) })
def test_path_extension(self): attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'Foo.Mp3' self.assertEqual( os.path.join(self.env.attachments_dir, 'ticket', hashes['42'][0:3], hashes['42'], hashes['Foo.Mp3'] + '.Mp3'), attachment.path) attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.filename = 'bar.7z' self.assertEqual( os.path.join(self.env.attachments_dir, 'wiki', hashes['SomePage'][0:3], hashes['SomePage'], hashes['bar.7z'] + '.7z'), attachment.path) attachment = Attachment(self.env, 'ticket', 42) attachment.filename = 'foo.$$$' self.assertEqual( os.path.join(self.env.attachments_dir, 'ticket', hashes['42'][0:3], hashes['42'], hashes['foo.$$$']), attachment.path) attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.filename = 'bar.aäc' self.assertEqual( os.path.join(self.env.attachments_dir, 'wiki', hashes['SomePage'][0:3], hashes['SomePage'], hashes['bar.aäc']), attachment.path)
def get_attachment(env, filename, req, module=None, id=None): if not module or not id: 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] basename = os.path.basename(filename) try: attachment = Attachment(env, module, id, basename) return attachment except Exception: return None #Attachment not found
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 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 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 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 test_wiki_link_ticket(self): attachment = Attachment(self.env, 'ticket', 123) attachment.insert('foo.txt', tempfile.TemporaryFile(), 0) ns, func = AttachmentModule(self.env).get_link_resolvers().next() self.assertEqual('attachment', ns) req = Mock(path_info='/ticket/123') formatter = Formatter(self.env, req) self.assertEqual('<a class="attachment" title="Attachment #123: ' 'foo.txt" href="/trac.cgi/attachment/ticket/123/' 'foo.txt">Foo</a>', func(formatter, ns, 'foo.txt', 'Foo')) self.assertEqual('<a class="attachment" title="Attachment #123: ' 'foo.txt" href="/trac.cgi/attachment/ticket/123/' 'foo.txt?format=raw">Foo</a>', func(formatter, ns, 'foo.txt?format=raw', 'Foo'))
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 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 _reindex_attachment(self, realm, feedback, finish_fb): db = self.env.get_read_db() cursor = db.cursor() # This plugin was originally written for #define 4, a Trac derivative # that includes versioned attachments. TO try and keep compatibility # with both check support by checking for a version attribute on an # Attachment. Instantiating Attachment doesn't perform any queries, # so it doesn't matter if ticket:42 actually exists # The versioned attachment code used by #define is published on github # https://github.com/moreati/trac-gitsvn/tree/0.12-versionedattachments canary = Attachment(self.env, 'ticket', 42) if hasattr(canary, 'version'): # Adapted from Attachment.select() cursor.execute( """ SELECT type, id, filename, version, description, size, time, author, ipnr, status, deleted FROM attachment JOIN (SELECT type AS c_type, id AS c_id, filename AS c_filename, MAX(version) AS c_version FROM attachment WHERE deleted IS NULL GROUP BY c_type, c_id, c_filename) AS current ON type = c_type AND id = c_id AND filename = c_filename AND version = c_version ORDER BY time""", ) else: cursor.execute( "SELECT type,id,filename,description,size,time,author,ipnr " "FROM attachment " "ORDER by time", ) def att(row): parent_realm, parent_id = row[0], row[1] attachment = Attachment(self.env, parent_realm, parent_id) attachment._from_database(*row[2:]) return attachment def check(attachment, status): return (status is None or attachment.date > to_datetime(int(status))) resources = (att(row) for row in cursor) index = self.attachment_added return self._index(realm, resources, check, index, feedback, finish_fb)
def test_rename(self): """Rename an attachment.""" attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', io.BytesIO(), 0) original_path = attachment.path self.assertTrue(os.path.exists(original_path)) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(1, len(list(attachments))) attachment.move(new_filename='bar.txt') attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(1, len(list(attachments))) self.assertEqual('wiki', attachment.parent_realm) self.assertEqual('SomePage', attachment.parent_id) self.assertEqual('bar.txt', attachment.filename) self.assertFalse(os.path.exists(original_path)) self.assertTrue(os.path.exists(attachment.path))
def execute(hdf, txt, env): # args will be null if the macro is called without parenthesis. if not txt: return '' # parse arguments # we expect the 1st argument to be a filename (filespec) args = txt.split(',') if len(args) == 0: raise Exception("No argument.") filespec = args[0] # parse filespec argument to get module and id if contained. parts = filespec.split(':') if len(parts) == 3: # module:id:attachment if parts[0] in ['wiki', 'ticket']: module, id, file = parts else: raise Exception("%s module can't have attachments" % parts[0]) elif len(parts) == 2: # #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:] else: module = 'wiki' elif len(parts) == 1: # attachment file = filespec # get current module and id from hdf module = hdf.getValue('args.mode', 'wiki') if module == 'wiki': id = hdf.getValue('args.page', 'WikiStart') elif module == 'ticket': id = hdf['args.id'] # for ticket else: # limit of use raise Exception('Cannot use this macro in %s module' % module) else: raise Exception('No filespec given') try: attachment = Attachment(env, module, id, file) org_path = attachment.path return svg_render(images_folder, images_url, org_path) except: return '%s not found' % (filespec)
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 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 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 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 add_attachment(env, filename, time, req): 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] fin = open(filename, "r") size = os.fstat(fin.fileno())[6] attachment = Attachment(env, module, id) old_attachment = get_attachment(env, filename, req, module, id) if old_attachment: old_attachment.delete() basename = os.path.basename(filename) attachment.insert(basename, fin, size, time) fin.close() return attachment
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 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 test_add_attachment_html_notification(self): ticket = Ticket(self.env) ticket['description'] = 'Some ticket description' ticket['summary'] = 'Some ticket summary' ticket['type'] = 'defect' ticket['status'] = 'new' ticket.insert() attachment = Attachment(self.env, ticket) attachment.description = "`Some` '''!WikiFormatted''' ''text''" attachment.filename = 'somefile.txt' event = TicketChangeEvent('ticket', 'changed', ticket, author='user1', attachment=attachment) actual = self.tf.format([], 'ticket', 'text/html', event) filename = resource_filename(__name__, 'attachment_notification.html') file = open(filename, 'r') expected = file.read() file.close() self.assertEqual(expected, actual)
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 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_insert_outside_attachments_dir(self): attachment = Attachment(self.env, '../../../../../sth/private', 42) self.assertRaises(AssertionError, attachment.insert, 'foo.txt', tempfile.TemporaryFile(), 0)
def render_macro(self, req, name, content): # args will be null if the macro is called without parenthesis. if not content: return '' # parse arguments # we expect the 1st argument to be a filename (filespec) args = content.split(',') if len(args) == 0: raise Exception("No argument.") filespec = args[0] size_re = re.compile('[0-9]+%?$') attr_re = re.compile('(align|border|width|height|alt' '|title|longdesc|class|id|usemap)=(.+)') quoted_re = re.compile("(?:[\"'])(.*)(?:[\"'])$") attr = {} style = {} nolink = False for arg in args[1:]: arg = arg.strip() if size_re.match(arg): # 'width' keyword attr['width'] = arg continue if arg == 'nolink': nolink = True continue if arg in ('left', 'right', 'top', 'bottom'): style['float'] = arg continue match = attr_re.match(arg) if match: key, val = match.groups() m = quoted_re.search(val) # unquote "..." and '...' if m: val = m.group(1) if key == 'align': style['float'] = val elif key == 'border': style['border'] = ' %dpx solid' % int(val) else: attr[str(key)] = val # will be used as a __call__ keyword # 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: raise Exception("%s module can't have attachments" % parts[0]) 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') desc = filespec 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) desc = os.path.basename(file) elif id in ('http', 'https', 'ftp'): # external URLs raw_url = url = desc = 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') desc = attachment.description for key in ['title', 'alt']: if desc and not attr.has_key(key): attr[key] = desc if style: attr['style'] = '; '.join( ['%s:%s' % (k, escape(v)) for k, v in style.iteritems()]) result = Markup(html.IMG(src=raw_url, **attr)).sanitize() if not nolink: result = html.A(result, href=url, style='padding:0; border:none') return result
def add_attachment(tc, realm, id, file): attachment = Attachment(tc.env, realm, id) attachment.description = "image in %s" % id attachment.insert(file, io.BytesIO(), 0, 2)
def getAttachment(self, req, path): """ returns the content of an attachment. """ pagename, filename = os.path.split(path) attachment = Attachment(self.env, 'wiki', pagename, filename) req.perm(attachment.resource).require('ATTACHMENT_VIEW') return Binary(attachment.open().read())