示例#1
0
文件: roadmap.py 项目: rwbaumg/trac
 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))
示例#2
0
文件: roadmap.py 项目: rwbaumg/trac
 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))
示例#3
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
示例#4
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
    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
示例#6
0
    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
示例#7
0
	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
示例#8
0
	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)
示例#10
0
    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
示例#11
0
 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()
示例#12
0
    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)
示例#13
0
    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)
示例#14
0
    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"))