def test_reparent(self): attachment1 = Attachment(self.env, "wiki", "SomePage") attachment1.insert("foo.txt", StringIO(""), 0) path1 = attachment1.path 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))) attachments = Attachment.select(self.env, "ticket", 123) self.assertEqual(0, len(list(attachments))) assert os.path.exists(path1) and os.path.exists(attachment2.path) attachment1.reparent("ticket", 123) self.assertEqual("ticket", attachment1.parent_realm) self.assertEqual("ticket", attachment1.resource.parent.realm) self.assertEqual("123", attachment1.parent_id) self.assertEqual("123", attachment1.resource.parent.id) attachments = Attachment.select(self.env, "wiki", "SomePage") self.assertEqual(1, len(list(attachments))) attachments = Attachment.select(self.env, "ticket", 123) self.assertEqual(1, len(list(attachments))) assert not os.path.exists(path1) and os.path.exists(attachment1.path) assert os.path.exists(attachment2.path)
def test_reparent(self): """Change the parent realm and parent id of an attachment """ attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', io.BytesIO(), 0) path1 = attachment1.path attachment2 = Attachment(self.env, 'wiki', 'SomePage') attachment2.insert('bar.jpg', io.BytesIO(), 0) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(2, len(list(attachments))) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual(0, len(list(attachments))) self.assertTrue(os.path.exists(path1) and os.path.exists(attachment2.path)) attachment1.move('ticket', 42) self.assertEqual('ticket', attachment1.parent_realm) self.assertEqual('ticket', attachment1.resource.parent.realm) self.assertEqual('42', attachment1.parent_id) self.assertEqual('42', attachment1.resource.parent.id) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(1, len(list(attachments))) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual(1, len(list(attachments))) self.assertFalse(os.path.exists(path1) and os.path.exists(attachment1.path)) self.assertTrue(os.path.exists(attachment2.path))
def test_reparent(self): attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', StringIO(''), 0) path1 = attachment1.path 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))) attachments = Attachment.select(self.env, 'ticket', 123) self.assertEqual(0, len(list(attachments))) assert os.path.exists(path1) and os.path.exists(attachment2.path) attachment1.reparent('ticket', 123) self.assertEqual('ticket', attachment1.parent_realm) self.assertEqual('ticket', attachment1.resource.parent.realm) self.assertEqual('123', attachment1.parent_id) self.assertEqual('123', attachment1.resource.parent.id) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(1, len(list(attachments))) attachments = Attachment.select(self.env, 'ticket', 123) self.assertEqual(1, len(list(attachments))) assert not os.path.exists(path1) and os.path.exists(attachment1.path) assert os.path.exists(attachment2.path)
def test_reparent(self): attachment1 = Attachment(self.env, 'wiki', 'SomePage') attachment1.insert('foo.txt', StringIO(''), 0) path1 = attachment1.path 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))) attachments = Attachment.select(self.env, 'ticket', 123) self.assertEqual(0, len(list(attachments))) assert os.path.exists(path1) and os.path.exists(attachment2.path) attachment1.reparent('ticket', 123) self.assertEqual('ticket', attachment1.parent_realm) self.assertEqual('ticket', attachment1.resource.parent.realm) self.assertEqual('123', attachment1.parent_id) self.assertEqual('123', attachment1.resource.parent.id) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(1, len(list(attachments))) attachments = Attachment.select(self.env, 'ticket', 123) self.assertEqual(1, len(list(attachments))) assert not os.path.exists(path1) and os.path.exists(attachment1.path) assert os.path.exists(attachment2.path)
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([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.assertEqual(False, 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 listAttachments(self, req, ticket): """ Lists attachments for a given ticket. Returns (filename, description, size, time, author) for each attachment.""" attachments = [] for a in Attachment.select(self.env, 'ticket', ticket): if 'ATTACHMENT_VIEW' in req.perm(a.resource): yield (a.filename, a.description, a.size, a.date, a.author)
def images(self, ticket, href=None): """returns images for a ticket""" # construct a ticket from an id if isinstance(ticket, int): ticket = Ticket(self.env, ticket) if not ticket.exists: return {} attachments = list(Attachment.select(self.env, 'ticket', ticket.id)) images = {} for attachment in attachments: try: filename, category = self.image_category(attachment) except TypeError: continue images.setdefault(filename, {})[category] = attachment.filename if href is not None: # turn the keys into links for values in images.values(): for key, value in values.items(): values[key] = href('attachment', 'ticket', ticket.id, value, format='raw') return images
def _suggest_attachment(self, req, term): tokens = term.split(':', 2) if len(tokens) == 2: # "realm:..." realm = tokens[0] term = tokens[1] rows = self.env.db_query( """ SELECT DISTINCT id FROM attachment WHERE type=%s ORDER BY id""", (realm, )) completions = [ realm + ':' + row[0] + ':' for row in rows if row[0].startswith(term) ] else: completions = [] if len(tokens) == 3: # "realm:id:..." realm = tokens[0] id = tokens[1] term = tokens[2] else: completions.extend(row[0] + ':' for row in self.env.db_query( "SELECT DISTINCT type FROM attachment ORDER BY type") if row[0].startswith(term)) realm = req.args.get('realm') id = req.args.get('id') filenames = sorted( att.filename for att in Attachment.select(self.env, realm, id) if att.filename.startswith(term) and 'ATTACHMENT_VIEW' in req.perm(att.resource)) if len(tokens) == 3: completions.extend('%s:%s:%s' % (realm, id, filename) for filename in filenames) else: completions.extend(filenames) return completions
def _do_seed(self): # Create a subscription for all existing attachments for row in self.env.db_query(""" SELECT DISTINCT type, id FROM attachment """): for attachment in Attachment.select(self.env, row[0], row[1]): Subscription.from_attachment(self.env, attachment) # Create a subscription for all existing revisions rm = RepositoryManager(self.env) repos = rm.get_real_repositories() for repo in repos: _rev = repo.get_oldest_rev() while _rev: try: _cs = repo.get_changeset(_rev) Subscription.from_changeset(self.env, _cs) except NoSuchChangeset: pass _rev = repo.next_rev(_rev) # Create a subscription for all existing comments comments = Comments(None, self.env).all() for comment in comments: Subscription.from_comment(self.env, comment)
def test_rename_page(self): cursor = self.db.cursor() data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) cursor.execute("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) cursor.execute( "SELECT version,time,author,ipnr,text,comment," "readonly FROM wiki WHERE name=%s", ('PageRenamed', )) self.assertEqual(data, cursor.fetchone()) self.assertEqual(None, cursor.fetchone()) 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', self.db) old_page = WikiPage(self.env, 'TestPage') self.assertEqual(False, old_page.exists) cursor.execute( "SELECT version,time,author,ipnr,text,comment," "readonly FROM wiki WHERE name=%s", ('TestPage', )) self.assertEqual(None, cursor.fetchone()) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0])
def _render_confirm_delete(self, req, page): req.perm(page.resource).require('WIKI_DELETE') version = None if 'delete_version' in req.args: version = int(req.args.get('version', 0)) old_version = int(req.args.get('old_version') or 0) or 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, ipnr 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, None
def reparent_blog_attachments(env, orig_name, new_name): """ Re-associate blog post attachments to FullBlog posts """ cnx = env.get_db_cnx() cur = cnx.cursor() new_dir = Attachment(env, 'blog', new_name).path attachment_paths = list() for attachment in Attachment.select(env, 'wiki', orig_name): if os.path.exists(os.path.join(new_dir, attachment.filename)): print "Attachment", attachment.filename, "already where it should be" continue if not os.path.exists(attachment.path): raise Exception("Cannot find attachment %s for post %s" % (attachment.filename, orig_name)) attachment_paths.append(attachment.path) try: cur.execute( "UPDATE attachment " "SET type = 'blog', id = %s " "WHERE type = 'wiki' AND id = %s", (new_name, orig_name)) except Exception, e: print("Unable to import blog attachment %s into the FullBlog: %s" % (orig_name, e)) raise
def listAttachments(self, req, ticket): """ Lists attachments for a given ticket. Returns (filename, description, size, time, author) for each attachment.""" attachments = [] for a in Attachment.select(self.env, 'ticket', ticket): if 'ATTACHMENT_VIEW' in req.perm(a.resource): yield (a.filename, a.description, a.size, a.date, a.author)
def test_rename_page(self): cursor = self.db.cursor() data = (1, 42, 'joe', '::1', 'Bla bla', 'Testing', 0) cursor.execute("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) cursor.execute("SELECT version,time,author,ipnr,text,comment," "readonly FROM wiki WHERE name=%s", ('PageRenamed',)) self.assertEqual(data, cursor.fetchone()) self.assertEqual(None, cursor.fetchone()) 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', self.db) old_page = WikiPage(self.env, 'TestPage') self.assertEqual(False, old_page.exists) cursor.execute("SELECT version,time,author,ipnr,text,comment," "readonly FROM wiki WHERE name=%s", ('TestPage',)) self.assertEqual(None, cursor.fetchone()) listener = TestWikiChangeListener(self.env) self.assertEqual((page, 'TestPage'), listener.renamed[0])
def images(self, ticket, href=None): """returns images for a ticket""" # construct a ticket from an id if isinstance(ticket, int): ticket = Ticket(self.env, ticket) if not ticket.exists: return {} attachments = list(Attachment.select(self.env, 'ticket', ticket.id)) images = {} for attachment in attachments: try: filename, category = self.image_category(attachment) except TypeError: continue images.setdefault(filename, {})[category] = attachment.filename if href is not None: # turn the keys into links for values in images.values(): for key, value in values.items(): values[key] = href('attachment', 'ticket', ticket.id, value, format='raw') return images
def _do_seed(self): # Create a subscription for all existing attachments cursor = self.env.get_read_db().cursor() cursor.execute("SELECT DISTINCT type, id FROM attachment") rows = cursor.fetchall() for row in rows: for attachment in Attachment.select(self.env, row[0], row[1]): Subscription.from_attachment(self.env, attachment) # Create a subscription for all existing revisions rm = RepositoryManager(self.env) repos = rm.get_real_repositories() for repo in repos: _rev = repo.get_oldest_rev() while _rev: try: _cs = repo.get_changeset(_rev) Subscription.from_changeset(self.env, _cs) except NoSuchChangeset: pass _rev = repo.next_rev(_rev) # Create a subscription for all existing comments comments = Comments(None, self.env).all() for comment in comments: Subscription.from_comment(self.env, comment)
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 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 reparent_blog_attachments(env, orig_name, new_name): """ Re-associate blog post attachments to FullBlog posts """ cnx = env.get_db_cnx() cur = cnx.cursor() new_dir = Attachment(env, 'blog', new_name).path attachment_paths = list() for attachment in Attachment.select(env, 'wiki', orig_name): if os.path.exists(os.path.join(new_dir, attachment.filename)): print "Attachment", attachment.filename, "already where it should be" continue if not os.path.exists(attachment.path): raise Exception("Cannot find attachment %s for post %s" % ( attachment.filename, orig_name )) attachment_paths.append(attachment.path) try: cur.execute( "UPDATE attachment " "SET type = 'blog', id = %s " "WHERE type = 'wiki' AND id = %s", (new_name, orig_name) ) except Exception, e: print("Unable to import blog attachment %s into the FullBlog: %s" % (orig_name, e)) raise
def _render_attachment(self, req, cr_id, perm = False): for idx, attachment in enumerate(Attachment.select(self.env, 'CodeReview', cr_id)): hdf = attachment_to_hdf(self.env, db=self.env.get_db_cnx(), req=req, attachment=attachment) req.hdf['codereview.attachments.%s' % idx] = hdf if req.perm.has_permission('CODE_REVIEW_EDIT') and perm: req.hdf['codereview.attach_href'] = self.env.href.attachment('CodeReview', cr_id)
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_upgrading_database_moves_attachment_to_correct_product(self): ticket = self.insert_ticket('ticket') wiki = self.insert_wiki('MyWiki') attachment = self._create_file_with_content('Hello World!') self.add_attachment(ticket.resource, attachment) self.add_attachment(wiki.resource, attachment) self._enable_multiproduct() self.env.upgrade() with self.product('@'): attachments = list(Attachment.select(self.env, 'ticket', ticket.id)) attachments.extend(Attachment.select(self.env, 'wiki', wiki.name)) self.assertEqual(len(attachments), 2) for attachment in attachments: self.assertEqual(attachment.open().read(), 'Hello World!')
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 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", 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_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 test_upgrading_database_moves_attachment_to_correct_product(self): ticket = self.insert_ticket('ticket') wiki = self.insert_wiki('MyWiki') attachment = self._create_file_with_content('Hello World!') self.add_attachment(ticket.resource, attachment) self.add_attachment(wiki.resource, attachment) self._enable_multiproduct() self.env.upgrade() with self.product('@'): attachments = list( Attachment.select(self.env, 'ticket', ticket.id)) attachments.extend( Attachment.select(self.env, 'wiki', wiki.name)) self.assertEqual(len(attachments), 2) for attachment in attachments: self.assertEqual(attachment.open().read(), 'Hello World!')
def process_request(self, req): id = req.args.getint('id') req.perm('ticket', id).require('TICKET_ADMIN') ticket = Ticket(self.env, id) action = req.args['action'] cnum = req.args.get('cnum') if req.method == 'POST': if 'cancel' in req.args: href = req.href.ticket(id) if action == 'delete-comment': href += '#comment:%s' % cnum req.redirect(href) if action == 'delete': ticket.delete() add_notice( req, _("Ticket #%(num)s and all associated data " "removed.", num=ticket.id)) req.redirect(req.href()) elif action == 'delete-comment': cdate = from_utimestamp(long(req.args.get('cdate'))) ticket.delete_change(cdate=cdate) add_notice( req, _( "The ticket comment %(num)s on ticket " "#%(id)s has been deleted.", num=cnum, id=ticket.id)) req.redirect(req.href.ticket(id)) tm = TicketModule(self.env) data = tm._prepare_data(req, ticket) tm._insert_ticket_data(req, ticket, data, get_reporter_id(req, 'author'), {}) data.update(action=action, cdate=None) if action == 'delete-comment': data['cdate'] = req.args.get('cdate') cdate = from_utimestamp(long(data['cdate'])) for change in data['changes']: if change.get('date') == cdate: data['change'] = change data['cnum'] = change.get('cnum') break else: raise TracError(_("Comment %(num)s not found", num=cnum)) elif action == 'delete': attachments = Attachment.select(self.env, ticket.realm, ticket.id) data.update(attachments=list(attachments)) add_stylesheet(req, 'common/css/ticket.css') return 'ticket_delete.html', data
def test_insert(self): attachment = Attachment(self.env, 'ticket', 42) attachment.insert('foo.txt', io.BytesIO(), 0, 1) attachment = Attachment(self.env, 'ticket', 42) attachment.insert('bar.jpg', io.BytesIO(), 0, 2) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual('foo.txt', next(attachments).filename) self.assertEqual('bar.jpg', next(attachments).filename) self.assertRaises(StopIteration, next, attachments)
def test_insert(self): attachment = Attachment(self.env, 'ticket', 42) attachment.insert('foo.txt', StringIO(''), 0, 1) attachment = Attachment(self.env, 'ticket', 42) attachment.insert('bar.jpg', StringIO(''), 0, 2) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual('foo.txt', attachments.next().filename) self.assertEqual('bar.jpg', attachments.next().filename) self.assertRaises(StopIteration, attachments.next)
def test_insert(self): attachment = Attachment(self.env, 'ticket', 42) attachment.insert('foo.txt', StringIO(''), 0, 1) attachment = Attachment(self.env, 'ticket', 42) attachment.insert('bar.jpg', StringIO(''), 0, 2) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual('foo.txt', attachments.next().filename) self.assertEqual('bar.jpg', attachments.next().filename) self.assertRaises(StopIteration, attachments.next)
def test_insert(self): attachment = Attachment(self.env, 'ticket', 42) attachment.insert('foo.txt', tempfile.TemporaryFile(), 0) attachment = Attachment(self.env, 'ticket', 42) attachment.insert('bar.jpg', tempfile.TemporaryFile(), 0) attachments = Attachment.select(self.env, 'ticket', 42) self.assertEqual('foo.txt', attachments.next().filename) self.assertEqual('bar.jpg', attachments.next().filename) self.assertRaises(StopIteration, attachments.next)
def test_insert(self): attachment = Attachment(self.env, "ticket", 42) attachment.insert("foo.txt", StringIO(""), 0, 1) attachment = Attachment(self.env, "ticket", 42) attachment.insert("bar.jpg", StringIO(""), 0, 2) attachments = Attachment.select(self.env, "ticket", 42) self.assertEqual("foo.txt", attachments.next().filename) self.assertEqual("bar.jpg", attachments.next().filename) self.assertRaises(StopIteration, attachments.next)
def test_reparent_all(self): """Change the parent realm and parent id of multiple attachments. """ attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('foo.txt', io.BytesIO(), 0) attachment = Attachment(self.env, 'wiki', 'SomePage') attachment.insert('bar.txt', io.BytesIO(), 0) attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(2, len(list(attachments))) attachments = Attachment.select(self.env, 'wiki', 'WikiStart') self.assertEqual(0, len(list(attachments))) Attachment.reparent_all(self.env, 'wiki', 'SomePage', 'wiki', 'WikiStart') attachments = Attachment.select(self.env, 'wiki', 'SomePage') self.assertEqual(0, len(list(attachments))) attachments = Attachment.select(self.env, 'wiki', 'WikiStart') self.assertEqual(2, len(list(attachments)))
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 _render_attachment(self, req, cr_id, perm=False): for idx, attachment in enumerate( Attachment.select(self.env, 'CodeReview', cr_id)): hdf = attachment_to_hdf(self.env, db=self.env.get_db_cnx(), req=req, attachment=attachment) req.hdf['codereview.attachments.%s' % idx] = hdf if req.perm.has_permission('CODE_REVIEW_EDIT') and perm: req.hdf['codereview.attach_href'] = self.env.href.attachment( 'CodeReview', cr_id)
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_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 export_wiki_attachments(self, req, template_name): """Export wiki attachent files into a new wiki attachment directory. Exports files attached to wiki pages. To do this we need to export the wiki attachment data and put that into an XML file, plus we need to store the actual files in our template directory! """ # a list to return to the template with info about transaction successful_exports = list() # Get information about attachments # Not really a nice way to get all the attachments in trac/attachments attachments = list() for wiki_name in WikiSystem(self.env).get_pages(): for attachment in Attachment.select(self.env, 'wiki', wiki_name): if attachment.exists: attachments.append(attachment) # write this information to XML tree if there are attachments to export if attachments: self.log.info("Creating wiki attachment XML file for template archive") root = ET.Element("attachments", project=self.env.project_name, date=datetime.date.today().isoformat()) for attachment in attachments: ET.SubElement(root, "attachment", name=attachment.filename, parent_id=attachment.parent_id, size=str(attachment.size), version=str(attachment.version)).text = attachment.description successful_exports.append(attachment.filename) # create the xml file filename = os.path.join(self.template_dir_path, template_name, "attachment.xml") ET.ElementTree(root).write(filename) self.log.info("File %s has been created at %s" % (filename, os.path.join(self.template_dir_path, template_name))) # copy the project attachments into our new directory attachment_dir_path = os.path.join(self.env.path, 'attachments', 'wiki') attachment_template_path = os.path.join(self.template_dir_path, template_name, 'attachments', 'wiki') # the directory we copy to can't exist before shutil.copytree() try: shutil.rmtree(attachment_template_path) except OSError as exception: # no directory to remove if exception.errno == errno.ENOENT: self.log.debug("No workflow directory at %s to remove", attachment_template_path) # now copy the directory shutil.copytree(attachment_dir_path, attachment_template_path) self.log.info("Copied wiki attachments to %s", attachment_template_path) return successful_exports
def image(self, ticket): """ return the first image attachment or None if there aren't any """ attachments = list(Attachment.select(self.env, 'ticket', ticket.id)) mimeview = Mimeview(self.env) for attachment in attachments: mimetype = mimeview.get_mimetype(attachment.filename) if not mimetype or mimetype.split('/',1)[0] != 'image': continue return attachment.filename
def test_delete_milestone_with_attachment(self): milestone = Milestone(self.env) milestone.name = 'MilestoneWithAttachment' milestone.insert() attachment = Attachment(self.env, 'milestone', milestone.name) attachment.insert('foo.txt', StringIO(), 0, 1) milestone.delete() self.assertEqual(False, milestone.exists) attachments = Attachment.select(self.env, 'milestone', milestone.name) self.assertRaises(StopIteration, attachments.next)
def process_request(self, req): id = int(req.args.get('id')) req.perm('ticket', id).require('TICKET_ADMIN') ticket = Ticket(self.env, id) action = req.args['action'] cnum = req.args.get('cnum') if req.method == 'POST': if 'cancel' in req.args: href = req.href.ticket(id) if action == 'delete-comment': href += '#comment:%s' % cnum req.redirect(href) if action == 'delete': ticket.delete() add_notice(req, _('The ticket #%(id)s has been deleted.', id=ticket.id)) req.redirect(req.href()) elif action == 'delete-comment': cdate = from_utimestamp(long(req.args.get('cdate'))) ticket.delete_change(cdate=cdate) add_notice(req, _('The ticket comment %(num)s on ticket ' '#%(id)s has been deleted.', num=cnum, id=ticket.id)) req.redirect(req.href.ticket(id)) tm = TicketModule(self.env) data = tm._prepare_data(req, ticket) tm._insert_ticket_data(req, ticket, data, get_reporter_id(req, 'author'), {}) data.update(action=action, cdate=None) if action == 'delete-comment': data['cdate'] = req.args.get('cdate') cdate = from_utimestamp(long(data['cdate'])) for change in data['changes']: if change.get('date') == cdate: data['change'] = change data['cnum'] = change.get('cnum') break else: raise TracError(_('Comment %(num)s not found', num=cnum)) elif action == 'delete': attachments = Attachment.select(self.env, ticket.realm, ticket.id) data.update(attachments=list(attachments)) add_stylesheet(req, 'common/css/ticket.css') return 'ticket_delete.html', data, None
def test_process_attach_build(self): body, content_type = encode_multipart_formdata({ 'description': 'baz baz', 'file': ('baz.txt', 'hello baz'), '__FORM_TOKEN': '123456'}) args = {} for k, v in dict(cgi.FieldStorage(fp=StringIO(body), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': content_type}) ).items(): if v.filename: args[k] = v else: args[k] = v.value args.update({'collection': 'attach', 'member': 'build'}) self.assertTrue('file' in args) outheaders = {} outbody = StringIO() req = Mock(args=args, form_token='123456', authname='hal', remote_addr='127.0.0.1', send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write) config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='') config.insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.insert() module = BuildMaster(self.env) self.assertRaises(RequestDone, module._process_attachment, req, config, build) self.assertEqual(201, outheaders['Status']) self.assertEqual('18', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Attachment created', outbody.getvalue()) build_atts = list(Attachment.select(self.env, 'build', 'test/1')) self.assertEquals(1, len(build_atts)) self.assertEquals('hal', build_atts[0].author) self.assertEquals('baz baz', build_atts[0].description) self.assertEquals('baz.txt', build_atts[0].filename) self.assertEquals('hello baz', build_atts[0].open().read())
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_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': milestone.get_num_tickets(), 'retarget_to': self.default_retarget_to, 'attachments': list(attachments) } add_stylesheet(req, 'common/css/roadmap.css') return 'milestone_delete.html', data, None
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 _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 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 test_add_message_with_attachment(self): mailinglist = Mailinglist(self.env, emailaddress="LIST1", name="Sample List 1", private=True, postperm="OPEN") mailinglist.insert() mailinglist.insert_raw_email(raw_message_with_attachment % dict(sender="Jack Sparrow", email="*****@*****.**", list="list1", domain="example.com", subject="Boats", asctime=time.asctime(), id="asdfasdf", body="Need images of boats.")) message = mailinglist.conversations().next().messages().next() attachment_path = Attachment.select(self.env, message.resource.realm, message.resource.id).next().path assert os.path.exists(attachment_path) message.delete() assert not os.path.exists(attachment_path)
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 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_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 _render_view(self, req, db, page): req.perm.assert_permission("WIKI_VIEW") if page.name == "WikiStart": req.hdf["title"] = "" else: req.hdf["title"] = 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"] = history_href else: if not req.perm.has_permission("WIKI_CREATE"): raise TracError("Page %s not found" % page.name) req.hdf["wiki.page_html"] = Markup('<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 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 _insert_ticket_data(self, req, db, ticket, reporter_id): """Insert ticket data into the hdf""" req.hdf['ticket'] = ticket.values req.hdf['ticket.id'] = ticket.id req.hdf['ticket.href'] = self.env.href.ticket(ticket.id) for field in TicketSystem(self.env).get_ticket_fields(): if field['type'] in ('radio', 'select'): value = ticket.values.get(field['name']) options = field['options'] if value and not value in options: # Current ticket value must be visible even if its not in the # possible values options.append(value) field['options'] = options name = field['name'] del field['name'] if name in ('summary', 'reporter', 'description', 'type', 'status', 'resolution', 'owner'): field['skip'] = True req.hdf['ticket.fields.' + name] = field req.hdf['ticket.reporter_id'] = reporter_id req.hdf['title'] = '#%d (%s)' % (ticket.id, ticket['summary']) req.hdf['ticket.description.formatted'] = wiki_to_html(ticket['description'], self.env, req, db) req.hdf['ticket.opened'] = util.format_datetime(ticket.time_created) req.hdf['ticket.opened_delta'] = util.pretty_timedelta(ticket.time_created) if ticket.time_changed != ticket.time_created: req.hdf['ticket.lastmod'] = util.format_datetime(ticket.time_changed) req.hdf['ticket.lastmod_delta'] = util.pretty_timedelta(ticket.time_changed) changelog = ticket.get_changelog(db=db) curr_author = None curr_date = 0 changes = [] for date, author, field, old, new in changelog: if date != curr_date or author != curr_author: changes.append({ 'date': util.format_datetime(date), 'author': author, 'fields': {} }) curr_date = date curr_author = author if field == 'comment': changes[-1]['comment'] = wiki_to_html(new, self.env, req, db) elif field == 'description': changes[-1]['fields'][field] = '' else: changes[-1]['fields'][field] = {'old': old, 'new': new} req.hdf['ticket.changes'] = changes # List attached files for idx, attachment in util.enum(Attachment.select(self.env, 'ticket', ticket.id)): hdf = attachment_to_hdf(self.env, db, req, attachment) req.hdf['ticket.attachments.%s' % idx] = hdf if req.perm.has_permission('TICKET_APPEND'): req.hdf['ticket.attach_href'] = self.env.href.attachment('ticket', ticket.id) # Add the possible actions to hdf actions = TicketSystem(self.env).get_available_actions(ticket, req.perm) for action in actions: req.hdf['ticket.actions.' + action] = '1'
def listAttachments(self, req, pagename): """ Lists attachments on a given page. """ for a in Attachment.select(self.env, "wiki", pagename): if "ATTACHMENT_VIEW" in req.perm(a.resource): yield pagename + "/" + a.filename
def test_select_empty(self): self.assertRaises(StopIteration, Attachment.select(self.env, 'ticket', 42).next) self.assertRaises(StopIteration, Attachment.select(self.env, 'wiki', 'SomePage').next)