Ejemplo n.º 1
0
    def add_template_data(self, req, data, tickets):
        if isinstance(self.env, ProductEnvironment):
            super(ProductBatchModifyModule, self).add_template_data(req, data,
                                                                    tickets)
            return

        data['batch_modify'] = True
        data['query_href'] = req.session['query_href'] or req.href.query()

        tickets_by_product = {}
        for t in tickets:
            tickets_by_product.setdefault(t['product'], []).append(t)

        data['action_controls'] = []
        global_env = ProductEnvironment.lookup_global_env(self.env)
        cache = {}
        for k, v in tickets_by_product.iteritems():
            batch_module = cache.get(k or '')
            if batch_module is None:
                env = ProductEnvironment(global_env, k) if k else global_env
                cache[k] = batch_module = ProductBatchModifyModule(env)
            data['action_controls'] += batch_module._get_action_controls(req,
                                                                         v)
        batch_list_modes = [
            {'name': _("add"), 'value': "+"},
            {'name': _("remove"), 'value': "-"},
            {'name': _("add / remove"), 'value': "+-"},
            {'name': _("set to"), 'value': "="},
        ]
        add_script_data(req, batch_list_modes=batch_list_modes,
                        batch_list_properties=self._get_list_fields())
Ejemplo n.º 2
0
    def add_template_data(self, req, data, tickets):
        if isinstance(self.env, ProductEnvironment):
            super(ProductBatchModifyModule, self).add_template_data(req, data,
                                                                    tickets)
            return

        data['batch_modify'] = True
        data['query_href'] = req.session['query_href'] or req.href.query()

        tickets_by_product = {}
        for t in tickets:
            tickets_by_product.setdefault(t['product'], []).append(t)

        data['action_controls'] = []
        global_env = ProductEnvironment.lookup_global_env(self.env)
        cache = {}
        for k, v in tickets_by_product.iteritems():
            batch_module = cache.get(k or '')
            if batch_module is None:
                env = ProductEnvironment(global_env, k) if k else global_env
                cache[k] = batch_module = ProductBatchModifyModule(env)
            data['action_controls'] += batch_module._get_action_controls(req,
                                                                         v)
        batch_list_modes = [
            {'name': _("add"), 'value': "+"},
            {'name': _("remove"), 'value': "-"},
            {'name': _("add / remove"), 'value': "+-"},
            {'name': _("set to"), 'value': "="},
        ]
        add_script_data(req, batch_list_modes=batch_list_modes,
                        batch_list_properties=self._get_list_fields())
Ejemplo n.º 3
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))
Ejemplo n.º 4
0
 def load_manager(self, neighborhood):
     """Load global environment or product environment given its prefix
     """
     if neighborhood._realm == 'global':
         # FIXME: ResourceNotFound if neighborhood ID != None ?
         prefix = GLOBAL_PRODUCT
     elif neighborhood._realm == 'product':
         prefix = neighborhood._id
     else:
         raise ResourceNotFound(_(u'Unsupported neighborhood %(realm)s',
                                  realm=neighborhood._realm))
     try:
         return lookup_product_env(self.env, prefix)
     except LookupError:
         raise ResourceNotFound(_(u'Unknown product prefix %(prefix)s',
                                  prefix=prefix))
Ejemplo n.º 5
0
 def load_manager(self, neighborhood):
     """Load global environment or product environment given its prefix
     """
     if neighborhood._realm == 'global':
         # FIXME: ResourceNotFound if neighborhood ID != None ?
         prefix = GLOBAL_PRODUCT
     elif neighborhood._realm == 'product':
         prefix = neighborhood._id
     else:
         raise ResourceNotFound(_(u'Unsupported neighborhood %(realm)s',
                                  realm=neighborhood._realm))
     try:
         return lookup_product_env(self.env, prefix)
     except LookupError:
         raise ResourceNotFound(_(u'Unknown product prefix %(prefix)s',
                                  prefix=prefix))
Ejemplo n.º 6
0
 def get_resource_description(self, resource, format='default', context=None,
                              **kwargs):
     """Describe product resource.
     """
     desc = resource.id
     if format != 'compact':
         desc = _('Product %(name)s', name=resource.id)
     if context:
         return self._render_link(context, resource.id, desc)
     else:
         return desc
Ejemplo n.º 7
0
 def get_resource_description(self, resource, format='default', context=None,
                              **kwargs):
     """Describe product resource.
     """
     desc = resource.id
     if format != 'compact':
         desc = _('Product %(name)s', name=resource.id)
     if context:
         return self._render_link(context, resource.id, desc)
     else:
         return desc
Ejemplo n.º 8
0
    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))
Ejemplo n.º 9
0
    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))
Ejemplo n.º 10
0
 def process_request(self, req):
     """Anticipate permission error to hijack admin panel dispatching
     process in product context if `TRAC_ADMIN` expectations are not met.
     """
     # TODO: Verify `isinstance(self.env, ProductEnvironment)` once again ?
     cat_id = req.args.get('cat_id')
     panel_id = req.args.get('panel_id')
     if self._check_panel(cat_id, panel_id):
         with sudo(req):
             return self.global_process_request(req)
     else:
         raise HTTPNotFound(_('Unknown administration panel'))
Ejemplo n.º 11
0
 def validate_ticket(self, req, ticket):
     # check whether the owner exists in db, add a warning if not
     if req.args.get('action') == 'reassign' and \
        ticket['owner'] != self.env.config.get('ticket', 'default_owner'):
         owner = self.env.db_direct_query(
             "SELECT sid FROM session WHERE sid=%s",
             (ticket['owner'], ))
         if not owner:
             # Note: add_warning() is used intead of returning a list of
             # error tuples, since the latter results in trac rendering
             # errors (ticket's change.date is not populated)
             add_warning(req, _('The user "%s" does not exist.') %
                 ticket['owner'])
     return []
Ejemplo n.º 12
0
 def validate_ticket(self, req, ticket):
     # check whether the owner exists in db, add a warning if not
     if req.args.get('action') == 'reassign' and \
        ticket['owner'] != self.env.config.get('ticket', 'default_owner'):
         owner = self.env.db_direct_query(
             "SELECT sid FROM session WHERE sid=%s",
             (ticket['owner'], ))
         if not owner:
             # Note: add_warning() is used intead of returning a list of
             # error tuples, since the latter results in trac rendering
             # errors (ticket's change.date is not populated)
             add_warning(req, _('The user "%s" does not exist.') %
                 ticket['owner'])
     return []
Ejemplo n.º 13
0
 def _do_product_admin(self, prefix, *args):
     mgr = self.product_admincmd_mgr(prefix)
     if args and args[0] in self.GLOBAL_COMMANDS:
         raise AdminCommandError('%s command not supported for products' %
                                 (args[0],))
     if args and args[0] == 'help':
         help_args = args[1:]
         if help_args:
             doc = mgr.get_command_help(list(help_args))
             if doc:
                 TracAdmin.print_doc(doc)
             else:
                 printerr(_("No documentation found for '%(cmd)s'."
                            " Use 'help' to see the list of commands.",
                            cmd=' '.join(help_args)))
                 cmds = mgr.get_similar_commands(help_args[0])
                 if cmds:
                     printout('')
                     printout(ngettext("Did you mean this?",
                                       "Did you mean one of these?",
                                       len(cmds)))
                     for cmd in cmds:
                         printout('    ' + cmd)
         else:
             printout(_("trac-admin - The Trac Administration Console "
                        "%(version)s", version=TRAC_VERSION))
             env = mgr.env
             TracAdmin.print_doc(TracAdmin.all_docs(env), short=True)
     else:
         try:
             mgr.execute_command(*args)
         except AdminCommandError, e:
             printerr(_("Error: %(msg)s", msg=to_unicode(e)))
             if e.show_usage:
                 print
                 self._do_product_admin(prefix, 'help', *args[:2])
         except:
Ejemplo n.º 14
0
 def ticket_groups():
     groups = []
     for v, g in groupby(tickets, lambda t: t[query.group]):
         q = ProductQuery.from_string(env, query_string)
         # produce the hint for the group
         q.group = q.groupdesc = None
         order = q.order
         q.order = None
         title = _("%(groupvalue)s %(groupname)s tickets matching "
                   "%(query)s", groupvalue=v, groupname=query.group,
                   query=q.to_string())
         # produce the href for the query corresponding to the group
         for constraint in q.constraints:
             constraint[str(query.group)] = v
         q.order = order
         href = q.get_href(formatter.context)
         groups.append((v, [t for t in g], href, title))
     return groups
Ejemplo n.º 15
0
    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')

        try:
            product = Product(self.env, {'prefix': pid})
        except ResourceNotFound:
            product = Product(self.env)

        path_info = req.args.get('pathinfo')
        if path_info and path_info != '/':
            if not product._exists:
                # bh:ticket:561 - Display product list and warning message
                if pid:
                    add_warning(req, _("Product %(pid)s not found", pid=pid))
                return self._render_list(req)
            else:
                raise HTTPNotFound(
                    _('Unable to render product page. Wrong setup?'))

        if pid:
            add_link(req, 'up', req.href.products(), _('Products'))

        action = req.args.get('action', 'view')
        if req.method == 'POST':
            if 'cancel' in req.args:
                req.redirect(req.href.products(product.prefix))
            elif action == 'edit':
                return self._do_save(req, product)
            elif action == 'delete':
                raise TracError(_('Product removal is not allowed!'))
        elif action in ('new', 'edit'):
            return self._render_editor(req, product)
        elif action == 'delete':
            raise TracError(_('Product removal is not allowed!'))

        if not product._exists:
            if pid:
                # bh:ticket:561 - Display product list and warning message
                add_warning(req, _("Product %(pid)s not found", pid=pid))
            return self._render_list(req)

        data = {
            'product': product,
            'context': web_context(req, product.resource)
        }
        return 'product_view.html', data, None
Ejemplo n.º 16
0
    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')

        try:
            product = Product(self.env, {'prefix': pid})
        except ResourceNotFound:
            product = Product(self.env)

        path_info = req.args.get('pathinfo')
        if path_info and path_info != '/':
            if not product._exists:
                # bh:ticket:561 - Display product list and warning message
                if pid:
                    add_warning(req, _("Product %(pid)s not found", pid=pid))
                return self._render_list(req)
            else:
                raise HTTPNotFound(
                    _('Unable to render product page. Wrong setup?'))

        if pid:
            add_link(req, 'up', req.href.products(), _('Products'))

        action = req.args.get('action', 'view')
        if req.method == 'POST':
            if 'cancel' in req.args:
                req.redirect(req.href.products(product.prefix))
            elif action == 'edit':
                return self._do_save(req, product)
            elif action == 'delete':
                raise TracError(_('Product removal is not allowed!'))
        elif action in ('new', 'edit'):
            return self._render_editor(req, product)
        elif action == 'delete':
            raise TracError(_('Product removal is not allowed!'))

        if not product._exists:
            if pid:
                # bh:ticket:561 - Display product list and warning message
                add_warning(req, _("Product %(pid)s not found", pid=pid))
            return self._render_list(req)

        data = {'product': product,
                'context': web_context(req, product.resource)}
        return 'product_view.html', data, None
Ejemplo n.º 17
0
 def ticket_groups():
     groups = []
     for v, g in groupby(tickets, lambda t: t[query.group]):
         q = ProductQuery.from_string(env, query_string)
         # produce the hint for the group
         q.group = q.groupdesc = None
         order = q.order
         q.order = None
         title = _(
             "%(groupvalue)s %(groupname)s tickets matching "
             "%(query)s",
             groupvalue=v,
             groupname=query.group,
             query=q.to_string())
         # produce the href for the query corresponding to the group
         for constraint in q.constraints:
             constraint[str(query.group)] = v
         q.order = order
         href = q.get_href(formatter.context)
         groups.append((v, [t for t in g], href, title))
     return groups
Ejemplo n.º 18
0
 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')])
Ejemplo n.º 19
0
    def execute(self, req=None, db=None, cached_ids=None, authname=None,
                tzinfo=None, href=None, locale=None):
        """Retrieve the list of matching tickets.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        with self.env.db_direct_query as db:
            cursor = db.cursor()

            self.num_items = 0
            sql, args = self.get_sql(req, cached_ids, authname, tzinfo, locale)
            if sql.startswith('SELECT ') and not sql.startswith('SELECT DISTINCT '):
                sql = 'SELECT DISTINCT * FROM (' + sql + ') AS subquery'
            if isinstance(self.env, ProductEnvironment):
                sql = sql + """ WHERE product='%s'""" % (self.env.product.prefix, )
            self.num_items = self._count(sql, args)

            if self.num_items <= self.max:
                self.has_more_pages = False

            if self.has_more_pages:
                max = self.max
                if self.group:
                    max += 1
                sql = sql + " LIMIT %d OFFSET %d" % (max, self.offset)
                if self.page > int(ceil(float(self.num_items) / self.max)) and \
                        self.num_items != 0:
                    raise TracError(_("Page %(page)s is beyond the number of "
                                      "pages in the query", page=self.page))

            # self.env.log.debug("SQL: " + sql % tuple([repr(a) for a in args]))
            cursor.execute(sql, args)
            columns = get_column_names(cursor)
            fields = []
            for column in columns:
                fields += [f for f in self.fields if f['name'] == column] or \
                          [None]
            results = []

            product_idx = columns.index('product')
            column_indices = range(len(columns))
            for row in cursor:
                result = {}
                for i in column_indices:
                    name, field, val = columns[i], fields[i], row[i]
                    if name == 'reporter':
                        val = val or 'anonymous'
                    elif name == 'id':
                        val = int(val)
                        result['href'] = self._get_ticket_href(
                            row[product_idx], val)
                    elif name in self.time_fields:
                        val = from_utimestamp(val)
                    elif field and field['type'] == 'checkbox':
                        try:
                            val = bool(int(val))
                        except (TypeError, ValueError):
                            val = False
                    elif val is None:
                        val = ''
                    result[name] = val
                results.append(result)
            cursor.close()
            return results
Ejemplo n.º 20
0
 def get_navigation_items(self, req):
     if 'REPORT_VIEW' in req.perm:
         href = ProductModule.get_product_path(self.env, req, 'report')
         yield ('mainnav', 'tickets', tag.a(_('View Tickets'), href=href))
Ejemplo n.º 21
0
 def get_navigation_items(self, req):
     if 'REPORT_VIEW' in req.perm:
         href = ProductModule.get_product_path(self.env, req, 'report')
         yield ('mainnav', 'tickets', tag.a(_('View Tickets'), href=href))
Ejemplo n.º 22
0
 def get_select_fields(self):
     """Product select fields"""
     return [(35, {'name': 'product', 'label': _('Product'),
                   'cls': Product, 'pk': 'prefix', 'optional': False,
                   'value': self.default_product})]
Ejemplo n.º 23
0
 def get_select_fields(self):
     """Product select fields"""
     return [(35, {'name': 'product', 'label': _('Product'),
                   'cls': Product, 'pk': 'prefix', 'optional': False,
                   'value': self.default_product})]
Ejemplo n.º 24
0
    def execute(self,
                req=None,
                db=None,
                cached_ids=None,
                authname=None,
                tzinfo=None,
                href=None,
                locale=None):
        """Retrieve the list of matching tickets.

        :since 1.0: the `db` parameter is no longer needed and will be removed
        in version 1.1.1
        """
        with self.env.db_direct_query as db:
            cursor = db.cursor()

            self.num_items = 0
            sql, args = self.get_sql(req, cached_ids, authname, tzinfo, locale)
            if sql.startswith(
                    'SELECT ') and not sql.startswith('SELECT DISTINCT '):
                sql = 'SELECT DISTINCT * FROM (' + sql + ') AS subquery'
            if isinstance(self.env, ProductEnvironment):
                sql = sql + """ WHERE product='%s'""" % (
                    self.env.product.prefix, )
            self.num_items = self._count(sql, args)

            if self.num_items <= self.max:
                self.has_more_pages = False

            if self.has_more_pages:
                max = self.max
                if self.group:
                    max += 1
                sql = sql + " LIMIT %d OFFSET %d" % (max, self.offset)
                if self.page > int(ceil(float(self.num_items) / self.max)) and \
                        self.num_items != 0:
                    raise TracError(
                        _(
                            "Page %(page)s is beyond the number of "
                            "pages in the query",
                            page=self.page))

            # self.env.log.debug("SQL: " + sql % tuple([repr(a) for a in args]))
            cursor.execute(sql, args)
            columns = get_column_names(cursor)
            fields = []
            for column in columns:
                fields += [f for f in self.fields if f['name'] == column] or \
                          [None]
            results = []

            product_idx = columns.index('product')
            column_indices = range(len(columns))
            for row in cursor:
                result = {}
                for i in column_indices:
                    name, field, val = columns[i], fields[i], row[i]
                    if name == 'reporter':
                        val = val or 'anonymous'
                    elif name == 'id':
                        val = int(val)
                        result['href'] = self._get_ticket_href(
                            row[product_idx], val)
                    elif name in self.time_fields:
                        val = from_utimestamp(val)
                    elif field and field['type'] == 'checkbox':
                        try:
                            val = bool(int(val))
                        except (TypeError, ValueError):
                            val = False
                    elif val is None:
                        val = ''
                    result[name] = val
                results.append(result)
            cursor.close()
            return results
Ejemplo n.º 25
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        query_string, kwargs, format = self.parse_args(content)
        if query_string:
            query_string += '&'
        query_string += '&'.join('%s=%s' % item for item in kwargs.iteritems())

        env = ProductEnvironment.lookup_global_env(self.env)
        query = ProductQuery.from_string(env, query_string)

        if format == 'count':
            cnt = query.count(req)
            return tag.span(cnt,
                            title='%d tickets for which %s' %
                            (cnt, query_string),
                            class_='query_count')

        tickets = query.execute(req)

        if format == 'table':
            data = query.template_data(formatter.context,
                                       tickets,
                                       req=formatter.context.req)

            add_stylesheet(req, 'common/css/report.css')

            return Chrome(env).render_template(req,
                                               'query_results.html',
                                               data,
                                               None,
                                               fragment=True)

        if format == 'progress':
            from trac.ticket.roadmap import (RoadmapModule,
                                             apply_ticket_permissions,
                                             get_ticket_stats,
                                             grouped_stats_data)

            add_stylesheet(req, 'common/css/roadmap.css')

            def query_href(extra_args, group_value=None):
                q = ProductQuery.from_string(env, query_string)
                if q.group:
                    extra_args[q.group] = group_value
                    q.group = None
                for constraint in q.constraints:
                    constraint.update(extra_args)
                if not q.constraints:
                    q.constraints.append(extra_args)
                return q.get_href(formatter.context)

            chrome = Chrome(env)
            tickets = apply_ticket_permissions(env, req, tickets)
            stats_provider = RoadmapModule(env).stats_provider
            by = query.group
            if not by:
                stat = get_ticket_stats(stats_provider, tickets)
                data = {
                    'stats':
                    stat,
                    'stats_href':
                    query_href(stat.qry_args),
                    'interval_hrefs': [
                        query_href(interval['qry_args'])
                        for interval in stat.intervals
                    ],
                    'legend':
                    True,
                }
                return tag.div(chrome.render_template(req,
                                                      'progress_bar.html',
                                                      data,
                                                      None,
                                                      fragment=True),
                               class_='trac-progress')

            def per_group_stats_data(gstat, group_name):
                return {
                    'stats':
                    gstat,
                    'stats_href':
                    query_href(gstat.qry_args, group_name),
                    'interval_hrefs': [
                        query_href(interval['qry_args'], group_name)
                        for interval in gstat.intervals
                    ],
                    'percent':
                    '%d / %d' % (gstat.done_count, gstat.count),
                    'legend':
                    False,
                }

            groups = grouped_stats_data(env, stats_provider, tickets, by,
                                        per_group_stats_data)
            data = {
                'groups':
                groups,
                'grouped_by':
                by,
                'summary':
                _("Ticket completion status for each %(group)s", group=by),
            }
            return tag.div(chrome.render_template(req,
                                                  'progress_bar_grouped.html',
                                                  data,
                                                  None,
                                                  fragment=True),
                           class_='trac-groupprogress')

        # Formats above had their own permission checks, here we need to
        # do it explicitly:

        tickets = [
            t for t in tickets if 'TICKET_VIEW' in req.perm('ticket', t['id'])
        ]

        if not tickets:
            return tag.span(_("No results"), class_='query_no_results')

        # Cache resolved href targets
        hrefcache = {}

        def ticket_anchor(ticket):
            try:
                pvalue = ticket.get('product') or GLOBAL_PRODUCT
                envhref = hrefcache[pvalue]
            except KeyError:
                try:
                    env = lookup_product_env(self.env,
                                             prefix=pvalue,
                                             name=pvalue)
                except LookupError:
                    return tag.a('#%s' % ticket['id'],
                                 class_='missing product')
                hrefcache[pvalue] = envhref = \
                    resolve_product_href(to_env=env, at_env=self.env)
            return tag.a('#%s' % ticket['id'],
                         class_=ticket['status'],
                         href=envhref.ticket(int(ticket['id'])),
                         title=shorten_line(ticket['summary']))

        def ticket_groups():
            groups = []
            for v, g in groupby(tickets, lambda t: t[query.group]):
                q = ProductQuery.from_string(env, query_string)
                # produce the hint for the group
                q.group = q.groupdesc = None
                order = q.order
                q.order = None
                title = _(
                    "%(groupvalue)s %(groupname)s tickets matching "
                    "%(query)s",
                    groupvalue=v,
                    groupname=query.group,
                    query=q.to_string())
                # produce the href for the query corresponding to the group
                for constraint in q.constraints:
                    constraint[str(query.group)] = v
                q.order = order
                href = q.get_href(formatter.context)
                groups.append((v, [t for t in g], href, title))
            return groups

        if format == 'compact':
            if query.group:
                groups = [
                    (v, ' ',
                     tag.a('#%s' % u',\u200b'.join(str(t['id']) for t in g),
                           href=href,
                           class_='query',
                           title=title))
                    for v, g, href, title in ticket_groups()
                ]
                return tag(groups[0], [(', ', g) for g in groups[1:]])
            else:
                alist = [ticket_anchor(ticket) for ticket in tickets]
                return tag.span(alist[0], *[(', ', a) for a in alist[1:]])
        else:
            if query.group:
                return tag.div([
                    (tag.p(
                        tag_('%(groupvalue)s %(groupname)s tickets:',
                             groupvalue=tag.a(v,
                                              href=href,
                                              class_='query',
                                              title=title),
                             groupname=query.group)),
                     tag.dl([(tag.dt(ticket_anchor(t)), tag.dd(t['summary']))
                             for t in g],
                            class_='wiki compact'))
                    for v, g, href, title in ticket_groups()
                ])
            else:
                return tag.div(
                    tag.dl([(tag.dt(
                        ticket_anchor(ticket)), tag.dd(ticket['summary']))
                            for ticket in tickets],
                           class_='wiki compact'))
Ejemplo n.º 26
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
Ejemplo n.º 27
0
 def get_admin_panels(self, req):
     if 'VERSIONCONTROL_ADMIN' in req.perm:
         yield ('versioncontrol', _('Version Control'), 'repository',
                _('Repository Links') if isinstance(self.env, ProductEnvironment)
                 else _('Repositories'))
Ejemplo n.º 28
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))
Ejemplo n.º 29
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        query_string, kwargs, format = self.parse_args(content)
        if query_string:
            query_string += '&'
        query_string += '&'.join('%s=%s' % item
                                 for item in kwargs.iteritems())

        env = ProductEnvironment.lookup_global_env(self.env)
        query = ProductQuery.from_string(env, query_string)

        if format == 'count':
            cnt = query.count(req)
            return tag.span(cnt, title='%d tickets for which %s' %
                            (cnt, query_string), class_='query_count')

        tickets = query.execute(req)

        if format == 'table':
            data = query.template_data(formatter.context, tickets,
                                       req=formatter.context.req)

            add_stylesheet(req, 'common/css/report.css')

            return Chrome(env).render_template(
                req, 'query_results.html', data, None, fragment=True)

        if format == 'progress':
            from trac.ticket.roadmap import (RoadmapModule,
                                             apply_ticket_permissions,
                                             get_ticket_stats,
                                             grouped_stats_data)

            add_stylesheet(req, 'common/css/roadmap.css')

            def query_href(extra_args, group_value=None):
                q = ProductQuery.from_string(env, query_string)
                if q.group:
                    extra_args[q.group] = group_value
                    q.group = None
                for constraint in q.constraints:
                    constraint.update(extra_args)
                if not q.constraints:
                    q.constraints.append(extra_args)
                return q.get_href(formatter.context)
            chrome = Chrome(env)
            tickets = apply_ticket_permissions(env, req, tickets)
            stats_provider = RoadmapModule(env).stats_provider
            by = query.group
            if not by:
                stat = get_ticket_stats(stats_provider, tickets)
                data = {
                    'stats': stat,
                    'stats_href': query_href(stat.qry_args),
                    'interval_hrefs': [query_href(interval['qry_args'])
                                       for interval in stat.intervals],
                    'legend': True,
                }
                return tag.div(
                    chrome.render_template(req, 'progress_bar.html', data,
                                           None, fragment=True),
                    class_='trac-progress')

            def per_group_stats_data(gstat, group_name):
                return {
                    'stats': gstat,
                    'stats_href': query_href(gstat.qry_args,  group_name),
                    'interval_hrefs': [query_href(interval['qry_args'],
                                                  group_name)
                                       for interval in gstat.intervals],
                    'percent': '%d / %d' % (gstat.done_count,
                                            gstat.count),
                    'legend': False,
                }

            groups = grouped_stats_data(env, stats_provider, tickets, by,
                                        per_group_stats_data)
            data = {
                'groups': groups, 'grouped_by': by,
                'summary': _("Ticket completion status for each %(group)s",
                             group=by),
            }
            return tag.div(
                chrome.render_template(req, 'progress_bar_grouped.html', data,
                                       None, fragment=True),
                class_='trac-groupprogress')

        # Formats above had their own permission checks, here we need to
        # do it explicitly:

        tickets = [t for t in tickets
                   if 'TICKET_VIEW' in req.perm('ticket', t['id'])]

        if not tickets:
            return tag.span(_("No results"), class_='query_no_results')

        # Cache resolved href targets
        hrefcache = {}

        def ticket_anchor(ticket):
            try:
                pvalue = ticket.get('product') or GLOBAL_PRODUCT
                envhref = hrefcache[pvalue]
            except KeyError:
                try:
                    env = lookup_product_env(self.env, prefix=pvalue,
                                             name=pvalue)
                except LookupError:
                    return tag.a('#%s' % ticket['id'],
                                 class_='missing product')
                hrefcache[pvalue] = envhref = \
                    resolve_product_href(to_env=env, at_env=self.env)
            return tag.a('#%s' % ticket['id'],
                         class_=ticket['status'],
                         href=envhref.ticket(int(ticket['id'])),
                         title=shorten_line(ticket['summary']))

        def ticket_groups():
            groups = []
            for v, g in groupby(tickets, lambda t: t[query.group]):
                q = ProductQuery.from_string(env, query_string)
                # produce the hint for the group
                q.group = q.groupdesc = None
                order = q.order
                q.order = None
                title = _("%(groupvalue)s %(groupname)s tickets matching "
                          "%(query)s", groupvalue=v, groupname=query.group,
                          query=q.to_string())
                # produce the href for the query corresponding to the group
                for constraint in q.constraints:
                    constraint[str(query.group)] = v
                q.order = order
                href = q.get_href(formatter.context)
                groups.append((v, [t for t in g], href, title))
            return groups

        if format == 'compact':
            if query.group:
                groups = [(v, ' ',
                           tag.a('#%s' % u',\u200b'.join(str(t['id'])
                                                         for t in g),
                                 href=href, class_='query', title=title))
                          for v, g, href, title in ticket_groups()]
                return tag(groups[0], [(', ', g) for g in groups[1:]])
            else:
                alist = [ticket_anchor(ticket) for ticket in tickets]
                return tag.span(alist[0], *[(', ', a) for a in alist[1:]])
        else:
            if query.group:
                return tag.div(
                    [(tag.p(tag_('%(groupvalue)s %(groupname)s tickets:',
                                 groupvalue=tag.a(v, href=href, class_='query',
                                                  title=title),
                                 groupname=query.group)),
                      tag.dl([(tag.dt(ticket_anchor(t)),
                               tag.dd(t['summary'])) for t in g],
                             class_='wiki compact'))
                     for v, g, href, title in ticket_groups()])
            else:
                return tag.div(tag.dl([(tag.dt(ticket_anchor(ticket)),
                                        tag.dd(ticket['summary']))
                                       for ticket in tickets],
                                      class_='wiki compact'))
Ejemplo n.º 30
0
 def _do_product_remove(self, prefix):
     raise AdminCommandError(_("Command 'product remove' not supported yet"))