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_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 __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 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 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 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 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 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 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 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 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 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 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 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', ')') 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 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 test_constrained_by_empty_value_endswith(self): query = Query.from_string(self.env, 'owner$=|', 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) ORDER BY COALESCE(t.id,0)=0,t.id""") tickets = query.execute()
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_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_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_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_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_milestone(self): query = Query.from_string(self.env, 'milestone=milestone1', 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.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,'')=%s ORDER BY COALESCE(t.id,0)=0,t.id""") self.assertEqual(['milestone1'], args) tickets = query.execute(Mock(href=self.env.href))
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 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_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_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_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 _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_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_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 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_constrained_by_owner_endswith(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 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 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_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 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 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_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)