def test_get_tickets_for_all_milestones_custom_field(self): tickets = get_tickets_for_all_milestones(self.env, field='project') milestone1 = [{'id': 9, 'status': 'new', 'project': 'baz'}, {'id': 1, 'status': 'new', 'project': 'foo'}, {'id': 5, 'status': 'new', 'project': 'foo'}] milestone2 = [{'id': 6, 'status': 'new', 'project': 'bar'}, {'id': 10, 'status': 'new', 'project': 'baz'}, {'id': 2, 'status': 'new', 'project': 'foo'}] self.assertEqual(milestone1, tickets['milestone1']) self.assertEqual(milestone1, get_tickets_for_milestone(self.env, milestone='milestone1', field='project')) self.assertEqual(milestone2, tickets['milestone2']) self.assertEqual(milestone2, get_tickets_for_milestone(self.env, milestone='milestone2', field='project')) self.assertEqual(['milestone1', 'milestone2'], sorted(tickets))
def test_get_tickets_for_all_milestones(self): tickets = get_tickets_for_all_milestones(self.env, field='owner') milestone1 = [{'id': 9, 'status': 'new', 'owner': 'blah'}, {'id': 1, 'status': 'new', 'owner': 'joe'}, {'id': 5, 'status': 'new', 'owner': 'john'}] milestone2 = [{'id': 6, 'status': 'new', 'owner': 'blah'}, {'id': 10, 'status': 'new', 'owner': 'blah'}, {'id': 2, 'status': 'new', 'owner': 'joe'}] self.assertEqual(milestone1, tickets['milestone1']) self.assertEqual(milestone1, get_tickets_for_milestone(self.env, milestone='milestone1', field='owner')) self.assertEqual(milestone2, tickets['milestone2']) self.assertEqual(milestone2, get_tickets_for_milestone(self.env, milestone='milestone2', field='owner')) self.assertEqual(['milestone1', 'milestone2'], sorted(tickets))
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 _render_view(self, req, db, milestone): milestone_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'] != 'milestone' \ 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_milestone(self.env, db, milestone.name, by) stat = get_ticket_stats(self.stats_provider, tickets) tstat = get_ticket_stats(self.tickettype_stats_provider, tickets) # Parse the from date and adjust the timestamp to the last second of # the day today = datetime.now(req.tz) # Get milestone start date from session or use default day back. # TODO: add logic to remember the start date either in db or session. # if req.session.get('mdashboard.fromdate') != None: # # fromdate = parse_date(req.session.get('mdashboard.fromdate'), req.tz) # else: fromdate = today - timedelta(days=self.default_daysback + 1) fromdate = fromdate.replace(hour=23, minute=59, second=59) # Data for milestone and timeline data = {'fromdate': fromdate, 'milestone': milestone, 'tickethistory' : [], 'dates' : [], 'ticketstat' : {}, 'yui_base_url': self.yui_base_url } data.update(milestone_stats_data(self.env, req, stat, milestone.name)) ticketstat = {'name':'ticket type'} ticketstat.update(milestone_stats_data(self.env, req, tstat, milestone.name)) data['ticketstat'] = ticketstat #self.env.log.info("ticketstat = %s" % (ticketstat,)) # get list of ticket ids that in the milestone #ctickets = get_tickets_for_milestone(self.env, db, milestone.name, 'type') everytickets = get_every_tickets_in_milestone(db, milestone.name) if everytickets != []: #tkt_history = {} # collect_tickets_status_history(self.env, db, tkt_history, \ # everytickets, milestone) tkt_history = collect_tickets_status_history(self.env, db, everytickets, milestone) if tkt_history != {}: # Sort the key in the history list # returns sorted list of tuple of (key, value) sorted_events = sorted(tkt_history.items(), key=lambda(k,v):(k)) #debug self.env.log.info("sorted_event content") for event in sorted_events: self.env.log.info("date: %s: event: %s" % (format_date(to_datetime(event[0])), event[1])) # Get first date that ticket enter the milestone begin_date = to_datetime(min(sorted_events)[0]); if milestone.completed != None: end_date = milestone.completed else: end_date = datetime.now(utc).date() # this is array of date in numpy numdates = drange(begin_date, end_date + timedelta(days=1), timedelta(days=1)) tkt_history_table = make_ticket_history_table(self.env, numdates, sorted_events) #debug #self.env.log.info("tkt_history_table: %s", (tkt_history_table,)) #Create a data for the cumulative flow chart. tkt_cumulative_table = make_cumulative_data(self.env, tkt_history_table) #debug #self.env.log.info(tkt_cumulative_table) # creat list of dateobject from dates dates = [] for numdate in numdates: utc_date = num2date(numdate) dates.append(utc_date) #self.env.log.info("%s: %s" % (utc_date, format_date(utc_date, tzinfo=utc))) #prepare Yahoo datasource for comulative flow chart dscumulative = '' for idx, date in enumerate(dates): dscumulative = dscumulative + '{ date: "%s", enter: %d, leave: %d, finish: %d}, ' \ % (format_date(date,tzinfo=utc), tkt_cumulative_table['Enter'][idx], \ tkt_cumulative_table['Leave'][idx], tkt_cumulative_table['Finish'][idx]) data['tickethistory'] = tkt_cumulative_table data['dates'] = dates data['dscumulative'] = '[ ' + dscumulative + ' ];' return 'mdashboard.html', data, None
def _render_view(self, req, milestone): available_groups = [] component_group_available = False project_id = req.data['project_id'] ticket_fields = TicketSystem(self.env).get_ticket_fields(pid=project_id) # collect fields that can be used for grouping for name, field in ticket_fields.iteritems(): if field['type'] == 'select' and name != 'milestone' \ or name in ('owner', 'reporter'): available_groups.append({'name': name, 'label': field['label']}) if 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) db = self.env.get_read_db() tickets = get_tickets_for_milestone(self.env, db, milestone, by) stat = get_ticket_stats(self.stats_provider, tickets, project_id) tstat = get_ticket_stats(self.tickettype_stats_provider, tickets, project_id) # Data for milestone and timeline data = { 'milestone': milestone, 'tickethistory' : [], 'dates' : [], 'ticketstat' : {}, 'yui_base_url': self.tm.yui_base_url, '_': _, } data.update(milestone_stats_data(self.env, req, stat, milestone)) ticketstat = {'name':'ticket type'} ticketstat.update(milestone_stats_data(self.env, req, tstat, milestone)) data['ticketstat'] = ticketstat # get list of ticket ids that in the milestone everytickets = get_every_tickets_in_milestone(db, project_id, milestone.name) if everytickets: tkt_history = collect_tickets_status_history(db, everytickets, milestone) if tkt_history: # Sort the key in the history list # returns sorted list of tuple of (key, value) sorted_events = sorted(tkt_history.items(), key=lambda(t,events):(t)) # Get first date that ticket enter the milestone min_time = sorted_events[0][0] begin_date = to_datetime(min_time, tzinfo=req.tz) if milestone.is_completed: end_date = milestone.completed else: end_date = None end_date = to_datetime(end_date, tzinfo=req.tz) dates = list(date_generator(begin_date, end_date)) #Create a data for the cumulative flow chart. date_history = prepare_to_cumulate(sorted_events) tkt_cumulative_table = make_cumulative_data(dates, date_history) #prepare Yahoo datasource for comulative flow chart dscumulative = '' for idx, date in enumerate(dates): dscumulative = dscumulative + '{ date: "%s", enter: %d, leave: %d, finish: %d}, ' \ % (format_date(date,tzinfo=utc), tkt_cumulative_table['Enter'][idx], \ tkt_cumulative_table['Leave'][idx], tkt_cumulative_table['Finish'][idx]) data['tickethistory'] = tkt_cumulative_table data['dates'] = dates data['dscumulative'] = '[ ' + dscumulative + ' ];' return 'mdashboard.html', data, None
def process_request(self, req): # This tuple is for Genshi (template_name, data, content_type) # Without data the Trac layout will not appear. data = {} # Layout for QA Tracker add_stylesheet(req, 'qa/css/qatracker.css') if req.method.upper() != 'POST': """ User enters data into the qatracker.html form to setup the new test run """ # milestones milestones = self._find_milestones() if milestones and len(milestones) > 0: data['milestones'] = [x for x in milestones] # usernames usernames = self._find_usernames() if usernames and len(usernames) > 0: data['usernames'] = [x for x in usernames] return 'qatracker.html', data, None ############################### # Processing a POST request # ############################### # 1. Are there errors? If so, bail. errors = req.args.get('errors') if errors and len(errors) > 0: # TO-DO, do a meaningful redirect req.redirect(req.href.admin()) # 2. Cool, we're supposedly golden errors = {} action = None # 3. Parse the POST arguments action1 = req.args.get('action1') action2 = req.args.get('action2') if action1 and action1 == "create": action = "create" newRun = self.validate_args(req.args.get('newrun')) due = self.validate_args(req.args.get('duedate'), parse_date) assign = self.validate_args(req.args.get('assign1')) desc = self.validate_args(req.args.get('description')) master = self.validate_args(req.args.get('masterplan1')) elif action2 and action2 == "change": action = "change" current = self.validate_args(req.args.get('currentrun')) master = self.validate_args(req.args.get('masterplan2')) assign = self.validate_args(req.args.get('assign2')) else: errors['action'] = "Unknown form action" # 4. If we're doing a create, sanatize the new test run's name if action == "create": if not newRun: errors['newRun'] = "Missing Name for the new Test Run" elif len(newRun.strip()) < 1: errors['newRun'] = "Invalid Name for the new Test Run" elif "test run" not in newRun.lower(): newRun = "%s Test Run" % newRun # 5. check for errors # TO-DO, add redirect to error page if we have errors # 6. Set the milestone properties if action == "create": self._create_milestone(newRun, due, desc) milestone = newRun elif action == "change": milestone = current # 7. Find all the test cases in the Master Test Plan db = self.env.get_db_cnx() #self._delete_tickets_from_milestone(db, "Useless Test Cases") tickets = get_tickets_for_milestone(self.env, db, master) self.env.log.info("Found %d tickets in milestone %s" % (len(tickets), master)) # 8. Clone each ticket from the master into the new test run for t in tickets: status = t['status'] component = t['component'] id = t['id'] if status.lower() == 'closed': self.env.log.info("Skipping ticket %d (status == %s)" % (id, status)) continue self._clone_testcase(db, id, status, milestone, assign) # 9. Redirect to the the milestone roadmap req.redirect(req.href('milestone', milestone)) # Done with POST # Should never get here, but just in case return 'qatracker.html', data, None
def _delete_tickets_from_milestone(self, db, milestone): tickets = get_tickets_for_milestone(self.env, db, milestone) for t in tickets: id = t['id'] ticket = Ticket(self.env, tkt_id=id, db=db) ticket.delete()
def _render_view(self, req, db): showall = req.args.get('show') == 'all' showmetrics = req.args.get('showmetrics') == 'true' # Get list of milestone object for the project milestones = list(Milestone.select(self.env, showall, db)) stats = [] queries = [] self.env.log.info("getting milestones statistics") for milestone in milestones: tickets = get_tickets_for_milestone(self.env, db, milestone.name, 'owner') stat = get_ticket_stats(self.stats_provider, tickets) stats.append(milestone_stats_data(self.env, req, stat, milestone.name)) project = { 'name': self.env.project_name, 'description': self.env.project_description } data = { 'context': Context.from_request(req), 'milestones': milestones, 'milestone_stats': stats, 'queries': queries, 'showall': showall, 'showmetrics': showmetrics, 'project' : project, 'yui_base_url': self.yui_base_url } self.env.log.info("getting project statistics") project_tickets = get_project_tickets(self.env) # Get project progress stats proj_stat = self.stats_provider.get_ticket_group_stats(project_tickets) data['proj_progress_stat'] = {'stats': proj_stat, 'stats_href': req.href.query(proj_stat.qry_args), 'interval_hrefs': [req.href.query(interval['qry_args']) for interval in proj_stat.intervals]} closed_stat = self.stats_provider.get_ticket_resolution_group_stats(project_tickets) data['proj_closed_stat'] = {'stats': closed_stat, 'stats_href': req.href.query(closed_stat.qry_args), 'interval_hrefs': [req.href.query(interval['qry_args']) for interval in closed_stat.intervals]} tkt_frequency_stats = {} tkt_duration_stats = {} bmi_stats = [] daily_backlog_chart = {} today = datetime.now() if showmetrics: self.env.log.info("getting ticket metrics") tkt_group_metrics = TicketGroupMetrics(self.env, project_tickets) tkt_frequency_stats = tkt_group_metrics.get_frequency_metrics_stats() tkt_duration_stats = tkt_group_metrics.get_duration_metrics_stats() #stat for this month first_day = datetime(today.year, today.month, 1, tzinfo=utc) last_day = last_day_of_month(today.year, today.month) bmi_stats.append(tkt_group_metrics.get_bmi_monthly_stats(first_day, last_day)) # stat for last month last_day = first_day - timedelta(days=1) first_day = datetime(last_day.year, last_day.month, 1, tzinfo=utc) bmi_stats.append(tkt_group_metrics.get_bmi_monthly_stats(first_day, last_day)) # get daily backlog history last_day = datetime(today.year, today.month, today.day, tzinfo=utc) first_day = last_day - timedelta(days=DAYS_BACK) self.env.log.info("getting backlog history") backlog_history = tkt_group_metrics.get_daily_backlog_history(first_day, last_day) daily_backlog_chart = tkt_group_metrics.get_daily_backlog_chart(backlog_history) # Get dialy commits history last_day = datetime(today.year, today.month, today.day, tzinfo=utc) first_day = last_day - timedelta(days=DAYS_BACK) changeset_group_stats = ChangesetsStats(self.env, first_day, last_day) commits_by_date = changeset_group_stats.get_commit_by_date() commits_by_date_chart = changeset_group_stats.get_commit_by_date_chart(commits_by_date) data['project_bmi_stats'] = bmi_stats #self.env.log.info(bmi_stats) data['ticket_frequency_stats'] = tkt_frequency_stats data['ticket_duration_stats'] = tkt_duration_stats data['ds_daily_backlog'] = daily_backlog_chart data['ds_commit_by_date'] = commits_by_date_chart add_stylesheet(req, 'pd/css/dashboard.css') add_stylesheet(req, 'common/css/report.css') return ('pdashboard.html', data, None)
def _render_view(self, req, db): showall = req.args.get('show') == 'all' showmetrics = req.args.get('showmetrics') == 'true' # Get list of milestone object for the project milestones = list(Milestone.select(self.env, showall, db)) stats = [] queries = [] self.env.log.info("getting milestones statistics") for milestone in milestones: tickets = get_tickets_for_milestone(self.env, db, milestone.name, 'owner') stat = get_ticket_stats(self.stats_provider, tickets) stats.append( milestone_stats_data(self.env, req, stat, milestone.name)) project = { 'name': self.env.project_name, 'description': self.env.project_description } data = { 'context': Context.from_request(req), 'milestones': milestones, 'milestone_stats': stats, 'queries': queries, 'showall': showall, 'showmetrics': showmetrics, 'project': project, 'yui_base_url': self.yui_base_url } self.env.log.info("getting project statistics") # Get project progress stats query = Query.from_string(self.env, 'max=0&order=id') tickets = query.execute(req) proj_stat = get_ticket_stats(self.stats_provider, tickets) data['proj_progress_stat'] = { 'stats': proj_stat, 'stats_href': req.href.query(proj_stat.qry_args), 'interval_hrefs': [ req.href.query(interval['qry_args']) for interval in proj_stat.intervals ] } ticket_ids = [t['id'] for t in tickets] closed_stat = self.stats_provider.get_ticket_resolution_group_stats( ticket_ids) data['proj_closed_stat'] = { 'stats': closed_stat, 'stats_href': req.href.query(closed_stat.qry_args), 'interval_hrefs': [ req.href.query(interval['qry_args']) for interval in closed_stat.intervals ] } tkt_frequency_stats = {} tkt_duration_stats = {} bmi_stats = [] daily_backlog_chart = {} today = to_datetime(None) if showmetrics: self.env.log.info("getting ticket metrics") tkt_group_metrics = TicketGroupMetrics(self.env, ticket_ids) tkt_frequency_stats = tkt_group_metrics.get_frequency_metrics_stats( ) tkt_duration_stats = tkt_group_metrics.get_duration_metrics_stats() #stat for this month first_day = datetime(today.year, today.month, 1, tzinfo=utc) last_day = last_day_of_month(today.year, today.month) bmi_stats.append( tkt_group_metrics.get_bmi_monthly_stats(first_day, last_day)) # stat for last month last_day = first_day - timedelta(days=1) first_day = datetime(last_day.year, last_day.month, 1, tzinfo=utc) bmi_stats.append( tkt_group_metrics.get_bmi_monthly_stats(first_day, last_day)) # get daily backlog history last_day = datetime(today.year, today.month, today.day, tzinfo=utc) first_day = last_day - timedelta(days=DAYS_BACK) self.env.log.info("getting backlog history") backlog_history = tkt_group_metrics.get_daily_backlog_history( first_day, last_day) daily_backlog_chart = tkt_group_metrics.get_daily_backlog_chart( backlog_history) # Get dialy commits history last_day = datetime(today.year, today.month, today.day, tzinfo=utc) first_day = last_day - timedelta(days=DAYS_BACK) changeset_group_stats = ChangesetsStats(self.env, first_day, last_day) commits_by_date = changeset_group_stats.get_commit_by_date() commits_by_date_chart = changeset_group_stats.get_commit_by_date_chart( commits_by_date) data['project_bmi_stats'] = bmi_stats #self.env.log.info(bmi_stats) data['ticket_frequency_stats'] = tkt_frequency_stats data['ticket_duration_stats'] = tkt_duration_stats data['ds_daily_backlog'] = daily_backlog_chart data['ds_commit_by_date'] = commits_by_date_chart add_stylesheet(req, 'pd/css/dashboard.css') add_stylesheet(req, 'common/css/report.css') return ('pdashboard.html', data, None)
def _render_project_stats(self, req, data): project_id = req.data['project_id'] defaults = { # summary 'tkt_summary': True, 'milestones_stats': True, 'tkt_extra_stats': False, # time range 'tkt_activity': False, 'repos_stats': True, 'backlog_daily': True, # time groups 'repos_activity': True, 'backlog_table': False, 'wiki_activity': True, } metrics = self._enabled_metrics(req, defaults) show_completed = req.args.has_key('show_completed') data.update({ 'metrics': metrics, 'show_completed': show_completed, }) groupsize = data['groupsize'] groupcnt = data['groupcnt'] first_day = data['first_day'] first_day_group = data['first_day_group'] last_day = data['last_day'] db = self.env.get_read_db() if metrics['milestones_stats']: # Get list of milestone object for the project milestones = list(Milestone.select(self.env, project_id, show_completed, db)) stats = [] for milestone in milestones: tickets = get_tickets_for_milestone(self.env, db, milestone, 'owner') stat = get_ticket_stats(self.stats_provider, tickets, project_id) stats.append(milestone_stats_data(self.env, req, stat, milestone)) add_stylesheet(req, 'common/css/roadmap.css') data.update({ 'milestones': milestones, 'milestone_stats': stats, }) project_tickets = get_project_tickets(self.env, project_id) if metrics['tkt_summary']: # Get project progress stats proj_stat = self.stats_provider.get_ticket_group_stats(project_tickets, project_id) data['proj_progress_stat'] = {'stats': proj_stat, 'stats_href': req.href.query(proj_stat.qry_args, project_id=project_id), 'interval_hrefs': [req.href.query(interval['qry_args']) for interval in proj_stat.intervals]} closed_stat = self.stats_provider.get_ticket_resolution_group_stats(project_tickets, project_id) data['proj_closed_stat'] = {'stats': closed_stat, 'stats_href': req.href.query(closed_stat.qry_args, project_id=project_id), 'interval_hrefs': [req.href.query(interval['qry_args']) for interval in closed_stat.intervals]} if metrics['backlog_daily'] or metrics['backlog_table'] or metrics['tkt_extra_stats']: tkt_group_metrics = TicketGroupMetrics(self.env, project_tickets) if metrics['tkt_extra_stats']: tkt_frequency_stats = tkt_group_metrics.get_frequency_metrics_stats() tkt_duration_stats = tkt_group_metrics.get_duration_metrics_stats() data.update({ 'ticket_frequency_stats': tkt_frequency_stats, 'ticket_duration_stats': tkt_duration_stats, }) if metrics['backlog_table']: bmi_stats = [] d = first_day_group fday = datetime(d.year, d.month, d.day, tzinfo=req.tz) for _i in xrange(groupcnt): lday = fday + timedelta(groupsize, microseconds=-1) bstats = tkt_group_metrics.get_bmi_stats(fday, lday) bmi_stats.append(('%s - %s' % (format_date(fday), format_date(lday)),) + bstats) fday += timedelta(groupsize) data['project_bmi_stats'] = bmi_stats if metrics['backlog_daily']: # get daily backlog history backlog_history = tkt_group_metrics.get_daily_backlog_history(first_day, last_day) daily_backlog_chart = tkt_group_metrics.get_daily_backlog_chart(backlog_history) data['ds_daily_backlog'] = daily_backlog_chart if metrics['repos_stats']: # Get daily commits history changeset_group_stats = ChangesetsStats(self.env, project_id, first_day, last_day) commits_by_date = changeset_group_stats.get_commit_by_date() commits_by_date_chart = changeset_group_stats.get_commit_by_date_chart(commits_by_date) data['ds_commit_by_date'] = commits_by_date_chart data_json = {} if metrics['tkt_activity']: data['ticket_activity'] = reports.ticket_activity(project_id, first_day, last_day, db, req) data_json['ticket_activity'] = simplejson.dumps(data['ticket_activity'].get_data()) if metrics['repos_activity']: data['repository_activity'] = reports.repository_activity(project_id, first_day_group, last_day, groupsize, groupcnt, db, req, authors_limit=self.tm.authors_limit_repos) data_json['repository_activity'] = simplejson.dumps(data['repository_activity'].get_data()) if metrics['wiki_activity']: data['wiki_activity'] = reports.wiki_activity(project_id, first_day, last_day, groupsize, groupcnt, db, req, authors_limit=self.tm.authors_limit_wiki) data_json['wiki_activity'] = simplejson.dumps(data['wiki_activity'].get_data()) data['json'] = data_json return ('pdashboard.html', data, None)
def _render_view(self, req, db, milestone): milestone_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'] != 'milestone' \ 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_milestone(self.env, db, milestone.name, by) stat = get_ticket_stats(self.stats_provider, tickets) tstat = get_ticket_stats(self.tickettype_stats_provider, tickets) # Parse the from date and adjust the timestamp to the last second of # the day today = to_datetime(None, req.tz) # Get milestone start date from session or use default day back. # TODO: add logic to remember the start date either in db or session. # if req.session.get('mdashboard.fromdate') != None: # # fromdate = parse_date(req.session.get('mdashboard.fromdate'), req.tz) # else: fromdate = today - timedelta(days=self.default_daysback + 1) fromdate = fromdate.replace(hour=23, minute=59, second=59) # Data for milestone and timeline data = { 'fromdate': fromdate, 'milestone': milestone, 'tickethistory': [], 'dates': [], 'ticketstat': {}, 'yui_base_url': self.yui_base_url } data.update(milestone_stats_data(self.env, req, stat, milestone.name)) ticketstat = {'name': 'ticket type'} ticketstat.update( milestone_stats_data(self.env, req, tstat, milestone.name)) data['ticketstat'] = ticketstat #self.env.log.info("ticketstat = %s" % (ticketstat,)) # get list of ticket ids that in the milestone #ctickets = get_tickets_for_milestone(self.env, db, milestone.name, 'type') everytickets = get_every_tickets_in_milestone(db, milestone.name) if everytickets != []: #tkt_history = {} # collect_tickets_status_history(self.env, db, tkt_history, \ # everytickets, milestone) tkt_history = collect_tickets_status_history( self.env, db, everytickets, milestone) if tkt_history != {}: # Sort the key in the history list # returns sorted list of tuple of (key, value) sorted_events = sorted(tkt_history.items(), key=lambda (k, v): (k)) #debug self.env.log.info("sorted_event content") for event in sorted_events: self.env.log.info( "date: %s: event: %s" % (format_date(to_datetime(event[0])), event[1])) # Get first date that ticket enter the milestone min_time = min(sorted_events)[0] #in Epoch Seconds begin_date = to_datetime(min_time).date() end_date = milestone.completed or to_datetime(None).date() # this is array of date in numpy numdates = drange(begin_date, end_date + timedelta(days=1), timedelta(days=1)) tkt_history_table = make_ticket_history_table( self.env, numdates, sorted_events) #debug #self.env.log.info("tkt_history_table: %s", (tkt_history_table,)) #Create a data for the cumulative flow chart. tkt_cumulative_table = make_cumulative_data( self.env, tkt_history_table) #debug #self.env.log.info(tkt_cumulative_table) # creat list of dateobject from dates dates = [] for numdate in numdates: utc_date = num2date(numdate) dates.append(utc_date) #self.env.log.info("%s: %s" % (utc_date, format_date(utc_date, tzinfo=utc))) #prepare Yahoo datasource for comulative flow chart dscumulative = '' for idx, date in enumerate(dates): dscumulative = dscumulative + '{ date: "%s", enter: %d, leave: %d, finish: %d}, ' \ % (format_date(date, tzinfo=utc), tkt_cumulative_table['Enter'][idx], \ tkt_cumulative_table['Leave'][idx], tkt_cumulative_table['Finish'][idx]) data['tickethistory'] = tkt_cumulative_table data['dates'] = dates data['dscumulative'] = '[ ' + dscumulative + ' ];' return 'mdashboard.html', data, None
def expand_macro(self, formatter, name, content): db = self.env.get_read_db() args, kwargs = parse_args(content) milestone_arg = args[0].strip() hoursavailable_arg = float(args[1].strip()) start_arg = datetime.datetime(*(time.strptime(args[2].strip(), "%Y-%m-%d")[0:6])).replace(tzinfo=localtz) milestone = Milestone(self.env, milestone_arg, db) if milestone.due is None: raise Exception("Milestone %s has no due date set." % milestone.name) formatter.req.perm.require("MILESTONE_VIEW", milestone.resource) estimatedhours = 0.0 remaininghours = 0.0 totalhours = 0.0 for row in get_tickets_for_milestone(self.env, db, milestone.name): ticket = Ticket(self.env, row['id'], db) if ticket['status'] == "closed": continue if ticket['estimatedhours']: estimatedhours += float(ticket['estimatedhours']) if ticket['remaininghours']: remaininghours += float(ticket['remaininghours']) if ticket['totalhours']: totalhours += float(ticket['totalhours']) table = tag.table(class_='MilestoneTrafficLights') days_to_go = (milestone.due - datetime.datetime.now(localtz)).days table.append(tag.tr(tag.td('Milestone'), tag.td(milestone.name))) table.append(tag.tr(tag.td('Due Date'), tag.td(milestone.due.strftime("%Y-%m-%d")))) table.append(tag.tr(tag.td('Days to Go'), tag.td(days_to_go))) table.append(tag.tr(tag.td('Work Hours Available'), tag.td("%d between %s and %s" % (hoursavailable_arg, start_arg.strftime("%Y-%m-%d"), milestone.due.strftime("%Y-%m-%d"))))) table.append(tag.tr(tag.td('Originally Estimated Hours'), tag.td(estimatedhours))) table.append(tag.tr(tag.td('Currently Estimated Hours'), tag.td(remaininghours))) table.append(tag.tr(tag.td('Ticket Spent Hours'), tag.td(totalhours))) #return hoursavailable_arg / float((datetime.datetime.now() - start_arg).days) hours_avail_per_day = hoursavailable_arg / float((milestone.due - start_arg).days) work_hours_left = hours_avail_per_day * days_to_go table.append(tag.tr(tag.td('Work Pro-rota Hours Left'), tag.td("%.1f" % work_hours_left))) sparehours = work_hours_left - remaininghours if sparehours > 100: colour = "green" elif sparehours > 48: colour = "orange" else: colour = "red" table.append(tag.tr(tag.td('Spare Hours'), tag.td("%.1f" % sparehours,style="background: %s" % colour))) return table
def process_request(self, req): name = req.args.get('name') if not (name == 'query'): id = req.args.get('id') if name == 'ticket': ticket = Ticket(self.env, id) comm_num = 0 attachment_num = len(self.get_attachments('ticket', id)) ticket_log = self.changeLog(id) for log in ticket_log: if log[2] == 'comment' and log[4]: comm_num += 1 data = {'ticket': ticket, 'comm_num': comm_num, 'attachment_num': attachment_num} return 'bh_emb_ticket.html', data, None elif name == 'milestone': ticket_num = len(get_tickets_for_milestone(self.env, milestone=id)) attachment_num = len(self.get_attachments('milestone', id)) data = {'milestone': Milestone(self.env, id), 'product': self.env.product, 'ticket_number': ticket_num, 'attachment_number': attachment_num } return 'bh_emb_milestone.html', data, None elif name == 'products': product = Product(self.env, {'prefix': id}) ticket_num = len(self.get_tickets_for_product(self.env, id)) product_env = ProductEnvironment(self.env, product.prefix) milestone_num = len(Milestone.select(product_env)) version_num = len(Version.select(product_env)) components = component.select(product_env) component_num = 0 for c in components: component_num += 1 data = {'product': product, 'ticket_num': ticket_num, 'owner': product.owner, 'milestone_num': milestone_num, 'version_num': version_num, 'component_num': component_num} return 'bh_emb_product.html', data, None elif name == 'query': qstr = req.query_string qstr = urllib.unquote(qstr).decode('utf8') if qstr=='': qstr = 'status!=closed' qresults = self.query(req, qstr) filters = qresults[0] tickets = qresults[1] data={'tickets': tickets, 'query': qstr, 'filters': filters} return 'bh_emb_query.html', data, None else: msg = "It is not possible to embed this resource." raise ResourceNotFound((msg), ("Invalid resource"))