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 test_trac(build_trac_env): """Create a sample Ticket and check if the Ticket-Count == 1 """ env = build_trac_env env_dict = {} env_dict['trac.base_url'] = 'http://127.0.0.1:8000/trac/' # Create the Request req = Request(env_dict, None) req.authname = 'JohnDoe' req.perm = 'TICKET_ADMIN' req.tz = 42 req.locale = 42 # Create a Ticket t = model.Ticket(env) t['summary'] = 'Summary' t['description'] = 'Description' t['reporter'] = req.authname t['status'] = 'new' t['resolution'] = '' t.insert() # Count Tickets q = Query(env) qc = q.count(req) assert qc == 1
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_repeated_constraint_field(self): like_query = Query.from_string(self.env, "owner!=someone|someone_else", order="id") query = Query.from_string(self.env, "owner!=someone&owner!=someone_else", order="id") like_sql, like_args = like_query.get_sql() sql, args = query.get_sql() self.assertEqualSQL(sql, like_sql) self.assertEqual(args, like_args) tickets = query.execute(self.req)
def _get_product_info(self, product, href, resource, max_): penv = ProductEnvironment(self.env, product.prefix) results = [] # some queries return a list/tuple, some a generator, # hence count() to get the result length def count(iter_): try: return len(iter_) except TypeError: return sum(1 for _ in iter_) query = resource['type'].select(penv) for q in itertools.islice(query, max_): q.url = href(resource['name'], q.name) \ if resource.get('hrefurl') \ else Query.from_string(penv, '%s=%s&%s&col=%s' % (resource['name'], q.name, self.COMMON_QUERY, resource['name']) ).get_href(href) q.ticket_count = penv.db_query(""" SELECT COUNT(*) FROM ticket WHERE ticket.%s='%s' AND ticket.status <> 'closed' """ % (resource['name'], q.name))[0][0] results.append(q) # add a '(No <milestone/component/version>)' entry if there are # tickets without an assigned resource in the product ticket_count = penv.db_query( """SELECT COUNT(*) FROM ticket WHERE %s='' AND status <> 'closed'""" % (resource['name'],))[0][0] if ticket_count != 0: q = resource['type'](penv) q.name = '(No %s)' % (resource['name'],) q.url = Query.from_string(penv, 'status=!closed&col=id&col=summary&col=owner' '&col=status&col=priority&order=priority&%s=' % (resource['name'],) ).get_href(href) q.ticket_count = ticket_count results.append(q) results.sort(key=lambda x: x.ticket_count, reverse=True) # add a link to the resource list if there are # more than max resources defined if count(query) > max_: q = resource['type'](penv) q.name = _('... more') q.ticket_count = None q.url = href(resource['name']) if resource.get('hrefurl') \ else href.dashboard() results.append(q) return results
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_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_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_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 __init__(self, env, **kwargs): self.env = env if kwargs: querystring = "type=testrun" for key, value in kwargs.iteritems(): querystring += "&%s=%s" % (key, value) self.query = TicketQuery.from_string(env, querystring) else: # query * testrun tickets self.query = TicketQuery.from_string(env, "type=testrun")
def query(self, req, qstr): """Retrieve all tickets associated with a query string""" q = Query.from_string(self.env, qstr) filters = Query.to_string(q) ticket_realm = Resource('ticket') out = [] for t in q.execute(req): tid = t['id'] if 'TICKET_VIEW' in req.perm(ticket_realm(id=tid)): out.append(tid) return filters, out
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_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_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_template_data(self): req = Mock(href=self.env.href, perm=MockPerm(), authname="anonymous", tz=None, locale=None) context = web_context(req, "query") query = Query.from_string(self.env, "owner=$USER&order=id") tickets = query.execute(req) data = query.template_data(context, tickets, req=req) self.assertEqual(["anonymous"], data["clauses"][0]["owner"]["values"]) query = Query.from_string(self.env, "owner=$USER&order=id") tickets = query.execute(req) data = query.template_data(context, tickets) self.assertEqual(["$USER"], data["clauses"][0]["owner"]["values"])
def test_template_data(self): req = Mock(href=self.env.href, perm=MockPerm(), authname='anonymous', tz=None, locale=None) context = web_context(req, 'query') query = Query.from_string(self.env, 'owner=$USER&order=id') tickets = query.execute(req) data = query.template_data(context, tickets, req=req) self.assertEqual(['anonymous'], data['clauses'][0]['owner']['values']) query = Query.from_string(self.env, 'owner=$USER&order=id') tickets = query.execute(req) data = query.template_data(context, tickets) self.assertEqual(['$USER'], data['clauses'][0]['owner']['values'])
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 get_query(self, constraints=None, args=None): req = self.req if not args: args = req.args if not constraints: # If no constraints are given in the URL, use the default ones. if req.authname and req.authname != 'anonymous': qstring = self.default_query user = req.authname else: email = req.session.get('email') name = req.session.get('name') qstring = self.default_anonymous_query user = email or name or None query = Query.from_string(self.env, qstring) args = {'order': query.order, 'col': query.cols, 'max': 0} constraints = query.constraints # Substitute $USER, or ensure no field constraints that depend # on $USER are used if we have no username. for clause in constraints: for field, vals in clause.items(): for (i, val) in enumerate(vals): if user: vals[i] = val.replace('$USER', user) elif val.endswith('$USER'): del clause[field] break query = Query(self.env, args.get('report'), constraints, self._get_cols(), args.get('order'), args.get('desc')) self._set_no_paginator(query) return query
def harvest(self, req, content): """TicketQuery provider method.""" # Options in 'wikicalendar' configuration section take precedence over # those in old 'wikiticketcalendar' section. c = self.config if 'wikicalendar' in c.sections(): tkt_due_field = c.get('wikicalendar', 'ticket.due_field') else: tkt_due_field = c.get('wikiticketcalendar', 'ticket.due_field.name') # Parse args and kwargs. argv, kwargs = parse_args(content, strict=False) # Define minimal set of values. std_fields = ['description', 'owner', 'status', 'summary'] kwargs['col'] = "|".join(std_fields + [tkt_due_field]) # Construct the querystring. query_string = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) # Get the Query Object. query = Query.from_string(self.env, query_string) # Get the tickets. tickets = self._get_tickets(query, req) return tickets
def execute_query(env, req, query_args): # set maximum number of returned tickets to 0 to get all tickets at once query_args['max'] = 0 def encode(params): from trac.util.text import empty if isinstance(params, dict): params = params.iteritems() l = [] for k, v in params: if v is empty: l.append(k) else: l.append(k + '=' + unicode(v)) return '&'.join(l) query_string = encode(query_args) env.log.debug("query_string: %s", query_string) query = Query.from_string(env, query_string) tickets = query.execute(req) tickets = [t for t in tickets if ('TICKET_VIEW' or 'TICKET_VIEW_CC') in req.perm('ticket', t['id'])] return tickets
def get_profile_actions(self, req, user): """ Return list of actions """ actions = [] homeperm = self._get_home_perm(req) uresource = Resource('user', user.id) # Project settings for own account if user.username == req.authname: actions.append((-40, tag.a(_('View your projects'), href=homeperm.env.href('myprojects')))) actions.append((0, tag.a(_('Edit your settings'), href=homeperm.env.href('prefs')))) # View other user profile else: actions.append((-50, tag.a(_('View service profile'), href=homeperm.env.href('user', user.username)))) # If user can fully manage account if homeperm.has_permission('USER_EDIT', uresource): label = 'Manage your account' if user.username == req.authname else 'Manage account' actions.append((-2, tag.a(_(label), href=homeperm.env.href('admin/users/manage', username=user.username)))) # Tickets assigned to or created by user (if component is enabled and user has permissions to view them) # Note: href.kwargs cannot be used because of reserved word 'or' and un-ordered nature of dict if (self.env.is_component_enabled('trac.ticket.query.QueryModule') or self.env.is_component_enabled('multiproject.project.tickets.viewtickets.QueryModuleInterceptor')) \ and 'TICKET_VIEW' in req.perm: qstring = 'owner={0}&or&reporter={0}&group=status'.format(user.username) query = Query.from_string(self.env, qstring) actions.append((5, (tag.a(_('View tickets'), href=query.get_href(req.href))))) return actions
def harvest(self, req, content): """TicketQuery provider method.""" # Parse args and kwargs. argv, kwargs = parse_args(content, strict=False) # Define minimal set of values. std_fields = ['description', 'owner', 'status', 'summary'] kwargs['col'] = "|".join(std_fields) # Options from old 'wikiticketcalendar' section have been migrated to # 'wikicalendar' configuration section. due_field = self.config.get('wikicalendar', 'ticket.due_field') if due_field: kwargs['col'] += '|' + due_field # Construct the query-string. query_string = '&'.join(['%s=%s' % i for i in kwargs.iteritems()]) # Get the Query object. query = Query.from_string(self.env, query_string) # Initialize query and get 1st "page" of Ticket objects. result = query.execute(req) # Collect tickets from all other query "pages", if available. while query.offset + query.max < query.num_items: query.offset += query.max result.extend(query.execute(req)) # Filter tickets according to (view) permission. tickets = [t for t in result if 'TICKET_VIEW' in req.perm('ticket', t['id'])] return tickets
def process_request(self, req): if req.method != 'POST': raise HTTPBadRequest(_("Only POST is supported")) query = Query(self.env, constraints=QueryModule(self.env)._get_constraints(req), cols=req.args['col'], desc=req.args.get('desc', 0), group=req.args['group'], groupdesc=req.args.get('groupdesc', 0), max=req.args['max'], order=req.args['order']) req.session['default_user_query'] = query.get_href(req.href) add_notice(req, _("Your default query has been changed")) # Let the query system handle the request req.redirect(query.get_href(req.href))
def expand_macro(self, formatter, name, content): req = formatter.req stats_provider, kwargs, is_preview_with_self = self._parse_macro_content(content, req) if is_preview_with_self: # previewing newticket, without a number but with a reference # to current ticket number; show a helpful message return tag.div('Progress meter will be inserted here in final ticket') # Create & execute the query string qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, qstr, max=0) try: constraints = query.constraints[0] except IndexError: constraints = query.constraints # Calculate stats qres = query.execute(req) tickets = apply_ticket_permissions(self.env, req, qres) stats = get_ticket_stats(stats_provider, tickets) stats_data = query_stats_data(req, stats, constraints) # ... and finally display them add_stylesheet(req, 'common/css/roadmap.css') chrome = Chrome(self.env) return chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
def expand_macro(self, formatter, name, content): req = formatter.req query_string = "" argv, kwargs = parse_args(content, strict=False) if "order" not in kwargs: kwargs["order"] = "id" if "max" not in kwargs: kwargs["max"] = "0" # unlimited by default query_string = "&".join(["%s=%s" % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, query_string) tickets = query.execute(req) tickets = [t for t in tickets if "TICKET_VIEW" in req.perm("ticket", t["id"])] ticket_ids = [t["id"] for t in tickets] # locate the tickets geoticket = GeoTicket(self.env) locations = geoticket.locate_tickets(ticket_ids, req) if not locations: return tag.div(tag.b("MapTickets: "), "No locations found for ", tag.i(content)) data = dict(locations=Markup(simplejson.dumps(locations)), query_href=query.get_href(req), query_string=content) # set an id for the map map_id = req.environ.setdefault("MapTicketsId", 0) + 1 req.environ["MapTicketsId"] = map_id data["map_id"] = "tickets-map-%d" % map_id return Chrome(self.env).render_template(req, "map_tickets.html", data, None, fragment=True)
def execute_query(env, req, query_args): # set maximum number of returned tickets to 0 to get all tickets at once query_args['max'] = 0 # urlencode the args, converting back a few vital exceptions: # see the authorized fields in the query language in # http://trac.edgewall.org/wiki/TracQuery#QueryLanguage query_string = unicode_urlencode(query_args)\ .replace('%21=', '!=')\ .replace('%21%7E=', '!~=')\ .replace('%7E=', '~=')\ .replace('%5E=', '^=')\ .replace('%24=', '$=')\ .replace('%21%5E=', '!^=')\ .replace('%21%24=', '!$=')\ .replace('%7C', '|')\ .replace('+', ' ')\ .replace('%23', '#')\ .replace('%28', '(')\ .replace('%29', ')')\ .replace('%2F', '/') env.log.debug("query_string: %s" % query_string) query = Query.from_string(env, query_string) tickets = query.execute(req) tickets = [t for t in tickets if ('TICKET_VIEW' or 'TICKET_VIEW_CC') in req.perm('ticket', t['id'])] return tickets
def expand_macro(self, formatter, name, content): req = formatter.req stats_provider, kwargs = self._parse_macro_content(content, req) # Create & execute the query string qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, qstr, max=0) try: constraints = query.constraints[0] except IndexError: constraints = query.constraints # Calculate stats qres = query.execute(req) tickets = apply_ticket_permissions(self.env, req, qres) stats = get_ticket_stats(stats_provider, tickets) stats_data = query_stats_data(req, stats, constraints) # ... and finally display them add_stylesheet(req, 'common/css/roadmap.css') chrome = Chrome(self.env) return chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
def expand_macro(self, formatter, name, content): req = formatter.req # Parse arguments args, kwargs = parse_args(content, strict=False) assert not args and not ('status' in kwargs or 'format' in kwargs), \ "Invalid input!" # hack the `format` kwarg in order to display all-tickets stats # when no kwargs are supplied kwargs['format'] = 'count' # special case for values equal to 'self': replace with current # ticket number, if available for key in kwargs.keys(): if kwargs[key] == 'self': current_ticket = self._this_ticket(req) if current_ticket: kwargs[key] = current_ticket # Create & execute the query string qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, qstr, max=0) # Calculate stats qres = query.execute(req) tickets = apply_ticket_permissions(self.env, req, qres) stats = get_ticket_stats(self.stats_provider, tickets) stats_data = query_stats_data(req, stats, query.constraints) # ... and finally display them add_stylesheet(req, 'common/css/roadmap.css') chrome = Chrome(self.env) return chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
def expand_macro(self, formatter, name, content): req = formatter.req stats_provider, kwargs, preview = self._parse_macro_content(content, req) # Create & execute the query string qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, qstr) try: # XXX: simplification, may cause problems with more complex queries constraints = query.constraints[0] except IndexError: constraints = {} # Calculate stats qres = query.execute(req) tickets = apply_ticket_permissions(self.env, req, qres) stats = get_ticket_stats(stats_provider, tickets) stats_data = query_stats_data(req, stats, constraints) # ... and finally display them add_stylesheet(req, 'common/css/roadmap.css') chrome = Chrome(self.env) stats_data.update({'preview': preview}) # displaying a preview? return chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
def fetch(self): from trac.ticket.query import Query env = self._connect() cursor = env.get_db_cnx().cursor() for label, info, query in self.queries: q = Query.from_string(env, query) cursor.execute(*q.get_sql()) yield ("%s.value" % label, len(list(cursor)))
def test_constrained_by_empty_value_endswith(self): query = Query.from_string(self.env, 'owner$=|', order='id') 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(t.id,0)=0,t.id""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_constrained_by_id_ranges(self): query = Query.from_string(self.env, 'id=42,44,51-55&order=id') 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) WHERE ((t.id BETWEEN %s AND %s OR t.id IN (42,44))) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual([51, 55], args)
def test_constrained_by_milestone(self): query = Query.from_string(self.env, 'milestone=milestone1', 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.component AS component,t.time AS time,t.changetime AS changetime,t.milestone AS milestone,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE COALESCE(t.milestone,'')='milestone1' ORDER BY COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_all_ordered_by_id_from_unicode(self): query = Query.from_string(self.env, u'order=id') 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,t.id""") self.assertEqual([], args) tickets = query.execute(self.req)
def test_constrained_by_multiple_owners_contain(self): query = Query.from_string(self.env, 'owner~=someone|someone_else', 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 FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE (COALESCE(t.owner,'') LIKE '%someone%' OR COALESCE(t.owner,'') LIKE '%someone_else%') ORDER BY COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_user_var(self): query = Query.from_string(self.env, 'owner=$USER&order=id') sql, args = query.get_sql(req=self.req) 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) WHERE ((COALESCE(t.owner,'')=%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['anonymous'], args) tickets = query.execute(self.req)
def test_constrained_by_owner_not_containing(self): query = Query.from_string(self.env, 'owner!~=someone', order='id') 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) WHERE ((COALESCE(t.owner,'') NOT %(like)s)) ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_read_db().like()}) self.assertEqual(['%someone%'], args) tickets = query.execute(self.req)
def test_constrained_by_milestone_or_version(self): query = Query.from_string(self.env, 'milestone=milestone1&or&version=version1', order='id') 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,t.version AS version,t.milestone AS milestone,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE ((COALESCE(t.milestone,'')=%s)) OR ((COALESCE(t.version,'')=%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['milestone1', 'version1'], args) tickets = query.execute(self.req)
def test_constrained_by_keywords(self): query = Query.from_string(self.env, 'keywords~=foo -bar baz', order='id') sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,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) WHERE (((COALESCE(t.keywords,'') %(like)s AND COALESCE(t.keywords,'') NOT %(like)s AND COALESCE(t.keywords,'') %(like)s))) ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_read_db().like()}) self.assertEqual(['%foo%', '%bar%', '%baz%'], args) tickets = query.execute(self.req)
def expand_macro(self, formatter, name, content): req = formatter.req query_string = TicketQueryMacro.parse_args(content)[0] kwargs = dict([item.split('=') for item in content.split(',')[1:]]) try: query = Query.from_string(self.env, query_string) except QuerySyntaxError as e: raise MacroError(e) try: tickets = query.execute(req) except QueryValueError as e: raise MacroError(e) # Formats above had their own permission checks, here we need to # do it explicitly: tickets = [t for t in tickets if 'TICKET_VIEW' in req.perm(self.realm, t['id'])] tickets = map(lambda x: Ticket(self.env, x['id']), tickets) schedule_info = {'test': TicketScheduleSystem(self.env).get_schedule(tickets)} add_script(req, 'ticketrelation/js/bundle.js') add_stylesheet(req, 'ticketrelation/css/schedule.css') random_id = str(random.randint(0, 10000)) config = { 'url': req.base_url, 'startDate': kwargs.get('startdate', None), 'finishDate': kwargs.get('finishdate', None), 'showUnavailable': kwargs.get('showunavailable', 1) } return tag.div(tag.div( tag.schedule(**{':schedule': 'schedule', ':config': 'config'}), class_='schedule_container', id='schedule_container_' + random_id), tag.script(""" $(window).load(function() { var data = %s; var config = %s; var app = new window.Vue({ el: '#schedule_container_%s', data: { schedule: data, config: config, } }); });""" % (json.dumps(schedule_info, cls=DateTimeEncoder), json.dumps(config, cls=DateTimeEncoder), random_id)) )
def test_constrained_by_time_range_modified(self): query = Query.from_string(self.env, 'modified=2008-08-01..2008-09-01', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.changetime AS changetime,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s))) ORDER BY COALESCE(t.id,0)=0,t.id""" % { 'cast_changetime': self.env.get_read_db().cast('t.changetime', 'int64')}) self.assertEqual([1217548800000000L, 1220227200000000L], args) tickets = query.execute(self.req)
def _format_link(self, formatter, ns, query, label): if query[0] == '?': return '<a class="query" href="%s">%s</a>' \ % (formatter.href.query() + escape(query), escape(label)) else: from trac.ticket.query import Query, QuerySyntaxError try: query = Query.from_string(formatter.env, query) return '<a class="query" href="%s">%s</a>' \ % (escape(query.get_href()), escape(label)) except QuerySyntaxError, e: return '<em class="error">[Error: %s]</em>' % escape(e)
def test_constrained_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query.from_string(self.env, 'foo=something', 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) WHERE COALESCE(foo.value,'')='something' ORDER BY COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
def test_special_character_escape(self): query = Query.from_string(self.env, r'status=here\&now|maybe\|later|back\slash', order='id') sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.status AS status,t.owner AS owner,t.type AS type,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) WHERE (COALESCE(t.status,'') IN (%s,%s,%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['here&now', 'maybe|later', 'back\\slash'], args) tickets = query.execute(self.req)
def test_equal_in_value(self): query = Query.from_string(self.env, r'status=this=that&version=version1', order='id') 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.priority AS priority,t.milestone AS milestone,t.component AS component,t.status AS status,t.time AS time,t.changetime AS changetime,t.version AS version,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE ((COALESCE(t.status,'')=%s) AND (COALESCE(t.version,'')=%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['this=that', 'version1'], args) tickets = query.execute(self.req)
def test_query(self): mod = ExcelTicketModule(self.env) req = MockRequest(self.env) query = Query.from_string(self.env, 'status=!closed&max=9') content, mimetype = mod.convert_content(req, self._mimetype, query, 'excel') self.assertEqual(self._magic_number, content[:8]) self.assertEqual(self._mimetype, mimetype) content, mimetype = mod.convert_content(req, self._mimetype, query, 'excel-history') self.assertEqual(self._magic_number, content[:8]) self.assertEqual(self._mimetype, mimetype)
def test_constrained_by_status(self): query = Query.from_string(self.env, 'status=new|assigned|reopened', order='id') sql, args = query.get_sql() self.assertEqualSQL(sql, """SELECT t.id AS id,t.summary AS summary,t.status AS status,t.owner AS owner,t.type AS type,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) WHERE (COALESCE(t.status,'') IN (%s,%s,%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['new', 'assigned', 'reopened'], args) tickets = query.execute(self.req)
def test_constrained_by_multiple_owners_not(self): query = Query.from_string(self.env, 'owner!=someone|someone_else', order='id') 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) WHERE (COALESCE(t.owner,'') NOT IN (%s,%s)) ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['someone', 'someone_else'], args) tickets = query.execute(self.req)
def test_constrained_by_owner_beginswith(self): query = Query.from_string(self.env, 'owner^=someone', 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) WHERE COALESCE(t.owner,'') LIKE %s ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['someone%'], args) tickets = query.execute(Mock(href=self.env.href))
def convert_content(self, req, mimetype, content, key): if key == 'excel': return self._convert_query(req, content) if key == 'excel-history': kwargs = {} if isinstance(content, Ticket): content = Query.from_string(self.env, 'id=%d' % content.id) kwargs['sheet_query'] = False kwargs['sheet_history'] = True else: kwargs['sheet_query'] = True kwargs['sheet_history'] = True return self._convert_query(req, content, **kwargs)
def test_constrained_by_id_and_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') ticket = Ticket(self.env) ticket['reporter'] = 'joe' ticket['summary'] = 'Foo' ticket['foo'] = 'blah' ticket.insert() query = Query.from_string(self.env, 'id=%d-42&foo=blah' % ticket.id) tickets = query.execute(self.req) self.assertEqual(1, len(tickets)) self.assertEqual(ticket.id, tickets[0]['id']) query = Query.from_string(self.env, 'id=%d,42&foo=blah' % ticket.id) tickets = query.execute(self.req) self.assertEqual(1, len(tickets)) self.assertEqual(ticket.id, tickets[0]['id']) query = Query.from_string(self.env, 'id=%d,42,43-84&foo=blah' % ticket.id) tickets = query.execute(self.req) self.assertEqual(1, len(tickets)) self.assertEqual(ticket.id, tickets[0]['id'])
def test_constrained_by_custom_field(self): self.env.config.set('ticket-custom', 'foo', 'text') query = Query.from_string(self.env, 'foo=something', 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) WHERE ((COALESCE(%s.value,'')=%%s)) ORDER BY COALESCE(t.id,0)=0,t.id""" % ((foo,) * 6)) self.assertEqual(['something'], args) tickets = query.execute(self.req)
def render_widget(self, name, context, options): """Gather product list and render data in compact view """ data = {} req = context.req title = '' params = ('max', 'cols') max_, cols = self.bind_params(name, options, *params) if not isinstance(req.perm.env, ProductEnvironment): for p in Product.select(self.env): if 'PRODUCT_VIEW' in req.perm(Neighborhood( 'product', p.prefix)): for resource in ( { 'type': Milestone, 'name': 'milestone', 'hrefurl': True }, { 'type': Component, 'name': 'component' }, { 'type': Version, 'name': 'version' }, ): setattr(p, resource['name'] + 's', self._get_product_info(p, resource, max_)) p.owner_link = Query.from_string( self.env, 'status!=closed&' 'col=id&col=summary&col=owner&col=status&col=priority&' 'order=priority&group=product&owner=%s' % (p._data['owner'] or '', )).get_href(req.href) data.setdefault('product_list', []).append(p) title = _('Products') data['colseq'] = itertools.cycle(xrange(cols - 1, -1, -1)) if cols \ else itertools.repeat(1) return 'widget_product.html', \ { 'title': title, 'data': data, 'ctxtnav' : [ tag.a(_('More'), href = context.req.href('products'))], }, \ context
def test_too_many_custom_fields(self): fields = ['col_%02d' % i for i in xrange(100)] for f in fields: self.env.config.set('ticket-custom', f, 'text') ticket = Ticket(self.env) ticket['reporter'] = 'joe' ticket['summary'] = 'Foo' for idx, f in enumerate(fields): ticket[f] = '%d.%s' % (idx, f) ticket.insert() string = 'col_00=0.col_00&order=id&col=id&col=reporter&col=summary' + \ ''.join('&col=' + f for f in fields) query = Query.from_string(self.env, string) tickets = query.execute(self.req) self.assertEqual(ticket.id, tickets[0]['id']) self.assertEqual('joe', tickets[0]['reporter']) self.assertEqual('Foo', tickets[0]['summary']) self.assertEqual('0.col_00', tickets[0]['col_00']) self.assertEqual('99.col_99', tickets[0]['col_99']) query = Query.from_string(self.env, 'col_00=notfound') self.assertEqual([], query.execute(self.req))
def execute_query(env, req, query_args): query_string = '&'.join(['%s=%s' % item for item in query_args.iteritems()]) query = Query.from_string(env, query_string) # oooh, nasty import sys query.max = sys.maxint tickets = query.execute(req) tickets = [t for t in tickets if ('TICKET_VIEW' or 'TICKET_VIEW_CC') in req.perm('ticket', t['id'])] return tickets
def render_poll(self, req, title, votes): from trac.ticket.model import Ticket, Priority from trac.ticket.query import Query add_stylesheet(req, 'poll/css/poll.css') if not req.perm.has_permission('POLL_VIEW') or \ not req.perm.has_permission('TICKET_VIEW'): return '' all_votes = [] ticket_count = 0 for vote in votes: tickets = [] if vote.startswith('#'): try: tickets.append(int(vote.strip('#'))) except ValueError: raise TracError('Invalid ticket number %s' % vote) elif vote.startswith('query:'): query = vote[6:] tickets = [q['id'] for q in Query.from_string(self.env, query).execute(req)] else: all_votes.append(('%08x' % abs(hash(vote)), None, wiki_to_oneliner(vote, self.env))) # Make tickets look pretty for idx, id in enumerate(tickets): try: ticket = Ticket(self.env, id) except Exception: continue summary = ticket['summary'] + ' (#%i)' % id priority = Priority(self.env, ticket['priority']).value summary = wiki_to_oneliner(summary, self.env) all_votes.append((str(id), "ticket prio%s%s%s" % (priority, ticket_count % 2 and ' even' or '', ticket['status'] == 'closed' and ' closed' or ''), summary)) ticket_count += 1 if not all_votes: raise TracError('No votes provided') poll = Poll(self.base_dir, title, all_votes) if req.perm.has_permission('POLL_VOTE'): poll.populate(req) return poll.render(self.env, req)
def get_profile_actions(self, req, user): """ Return list of actions """ actions = [] homeperm = self._get_home_perm(req) uresource = Resource('user', user.id) # Project settings for own account if user.username == req.authname: actions.append((-40, tag.a(_('View your projects'), href=homeperm.env.href('myprojects')))) actions.append((0, tag.a(_('Edit your settings'), href=homeperm.env.href('prefs')))) # View other user profile else: actions.append( (-50, tag.a(_('View service profile'), href=homeperm.env.href('user', user.username)))) # If user can fully manage account if homeperm.has_permission('USER_EDIT', uresource): label = 'Manage your account' if user.username == req.authname else 'Manage account' actions.append( (-2, tag.a(_(label), href=homeperm.env.href('admin/users/manage', username=user.username)))) # Tickets assigned to or created by user (if component is enabled and user has permissions to view them) # Note: href.kwargs cannot be used because of reserved word 'or' and un-ordered nature of dict if (self.env.is_component_enabled('trac.ticket.query.QueryModule') or self.env.is_component_enabled('multiproject.project.tickets.viewtickets.QueryModuleInterceptor')) \ and 'TICKET_VIEW' in req.perm: qstring = 'owner={0}&or&reporter={0}&group=status'.format( user.username) query = Query.from_string(self.env, qstring) actions.append((5, (tag.a(_('View tickets'), href=query.get_href(req.href))))) return actions
def get_tickets(self): """ yield all the tickets per self._env and self._milestones """ query = ['status!=closed'] if self._milestones: query.append('milestone={}'.format('|'.join( mstone for mstone in self._milestones))) print "query: ", query q = Query.from_string(self._env, '&'.join(query)) q.max = 10000000 res = q.execute() res = filter(lambda ticket: (ticket['time'].year >= self._min_year), res) for i, ticket in enumerate(res): ticket = self.ticket(ticket) print "handling ticket", ticket, i, "/", len(res) yield ticket
def expand_macro(self, formatter, name, content): req = formatter.req query_string = '' argv, kwargs = parse_args(content, strict=False) if 'order' not in kwargs: kwargs['order'] = 'id' if 'max' not in kwargs: kwargs['max'] = '0' # unlimited by default query_string = '&'.join( ['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, query_string) tickets = query.execute(req) tickets = [ t for t in tickets if 'TICKET_VIEW' in req.perm('ticket', t['id']) ] ticket_ids = [t['id'] for t in tickets] # locate the tickets geoticket = GeoTicket(self.env) locations = geoticket.locate_tickets(ticket_ids, req) if not locations: return tag.div(tag.b('MapTickets: '), "No locations found for ", tag.i(content)) data = dict(locations=Markup(simplejson.dumps(locations)), query_href=query.get_href(req), query_string=content) # set an id for the map map_id = req.environ.setdefault('MapTicketsId', 0) + 1 req.environ['MapTicketsId'] = map_id data['map_id'] = 'tickets-map-%d' % map_id return Chrome(self.env).render_template(req, 'map_tickets.html', data, None, fragment=True)