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 = 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)
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)
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)
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
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)
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
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)
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
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
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
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
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
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'))
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
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
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
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