def test_export_ical_from_roadmap(self): self.insert_milestone('milestone1', datetime_now(utc)) self.insert_milestone('milestone2') rm = RoadmapModule(self.env) req = MockRequest(self.env, path_info='/roadmap', args={'format': 'ics'}) self.assertTrue(rm.match_request(req)) with self.assertRaises(RequestDone): rm.process_request(req) self.assertEqual('200 Ok', req.status_sent[0]) self.assertRegexpMatches( req.response_sent.getvalue(), """\ BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Edgewall Software//NONSGML Trac [\.\w]+//EN METHOD:PUBLISH X-WR-CALNAME:My Project - Roadmap X-WR-CALDESC:My example project X-WR-TIMEZONE:UTC BEGIN:VEVENT UID:</trac.cgi/milestone/[email protected]/trac.cgi> DTSTAMP:\w+ DTSTART;VALUE=DATE:\w+ SUMMARY:Milestone milestone1 URL:http://example.org/trac.cgi/milestone/milestone1 END:VEVENT END:VCALENDAR """.replace('\n', '\r\n'))
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 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'))