def test_delete(self): """test that we are able to delete Products""" product = list(Product.select(self.env, where={'prefix':'tp'}))[0] product.delete() post = list(Product.select(self.env, where={'prefix':'tp'})) self.assertEqual(0, len(post))
def test_select(self): """tests that select can search Products by fields""" p2_data = {'prefix':'tp2', 'name':'test project 2', 'description':'a different test project'} p3_data = {'prefix':'tp3', 'name':'test project 3', 'description':'test project'} product2 = Product(self.env) product2._data.update(p2_data) product3 = Product(self.env) product3._data.update(p3_data) product2.insert() product3.insert() products = list(Product.select(self.env, where={'prefix':'tp'})) self.assertEqual(1, len(products)) products = list(Product.select(self.env, where={'name':'test project'})) self.assertEqual(1, len(products)) products = list(Product.select(self.env, where={'prefix':'tp3', 'name':'test project 3'})) self.assertEqual(1, len(products))
def _do_save(self, req, product): """common processing for product save events""" req.perm.require('PRODUCT_VIEW') name = req.args.get('name') prefix = req.args.get('prefix') description = req.args.get('description', '') owner = req.args.get('owner') or req.authname keys = {'prefix': prefix} field_data = {'name': name, 'description': description, 'owner': owner, } warnings = [] def warn(msg): add_warning(req, msg) warnings.append(msg) if product._exists: if name != product.name and Product.select(self.env, where={'name': name}): warn(_('A product with name "%(name)s" already exists, please ' 'choose a different name.', name=name)) elif not name: warn(_('You must provide a name for the product.')) else: req.perm.require('PRODUCT_MODIFY') product.update_field_dict(field_data) product.update(req.authname) add_notice(req, _('Your changes have been saved.')) else: req.perm.require('PRODUCT_CREATE') if not prefix: warn(_('You must provide a prefix for the product.')) elif Product.select(self.env, where={'prefix': prefix}): warn(_('Product "%(id)s" already exists, please choose another ' 'prefix.', id=prefix)) if not name: warn(_('You must provide a name for the product.')) elif Product.select(self.env, where={'name': name}): warn(_('A product with name "%(name)s" already exists, please ' 'choose a different name.', name=name)) if not warnings: prod = Product(self.env) prod.update_field_dict(keys) prod.update_field_dict(field_data) prod.insert() add_notice(req, _('The product "%(id)s" has been added.', id=prefix)) if warnings: product.update_field_dict(keys) product.update_field_dict(field_data) return self._render_editor(req, product) req.redirect(req.href.products(prefix))
def test_update(self): """tests that we can use update to push data to the database""" product = list(Product.select(self.env, where={'prefix':'tp'}))[0] self.assertEqual('test project', product._data['name']) new_data = {'prefix':'tp', 'name':'updated', 'description':'nothing'} product._data.update(new_data) product.update() comp_product = list(Product.select(self.env, where={'prefix':'tp'}))[0] self.assertEqual('updated', comp_product._data['name'])
def lookup_env(cls, env, prefix=None, name=None): """Instantiate environment according to product prefix or name @throws LookupError if no product matches neither prefix nor name """ if isinstance(env, ProductEnvironment): global_env = env.parent else: global_env = env # FIXME: Update if multiproduct.dbcursor.GLOBAL_PRODUCT != '' if not prefix and not name: return global_env elif isinstance(env, ProductEnvironment) and \ env.product.prefix == prefix: return env if prefix: try: return ProductEnvironment(global_env, prefix) except LookupError: if not name: raise if name: # Lookup product by name products = Product.select(global_env, where={'name' : name}) if products: return ProductEnvironment(global_env, products[0]) else: raise LookupError("Missing product '%s'" % (name,)) else: raise LookupError("Mising product '%s'" % (prefix or name,))
def find_ticket(self, ticket_spec): ticket = None m = re.match(r'#?(?P<tid>\d+)', ticket_spec) if m: tid = m.group('tid') try: ticket = Ticket(self.env, tid) except ResourceNotFound: # ticket not found in current product, try all other products for p in Product.select(self.env): if p.prefix != self.env.product.prefix: # TODO: check for PRODUCT_VIEW permissions penv = ProductEnvironment(self.env.parent, p.prefix) try: ticket = Ticket(penv, tid) except ResourceNotFound: pass else: break # ticket still not found, use fallback for <prefix>:ticket:<id> syntax if ticket is None: try: resource = ResourceIdSerializer.get_resource_by_id(ticket_spec) ticket = self._create_ticket_by_full_id(resource) except: raise NoSuchTicketError return ticket
def test_update_key_change(self): """tests that we raise an error for attempting to update key fields""" bad_data = {'prefix':'tp0', 'name':'update', 'description':'nothing'} product = list(Product.select(self.env, where={'prefix':'tp'}))[0] product._data.update(bad_data) self.assertRaises(TracError, product.update)
def _render_list(self, req): """products list""" products = [p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', p.prefix))] data = {'products': products, 'context': web_context(req, Resource('product', None))} return 'product_list.html', data, None
def test_field_set(self): """tests that we can use table.field = something to set field data""" prefix = self.default_data['prefix'] product = list(Product.select(self.env, where={'prefix':prefix}))[0] new_description = 'test change of description' product.description = new_description self.assertEqual(new_description, product.description)
def test_field_data_get(self): """tests that we can use table.field syntax to get to the field data""" prefix = self.default_data['prefix'] name = self.default_data['name'] description = self.default_data['description'] product = list(Product.select(self.env, where={'prefix': prefix}))[0] self.assertEqual(prefix, product.prefix) self.assertEqual(name, product.name) self.assertEqual(description, product.description)
def test_field_data_get(self): """tests that we can use table.field syntax to get to the field data""" prefix = self.default_data['prefix'] name = self.default_data['name'] description = self.default_data['description'] product = list(Product.select(self.env, where={'prefix':prefix}))[0] self.assertEqual(prefix, product.prefix) self.assertEqual(name, product.name) self.assertEqual(description, product.description)
def _render_list(self, req): """products list""" products = [p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', p.prefix))] map(lambda p: setattr(p, 'href', resolve_product_href( lookup_product_env(self.env, p.prefix), self.env)), products) data = {'products': products, 'context': web_context(req, Resource('product', None))} return 'product_list.html', data, None
def test_update_key_change(self): """tests that we raise an error for attempting to update key fields""" bad_data = { 'prefix': 'tp0', 'name': 'update', 'description': 'nothing' } product = list(Product.select(self.env, where={'prefix': 'tp'}))[0] product._data.update(bad_data) self.assertRaises(TracError, product.update)
def test_migrating_to_multiproduct_with_custom_default_prefix(self): ticket = self.insert_ticket('ticket') self.env.config.set('multiproduct', 'default_product_prefix', 'xxx') self._enable_multiproduct() self.env.upgrade() products = Product.select(self.env) self.assertEqual(len(products), 1) self.assertEqual(products[0].prefix, 'xxx')
def _render_list(self, req): """products list""" products = [ p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', p.prefix)) ] data = { 'products': products, 'context': web_context(req, Resource('product', None)) } return 'product_list.html', data, None
def test_insert(self): """test saving new Product""" data = {'prefix':'new', 'name':'new', 'description':'new'} product = Product(self.env) product._data.update(data) product.insert() check_products = list(Product.select(self.env, where={'prefix':'new'})) self.assertEqual(product._data['prefix'], check_products[0]._data['prefix']) self.assertEqual(1, len(check_products))
def get_product_list(cls, env, req, href_fcn=None): """Returns a list of products as (prefix, name, url) tuples """ if href_fcn is None: href_fcn = req.href.products product_list = [] for product in Product.select(env): if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', product.prefix). child(product.resource)): product_list.append((product.prefix, product.name, href_fcn(product.prefix))) return product_list
def get_product_list(cls, env, req, href_fcn=None): """Returns a list of products as (prefix, name, url) tuples """ if href_fcn is None: href_fcn = req.href.products product_list = [] for product in Product.select(env): if 'PRODUCT_VIEW' in req.perm( Neighborhood('product', product.prefix).child(product.resource)): product_list.append( (product.prefix, product.name, href_fcn(product.prefix))) return product_list
def _render_list(self, req): """products list""" products = [ p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', p.prefix)) ] map( lambda p: setattr( p, 'href', resolve_product_href(lookup_product_env(self.env, p.prefix), self.env)), products) data = { 'products': products, 'context': web_context(req, Resource('product', None)) } return 'product_list.html', data, None
def pre_process_request(self, req, handler): """pre process request filter""" pid = None match = PRODUCT_RE.match(req.path_info) if match: dispatcher = self.env[RequestDispatcher] if dispatcher is None: raise TracError('Unable to load RequestDispatcher.') pid = match.group('pid') if pid: products = Product.select(self.env, where={'prefix': pid}) if pid and len(products) == 1: req.args['productid'] = pid req.args['product'] = products[0].name if handler is self and match.group('pathinfo') not in ('', '/'): # select a new handler environ = req.environ.copy() pathinfo = environ['PATH_INFO'].split('/') pathinfo = '/'.join(pathinfo[:1] + pathinfo[3:]) environ['PATH_INFO'] = pathinfo newreq = Request(environ, lambda *args, **kwds: None) new_handler = None for hndlr in dispatcher.handlers: if hndlr is not self and hndlr.match_request(newreq): new_handler = hndlr req.args.update(newreq.args) break if new_handler is None: if req.path_info.endswith('/'): target = req.path_info.rstrip('/').encode('utf-8') if req.query_string: target += '?' + req.query_string req.redirect(req.href + target, permanent=True) raise HTTPNotFound('No handler matched request to %s', req.path_info) handler = new_handler else: raise ResourceNotFound( _("Product %(id)s does not exist.", id=pid), _("Invalid product id")) return handler
def pre_process_request(self, req, handler): """pre process request filter""" pid = None match = PRODUCT_RE.match(req.path_info) if match: dispatcher = self.env[RequestDispatcher] if dispatcher is None: raise TracError('Unable to load RequestDispatcher.') pid = match.group('pid') if pid: products = Product.select(self.env, where={'prefix': pid}) if pid and len(products) == 1: req.args['productid'] = pid req.args['product'] = products[0].name if handler is self and match.group('pathinfo') not in ('', '/'): # select a new handler environ = req.environ.copy() pathinfo = environ['PATH_INFO'].split('/') pathinfo = '/'.join(pathinfo[:1] + pathinfo[3:]) environ['PATH_INFO'] = pathinfo newreq = Request(environ, lambda *args, **kwds: None) new_handler = None for hndlr in dispatcher.handlers: if hndlr is not self and hndlr.match_request(newreq): new_handler = hndlr req.args.update(newreq.args) break if new_handler is None: if req.path_info.endswith('/'): target = req.path_info.rstrip('/').encode('utf-8') if req.query_string: target += '?' + req.query_string req.redirect(req.href + target, permanent=True) raise HTTPNotFound('No handler matched request to %s', req.path_info) handler = new_handler else: raise ResourceNotFound(_("Product %(id)s does not exist.", id=pid), _("Invalid product id")) return handler
def process_request(self, req): """Override for TicketModule process_request""" ticketid = req.args.get('id') productid = req.args.get('productid', '') if not ticketid: # if /newticket is executed in global scope (from QCT), redirect # the request to /products/<first_product_in_DB>/newticket if not productid and \ not isinstance(self.env, ProductEnvironment): default_product = self.env.config.get('ticket', 'default_product') products = Product.select(self.env, {'fields': ['prefix']}) prefixes = [prod.prefix for prod in products] if not default_product or default_product not in prefixes: default_product = products[0].prefix req.redirect(req.href.products(default_product, 'newticket')) return self._process_newticket_request(req) if req.path_info in ('/newticket', '/products'): raise TracError(_("id can't be set for a new ticket request.")) if isinstance(self.env, ProductEnvironment): ticket = Ticket(self.env, ticketid) if productid and ticket['product'] != productid: msg = "Ticket %(id)s in product '%(prod)s' does not exist." raise ResourceNotFound(_(msg, id=ticketid, prod=productid), _("Invalid ticket number")) return self._process_ticket_request(req) # executed in global scope -> assume ticketid=UID, redirect to product with self.env.db_direct_query as db: rows = db("""SELECT id,product FROM ticket WHERE uid=%s""", (ticketid,)) if not rows: msg = "Ticket with uid %(uid)s does not exist." raise ResourceNotFound(_(msg, uid=ticketid), _("Invalid ticket number")) tid, prefix = rows[0] req.redirect(req.href.products(prefix, 'ticket', tid))
def process_request(self, req): """Override for TicketModule process_request""" ticketid = req.args.get('id') productid = req.args.get('productid', '') if not ticketid: # if /newticket is executed in global scope (from QCT), redirect # the request to /products/<first_product_in_DB>/newticket if not productid and \ not isinstance(self.env, ProductEnvironment): default_product = self.env.config.get('ticket', 'default_product') products = Product.select(self.env, {'fields': ['prefix']}) prefixes = [prod.prefix for prod in products] if not default_product or default_product not in prefixes: default_product = products[0].prefix req.redirect(req.href.products(default_product, 'newticket')) return self._process_newticket_request(req) if req.path_info in ('/newticket', '/products'): raise TracError(_("id can't be set for a new ticket request.")) if isinstance(self.env, ProductEnvironment): ticket = Ticket(self.env, ticketid) if productid and ticket['product'] != productid: msg = "Ticket %(id)s in product '%(prod)s' does not exist." raise ResourceNotFound(_(msg, id=ticketid, prod=productid), _("Invalid ticket number")) return self._process_ticket_request(req) # executed in global scope -> assume ticketid=UID, redirect to product with self.env.db_direct_query as db: rows = db("""SELECT id,product FROM ticket WHERE uid=%s""", (ticketid, )) if not rows: msg = "Ticket with uid %(uid)s does not exist." raise ResourceNotFound(_(msg, uid=ticketid), _("Invalid ticket number")) tid, prefix = rows[0] req.redirect(req.href.products(prefix, 'ticket', tid))
def _render_link(self, context, name, label, extra='', prefix=None): """Render link to product page. """ product_env = product = None env = self.env if isinstance(env, ProductEnvironment): if (prefix is not None and env.product.prefix == prefix) \ or (prefix is None and env.name == name): product_env = env env = env.parent try: if product_env is None: if prefix is not None: product_env = ProductEnvironment(env, to_unicode(prefix)) else: product = Product.select(env, where={'name' : to_unicode(name)}) if not product: raise LookupError("Missing product") product_env = ProductEnvironment(env, to_unicode(product[0])) except LookupError: pass if product_env is not None: product = product_env.product href = resolve_product_href(to_env=product_env, at_env=self.env) if 'PRODUCT_VIEW' in context.perm(product.resource): return tag.a(label, class_='product', href=href() + extra, title=product.name) if 'PRODUCT_CREATE' in context.perm('product', name): params = [('action', 'new')] if prefix: params.append( ('prefix', prefix) ) if name: params.append( ('name', name) ) return tag.a(label, class_='missing product', href=env.href('products', params), rel='nofollow') return tag.a(label, class_='missing product')
def __init__(self, env, product, create=False): """Initialize the product environment. :param env: the global Trac environment :param product: product prefix or an instance of multiproduct.model.Product """ if not isinstance(env, trac.env.Environment): cls = self.__class__ raise TypeError("Initializer must be called with " \ "trac.env.Environment instance as first argument " \ "(got %s instance instead)" % (cls.__module__ + '.' + cls.__name__, )) ComponentManager.__init__(self) if isinstance(product, Product): if product._env is not env: raise ValueError("Product's environment mismatch") elif isinstance(product, basestring): products = Product.select(env, where={'prefix': product}) if len(products) == 1 : product = products[0] else: env.log.debug("Products for '%s' : %s", product, products) raise LookupError("Missing product %s" % (product,)) self.parent = env self.product = product self.systeminfo = [] self.setup_config() # when creating product environment, invoke `IEnvironmentSetupParticipant.environment_created` # for all setup participants that don't support multi product environments if create: for participant in self.product_setup_participants: with ComponentEnvironmentContext(self, participant): participant.environment_created()
def __init__(self, env, product, create=False): """Initialize the product environment. :param env: the global Trac environment :param product: product prefix or an instance of multiproduct.model.Product """ if not isinstance(env, trac.env.Environment): cls = self.__class__ raise TypeError("Initializer must be called with " \ "trac.env.Environment instance as first argument " \ "(got %s instance instead)" % (cls.__module__ + '.' + cls.__name__, )) ComponentManager.__init__(self) if isinstance(product, Product): if product._env is not env: raise ValueError("Product's environment mismatch") elif isinstance(product, basestring): products = Product.select(env, where={'prefix': product}) if len(products) == 1: product = products[0] else: env.log.debug("Products for '%s' : %s", product, products) raise LookupError("Missing product %s" % (product, )) self.parent = env self.product = product self.systeminfo = [] self.setup_config() # when creating product environment, invoke `IEnvironmentSetupParticipant.environment_created` # for all setup participants that don't support multi product environments if create: for participant in self.product_setup_participants: with ComponentEnvironmentContext(self, participant): participant.environment_created()
def _upgrade_system_tables(self, db, create_temp_table): # migrate system table (except wiki which is handled separately) # to a new schema # - create tables with the new schema # - populate system tables with global configuration for each product # - exception is permission table where permissions # are also populated in global scope # # permission table specifics: 'anonymous' and 'authenticated' users # should by default have a PRODUCT_VIEW permission for all products self.log.info("Migrating system tables to a new schema") for table in self.MIGRATE_TABLES: if table == 'wiki': continue temp_table_name, cols = create_temp_table(table) for product in Product.select(self.env): self.log.info("Populating table '%s' for product '%s' ('%s')", table, product.name, product.prefix) db("""INSERT INTO %s (%s, product) SELECT %s,'%s' FROM %s""" % (table, cols, cols, product.prefix, temp_table_name)) if table == 'permission': db.executemany( """INSERT INTO permission (username, action, product) VALUES (%s, %s, %s)""", [('anonymous', 'PRODUCT_VIEW', product.prefix), ('authenticated', 'PRODUCT_VIEW', product.prefix)]) if table == 'permission': self.log.info("Populating table '%s' for global scope", table) db("""INSERT INTO %s (%s, product) SELECT %s,'%s' FROM %s""" % (table, cols, cols, '', temp_table_name)) self._drop_temp_table(db, temp_table_name) db.executemany( """INSERT INTO permission (username, action, product) VALUES (%s, %s, %s)""", [('anonymous', 'PRODUCT_VIEW', ''), ('authenticated', 'PRODUCT_VIEW', '')])
def find_ticket(self, ticket_spec): ticket = None m = re.match(r'#?(?:(?P<pid>[^-]+)-)?(?P<tid>\d+)', ticket_spec) if m: pid = m.group('pid') tid = m.group('tid') if pid: try: env = ProductEnvironment(self.env.parent, pid) ticket = Ticket(env, tid) except: pass else: try: ticket = Ticket(self.env, tid) except ResourceNotFound: # ticket not found in current product, try all other products for p in Product.select(self.env): if p.prefix != self.env.product.prefix: # TODO: check for PRODUCT_VIEW permissions penv = ProductEnvironment(self.env.parent, p.prefix) try: ticket = Ticket(penv, tid) except ResourceNotFound: pass else: break # ticket still not found, use fallback for <prefix>:ticket:<id> syntax if ticket is None: try: resource = ResourceIdSerializer.get_resource_by_id(ticket_spec) ticket = self._create_ticket_by_full_id(resource) except: raise NoSuchTicketError return ticket
def process_request(self, req): """process request handler""" req.perm.require('PRODUCT_VIEW') pid = req.args.get('productid', None) if pid: req.perm('product', pid).require('PRODUCT_VIEW') action = req.args.get('action', 'view') products = [p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(p.resource)] if pid is not None: add_link(req, 'up', req.href.products(), _('Products')) try: product = Product(self.env, {'prefix': pid}) except ResourceNotFound: product = Product(self.env) data = {'product': product, 'context': web_context(req, product.resource)} if req.method == 'POST': if req.args.has_key('cancel'): req.redirect(req.href.products(product.prefix)) elif action == 'edit': return self._do_save(req, product) elif action == 'delete': req.perm(product.resource).require('PRODUCT_DELETE') retarget_to = req.args.get('retarget', None) name = product.name product.delete(resources_to=retarget_to) add_notice(req, _('The product "%(n)s" has been deleted.', n = name)) req.redirect(req.href.products()) elif action in ('new', 'edit'): return self._render_editor(req, product) elif action == 'delete': req.perm(product.resource).require('PRODUCT_DELETE') return 'product_delete.html', data, None if pid is None: data = {'products': products, 'context': web_context(req, Resource('products', None))} return 'product_list.html', data, None def add_product_link(rel, product): href = req.href.products(product.prefix) add_link(req, rel, href, _('Product "%(name)s"', name=product.name)) idx = [i for i, p in enumerate(products) if p.name == product.name] if idx: idx = idx[0] if idx > 0: add_product_link('first', products[0]) add_product_link('prev', products[idx - 1]) if idx < len(products) - 1: add_product_link('next', products[idx + 1]) add_product_link('last', products[-1]) prevnext_nav(req, _('Previous Product'), _('Next Product'), _('Back to Product List')) return 'product_view.html', data, None
def load_product(prefix): products = Product.select(self.env, where={'prefix': prefix}) if not products: raise LookupError('Missing product %s' % (prefix, )) else: return products[0]
def load_product(self, prefix): products = Product.select(self.env, where={'prefix' : prefix}) if not products: raise AdminCommandError('Unknown product %s' % (prefix,)) return products[0]
def test_upgrade_creates_default_product(self): self._enable_multiproduct() self.env.upgrade() products = Product.select(self.env) self.assertEqual(len(products), 1)
def process_request(self, req): """process request handler""" req.perm.require('PRODUCT_VIEW') pid = req.args.get('productid', None) action = req.args.get('action', 'view') products = [ p for p in Product.select(self.env) if 'PRODUCT_VIEW' in req.perm(p.resource) ] if pid is not None: add_link(req, 'up', req.href.products(), _('Products')) try: product = Product(self.env, {'prefix': pid}) except ResourceNotFound: product = Product(self.env) data = {'product': product} if req.method == 'POST': if req.args.has_key('cancel'): req.redirect(req.href.products(product.prefix)) elif action == 'edit': return self._do_save(req, product) elif action == 'delete': req.perm(product.resource).require('PRODUCT_DELETE') retarget_to = req.args.get('retarget', None) name = product.name product.delete(resources_to=retarget_to) add_notice(req, _('The product "%(n)s" has been deleted.', n=name)) req.redirect(req.href.products()) elif action in ('new', 'edit'): return self._render_editor(req, product) elif action == 'delete': req.perm(product.resource).require('PRODUCT_DELETE') return 'product_delete.html', data, None if pid is None: data = {'products': products} return 'product_list.html', data, None def add_product_link(rel, product): href = req.href.products(product.prefix) add_link(req, rel, href, _('Product "%(name)s"', name=product.name)) idx = [i for i, p in enumerate(products) if p.name == product.name] if idx: idx = idx[0] if idx > 0: add_product_link('first', products[0]) add_product_link('prev', products[idx - 1]) if idx < len(products) - 1: add_product_link('next', products[idx + 1]) add_product_link('last', products[-1]) prevnext_nav(req, _('Previous Product'), _('Next Product'), _('Back to Product List')) return 'product_view.html', data, None
def resource_exists(self, resource): """Check whether product exists physically. """ products = Product.select(self.env, where={'name' : resource.id}) return bool(products)
def test_delete_twice(self): """test that we error when deleting twice on the same key""" product = list(Product.select(self.env, where={'prefix':'tp'}))[0] product.delete() self.assertRaises(TracError, product.delete)
def _replace_product_on_ticket_with_product_prefix(self, db): for prod in Product.select(self.env): db("""UPDATE ticket SET product=%s WHERE product=%s""", (prod.prefix, prod.name))
def get_products(env): return [p.prefix for p in Product.select(env)]
def _render_admin_panel(self, req, cat, page, product): req.perm.require('PRODUCT_VIEW') name = req.args.get('name') description = req.args.get('description', '') prefix = req.args.get('prefix') if product is None else product owner = req.args.get('owner') keys = {'prefix': prefix} field_data = { 'name': name, 'description': description, 'owner': owner, } # Detail view? if product: prod = Product(self.env, keys) if req.method == 'POST': if req.args.get('save'): req.perm.require('PRODUCT_MODIFY') prod.update_field_dict(field_data) prod.update() add_notice(req, _('Your changes have been saved.')) req.redirect(req.href.admin(cat, page)) elif req.args.get('cancel'): req.redirect(req.href.admin(cat, page)) Chrome(self.env).add_wiki_toolbars(req) data = {'view': 'detail', 'product': prod} else: default = self.config.get('ticket', 'default_product') if req.method == 'POST': # Add Product if req.args.get('add') and req.args.get('prefix'): req.perm.require('PRODUCT_CREATE') if not owner: add_warning(req, _('All fields are required!')) req.redirect(req.href.admin(cat, page)) try: prod = Product(self.env, keys) except ResourceNotFound: prod = Product(self.env) prod.update_field_dict(keys) prod.update_field_dict(field_data) prod.insert() add_notice( req, _('The product "%(id)s" has been added.', id=prefix)) req.redirect(req.href.admin(cat, page)) else: if prod.prefix is None: raise TracError(_('Invalid product id.')) raise TracError( _("Product %(id)s already exists.", id=prefix)) # Remove product elif req.args.get('remove'): raise TracError(_('Product removal is not allowed!')) # Set default product elif req.args.get('apply'): prefix = req.args.get('default') if prefix and prefix != default: self.log.info("Setting default product to %s", prefix) self.config.set('ticket', 'default_product', prefix) _save_config(self.config, req, self.log) req.redirect(req.href.admin(cat, page)) products = Product.select(self.env) data = {'view': 'list', 'products': products, 'default': default} if self.config.getbool('ticket', 'restrict_owner'): perm = PermissionSystem(self.env) def valid_owner(username): return perm.get_user_permissions(username).get('TICKET_MODIFY') data['owners'] = [ username for username, name, email in self.env.get_known_users() if valid_owner(username) ] data['owners'].insert(0, '') data['owners'].sort() else: data['owners'] = None return 'admin_products.html', data
def _do_product_list(self): if not isinstance(self.env, ProductEnvironment): print_table( [(p.prefix, p.owner, p.name) for p in Product.select(self.env)], [_('Prefix'), _('Owner'), _('Name')])
def load_product(self, prefix): products = Product.select(self.env, where={'prefix': prefix}) if not products: raise AdminCommandError('Unknown product %s' % (prefix, )) return products[0]
def _render_admin_panel(self, req, cat, page, product): req.perm.require('PRODUCT_VIEW') name = req.args.get('name') description = req.args.get('description','') prefix = req.args.get('prefix') if product is None else product owner = req.args.get('owner') keys = {'prefix':prefix} field_data = {'name':name, 'description':description, 'owner':owner, } data = {} # Detail view? if product: prod = Product(self.env, keys) if req.method == 'POST': if req.args.get('save'): req.perm.require('PRODUCT_MODIFY') prod.update_field_dict(field_data) prod.update(req.authname) add_notice(req, _('Your changes have been saved.')) req.redirect(req.href.admin(cat, page)) elif req.args.get('cancel'): req.redirect(req.href.admin(cat, page)) Chrome(self.env).add_wiki_toolbars(req) data = {'view': 'detail', 'product': prod} else: default = self.config.get('ticket', 'default_product') if req.method == 'POST': # Add Product if req.args.get('add'): req.perm.require('PRODUCT_CREATE') if not (prefix and name and owner): if not prefix: add_warning(req, _("You must provide a prefix " "for the product.")) if not name: add_warning(req, _("You must provide a name " "for the product.")) if not owner: add_warning(req, _("You must provide an owner " "for the product.")) data['prefix'] = prefix data['name'] = name data['owner'] = owner else: try: prod = Product(self.env, keys) except ResourceNotFound: prod = Product(self.env) prod.update_field_dict(keys) prod.update_field_dict(field_data) prod.insert() add_notice(req, _('The product "%(id)s" has been ' 'added.', id=prefix)) req.redirect(req.href.admin(cat, page)) else: if prod.prefix is None: raise TracError(_('Invalid product id.')) raise TracError(_("Product %(id)s already exists.", id=prefix)) # Remove product elif req.args.get('remove'): raise TracError(_('Product removal is not allowed!')) # Set default product elif req.args.get('apply'): prefix = req.args.get('default') if prefix and prefix != default: self.log.info("Setting default product to %s", prefix) self.config.set('ticket', 'default_product', prefix) _save_config(self.config, req, self.log) req.redirect(req.href.admin(cat, page)) # Clear default product elif req.args.get('clear'): self.log.info("Clearing default product") self.config.set('ticket', 'default_product', '') _save_config(self.config, req, self.log) req.redirect(req.href.admin(cat, page)) data['view'] = 'list' data['products'] = Product.select(self.env) data['default'] = default if self.config.getbool('ticket', 'restrict_owner'): perm = PermissionSystem(self.env) def valid_owner(username): return perm.get_user_permissions(username).get('TICKET_MODIFY') data['owners'] = [username for username, name, email in self.env.get_known_users() if valid_owner(username)] data['owners'].insert(0, '') data['owners'].sort() else: data['owners'] = None return 'admin_products.html', data
def all_product_envs(self): return [ProductEnvironment(self, product) for product in Product.select(self)]
def load_product(prefix): products = Product.select(self.env, where={'prefix' : prefix}) if not products: raise LookupError('Missing product %s' % (prefix,)) else: return products[0]
def _do_save(self, req, product): """common processing for product save events""" req.perm.require('PRODUCT_VIEW') name = req.args.get('name') prefix = req.args.get('prefix') description = req.args.get('description', '') owner = req.args.get('owner') or req.authname keys = {'prefix': prefix} field_data = { 'name': name, 'description': description, 'owner': owner, } warnings = [] def warn(msg): add_warning(req, msg) warnings.append(msg) if product._exists: if name != product.name and Product.select(self.env, where={'name': name}): warn( _( 'A product with name "%(name)s" already exists, please ' 'choose a different name.', name=name)) elif not name: warn(_('You must provide a name for the product.')) else: req.perm.require('PRODUCT_MODIFY') product.update_field_dict(field_data) product.update(req.authname) add_notice(req, _('Your changes have been saved.')) else: req.perm.require('PRODUCT_CREATE') if not prefix: warn(_('You must provide a prefix for the product.')) elif Product.select(self.env, where={'prefix': prefix}): warn( _( 'Product "%(id)s" already exists, please choose another ' 'prefix.', id=prefix)) if not name: warn(_('You must provide a name for the product.')) elif Product.select(self.env, where={'name': name}): warn( _( 'A product with name "%(name)s" already exists, please ' 'choose a different name.', name=name)) if not warnings: prod = Product(self.env) prod.update_field_dict(keys) prod.update_field_dict(field_data) prod.insert() add_notice( req, _('The product "%(id)s" has been added.', id=prefix)) if warnings: product.update_field_dict(keys) product.update_field_dict(field_data) return self._render_editor(req, product) req.redirect(req.href.products(prefix))
def all_product_envs(self): return [ ProductEnvironment(self, product) for product in Product.select(self) ]
def _do_product_list(self): if not isinstance(self.env, ProductEnvironment): print_table([(p.prefix, p.owner, p.name) for p in Product.select(self.env)], [_('Prefix'), _('Owner'), _('Name')])