def _sticky_from_report(self, req, data): ids = [] for value_for_group, row_group in data['row_groups']: ids.extend([int(row['id']) for row in row_group if row['resource'] and row['resource'].realm == 'ticket' and 'TICKET_VIEW' in req.perm(row['resource'])]) cols = ['id', 'summary', 'type'] for col in self._fields: if col not in cols: cols.append(col) if hasattr(self.env, 'get_read_db'): db = self.env.get_read_db() else: db = self.env.get_db_cnx() start = 0 count = 100 tickets = [] while start < len(ids): constraints = [{ 'id': [str(id) for id in ids[start:start + count]], }] query = Query(self.env, constraints=constraints, cols=cols, max=0) tickets.extend(query.execute(req, db)) start += count tickets_dict = dict((int(ticket['id']), ticket) for ticket in tickets) tickets = [tickets_dict[id] for id in ids if id in tickets_dict] return self._sticky(req, tickets)
def _get_permitted_tickets(self, req, constraints=None, columns=None): """ If we don't pass a list of column/field values, the Query module defaults to the first seven colums - see get_default_columns(). """ if columns is None: columns = [] else: columns = columns[:] # avoid mutating callers list # make sure that we get certain ticket fields for f in ('summary', 'type', 'remaininghours', 'effort', 'date'): if f not in columns: columns.append(f) # what field data should we get query = Query(self.env, constraints=constraints, max=0, cols=columns) tickets = [] for ticket in query.execute(req): if 'TICKET_VIEW' in req.perm('ticket', ticket['id']): for k in ('effort', 'remaininghours'): try: ticket[k] = float(ticket[k]) except KeyError: pass except TypeError: ticket[k] = 0.0 tickets.append(ticket) return tickets
def test_all_ordered_by_id_verbose(self): query = Query(self.env, order='id', verbose=1) sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.reporter AS reporter,t.description AS description,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_all_ordered_by_priority_desc(self): query = Query(self.env, desc=1) # priority is default order sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.priority,'')='' DESC,priority.value DESC,t.id""") tickets = query.execute()
def test_grouped_by_priority(self): query = Query(self.env, group='priority') sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.milestone AS milestone,t.component AS component,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.priority,'')='',priority.value,t.id""") tickets = query.execute()
def test_all_ordered_by_id_verbose(self): query = Query(self.env, order='id', verbose=1) sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.reporter AS reporter,t.description AS description,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_all_ordered_by_id_desc(self): query = Query(self.env, order='id', desc=1) sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.product AS product,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.id,0)=0 DESC,t.id DESC""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_all_ordered_by_version_desc(self): query = Query(self.env, order='version', desc=1) sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) LEFT OUTER JOIN version ON (version.name=version) ORDER BY COALESCE(t.version,'')='' DESC,COALESCE(version.time,0)=0 DESC,version.time DESC,t.version DESC,t.id""") tickets = query.execute()
def test_all_grouped_by_milestone_desc(self): query = Query(self.env, order='id', group='milestone', groupdesc=1) sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) LEFT OUTER JOIN milestone ON (milestone.name=milestone) ORDER BY COALESCE(t.milestone,'')='' DESC,COALESCE(milestone.due,0)=0 DESC,milestone.due DESC,t.milestone DESC,COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_all_ordered_by_priority_desc(self): query = Query(self.env, desc=1) # priority is default order sql, args = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.priority,'')='' DESC,priority.value DESC,t.id""") self.assertEqual([], args) tickets = query.execute(Mock(href=self.env.href))
def test_all_ordered_by_id(self): query = Query(self.env, order='id') sql, args = query.get_sql() self.assertEqual( sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual([], args) tickets = query.execute(Mock(href=self.env.href))
def test_all_ordered_by_version_desc(self): query = Query(self.env, order='version', desc=1) sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) LEFT OUTER JOIN version ON (version.name=version) ORDER BY COALESCE(t.version,'')='' DESC,COALESCE(version.time,0)=0 DESC,version.time DESC,t.version DESC,t.id""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_grouped_by_priority(self): query = Query(self.env, group='priority') sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.product AS product,t.milestone AS milestone,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(priority.value,'')='',%(cast_priority)s,t.id""" % { 'cast_priority': self.env.get_read_db().cast('priority.value', 'int')}) self.assertEqual([], args) tickets = query.execute(self.req)
def test_all_grouped_by_milestone_desc(self): query = Query(self.env, order='id', group='milestone', groupdesc=1) sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.product AS product,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) LEFT OUTER JOIN milestone ON (milestone.name=milestone) ORDER BY COALESCE(t.milestone,'')='' DESC,COALESCE(milestone.completed,0)=0 DESC,milestone.completed DESC,COALESCE(milestone.due,0)=0 DESC,milestone.due DESC,t.milestone DESC,COALESCE(t.id,0)=0,t.id""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_grouped_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query(self.env, group='foo', order='id') sql = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value,foo.value AS foo FROM ticket AS t LEFT OUTER JOIN ticket_custom AS foo ON (id=foo.ticket AND foo.name='foo') LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(foo.value,'')='',foo.value,COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_all_ordered_by_priority_desc(self): query = Query(self.env, desc=1) # priority is default order sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(priority.value,'')='' DESC,%(cast_priority)s DESC,t.id""" % { 'cast_priority': self.env.get_db_cnx().cast('priority.value', 'int')}) self.assertEqual([], args) tickets = query.execute(self.req)
def test_grouped_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query(self.env, group='foo', order='id') sql, args = query.get_sql() self.assertEqual(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value,foo.value AS foo FROM ticket AS t LEFT OUTER JOIN ticket_custom AS foo ON (id=foo.ticket AND foo.name='foo') LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(foo.value,'')='',foo.value,COALESCE(t.id,0)=0,t.id""") self.assertEqual([], args) tickets = query.execute(Mock(href=self.env.href))
def test_grouped_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query(self.env, group='foo', order='id') sql, args = query.get_sql() foo = self.env.get_read_db().quote('foo') self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.product AS product,t.time AS time,t.changetime AS changetime,priority.value AS priority_value,%s.value AS %s FROM ticket AS t LEFT OUTER JOIN ticket_custom AS %s ON (id=%s.ticket AND %s.name='foo') LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(%s.value,'')='',%s.value,COALESCE(t.id,0)=0,t.id""" % ((foo,) * 7)) self.assertEqual([], args) tickets = query.execute(self.req)
def test_all_ordered_by_priority_desc(self): query = Query(self.env, desc=1) # priority is default order sql, args = query.get_sql() self.assertEqualSQL( sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(priority.value,'')='' DESC,%(cast_priority)s DESC,t.id""" % { 'cast_priority': self.env.get_db_cnx().cast('priority.value', 'int') }) self.assertEqual([], args) tickets = query.execute(self.req)
def test_grouped_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query(self.env, group='foo', order='id') sql, args = query.get_sql() foo = self.env.get_read_db().quote('foo') self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value,c.%s AS %s FROM ticket AS t LEFT JOIN (SELECT id AS ticket, (SELECT c.value FROM ticket_custom c WHERE c.ticket=t.id AND c.name='foo') AS %s FROM ticket t) AS c ON (c.ticket=t.id) LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(c.%s,'')='',c.%s,COALESCE(t.id,0)=0,t.id""" % ((foo,) * 5)) self.assertEqual([], args) tickets = query.execute(self.req)
def test_grouped_by_custom_field(self): self.env.config.set("ticket-custom", "foo", "text") query = Query(self.env, group="foo", order="id") sql, args = query.get_sql() foo = self.env.get_read_db().quote("foo") self.assertEqualSQL( sql, """SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value,c.%s AS %s FROM ticket AS t LEFT JOIN (SELECT id AS ticket, (SELECT c.value FROM ticket_custom c WHERE c.ticket=t.id AND c.name='foo') AS %s FROM ticket t) AS c ON (c.ticket=t.id) LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) ORDER BY COALESCE(c.%s,'')='',c.%s,COALESCE(t.id,0)=0,t.id""" % ((foo,) * 5), ) self.assertEqual([], args) tickets = query.execute(self.req)
def save_change(self, req, milestone): """Try to save changes and return new data, else return error dict. As with getting ticket data, we check for a custom save method, and else use the standard implementation """ try: ticket_id = int(req.args.get("ticket")) except (ValueError, TypeError): return self._save_error(req, ["Must supply a ticket to change"]) field = req.args.get("group_name") if not field or re.search("[^a-zA-Z0-9_]", field): return self._save_error(req, ["Invalid field name"]) else: # Check to see if we process this field in a unique way try: save_f = getattr(self, "_save_%s_change" % field) except AttributeError: save_f = self._save_standard_change_ # Try to save the ticket using the relevant save method try: if save_f.__name__ == "_save_standard_change_": save_f(req, ticket_id, field, req.args.get("value")) else: save_f(req, ticket_id, req.args.get("action")) # Retrieve new ticket information query = Query(self.env, constraints={'id': [str(ticket_id)]}, cols=['id', 'type', 'effort', 'remaininghours']) results = query.execute(req) req.perm('ticket', ticket_id).require('TICKET_VIEW') for k in ('effort', 'remaininghours'): try: results[0][k] = float(results[0][k]) except KeyError: pass return self.get_ticket_data(req, milestone, field, results) except ValueError, e: return self._save_error(req, list(e)) except TracError, e: return self._save_error(req, [e])
def process_request(self, req): realm = req.args['realm'] id_ = req.args['id'] if not which(self.dot_path): raise TracError( _("Path to dot executable is invalid: %(path)s", path=self.dot_path)) # Urls to generate the depgraph for a ticket is /depgraph/ticketnum # Urls to generate the depgraph for a milestone is # /depgraph/milestone/milestone_name # List of tickets to generate the depgraph. if realm == 'milestone': # We need to query the list of tickets in the milestone query = Query(self.env, constraints={'milestone': [id_]}, max=0) tkt_ids = [fields['id'] for fields in query.execute(req)] else: tid = as_int(id_, None) if tid is None: raise TracError( tag_("%(id)s is not a valid ticket id.", id=html.tt(id_))) tkt_ids = [tid] # The summary argument defines whether we place the ticket id or # its summary in the node's label label_summary = 0 if 'summary' in req.args: label_summary = int(req.args.get('summary')) g = self._build_graph(req, tkt_ids, label_summary=label_summary) if req.path_info.endswith('/depgraph.png') or 'format' in req.args: format_ = req.args.get('format') if format_ == 'text': # In case g.__str__ returns unicode, convert it in ascii req.send( to_unicode(g).encode('ascii', 'replace'), 'text/plain') elif format_ == 'debug': import pprint req.send( pprint.pformat( [TicketLinks(self.env, tkt_id) for tkt_id in tkt_ids]), 'text/plain') elif format_ is not None: if format_ in self.acceptable_formats: req.send(g.render(self.dot_path, format_), 'text/plain') else: raise TracError( _("The %(format)s format is not allowed.", format=format_)) if self.use_gs: ps = g.render(self.dot_path, 'ps2') gs = subprocess.Popen([ self.gs_path, '-q', '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sDEVICE=png16m', '-sOutputFile=%stdout%', '-' ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) img, err = gs.communicate(ps) if err: self.log.debug('MasterTickets: Error from gs: %s', err) else: img = g.render(self.dot_path) req.send(img, 'image/png') else: data = {} # Add a context link to enable/disable labels in nodes. if label_summary: add_ctxtnav(req, 'Without labels', req.href(req.path_info, summary=0)) else: add_ctxtnav(req, 'With labels', req.href(req.path_info, summary=1)) if realm == 'milestone': add_ctxtnav(req, 'Back to Milestone: %s' % id_, req.href.milestone(id_)) data['milestone'] = id_ else: data['ticket'] = id_ add_ctxtnav(req, 'Back to Ticket #%s' % id_, req.href.ticket(id_)) data['graph'] = g data['graph_render'] = functools.partial(g.render, self.dot_path) data['use_gs'] = self.use_gs return 'depgraph.html', data, None
def _process_export(self, req): fields = [ {'name':'id', 'label':'id'} ] fields.extend( TicketSystem(self.env).get_ticket_fields() ) fieldsFormat = self._get_fields_format(fields) fieldsExport = self._get_fields_export(fields) fieldsWeight = self._get_fields_weight(fields) comment_changeset = req.args.get('export.changeset') and req.args.get('export.changeset') == 'True' fields = [c for c in fields if fieldsExport[ c['name'] ] ] fieldnames = [c['name'] for c in fields] fields.sort( lambda a, b : fieldsWeight[a['name']]-fieldsWeight[b['name']] ) # ticket #8805 : unavailable for python 2.4 or 2.5 #content = BytesIO() content = cStringIO.StringIO() headerStyle = xlwt.easyxf('font: bold on; pattern: pattern solid, fore-colour grey25; borders: top thin, bottom thin, left thin, right thin') wb = xlwt.Workbook() sheetName = ( 'Tickets - %s' % self.config.get('project','name', '') ); try: ws = wb.add_sheet( sheetName ) except: # Project name incompatible with sheet name constraints. sheetName = 'Tickets' ws = wb.add_sheet( sheetName ) colIndex = {} c = 0 for f in fields: ws.write(0, c, unicode(f['label']),headerStyle) colIndex[f['name']] = c c += 1 if comment_changeset: ws.write(0, c, unicode('Comments in change log'),headerStyle) constraints = {} if req.args.get('filter.type') and len(req.args['filter.type']) > 0 : if type( req.args['filter.type'] ) == list : constraints['type'] = req.args['filter.type'] else: constraints['type'] = [ req.args['filter.type'] ] if req.args.get('filter.version') and len(req.args['filter.version']) > 0 : if type( req.args['filter.version'] ) == list : constraints['version'] = req.args['filter.version'] else: constraints['version'] = [ req.args['filter.version'] ] if req.args.get('filter.milestone') and len(req.args['filter.milestone']) > 0 : if type( req.args['filter.milestone'] ) == list : constraints['milestone'] = req.args['filter.milestone'] else: constraints['milestone'] = [ req.args['filter.milestone'] ] if req.args.get('filter.component') and len(req.args['filter.component']) > 0 : if type( req.args['filter.component'] ) == list : constraints['component'] = req.args['filter.component'] else: constraints['component'] = [ req.args['filter.component'] ] if req.args.get('filter.status') and len(req.args['filter.status']) > 0 : if type( req.args['filter.status'] ) == list : constraints['status'] = req.args['filter.status'] else: constraints['status'] = [ req.args['filter.status'] ] if req.args.get('filter.priority') and len(req.args['filter.priority']) > 0 : if type( req.args['filter.priority'] ) == list : constraints['priority'] = req.args['filter.priority'] else: constraints['priority'] = [ req.args['filter.priority'] ] if req.args.get('filter.severity') and len(req.args['filter.severity']) > 0 : if type( req.args['filter.severity'] ) == list : constraints['severity'] = req.args['filter.severity'] else: constraints['severity'] = [ req.args['filter.severity'] ] if req.args.get('filter.resolution') and len(req.args['filter.resolution']) > 0 : if type( req.args['filter.resolution'] ) == list : constraints['resolution'] = req.args['filter.resolution'] else: constraints['resolution'] = [ req.args['filter.resolution'] ] query = Query(self.env, cols=fieldnames, order='id', max=sys.maxint, constraints=constraints) results = query.execute(req) r = 0 cols = query.get_columns() for result in results: r += 1 for col in cols: value = result[col] format = self.formats[ fieldsFormat[col] ] value = format.convert(value) style = format.get_style(value) ws.write(r, colIndex[col], value, style) if comment_changeset: format = self.formats[ 'longtext' ] value = format.convert( self._get_changelog_comments(result['id']) ) style = format.get_style(value) ws.write(r, len(cols), value, style) if req.args.get('export.statistics') and req.args.get('export.statistics') == 'True': wb = self._add_statistics_sheet(req, sheetName, wb, fields, colIndex, constraints) wb.save(content) return (content.getvalue(), 'application/excel')
# pulled directly from request.GET. query_module = QueryModule(self.env) req = FakeTracRequest(request) constraints = query_module._get_constraints(req) qd = request.GET kwargs = { 'cols': qd.getlist('col'), 'rows': qd.getlist('row'), 'constraints': constraints } kwargs.update(dict([ (k, qd.get(k)) for k in ('format', 'max', 'report', 'order', 'group', 'page') ])) kwargs.update(dict([ (k, k in qd) for k in 'desc', 'groupdesc', 'verbose' ])) orig_list = None orig_time = datetime.now(utc) query = Query(self.env, **kwargs) tickets = query.execute() return tickets def get_attachment(self, request): pass
def process_request(self, req): path_info = req.path_info[10:] img_format = req.args.get('format') m = self.IMAGE_RE.search(path_info) is_img = m is not None if is_img: img_format = m.group(1) path_info = path_info[:-(10+len(img_format))] is_full_graph = not path_info with_clusters = req.args.getbool('with_clusters', False) cur_pid = self.pm.get_current_project(req) #list of tickets to generate the depgraph for tkt_ids=[] if is_full_graph: # depgraph for full project # cluster by milestone self.pm.check_component_enabled(self, pid=cur_pid) db = self.env.get_read_db() cursor = db.cursor() if with_clusters: q = ''' SELECT milestone, id FROM ticket WHERE project_id=%s ORDER BY milestone, id ''' else: q = ''' SELECT id FROM ticket WHERE project_id=%s ORDER BY id ''' cursor.execute(q, (cur_pid,)) rows = cursor.fetchall() if with_clusters: tkt_ids = rows else: tkt_ids = [r[0] for r in rows] else: # degraph for resource resource = get_real_resource_from_url(self.env, path_info, req.args) # project check res_pid = resource.pid self.pm.check_component_enabled(self, pid=res_pid) if res_pid != cur_pid: self.pm.redirect_to_project(req, res_pid) is_milestone = isinstance(resource, Milestone) #Urls to generate the depgraph for a ticket is /depgraph/ticketnum #Urls to generate the depgraph for a milestone is /depgraph/milestone/milestone_name if is_milestone: #we need to query the list of tickets in the milestone milestone = resource query=Query(self.env, constraints={'milestone' : [milestone.name]}, max=0, project=milestone.pid) tkt_ids=[fields['id'] for fields in query.execute()] else: #the list is a single ticket ticket = resource tkt_ids = [ticket.id] #the summary argument defines whether we place the ticket id or #it's summary in the node's label label_summary=0 if 'summary' in req.args: label_summary=int(req.args.get('summary')) clustering = is_full_graph and with_clusters g = self._build_graph(req, tkt_ids, label_summary=label_summary, with_clusters=clustering) if is_img or img_format: if img_format == 'text': #in case g.__str__ returns unicode, we need to convert it in ascii req.send(to_unicode(g).encode('ascii', 'replace'), 'text/plain') elif img_format == 'debug': import pprint req.send( pprint.pformat( [TicketLinks(self.env, tkt_id) for tkt_id in tkt_ids] ), 'text/plain') elif img_format == 'svg': req.send(g.render(self.dot_path, img_format), 'image/svg+xml') elif img_format is not None: req.send(g.render(self.dot_path, img_format), 'text/plain') if self.use_gs: ps = g.render(self.dot_path, 'ps2') gs = subprocess.Popen([self.gs_path, '-q', '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sDEVICE=png16m', '-sOutputFile=%stdout%', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) img, err = gs.communicate(ps) if err: self.log.debug('MasterTickets: Error from gs: %s', err) else: img = g.render(self.dot_path) req.send(img, 'image/png') else: data = { 'graph': g, 'graph_render': partial(g.render, self.dot_path), 'use_gs': self.use_gs, 'full_graph': is_full_graph, 'img_format': self.default_format, 'summary': label_summary, 'with_clusters': with_clusters, } if is_full_graph: rsc_url = None else: if is_milestone: resource = milestone.resource add_ctxtnav(req, _('Back to Milestone %(name)s', name=milestone.name), get_resource_url(self.env, resource, req.href)) data['milestone'] = milestone.name else: # ticket data['tkt'] = ticket resource = ticket.resource add_ctxtnav(req, _('Back to Ticket #%(id)s', id=ticket.id), get_resource_url(self.env, resource, req.href)) rsc_url = get_resource_url(self.env, resource) data['img_url'] = req.href.depgraph(rsc_url, 'depgraph.%s' % self.default_format, summary=g.label_summary, with_clusters=int(with_clusters)) return 'depgraph.html', data, None
def _process_export(self, req): fields = [{'name': 'id', 'label': 'id'}] fields.extend(TicketSystem(self.env).get_ticket_fields()) fieldsFormat = self._get_fields_format(fields) fieldsExport = self._get_fields_export(fields) fieldsWeight = self._get_fields_weight(fields) comment_changeset = req.args.get('export.changeset') and req.args.get( 'export.changeset') == 'True' fields = [c for c in fields if fieldsExport[c['name']]] fieldnames = [c['name'] for c in fields] fields.sort( lambda a, b: fieldsWeight[a['name']] - fieldsWeight[b['name']]) # ticket #8805 : unavailable for python 2.4 or 2.5 #content = BytesIO() content = cStringIO.StringIO() headerStyle = xlwt.easyxf( 'font: bold on; pattern: pattern solid, fore-colour grey25; borders: top thin, bottom thin, left thin, right thin' ) wb = xlwt.Workbook() sheetName = ('Tickets - %s' % self.config.get('project', 'name', '')) try: ws = wb.add_sheet(sheetName) except: # Project name incompatible with sheet name constraints. sheetName = 'Tickets' ws = wb.add_sheet(sheetName) colIndex = {} c = 0 for f in fields: ws.write(0, c, unicode(f['label']), headerStyle) colIndex[f['name']] = c c += 1 if comment_changeset: ws.write(0, c, unicode('Comments in change log'), headerStyle) constraints = {} if req.args.get('filter.type') and len(req.args['filter.type']) > 0: if type(req.args['filter.type']) == list: constraints['type'] = req.args['filter.type'] else: constraints['type'] = [req.args['filter.type']] if req.args.get('filter.version') and len( req.args['filter.version']) > 0: if type(req.args['filter.version']) == list: constraints['version'] = req.args['filter.version'] else: constraints['version'] = [req.args['filter.version']] if req.args.get('filter.milestone') and len( req.args['filter.milestone']) > 0: if type(req.args['filter.milestone']) == list: constraints['milestone'] = req.args['filter.milestone'] else: constraints['milestone'] = [req.args['filter.milestone']] if req.args.get('filter.component') and len( req.args['filter.component']) > 0: if type(req.args['filter.component']) == list: constraints['component'] = req.args['filter.component'] else: constraints['component'] = [req.args['filter.component']] if req.args.get('filter.status') and len( req.args['filter.status']) > 0: if type(req.args['filter.status']) == list: constraints['status'] = req.args['filter.status'] else: constraints['status'] = [req.args['filter.status']] if req.args.get('filter.priority') and len( req.args['filter.priority']) > 0: if type(req.args['filter.priority']) == list: constraints['priority'] = req.args['filter.priority'] else: constraints['priority'] = [req.args['filter.priority']] if req.args.get('filter.severity') and len( req.args['filter.severity']) > 0: if type(req.args['filter.severity']) == list: constraints['severity'] = req.args['filter.severity'] else: constraints['severity'] = [req.args['filter.severity']] if req.args.get('filter.resolution') and len( req.args['filter.resolution']) > 0: if type(req.args['filter.resolution']) == list: constraints['resolution'] = req.args['filter.resolution'] else: constraints['resolution'] = [req.args['filter.resolution']] query = Query(self.env, cols=fieldnames, order='id', max=sys.maxint, constraints=constraints) results = query.execute(req) r = 0 cols = query.get_columns() for result in results: r += 1 for col in cols: value = result[col] format = self.formats[fieldsFormat[col]] value = format.convert(value) style = format.get_style(value) ws.write(r, colIndex[col], value, style) if comment_changeset: format = self.formats['longtext'] value = format.convert( self._get_changelog_comments(result['id'])) style = format.get_style(value) ws.write(r, len(cols), value, style) if req.args.get('export.statistics') and req.args.get( 'export.statistics') == 'True': wb = self._add_statistics_sheet(req, sheetName, wb, fields, colIndex, constraints) wb.save(content) return (content.getvalue(), 'application/excel')
def _get_permitted_tickets(self, req, constraints=None): qry = Query(self.env, constraints=constraints, cols=self.fields, max=0, order="_dynamic") return [ticket for ticket in qry.execute(req) if 'TICKET_VIEW' in req.perm('ticket', ticket['id'])]
def process_request(self, req): realm = req.args['realm'] id = req.args['id'] #Urls to generate the depgraph for a ticket is /depgraph/ticketnum #Urls to generate the depgraph for a milestone is /depgraph/milestone/milestone_name #List of tickets to generate the depgraph for tkt_ids = [] if realm == 'milestone': #we need to query the list of tickets in the milestone query = Query(self.env, constraints={'milestone': [id]}, max=0) tkt_ids = [fields['id'] for fields in query.execute(req)] else: #the list is a single ticket tkt_ids = [int(id)] #the summary argument defines whether we place the ticket id or #its summary in the node's label label_summary = 0 if 'summary' in req.args: label_summary = int(req.args.get('summary')) g = self._build_graph(req, tkt_ids, label_summary=label_summary) if req.path_info.endswith('/depgraph.png') or 'format' in req.args: format = req.args.get('format') if format == 'text': #in case g.__str__ returns unicode, we need to convert it in ascii req.send(to_unicode(g).encode('ascii', 'replace'), 'text/plain') elif format == 'debug': import pprint req.send( pprint.pformat( [TicketLinks(self.env, tkt_id) for tkt_id in tkt_ids] ), 'text/plain') elif format is not None: if format in self.acceptable_formats: req.send(g.render(self.dot_path, format), 'text/plain') else: raise TracError(_("The %(format)s format is not allowed.", format=format)) if self.use_gs: ps = g.render(self.dot_path, 'ps2') gs = subprocess.Popen( [self.gs_path, '-q', '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sDEVICE=png16m', '-sOutputFile=%stdout%', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) img, err = gs.communicate(ps) if err: self.log.debug('MasterTickets: Error from gs: %s', err) else: img = g.render(self.dot_path) req.send(img, 'image/png') else: data = {} #add a context link to enable/disable labels in nodes if label_summary: add_ctxtnav(req, 'Without labels', req.href(req.path_info, summary=0)) else: add_ctxtnav(req, 'With labels', req.href(req.path_info, summary=1)) if realm == 'milestone': add_ctxtnav(req, 'Back to Milestone: %s' % id, req.href.milestone(id)) data['milestone'] = id else: data['ticket'] = id add_ctxtnav(req, 'Back to Ticket #%s' % id, req.href.ticket(id)) data['graph'] = g data['graph_render'] = partial(g.render, self.dot_path) data['use_gs'] = self.use_gs return 'depgraph.html', data, None
def process_request(self, req): path_info = req.path_info[10:] if not path_info: raise TracError('No ticket specified') #list of tickets to generate the depgraph for tkt_ids = [] milestone = None split_path = path_info.split('/', 2) #Urls to generate the depgraph for a ticket is /depgraph/ticketnum #Urls to generate the depgraph for a milestone is /depgraph/milestone/milestone_name if split_path[0] == 'milestone': #we need to query the list of tickets in the milestone milestone = split_path[1] query = Query(self.env, constraints={'milestone': [milestone]}, max=0) tkt_ids = [fields['id'] for fields in query.execute()] else: #the list is a single ticket tkt_ids = [int(split_path[0])] #the summary argument defines whether we place the ticket id or #it's summary in the node's label label_summary = 0 if 'summary' in req.args: label_summary = int(req.args.get('summary')) g = self._build_graph(req, tkt_ids, label_summary=label_summary) if path_info.endswith('/depgraph.png') or 'format' in req.args: format = req.args.get('format') if format == 'text': #in case g.__str__ returns unicode, we need to convert it in ascii req.send( to_unicode(g).encode('ascii', 'replace'), 'text/plain') elif format == 'debug': import pprint req.send( pprint.pformat( [TicketLinks(self.env, tkt_id) for tkt_id in tkt_ids]), 'text/plain') elif format is not None: req.send(g.render(self.dot_path, format), 'text/plain') if self.use_gs: ps = g.render(self.dot_path, 'ps2') gs = subprocess.Popen([ self.gs_path, '-q', '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sDEVICE=png16m', '-sOutputFile=%stdout%', '-' ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) img, err = gs.communicate(ps) if err: self.log.debug('MasterTickets: Error from gs: %s', err) else: img = g.render(self.dot_path) req.send(img, 'image/png') else: data = {} #add a context link to enable/disable labels in nodes if label_summary: add_ctxtnav(req, 'Without labels', req.href(req.path_info, summary=0)) else: add_ctxtnav(req, 'With labels', req.href(req.path_info, summary=1)) if milestone is None: tkt = Ticket(self.env, tkt_ids[0]) data['tkt'] = tkt add_ctxtnav(req, 'Back to Ticket #%s' % tkt.id, req.href.ticket(tkt.id)) else: add_ctxtnav(req, 'Back to Milestone %s' % milestone, req.href.milestone(milestone)) data['milestone'] = milestone data['graph'] = g data['graph_render'] = partial(g.render, self.dot_path) data['use_gs'] = self.use_gs return 'depgraph.html', data, None
def _load_ticket_ids(self): query = Query(self.env, cols=['id'], order='id') return query.execute()
def _make_data(self,req,opts): arg_x_min = opts['start'] arg_x_max = opts['end'] per = opts['per'] query_str = opts['query'] fieldlist = opts['col'] upper = opts['upper'] if len(query_str)>1 and query_str[0]!='?': query_str = query_str + ''.join(['&col=%s'%field for field in fieldlist]) query = Query.from_string(self.env, query_str) elif len(query_str)>1 and query_str[0]=='?': constraints = self._get_constraints(self._urlstring_to_reqarg(query_str)) query = Query(self.env, constraints=constraints, cols=fieldlist) else: constraints = self._get_constraints(req.args) query = Query(self.env, constraints=constraints, cols=fieldlist) self.log.debug(query.get_sql()) result = query.execute(req, db=None, cached_ids=None) result_len = len(result) daylists = [] edgedays = [] for fieldname in fieldlist: daylist =[] dayids = {} for ticket in result: try: dtin = ticket[fieldname] # parse date if isinstance(dtin, (str,unicode)): dt = parse_date(dtin) else: dt = to_datetime(dtin) except: continue d = datetime(dt.year,dt.month,dt.day,tzinfo=req.tz) daylist.append(d) daylists.append( (daylist,dayids) ) if len(daylist)>0 : edgedays.append(min(daylist)) edgedays.append(max(daylist)) if len(edgedays)==0: return None#'''No data to output.''' x_min = arg_x_min or min(edgedays) x_max = arg_x_max or max(edgedays) x_min = datetime(x_min.year,x_min.month,x_min.day,tzinfo=x_min.tzinfo) x_max = datetime(x_max.year,x_max.month,x_max.day,tzinfo=x_max.tzinfo) if per=='week': x_axis = [x_min+timedelta(x) for x in range(0,(x_max-x_min).days+7,7)] x_max = x_axis[-1] # As x_axis[-1] may be larger than x_max. else: #'day','free' x_axis = [x_min+timedelta(x) for x in range(0,(x_max-x_min).days+1)] counts={} linenum = 0 for daylist,dayids in daylists: for x in x_axis: count = len([1 for c in daylist if c <= x]) #ids = [dayids[c] for c in daylist if c <= x and c>last_x ] #points.append(Point(x,count)) if not upper: count = result_len - count counts[(x,linenum)] = count linenum += 1 return {'x_axis':x_axis, 'counts':counts, 'linenum':linenum, 'x_min':x_min, 'x_max':x_max, 'fieldlist':fieldlist, 'result_len':result_len}