Пример #1
0
 def _versions_and_stats(self, req, filter_projects):
     req.perm.require('MILESTONE_VIEW')
     db = self.env.get_db_cnx()
     
     versions = Version.select(self.env, db)
 
     filtered_versions = []
     stats = []
 
     show = req.args.getlist('show')
     
     for version in sorted(versions, key=lambda v: self._version_time(v)):
         project = self.__SmpModel.get_project_version(version.name)
         
         if not filter_projects or (project and project[0] in filter_projects):
             if not version.time or version.time.replace(tzinfo=None) >= datetime.now() or 'completed' in show:
                 
                 if version.time:
                     if version.time.replace(tzinfo=None) >= datetime.now():
                         version.is_due = True;
                     else:
                         version.is_completed = True;
                     
                 filtered_versions.append(version)
                 tickets = get_tickets_for_any(self.env, db, 'version', version.name,
                                                     'owner')
                 tickets = apply_ticket_permissions(self.env, req, tickets)
                 stat = get_ticket_stats(self.stats_provider, tickets)
                 stats.append(any_stats_data(self.env, req, stat,
                                                   'version', version.name))
 
     return filtered_versions, stats
Пример #2
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        stats_provider, kwargs = self._parse_macro_content(content, req)

        # Create & execute the query string
        qstr = '&'.join(['%s=%s' % item
                               for item in kwargs.iteritems()])
        query = Query.from_string(self.env, qstr, max=0)
        try:
            constraints = query.constraints[0]
        except IndexError:
            constraints = query.constraints

        # Calculate stats
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)

        stats = get_ticket_stats(stats_provider, tickets)
        stats_data = query_stats_data(req, stats, constraints)

        # ... and finally display them
        add_stylesheet(req, 'common/css/roadmap.css')
        chrome = Chrome(self.env)
        return chrome.render_template(req, 'progressmeter.html', stats_data,
                                      fragment=True)
Пример #3
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        stats_provider, kwargs, preview = self._parse_macro_content(
            content, req)

        # Create & execute the query string
        qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()])
        query = Query.from_string(self.env, qstr)
        try:
            # XXX: simplification, may cause problems with more complex queries
            constraints = query.constraints[0]
        except IndexError:
            constraints = {}

        # Calculate stats
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)

        stats = get_ticket_stats(stats_provider, tickets)
        stats_data = query_stats_data(req, stats, constraints)

        # ... and finally display them
        add_stylesheet(req, 'common/css/roadmap.css')
        chrome = Chrome(self.env)
        stats_data.update({'preview': preview})  # displaying a preview?
        return chrome.render_template(req,
                                      'progressmeter.html',
                                      stats_data,
                                      fragment=True)
Пример #4
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        stats_provider, kwargs, is_preview_with_self = self._parse_macro_content(content, req)

        if is_preview_with_self:
            # previewing newticket, without a number but with a reference
            # to current ticket number; show a helpful message
            return tag.div('Progress meter will be inserted here in final ticket')

        # Create & execute the query string
        qstr = '&'.join(['%s=%s' % item
                               for item in kwargs.iteritems()])
        query = Query.from_string(self.env, qstr, max=0)
        try:
            constraints = query.constraints[0]
        except IndexError:
            constraints = query.constraints

        # Calculate stats
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)

        stats = get_ticket_stats(stats_provider, tickets)
        stats_data = query_stats_data(req, stats, constraints)

        # ... and finally display them
        add_stylesheet(req, 'common/css/roadmap.css')
        chrome = Chrome(self.env)
        return chrome.render_template(req, 'progressmeter.html', stats_data,
                                      fragment=True)
Пример #5
0
    def render_widget(self, name, context, options):
        """Prepare ticket stats
        """
        req = context.req
        params = ('query', 'stats_provider', 'skin', 'title', 'legend', 'desc',
                  'view')
        qstr, pnm, skin, title, legend, desc, view = \
                self.bind_params(name, options, *params)
        statsp = resolve_ep_class(ITicketGroupStatsProvider,
                                  self,
                                  pnm,
                                  default=RoadmapModule(
                                      self.env).stats_provider)
        if skin is not None:
            skin = (skin or '').split('-', 2)

        tickets = exec_query(self.env, req, qstr)
        tickets = apply_ticket_permissions(self.env, req, tickets)
        stat = get_ticket_stats(statsp, tickets)

        add_stylesheet(req, 'dashboard/css/bootstrap.css')
        add_stylesheet(req, 'dashboard/css/bootstrap-responsive.css')
        add_stylesheet(req, 'dashboard/css/roadmap.css')
        return 'widget_progress.html', \
                {
                    'title' : title,
                    'data' : dict(
                            desc=desc, legend=legend, bar_styles=skin,
                            stats=stat, view=view,
                        ),
                }, \
                context
Пример #6
0
    def _versions_and_stats(self, req, filter_projects):
        req.perm.require('MILESTONE_VIEW')
        db = self.env.get_db_cnx()

        versions = Version.select(self.env, db)

        filtered_versions = []
        stats = []

        show = req.args.getlist('show')

        for version in sorted(versions, key=lambda v: self._version_time(v)):
            project = self.__SmpModel.get_project_version(version.name)

            if not filter_projects or (project
                                       and project[0] in filter_projects):
                if not version.time or version.time.replace(
                        tzinfo=None) >= datetime.now() or 'completed' in show:

                    if version.time:
                        if version.time.replace(tzinfo=None) >= datetime.now():
                            version.is_due = True
                        else:
                            version.is_completed = True

                    filtered_versions.append(version)
                    tickets = get_tickets_for_any(self.env, db, 'version',
                                                  version.name, 'owner')
                    tickets = apply_ticket_permissions(self.env, req, tickets)
                    stat = get_ticket_stats(self.stats_provider, tickets)
                    stats.append(
                        any_stats_data(self.env, req, stat, 'version',
                                       version.name))

        return filtered_versions, stats
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        stats_provider, kwargs, preview = self._parse_macro_content(content, req)

        # Create & execute the query string
        qstr = '&'.join(['%s=%s' % item
                               for item in kwargs.iteritems()])
        query = Query.from_string(self.env, qstr)
        try:
            # XXX: simplification, may cause problems with more complex queries
            constraints = query.constraints[0]
        except IndexError:
            constraints = {}

        # Calculate stats
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)

        stats = get_ticket_stats(stats_provider, tickets)
        stats_data = query_stats_data(req, stats, constraints)

        # ... and finally display them
        add_stylesheet(req, 'common/css/roadmap.css')
        chrome = Chrome(self.env)
        stats_data.update({'preview': preview})     # displaying a preview?
        return chrome.render_template(req, 'progressmeter.html', stats_data,
                                      fragment=True)
Пример #8
0
    def render_widget(self, name, context, options):
        """Prepare ticket stats
        """
        req = context.req
        params = ('query', 'stats_provider', 'skin', 'title', 'legend', 'desc',
                'view')
        qstr, pnm, skin, title, legend, desc, view = \
                self.bind_params(name, options, *params)
        statsp = resolve_ep_class(ITicketGroupStatsProvider, self, pnm,
                                    default=RoadmapModule(self.env).stats_provider)
        if skin is not None :
            skin = (skin or '').split('-', 2)

        tickets = exec_query(self.env, req, qstr)
        tickets = apply_ticket_permissions(self.env, req, tickets)
        stat = get_ticket_stats(statsp, tickets)

        add_stylesheet(req, 'dashboard/css/bootstrap.css')
        add_stylesheet(req, 'dashboard/css/bootstrap-responsive.css')
        add_stylesheet(req, 'dashboard/css/roadmap.css')
        return 'widget_progress.html', \
                {
                    'title' : title,
                    'data' : dict(
                            desc=desc, legend=legend, bar_styles=skin,
                            stats=stat, view=view,
                        ), 
                }, \
                context
Пример #9
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req

        # Parse arguments
        args, kwargs = parse_args(content, strict=False)
        assert not args and not ('status' in kwargs or 'format' in kwargs), \
          "Invalid input!"
        # hack the `format` kwarg in order to display all-tickets stats
        # when no kwargs are supplied
        kwargs['format'] = 'count'

        # special case for values equal to 'self': replace with current
        # ticket number, if available
        for key in kwargs.keys():
            if kwargs[key] == 'self':
                current_ticket = self._this_ticket(req)
                if current_ticket: kwargs[key] = current_ticket

        # Create & execute the query string
        qstr = '&'.join(['%s=%s' % item
                                for item in kwargs.iteritems()])
        query = Query.from_string(self.env, qstr, max=0)

        # Calculate stats
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)

        stats = get_ticket_stats(self.stats_provider, tickets)
        stats_data = query_stats_data(req, stats, query.constraints)

        # ... and finally display them
        add_stylesheet(req, 'common/css/roadmap.css')
        chrome = Chrome(self.env)
        return chrome.render_template(req, 'progressmeter.html', stats_data,
                                      fragment=True)
Пример #10
0
    def _get_tickets_graph(self, req, milestones, type_groups):
        db = self.env.get_db_cnx()
        
        mils = isinstance(milestones, basestring) and [milestones] or list(milestones)
        if '' in mils:
            mils +=[None]

        all_requested_fields = \
            self._get_ticket_fields(
                [
                    'summary', 
                    'description',
                    'milestone',
                    'owner',
                    self.scope_element_weight_field, 
                    self.work_element_weight_field
                ]
            )
        all_ids = []
        roots = back_trace = None
        for types in type_groups:
            if roots is not None and not back_trace:
                #we do not have ids for none root of the graph
                break
                
            filters = {
                'milestone' : mils,
                'type' : types
            }
            
            if back_trace is not None:
                filters['id']= back_trace.keys()
                
            tickets = apply_ticket_permissions(
                self.env, req, get_tickets_by_filter(db, all_requested_fields, **filters))
                
            all_ids.extend([ticket['id'] for ticket in tickets])
            
            if roots is None:
                roots = list(tickets)
                
            if back_trace:
                for ticket in tickets:
                    referers = back_trace[ticket['id']]
                    if referers:
                        for referer in referers:
                            referer.setdefault('references',[]).append(ticket);

            back_trace = defaultdict(list)
            if tickets:
                tickets_by_id =dict((tkt['id'], tkt) for tkt in tickets)
                src_ids = tickets_by_id.keys()

                cursor = db.cursor()
                cursor.execute("SELECT dest, src FROM tkt_links WHERE dest IN (%s)" % (len(src_ids)*"%s,")[:-1], src_ids)
                for dest, src in cursor:
                    back_trace[src].append(tickets_by_id[dest])
        return roots, all_ids
Пример #11
0
    def process_request(self, req):
        req.perm.require('MILESTONE_VIEW')

        show = req.args.getlist('show')
        if 'all' in show:
            show = ['completed']

        db = self.env.get_db_cnx()
        milestones = Milestone.select(self.env, 'completed' in show, db)
        if 'noduedate' in show:
            milestones = [
                m for m in milestones if m.due is not None or m.completed
            ]
        milestones = [
            m for m in milestones if 'MILESTONE_VIEW' in req.perm(m.resource)
        ]

        stats = []
        queries = []

        for milestone in milestones:
            tickets = get_tickets_for_milestone(self.env, db, milestone.name,
                                                'owner')
            tickets = apply_ticket_permissions(self.env, req, tickets)
            stat = get_ticket_stats(self.stats_provider, tickets)
            stats.append(
                milestone_stats_data(self.env, req, stat,
                                     '^' + milestone.name))
            #milestone['tickets'] = tickets # for the iCalendar view

        if req.args.get('format') == 'ics':
            self.render_ics(req, db, milestones)
            return

        # FIXME should use the 'webcal:' scheme, probably
        username = None
        if req.authname and req.authname != 'anonymous':
            username = req.authname
        icshref = req.href.roadmap(show=show, user=username, format='ics')
        add_link(req, 'alternate', icshref, _('iCalendar'), 'text/calendar',
                 'ics')

        data = {
            'milestones': milestones,
            'milestone_stats': stats,
            'queries': queries,
            'show': show,
        }
        add_stylesheet(req, 'common/css/roadmap.css')
        return 'roadmap.html', data, None
Пример #12
0
    def _render_view(self, req, version):
        milestones = []
        tickets = []
        milestone_stats = []

        for name, in self.env.db_query(
                """
                SELECT name FROM milestone
                 INNER JOIN milestone_version ON (name = milestone)
                WHERE version = %s
                ORDER BY due
                """, (version.name, )):
            milestone = Milestone(self.env, name)
            milestones.append(milestone)

            mtickets = get_tickets_for_milestone(self.env, milestone.name,
                                                 'owner')
            mtickets = apply_ticket_permissions(self.env, req, mtickets)
            tickets += mtickets
            stat = get_ticket_stats(self.milestone_stats_provider, mtickets)
            milestone_stats.append(
                milestone_stats_data(self.env, req, stat, milestone.name))

        stats = get_ticket_stats(self.version_stats_provider, tickets)
        interval_hrefs = version_interval_hrefs(
            self.env, req, stats, [milestone.name for milestone in milestones])

        version.resource = Resource('version', version.name)
        context = web_context(req, version.resource)

        version.is_released = version.time \
            and version.time < datetime.now(utc)
        version.stats = stats
        version.interval_hrefs = interval_hrefs
        names = [milestone.name for milestone in milestones]
        version.stats_href = version_stats_href(self.env, req, names)
        data = {
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'milestones': milestones,
            'milestone_stats': milestone_stats,
            'show_milestone_description':
            self.show_milestone_description  # Not implemented yet
        }

        add_stylesheet(req, 'extendedversion/css/version.css')
        add_script(req, 'common/js/folding.js')
        add_ctxtnav(req, _("Back to Versions"), req.href.versions())
        return 'version_view.html', data, None
Пример #13
0
    def _render_view(self, req, db, version):

        db = self.env.get_db_cnx()
        sql = "SELECT name FROM milestone " \
              "INNER JOIN milestone_version ON (name = milestone) " \
              "WHERE version = %s " \
              "ORDER BY due"
        cursor = db.cursor()
        cursor.execute(sql, (version.name,))

        milestones = []
        tickets = []
        milestone_stats = []

        for row in cursor:
            milestone = Milestone(self.env, row[0])
            milestones.append(milestone)

            mtickets = get_tickets_for_milestone(self.env, db, milestone.name,
                                                 'owner')
            mtickets = apply_ticket_permissions(self.env, req, mtickets)
            tickets += mtickets
            stat = get_ticket_stats(self.milestone_stats_provider, mtickets)
            milestone_stats.append(milestone_stats_data(self.env, req, stat, milestone.name))

        stats = get_ticket_stats(self.version_stats_provider, tickets)
        interval_hrefs = version_interval_hrefs(self.env, req, stats,
                                                [milestone.name for milestone in milestones])

        version.resource = Resource('version', version.name)
        context = Context.from_request(req, version.resource)

        version.is_released = version.time and version.time.date() < date.today()
        version.stats = stats
        version.interval_hrefs = interval_hrefs
        version.stats_href = [] # Not implemented yet, see th:#10349
        data = {
            'context': context,
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'milestones': milestones,
            'milestone_stats': milestone_stats,
            'show_milestone_description': self.show_milestone_description # Not implemented yet
        }

        add_stylesheet(req, 'extendedversion/css/version.css')
        add_script(req, 'common/js/folding.js')
        add_ctxtnav(req, _("Back to Versions"), req.href.versions())
        return 'version_view.html', data, None
Пример #14
0
    def _construct_progress(self, req, ticket):
        chrome = Chrome(self.env)

        query = Query.from_string(self.env, "parent=%d" % ticket.id, max=0)
        try:
            constraints = query.constraints[0]
        except IndexError:
            constraints = query.constraints
        qres = query.execute(req)
        tickets = apply_ticket_permissions(self.env, req, qres)
        stats = get_ticket_stats(self._stats_provider, tickets)
        stats_data = query_stats_data(req, stats, constraints)

        progress = chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
        return progress
Пример #15
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'))
Пример #16
0
    def _render_view(self, req, db, version):
        version_groups = []
        available_groups = []
        component_group_available = False
        ticket_fields = TicketSystem(self.env).get_ticket_fields()

        # collect fields that can be used for grouping
        for field in ticket_fields:
            if field['type'] == 'select' and field['name'] != 'version' \
                    or field['name'] in ('owner', 'reporter'):
                available_groups.append({
                    'name': field['name'],
                    'label': field['label']
                })
                if field['name'] == 'component':
                    component_group_available = True

        # determine the field currently used for grouping
        by = None
        if component_group_available:
            by = 'component'
        elif available_groups:
            by = available_groups[0]['name']
        by = req.args.get('by', by)

        tickets = get_tickets_for_any(self.env, db, 'version', version.name,
                                      by)
        tickets = apply_ticket_permissions(self.env, req, tickets)
        stat = get_ticket_stats(self.stats_provider, tickets)

        context = Context.from_request(req)

        infodivclass = ''
        if VERSION <= '0.12':
            infodivclass = 'info'
        else:
            infodivclass = 'info trac-progress'

        data = {
            'context': context,
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'available_groups': available_groups,
            'grouped_by': by,
            'groups': version_groups,
            'infodivclass': infodivclass
        }
        data.update(
            any_stats_data(self.env, req, stat, 'version', version.name))

        if by:
            groups = []
            for field in ticket_fields:
                if field['name'] == by:
                    if 'options' in field:
                        groups = field['options']
                        if field.get('optional'):
                            groups.insert(0, '')
                    else:
                        cursor = db.cursor()
                        cursor.execute(
                            """
                            SELECT DISTINCT COALESCE(%s,'') FROM ticket
                            ORDER BY COALESCE(%s,'')
                            """, [by, by])
                        groups = [row[0] for row in cursor]

            max_count = 0
            group_stats = []

            for group in groups:
                values = group and (group, ) or (None, group)
                group_tickets = [t for t in tickets if t[by] in values]
                if not group_tickets:
                    continue

                gstat = get_ticket_stats(self.stats_provider, group_tickets)
                if gstat.count > max_count:
                    max_count = gstat.count

                group_stats.append(gstat)

                gs_dict = {'name': group}
                gs_dict.update(
                    any_stats_data(self.env, req, gstat, 'version',
                                   version.name, by, group))
                version_groups.append(gs_dict)

            for idx, gstat in enumerate(group_stats):
                gs_dict = version_groups[idx]
                percent = 1.0
                if max_count:
                    percent = float(gstat.count) / float(max_count) * 100
                gs_dict['percent_of_max_total'] = percent

        add_stylesheet(req, 'common/css/roadmap.css')
        add_script(req, 'common/js/folding.js')
        return 'version_view.html', data, None
Пример #17
0
    def process_request(self, req):
        milestone_realm = Resource('milestone')
        req.perm.require('MILESTONE_VIEW')

        showall = req.args.get('show') == 'all'
        db = self.env.get_db_cnx()
        milestones = [m for m in StructuredMilestone.select(self.env, True, db)
                        if 'MILESTONE_VIEW' in req.perm(m.resource)]
        requested_fmt = req.args.get('format')
        if requested_fmt == 'ics':
            self.render_ics(req, db, milestones)
            return
        max_level = len(IttecoEvnSetup(self.env).milestone_levels)
        max_level = max_level and max_level-1 or 0;
        current_level = int(req.args.get('mil_type', max_level))
        
        if current_level==-1:
            #show all milestones regardless to the level
            milestones = sum([_get_milestone_with_all_kids(mil) for mil in milestones], [])
        else:
            #filter by level
            i =0        
            while i<current_level:
                next_level_mils = []
                for m in milestones:
                    next_level_mils.extend(m.kids)
                milestones = next_level_mils
                i+=1

        calc_on = req.args.get('calc_on')
        ticket_group = req.args.get('ticket_group', 'all')
        selected_types = None
        if ticket_group=='scope_element':
            selected_types = IttecoEvnSetup(self.env).scope_element
        elif ticket_group=='work_element':
            selected_types = IttecoEvnSetup(self.env).work_element
        else:
            ticket_group = 'all'
            
        selected_type_names = [tkt_type.name for tkt_type in Type.select(self.env) 
            if selected_types is None or tkt_type.value in selected_types]

        stats = []
        milestones = [mil for mil in milestones if showall or not mil.is_completed]
        for milestone in milestones:
            tickets = get_tickets_for_structured_milestone(
                self.env, db, milestone.name, calc_on, selected_type_names)
            tickets = apply_ticket_permissions(self.env, req, tickets)
            stat = SelectionTicketGroupStatsProvider(self.env).get_ticket_group_stats(tickets, calc_on)
            stats.append(
                milestone_stats_data(
                    req, stat, [m.name for m in _get_milestone_with_all_kids(milestone)]))

        if requested_fmt=='json':
            self._render_milestones_stats_as_json(req, milestones, stats)
            return
        # FIXME should use the 'webcal:' scheme, probably
        username = None
        if req.authname and req.authname != 'anonymous':
            username = req.authname
        icshref = req.href.roadmap(show=req.args.get('show'), user=username,
                                   format='ics')
        add_link(req, 'alternate', icshref, _('iCalendar'), 'text/calendar',
                 'ics')
        visibility = [{'index':idx, 'label': label, 'active': idx==current_level} 
            for idx, label in enumerate(IttecoEvnSetup(self.env).milestone_levels)]
        ticket_groups = [{'index':value, 'label': name, 'active': value==ticket_group} 
                for value, name in self._ticket_groups]
        
        calculate_on = self.get_statistics_source(req.args.get('calc_on'))
        data = {
            'milestones': milestones,
            'milestone_stats': stats,
            'mil_types': visibility,
            'ticket_groups': ticket_groups,
            'calc_on': calculate_on,
            'queries': [],
            'showall': showall,
        }
        self.env.log.debug('data:%s' % data)
        return 'itteco_roadmap.html', data, None
Пример #18
0
    def _render_view(self, req, db, version):
        version_groups = []
        available_groups = []
        component_group_available = False
        ticket_fields = TicketSystem(self.env).get_ticket_fields()

        # collect fields that can be used for grouping
        for field in ticket_fields:
            if field['type'] == 'select' and field['name'] != 'version' \
                    or field['name'] in ('owner', 'reporter'):
                available_groups.append({'name': field['name'],
                                         'label': field['label']})
                if field['name'] == 'component':
                    component_group_available = True

        # determine the field currently used for grouping
        by = None
        if component_group_available:
            by = 'component'
        elif available_groups:
            by = available_groups[0]['name']
        by = req.args.get('by', by)

        tickets = get_tickets_for_any(self.env, db, 'version', version.name, by)
        tickets = apply_ticket_permissions(self.env, req, tickets)
        stat = get_ticket_stats(self.stats_provider, tickets)

        context = Context.from_request(req)

        infodivclass = ''
        if VERSION <= '0.12':
            infodivclass = 'info'
        else:
            infodivclass = 'info trac-progress'

        data = {
            'context': context,
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'available_groups': available_groups, 
            'grouped_by': by,
            'groups': version_groups,
            'infodivclass': infodivclass
            }
        data.update(any_stats_data(self.env, req, stat, 'version', version.name))

        if by:
            groups = []
            for field in ticket_fields:
                if field['name'] == by:
                    if 'options' in field:
                        groups = field['options']
                        if field.get('optional'):
                            groups.insert(0, '')
                    else:
                        cursor = db.cursor()
                        cursor.execute("""
                            SELECT DISTINCT COALESCE(%s,'') FROM ticket
                            ORDER BY COALESCE(%s,'')
                            """, [by, by])
                        groups = [row[0] for row in cursor]

            max_count = 0
            group_stats = []

            for group in groups:
                values = group and (group,) or (None, group)
                group_tickets = [t for t in tickets if t[by] in values]
                if not group_tickets:
                    continue

                gstat = get_ticket_stats(self.stats_provider, group_tickets)
                if gstat.count > max_count:
                    max_count = gstat.count

                group_stats.append(gstat) 

                gs_dict = {'name': group}
                gs_dict.update(any_stats_data(self.env, req, gstat,
                                                    'version', version.name, by, group))
                version_groups.append(gs_dict)

            for idx, gstat in enumerate(group_stats):
                gs_dict = version_groups[idx]
                percent = 1.0
                if max_count:
                    percent = float(gstat.count) / float(max_count) * 100
                gs_dict['percent_of_max_total'] = percent

        add_stylesheet(req, 'common/css/roadmap.css')
        add_script(req, 'common/js/folding.js')
        return 'version_view.html', data, None
Пример #19
0
    def process_request(self, req):
        milestone_realm = Resource('milestone')
        req.perm.require('MILESTONE_VIEW')

        showall = req.args.get('show') == 'all'
        db = self.env.get_db_cnx()
        milestones = [
            m for m in StructuredMilestone.select(self.env, True, db)
            if 'MILESTONE_VIEW' in req.perm(m.resource)
        ]
        requested_fmt = req.args.get('format')
        if requested_fmt == 'ics':
            self.render_ics(req, db, milestones)
            return
        max_level = len(IttecoEvnSetup(self.env).milestone_levels)
        max_level = max_level and max_level - 1 or 0
        current_level = int(req.args.get('mil_type', max_level))

        if current_level == -1:
            #show all milestones regardless to the level
            milestones = sum(
                [_get_milestone_with_all_kids(mil) for mil in milestones], [])
        else:
            #filter by level
            i = 0
            while i < current_level:
                next_level_mils = []
                for m in milestones:
                    next_level_mils.extend(m.kids)
                milestones = next_level_mils
                i += 1

        calc_on = req.args.get('calc_on')
        ticket_group = req.args.get('ticket_group', 'all')
        selected_types = None
        if ticket_group == 'scope_element':
            selected_types = IttecoEvnSetup(self.env).scope_element
        elif ticket_group == 'work_element':
            selected_types = IttecoEvnSetup(self.env).work_element
        else:
            ticket_group = 'all'

        selected_type_names = [
            tkt_type.name for tkt_type in Type.select(self.env)
            if selected_types is None or tkt_type.value in selected_types
        ]

        stats = []
        milestones = [
            mil for mil in milestones if showall or not mil.is_completed
        ]
        for milestone in milestones:
            tickets = get_tickets_for_structured_milestone(
                self.env, db, milestone.name, calc_on, selected_type_names)
            tickets = apply_ticket_permissions(self.env, req, tickets)
            stat = SelectionTicketGroupStatsProvider(
                self.env).get_ticket_group_stats(tickets, calc_on)
            stats.append(
                milestone_stats_data(
                    req, stat,
                    [m.name for m in _get_milestone_with_all_kids(milestone)]))

        if requested_fmt == 'json':
            self._render_milestones_stats_as_json(req, milestones, stats)
            return
        # FIXME should use the 'webcal:' scheme, probably
        username = None
        if req.authname and req.authname != 'anonymous':
            username = req.authname
        icshref = req.href.roadmap(show=req.args.get('show'),
                                   user=username,
                                   format='ics')
        add_link(req, 'alternate', icshref, _('iCalendar'), 'text/calendar',
                 'ics')
        visibility = [{
            'index': idx,
            'label': label,
            'active': idx == current_level
        } for idx, label in enumerate(
            IttecoEvnSetup(self.env).milestone_levels)]
        ticket_groups = [{
            'index': value,
            'label': name,
            'active': value == ticket_group
        } for value, name in self._ticket_groups]

        calculate_on = self.get_statistics_source(req.args.get('calc_on'))
        data = {
            'milestones': milestones,
            'milestone_stats': stats,
            'mil_types': visibility,
            'ticket_groups': ticket_groups,
            'calc_on': calculate_on,
            'queries': [],
            'showall': showall,
        }
        self.env.log.debug('data:%s' % data)
        return 'itteco_roadmap.html', data, None