def process_request(self, req): """Process the request.""" id = int(req.args.get('id')) req.perm('ticket', id).require('TICKET_VIEW') if 'TICKET_REMINDER_MODIFY' not in req.perm and \ 'TICKET_ADMIN' not in req.perm: raise PermissionError('TICKET_REMINDER_MODIFY', req.perm._resource, self.env) ticket = Ticket(self.env, id) if 'cancel' in req.args: req.redirect(get_resource_url(self.env, ticket.resource, req.href)) ticket_name = get_resource_name(self.env, ticket.resource) ticket_url = get_resource_url(self.env, ticket.resource, req.href) add_link(req, 'up', ticket_url, ticket_name) add_ctxtnav(req, _('Back to %(ticket)s', ticket=ticket_name), ticket_url) add_stylesheet(req, 'ticketreminder/css/ticketreminder.css') if req.args['action'] == "addreminder": return self._process_add(req, ticket) elif req.args['action'] == "deletereminder": return self._process_delete(req, ticket) else: raise ValueError('Unknown action "%s"' % (req.args['action'],))
def process_request(self, req): """Process the request.""" id = int(req.args.get('id')) req.perm('ticket', id).require('TICKET_VIEW') if 'TICKET_REMINDER_MODIFY' not in req.perm and \ 'TICKET_ADMIN' not in req.perm: raise PermissionError('TICKET_REMINDER_MODIFY', req.perm._resource, self.env) ticket = Ticket(self.env, id) if 'cancel' in req.args: req.redirect(get_resource_url(self.env, ticket.resource, req.href)) ticket_name = get_resource_name(self.env, ticket.resource) ticket_url = get_resource_url(self.env, ticket.resource, req.href) add_link(req, 'up', ticket_url, ticket_name) add_ctxtnav(req, _('Back to %(ticket)s', ticket=ticket_name), ticket_url) add_stylesheet(req, 'ticketreminder/css/ticketreminder.css') if req.args['action'] == "addreminder": return self._process_add(req, ticket) elif req.args['action'] == "deletereminder": return self._process_delete(req, ticket) else: raise ValueError('Unknown action "%s"' % (req.args['action'], ))
def format_and_send_attachment_notification(self, attachment, action): if not self.tickets_notifications: return args = self.make_args({ 'component': esc(attachment.parent_realm), 'timestamp': '' }) if action == 'added': args['author'] = esc(authorinfo(attachment.author)) args['url'] = esc( get_resource_url(self.env, attachment.resource, self.env.abs_href)) desc = attachment.description and (" '" + attachment.description + "'") or "" args['log'] = esc( 'File ' + attachment.filename + ("%s has been attached to " % desc) + get_resource_name(self.env, attachment.resource.parent)) args['version'] = '' elif action == 'deleted': args['author'] = '' args['log'] = esc( 'File ' + attachment.filename + ' has been deleted from ' + get_resource_name(self.env, attachment.resource.parent)) args['version'] = '' args['url'] = esc( get_resource_url(self.env, attachment.resource.parent, self.env.abs_href)) else: raise Exception('Unknown action type') self.send_message(message_template % args)
def expand_macro(self, formatter, name, content): env = formatter.env req = formatter.req if not 'VOTE_VIEW' in req.perm: return # Simplify function calls. format_author = partial(Chrome(self.env).format_author, req) if not content: args = [] compact = None kw = {} top = 5 else: args, kw = parse_args(content) compact = 'compact' in args and True top = as_int(kw.get('top'), 5, min=0) if name == 'LastVoted': lst = tag.ul() for i in self.get_votes(req, top=top): resource = Resource(i[0], i[1]) # Anotate who and when. voted = ('by %s at %s' % (format_author(i[3]), format_datetime(to_datetime(i[4])))) lst(tag.li(tag.a( get_resource_description(env, resource, compact and 'compact' or 'default'), href=get_resource_url(env, resource, formatter.href), title=(compact and '%+i %s' % (i[2], voted) or None)), (not compact and Markup(' %s %s' % (tag.b('%+i' % i[2]), voted)) or ''))) return lst elif name == 'TopVoted': realm = kw.get('realm') lst = tag.ul() for i in self.get_top_voted(req, realm=realm, top=top): if 'up-only' in args and i[2] < 1: break resource = Resource(i[0], i[1]) lst(tag.li(tag.a( get_resource_description(env, resource, compact and 'compact' or 'default'), href=get_resource_url(env, resource, formatter.href), title=(compact and '%+i' % i[2] or None)), (not compact and ' (%+i)' % i[2] or ''))) return lst elif name == 'VoteList': lst = tag.ul() resource = resource_from_path(env, req.path_info) for i in self.get_votes(req, resource, top=top): vote = ('at %s' % format_datetime(to_datetime(i[4]))) lst(tag.li( compact and format_author(i[3]) or Markup(u'%s by %s %s' % (tag.b('%+i' % i[2]), tag(format_author(i[3])), vote)), title=(compact and '%+i %s' % (i[2], vote) or None))) return lst
def filter_stream(self, req, method, filename, stream, data): if filename != 'report_view.html': return stream page_name = 'report:%s' % data['context'].resource.id page_label = data['title'] page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream text = '= Snapshot of [%s %s]: =\n' % (page_name, page_label) text += '{{{#!QueryResults\n' cols = [header['col'] for header in data.get('header_groups', [[]])[0] if not header['hidden']] cols_work = [t for t in cols] # copy if 'ticket' in cols_work: cols_work[cols_work.index('ticket')] = 'id' # replace 'ticket' to 'id' text += '||= href =||= %s\n' % ' =||= '.join(cols_work) for groupindex, row_group in data.get('row_groups', []): text += '|| group: %s\n' % groupindex for row in row_group: row = row['cell_groups'][0] ticket = {} for value in row: ticket[value['header']['col']] = value['value'] ticket['href'] = get_resource_url(self.env, Resource('ticket', ticket.get('ticket', 0)), self.env.href) text += '|| %s || %s\n' % (ticket['href'], ' || '.join([self.formatter(col, ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def post_process_request(self, req, template, data, content_type): if req.path_info.startswith('/ticket/'): # In case of an invalid ticket, the data is invalid if not data: return template, data, content_type tkt = data['ticket'] self.pm.check_component_enabled(self, pid=tkt.pid) links = TicketLinks(self.env, tkt) # Add link to depgraph if needed if links: add_ctxtnav(req, _('Depgraph'), req.href.depgraph(get_resource_url(self.env, tkt.resource))) for change in data.get('changes', {}): if not change.has_key('fields'): continue for field, field_data in change['fields'].iteritems(): if field in self.fields: vals = {} for i in ('new', 'old'): if isinstance(field_data[i], basestring): val = field_data[i].strip() else: val = '' if val: vals[i] = set([int(n) for n in val.split(',')]) else: vals[i] = set() add = vals['new'] - vals['old'] sub = vals['old'] - vals['new'] elms = tag() if add: elms.append( tag.em(u', '.join([unicode(n) for n in sorted(add)])) ) elms.append(u' added') if add and sub: elms.append(u'; ') if sub: elms.append( tag.em(u', '.join([unicode(n) for n in sorted(sub)])) ) elms.append(u' removed') field_data['rendered'] = elms #add a link to generate a dependency graph for all the tickets in the milestone if req.path_info.startswith('/milestone/'): if not data or not 'milestone' in data: return template, data, content_type milestone=data['milestone'] self.pm.check_component_enabled(self, pid=milestone.pid) add_ctxtnav(req, _('Depgraph'), req.href.depgraph(get_resource_url(self.env, milestone.resource))) return template, data, content_type
def test_resource_repository(self): res = Resource('repository', 'testrepo') self.assertEqual('Repository testrepo', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/browser/testrepo', get_resource_url(self.env, res, self.env.href)) res = Resource('repository', '') # default repository self.assertEqual('Default repository', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/browser', get_resource_url(self.env, res, self.env.href))
def test_resource_changeset(self): res = Resource('changeset', '42') self.assertEqual('Changeset 42', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/changeset/42', get_resource_url(self.env, res, self.env.href)) repo = Resource('repository', 'repo') res = Resource('changeset', '42', parent=repo) self.assertEqual('Changeset 42 in repo', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/changeset/42/repo', get_resource_url(self.env, res, self.env.href))
def get_resource_url(self, resource, href, form_realms=None, **kwargs): if self.wiki_page_link: page = WikiPage(self.env, resource.id) if page.exists: return get_resource_url(self.env, page.resource, href, **kwargs) return href.tags(unicode(resource.id), form_realms, **kwargs)
def filter_stream(self, req, method, filename, stream, data): if filename != 'query.html': return stream query_string = 'query:' + '&'.join(['%s=%s' % (key, '|'.join([cond for cond in values])) for constraint in data['query'].constraints for key, values in constraint.items()]) page_name = 'report_resource' in data and \ 'report:%s' % data['report_resource'].id or query_string if 'page_name' in req.args: page_name = req.args['page_name'] query_string += '&page_name=%s' % page_name page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream cols = [header['name'] for header in data['headers']] text = '= Snapshot of [%s the query]: =\n' % query_string text += '{{{#!QueryResults(group=%s) \n' % data['query'].group text += '||= href =||= %s\n' % ' =||= '.join(cols) for (group_name, tickets) in data['groups']: text += '|| group: %s\n' % group_name for ticket in tickets: text += '|| %s || %s\n' % (ticket['href'], ' || '.join([self.formatter(ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def _format_tagged(self, formatter, target, label): if label: href = formatter.context.href url = get_resource_url(self.env, Resource('tag', target), href) return tag.a(label, href=url) return render_resource_link(self.env, formatter.context, Resource('tag', target))
def _result(doc): changed = doc.changed href = get_resource_url(self.env, doc.resource, req.href) title = doc.title or get_resource_shortname(self.env, doc.resource) author = ", ".join(doc.author or []) excerpt = doc.oneline or "" return (href, title, changed, author, excerpt)
def get_href(self, req, per_page=None, page=None, tag=None, **kwargs): """Prepare href objects for tag links and pager navigation. Generate form-related arguments, strip arguments with default values. """ form_realms = {} # Prepare realm arguments to keep form data consistent. for realm in self.realms: form_realms[realm] = 'on' realms = self.realms if not page and not per_page: # We're not serving pager navigation here. return get_resource_url(self.env, tag, req.href, form_realms=form_realms, **kwargs) if page == 1: page = None if per_page == self.items_per_page: per_page = None return req.href(req.path_info, form_realms, q=self.query, realms=realms, listtagged_per_page=per_page, listtagged_page=page, **kwargs)
def _result(doc): changed = doc.changed href = get_resource_url(self.env, doc.resource, req.href) title = doc.title or get_resource_shortname(self.env, doc.resource) author = ", ".join(doc.author or []) excerpt = doc.oneline or '' return (href, title, changed, author, excerpt)
def _get_absolute_url(self, req, url): """ Generate an absolute url from the url with the special schemes {htdocs,chrome,ticket,wiki,source} simply return the url if given with {http,https,ftp} schemes. Examples: http://example.com/filename.ext ie. http://www.google.com/logo.jpg chrome://site/filename.ext htdocs://img/filename.ext note: `chrome` is an alias for `htdocs` ticket://number/attachment.pdf ie. ticket://123/specification.pdf wiki://WikiWord/attachment.jpg source://changeset/path/filename.ext ie. source://1024/trunk/docs/README """ scheme, netloc, path, query, params, fragment = urlparse(url) if scheme in ('htdocs', 'chrome'): return req.abs_href.chrome(netloc + path) if scheme in ('source',): return req.abs_href.export(netloc + path) if scheme in ('wiki','ticket'): resource = Resource(scheme, netloc).child('attachment', path) return get_resource_url(self.env, resource, req.abs_href, format='raw') return url
def get_resource_description(self, resource, format=None, **kwargs): env = self.env href = kwargs.get('href') if resource.parent is None: return _("Unparented form %(id)s", id=resource.id) parent_name = get_resource_name(env, resource.parent) parent_url = href and \ get_resource_url(env, resource.parent, href) or None parent = parent_url is not None and \ tag.a(parent_name, href=parent_url) or parent_name # DEVEL: resource description not implemented yet #if format == 'summary': # return Form(self.env, resource).description if resource.id: if format == 'compact': return _("Form %(form_id)s (%(parent)s)", form_id=resource.id, parent=get_resource_shortname(env, resource.parent)) # TRANSLATOR: Most verbose title, i.e. for form history page return tag_("Form %(form_id)s (in %(parent)s)", form_id=resource.id, parent=parent) else: # TRANSLATOR: Title printed i.e. in form select page if format == 'compact': return tag_("Forms (%(parent)s)", parent=parent) return tag_("Forms in %(parent)s", parent=parent)
def post_list_search_artifact_json(request, dbp, obj, resource): require_permission(request.req, resource, dbp.env) unparsed_spec = request.req.args.get('spec', '') spec_name = json.loads(unparsed_spec) if unparsed_spec else '' attributes = json.loads(request.req.args.get('attributes', '[]')) search_results = Searcher.search_artifacts(dbp, spec=spec_name, attributes=attributes) data = [ dict({ 'term': term, 'id': artifact.get_id(), 'title': unicode(artifact), 'spec': artifact.__class__.get_name() if artifact.__class__ != Instance else '', 'url': get_resource_url( dbp.env, Resource('asa', artifact.get_id(), artifact.version), request.req.href) }) for artifact, term in search_results ] _return_as_json(request, data) return
def filter_stream(self, req, method, filename, stream, data): if filename != 'query.html': return stream query_string = 'query:' + '&'.join([ '%s=%s' % (key, '|'.join([cond for cond in values])) for constraint in data['query'].constraints for key, values in constraint.items() ]) page_name = 'report_resource' in data and \ 'report:%s' % data['report_resource'].id or query_string if 'page_name' in req.args: page_name = req.args['page_name'] query_string += '&page_name=%s' % page_name page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream cols = [header['name'] for header in data['headers']] text = '= Snapshot of [%s the query]: =\n' % query_string text += '{{{#!QueryResults(group=%s) \n' % data['query'].group text += '||= href =||= %s\n' % ' =||= '.join(cols) for (group_name, tickets) in data['groups']: text += '|| group: %s\n' % group_name for ticket in tickets: text += '|| %s || %s\n' % (ticket['href'], ' || '.join( [self.formatter(ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def outline_tree(env, ol, outline, context, active, min_depth, max_depth): if min_depth > max_depth: min_depth, max_depth = max_depth, min_depth max_depth = min(6, max_depth) min_depth = max(1, min_depth) previous_depth = min_depth stack = [None] * (max_depth + 1) # stack of (<element for new sublists>, <element for new items>) stack[previous_depth] = (None, ol) for depth, anchor, heading in outline: if min_depth <= depth <= max_depth: for d in range(previous_depth, depth): li, ol = stack[d] if not li: li = tag.li() ol.append(li) stack[d] = (li, ol) new_ol = tag.ol() li.append(new_ol) stack[d + 1] = (None, new_ol) href = get_resource_url(env, context.resource, context.href) if href.endswith(context.req.path_info): href = '' href += '#' + anchor li, ol = stack[depth] li = tag.li(tag.a(Markup(heading), href=href), class_=active and 'active' or None) ol.append(li) stack[depth] = (li, ol) previous_depth = depth return stack[min_depth][0]
def _get_build_data(env, req, build, repos_name=None): chgset_url = '' if repos_name: chgset_resource = get_chgset_resource(env, repos_name, build.rev) chgset_url = get_resource_url(env, chgset_resource, req.href) platform = TargetPlatform.fetch(env, build.platform) data = {'id': build.id, 'name': build.slave, 'rev': build.rev, 'status': _status_label[build.status], 'platform': getattr(platform, 'name', 'unknown'), 'cls': _status_label[build.status].replace(' ', '-'), 'href': req.href.build(build.config, build.id), 'chgset_href': chgset_url} if build.started: data['started'] = format_datetime(build.started) data['started_delta'] = pretty_timedelta(build.started) data['duration'] = pretty_timedelta(build.started) if build.stopped: data['stopped'] = format_datetime(build.stopped) data['stopped_delta'] = pretty_timedelta(build.stopped) data['duration'] = pretty_timedelta(build.stopped, build.started) data['slave'] = { 'name': build.slave, 'ipnr': build.slave_info.get(Build.IP_ADDRESS), 'os_name': build.slave_info.get(Build.OS_NAME), 'os_family': build.slave_info.get(Build.OS_FAMILY), 'os_version': build.slave_info.get(Build.OS_VERSION), 'machine': build.slave_info.get(Build.MACHINE), 'processor': build.slave_info.get(Build.PROCESSOR) } return data
def get_list_pages(request, dbp, obj, resource): require_permission(request.req, resource, dbp.env) artifact_id = request.req.args.get('artifact', None) if artifact_id is None: raise Exception("No artifact was specified.") dbp.load_artifact(artifact_id) artifact = dbp.pool.get_item(artifact_id) results = [] for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts( artifact): page = WikiPage(dbp.env, pagename) results.append({ 'href': get_resource_url(dbp.env, page.resource, request.req.href), 'title': pagename, 'date': user_time(request.req, format_datetime, page.time), 'author': page.author, 'excerpt': shorten_result(page.text) }) data = { 'context': Context.from_request(request.req, resource), 'artifact': artifact, 'results': results, } return 'list_pages.html', data, None
def _process_add(self, req, ticket): if req.method == "POST" and self._validate_add(req): if req.args.get('reminder_type') == 'interval': time = clear_time(to_datetime(None)) delta = _time_intervals[req.args.get('unit')]( req.args.get('interval')) time += delta time = to_utimestamp(time) else: time = to_utimestamp(parse_date(req.args.get('date'))) origin = to_utimestamp(to_datetime(None)) self.env.db_transaction( """ INSERT INTO ticketreminder (ticket, time, author, origin, reminded, description) VALUES (%s, %s, %s, %s, 0, %s) """, (ticket.id, time, get_reporter_id( req, 'author'), origin, req.args.get('description'))) add_notice(req, "Reminder has been added.") req.redirect( get_resource_url(self.env, ticket.resource, req.href) + "#reminders") add_script(req, 'ticketreminder/js/ticketreminder.js') data = { 'ticket': ticket, 'date_hint': get_date_format_hint(), } return ("ticket_reminder_add.html", data, None)
def outline_tree(env, ol, outline, context, active, min_depth, max_depth): if min_depth > max_depth: min_depth, max_depth = max_depth, min_depth max_depth = min(6, max_depth) min_depth = max(1, min_depth) previous_depth = min_depth stack = [None] * (max_depth + 1) # stack of (<element for new sublists>, <element for new items>) stack[previous_depth] = (None, ol) for depth, anchor, heading in outline: if min_depth <= depth <= max_depth: for d in range(previous_depth, depth): li, ol = stack[d] if not li: li = tag.li() ol.append(li) stack[d] = (li, ol) new_ol = tag.ol() li.append(new_ol) stack[d+1] = (None, new_ol) href = get_resource_url(env, context.resource, context.href) if href.endswith(context.req.path_info): href = '' href += '#' + anchor li, ol = stack[depth] li = tag.li(tag.a(Markup(heading), href=href), class_=active and 'active' or None) ol.append(li) stack[depth] = (li, ol) previous_depth = depth return stack[min_depth][0]
def _format_tagged(self, formatter, ns, target, label, fullmatch=None): """Tag and tag query expression link formatter.""" def unquote(text): """Strip all matching pairs of outer quotes from string.""" while re.match(WikiParser.QUOTED_STRING, text): # Remove outer whitespace after stripped quotation too. text = text[1:-1].strip() return text label = label and unquote(label.strip()) or '' target = unquote(target.strip()) tag_res = Resource('tag', target) if 'TAGS_VIEW' in formatter.perm(tag_res): context = formatter.context href = get_resource_url(self.env, tag_res, context.href) tag_sys = TagSystem(self.env) # Tag exists or tags query yields at least one match. if target in tag_sys.get_all_tags(formatter.req) or \ [(res, tags) for res, tags in tag_sys.query(formatter.req, target)]: if label: return tag.a(label, href=href) return render_resource_link(self.env, context, tag_res) else: return tag.a(label+'?', href=href, class_='missing tags', rel='nofollow') else: return tag.span(label, class_='forbidden tags', title=_("no permission to view tags"))
def _process_delete(self, req, ticket): reminder_id = req.args.get('reminder') redirect_url = get_resource_url(self.env, ticket.resource, req.href) with self.env.db_transaction as db: for reminder in db( """ SELECT id, time, author, origin, description FROM ticketreminder WHERE id=%s """, (reminder_id, )): break else: add_warning(req, "Could not find reminder to delete.") req.redirect(redirect_url) if req.method == "POST": db( """ DELETE FROM ticketreminder WHERE id=%s """, (reminder_id, )) if req.method == "POST": add_notice(req, "Reminder has been deleted.") req.redirect(redirect_url + "#reminders") kwargs = {'delete_button': False} data = { 'ticket': ticket, 'formatted_reminder': self._format_reminder(req, ticket, *reminder, **kwargs), } return "ticket_reminder_delete.html", data, None
def get_list_pages(request, dbp, obj, resource): require_permission(request.req, resource, dbp.env) artifact_id = request.req.args.get('artifact', None) if artifact_id is None: raise Exception("No artifact was specified.") dbp.load_artifact(artifact_id) artifact = dbp.pool.get_item(artifact_id) results = [] for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts(artifact): page = WikiPage(dbp.env, pagename) results.append( {'href': get_resource_url(dbp.env, page.resource, request.req.href), 'title': pagename, 'date': user_time(request.req, format_datetime, page.time), 'author': page.author, 'excerpt': shorten_result(page.text)} ) data = { 'context': Context.from_request(request.req, resource), 'artifact': artifact, 'results': results, } return 'list_pages.html', data, None
def render_property_diff(self, req, ticket, field, old, new, resource_new=None): "Version for Trac 0.11" rendered = None # per type special rendering of diffs type_ = None for f in ticket.fields: if f['name'] == field: type_ = f['type'] break if type_ == 'checkbox': rendered = new == '1' and "set" or "unset" elif type_ == 'textarea': if not resource_new: rendered = _('modified') else: href = get_resource_url(self.env, resource_new, req.href, action='diff') rendered = tag('modified (', tag.a('diff', href=href), ')') # per name special rendering of diffs old_list, new_list = None, None render_elt = lambda x: x sep = ', ' if field == 'cc': chrome = Chrome(self.env) old_list, new_list = chrome.cc_list(old), chrome.cc_list(new) if not (Chrome(self.env).show_email_addresses or 'EMAIL_VIEW' in req.perm(resource_new or ticket.resource)): render_elt = obfuscate_email_address elif field == 'keywords': old_list, new_list = (old or '').split(), new.split() sep = ' ' if (old_list, new_list) != (None, None): added = [tag.em(render_elt(x)) for x in new_list if x not in old_list] remvd = [tag.em(render_elt(x)) for x in old_list if x not in new_list] added = added and tag(separated(added, sep), " added") remvd = remvd and tag(separated(remvd, sep), " removed") if added or remvd: rendered = tag(added, added and remvd and '; ', remvd) return rendered if field in ('reporter', 'owner'): if not (Chrome(self.env).show_email_addresses or 'EMAIL_VIEW' in req.perm(resource_new or ticket.resource)): old = obfuscate_email_address(old) new = obfuscate_email_address(new) # Added by MS if field == 'attachment': rendered = tag(tag.em(new), " added") # changed 'if' to 'elif': elif old and not new: rendered = tag(tag.em(old), " deleted") elif new and not old: rendered = tag("set to ", tag.em(new)) elif old and new: rendered = tag("changed from ", tag.em(old), " to ", tag.em(new)) return rendered
def _process_delete(self, req, ticket): reminder_id = req.args.get('reminder') redirect_url = get_resource_url(self.env, ticket.resource, req.href) with self.env.db_transaction as db: for reminder in db(""" SELECT id, time, author, origin, description FROM ticketreminder WHERE id=%s """, (reminder_id,)): break else: add_warning(req, "Could not find reminder to delete.") req.redirect(redirect_url) if req.method == "POST": db(""" DELETE FROM ticketreminder WHERE id=%s """, (reminder_id,)) if req.method == "POST": add_notice(req, "Reminder has been deleted.") req.redirect(redirect_url + "#reminders") kwargs = {'delete_button': False} data = { 'ticket': ticket, 'formatted_reminder': self._format_reminder(req, ticket, *reminder, **kwargs), } return "ticket_reminder_delete.html", data, None
def _process_add(self, req, ticket): if req.method == "POST" and self._validate_add(req): if req.args.get('reminder_type') == 'interval': time = clear_time(to_datetime(None)) delta = _time_intervals[req.args.get('unit')](req.args.get('interval')) time += delta time = to_utimestamp(time) else: time = to_utimestamp(parse_date(req.args.get('date'))) origin = to_utimestamp(to_datetime(None)) self.env.db_transaction(""" INSERT INTO ticketreminder (ticket, time, author, origin, reminded, description) VALUES (%s, %s, %s, %s, 0, %s) """, (ticket.id, time, get_reporter_id(req, 'author'), origin, req.args.get('description'))) add_notice(req, "Reminder has been added.") req.redirect(get_resource_url(self.env, ticket.resource, req.href) + "#reminders") add_script(req, 'ticketreminder/js/ticketreminder.js') data = { 'ticket': ticket, 'date_hint': get_date_format_hint(), } return ("ticket_reminder_add.html", data, None)
def validate_wiki_page(self, req, page): if req and 'TAGS_MODIFY' in req.perm(page.resource) \ and req.path_info.startswith('/wiki') and 'save' in req.args: if self._update_tags(req, page) and \ page.text == page.old_text and \ page.readonly == int('readonly' in req.args): req.redirect(get_resource_url(self.env, page.resource, req.href, version=None)) return []
def expand_macro(self, formatter, name, content): qrc_url = 'http://chart.apis.google.com/chart?cht=qr&chs=120x120&chl=' req_url = get_resource_url(self.env, formatter.context.resource, formatter.req.abs_href) out = '<a href="' + req_url + '"><img src="' + qrc_url + req_url + '" border="0"></a>' return out
def default_renderer(tag, count, percent): href = get_resource_url(env, Resource('tag', tag), req.href) return builder.a(tag, rel='tag', title='%i' % count, href=href, style='font-size: %ipx' % int(min_px + percent * (max_px - min_px)))
def normalise_resource(self, resource): if isinstance(resource, basestring): resource = resource.strip('/') # Special-case start page if not resource or resource == 'wiki': resource = 'wiki/WikiStart' return resource return get_resource_url(self.env, resource, Href('')).strip('/')
def abs_href(self, formatter): """ Get absolute href for trac resource. @param formatter """ return get_resource_url(self.env, formatter.resource, formatter.req.abs_href)
def normalise_resource(self, resource): if isinstance(resource, basestring): resource = resource.strip('/') # Special-case: Default TracWiki start page. if resource == 'wiki': resource += '/WikiStart' return resource return get_resource_url(self.env, resource, Href('')).strip('/')
def render_timeline_event(self, context, field, event): resource = event[3][0] if field == 'url': return get_resource_url(self.env, resource, context.href) elif field == 'title': name = builder.em(get_resource_name(self.env, resource)) return tag_("Tag change on %(resource)s", resource=name) elif field == 'description': return render_tag_changes(event[3][1], event[3][2])
def test_global_neighborhood_report(self): target = resource.Neighborhood("global", None).child(self.resource) self.assertEquals("[global:] report:1", resource.get_resource_description(self.env, target)) self.assertEquals("[global:] report:1", resource.get_resource_name(self.env, target)) self.assertEquals("[global:] report:1", resource.get_resource_shortname(self.env, target)) self.assertEquals("[global:] report:1 at version None", resource.get_resource_summary(self.env, target)) self.assertEquals( "http://example.org/trac.cgi/report/1", resource.get_resource_url(self.env, target, self.env.href) )
def normalise_resource(self, resource): if isinstance(resource, basestring): resource = resource.strip("/") # Special-case start page if not resource: resource = "wiki/WikiStart" elif resource == "wiki": resource += "/WikiStart" return resource return get_resource_url(self.env, resource, Href("")).strip("/")
def _format_link(self, formatter, ns, target, label, fullmatch=None): link, params, fragment = formatter.split_link(target) res = DjangoResource(ns, link) res.django_request = _get_django_request(req=formatter.req) res.django_context = _get_django_context(req=formatter.req) try: href = resource.get_resource_url(self.env, res, formatter.href) title = resource.get_resource_name(self.env, res) return tag.a(label, title=title, href=href + params + fragment) except resource.ResourceNotFound: return tag.a(label + '?', class_='missing', href=target, rel='nofollow')
def get_ticket_relations(self, ticket): grouped_relations = {} relsys = RelationsSystem(self.env) reltypes = relsys.get_relation_types() trs = TicketRelationsSpecifics(self.env) for r in relsys.get_relations(ticket): r['desthref'] = get_resource_url(self.env, r['destination'], self.env.href) r['destticket'] = trs._create_ticket_by_full_id(r['destination']) grouped_relations.setdefault(reltypes[r['type']], []).append(r) return grouped_relations
def test_resource_source(self): res = Resource('source', '/trunk/src') self.assertEqual('path /trunk/src', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/browser/trunk/src', get_resource_url(self.env, res, self.env.href)) repo = Resource('repository', 'repo') res = Resource('source', '/trunk/src', parent=repo) self.assertEqual('path /trunk/src in repo', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/browser/repo/trunk/src', get_resource_url(self.env, res, self.env.href)) repo = Resource('repository', 'repo') res = Resource('source', '/trunk/src', version=42, parent=repo) self.assertEqual('path /trunk/src@42 in repo', get_resource_description(self.env, res)) self.assertEqual('/trac.cgi/browser/repo/trunk/src?rev=42', get_resource_url(self.env, res, self.env.href))
def test_product_neighborhood_wiki(self): target = resource.Neighborhood("product", u"xü").child(self.resource) self.assertEquals(u"TestPage", resource.get_resource_description(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_name(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_shortname(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_summary(self.env, target)) self.assertEquals( "http://example.org/trac.cgi/products/x%C3%BC/wiki/TestPage?version=2", resource.get_resource_url(self.env, target, self.env.href), )
def filter_stream(self, req, method, filename, stream, data): if 'ticket' in data: latest = max([0] + [ int(c[3]) for c in data['ticket'].get_changelog() if c[2] == u'comment' and c[3] != u'' ]) ticket = data['ticket'].resource if ticket.version == None: # showing latest version, add fix-version link add_ctxtnav(req, _('Previous Version'), '?version=%s' % latest) else: # showing specified version; add latest-version link r, i, v = ticket.realm, ticket.id, ticket.version prev_link, next_link = None, None if v > 0: prev_link = tag.a(_('Previous Version'), href=get_resource_url( self.env, Resource(r, i, v - 1), req.href), class_='prev') if v < latest: next_link = tag.a(_('Next Version'), href=get_resource_url( self.env, Resource(r, i, v + 1), req.href), class_='next') add_ctxtnav( req, tag.span(Markup('← '), prev_link or _('Previous Version'), class_=not prev_link and 'missing' or None)) add_ctxtnav( req, tag.a(_('View Latest Version'), href=get_resource_url(self.env, Resource(r, i, None), req.href))) add_ctxtnav( req, tag.span(next_link or _('Next Version'), Markup(' →'), class_=not next_link and 'missing' or None)) return stream
def validate_wiki_page(self, req, page): if req and 'TAGS_MODIFY' in req.perm(page.resource) \ and req.path_info.startswith('/wiki') and 'save' in req.args: if self._update_tags(req, page) and \ page.text == page.old_text and \ page.readonly == int('readonly' in req.args): req.redirect( get_resource_url(self.env, page.resource, req.href, version=None)) return []
def validate_wiki_page(self, req, page): self.log.debug(" +++ in validate_wiki_page") #self.log.debug(dir(req.args)) #self.log.debug(req.args) # If the page hasn't been modified but the meta has, # redirect to avoid the "page has not been modified" warning. if req and req.path_info.startswith('/wiki') and 'save' in req.args: page_modified = req.args.get('text') != page.old_text or \ page.readonly != int('readonly' in req.args) if 'wikimeta' in req.args and not page_modified: req.redirect(get_resource_url(self.env, page.resource, req.href, version=None)) return []
def post_list_search_relatedpages_json(request, dbp, obj, resource): require_permission(request.req, resource, dbp.env) unparsed_spec = request.req.args.get('spec', '') spec_name = json.loads(unparsed_spec) if unparsed_spec else '' attributes = json.loads(request.req.args.get('attributes', '[]')) if attributes is None: raise Exception("No artifacts specified.") artifacts_array = [] for artifact in attributes: try: dbp.load_artifact(artifact) full_artifact = dbp.pool.get_item(artifact) #artifacts_array.append(full_artifact) results = [] for pagename, page_version_id, ref_count in dbp.get_wiki_page_ref_counts( full_artifact): page = WikiPage(dbp.env, pagename) results.append({ 'href': get_resource_url(dbp.env, page.resource, request.req.href), 'title': pagename, 'date': user_time(request.req, format_datetime, page.time), 'author': page.author, 'excerpt': shorten_result(page.text) }) artifacts_array.append({ 'id': full_artifact.get_id(), 'href': request.req.href.customartifacts('artifact', full_artifact.get_id(), action='view'), 'title': unicode(full_artifact), 'results': results }) except ValueError: continue _return_as_json(request, artifacts_array) return
def filter_stream(self, req, method, filename, stream, data): if filename != 'report_view.html': return stream page_name = 'report:%s' % data['context'].resource.id page_label = data['title'] page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream text = '= Snapshot of [%s %s]: =\n' % (page_name, page_label) text += '{{{#!QueryResults\n' cols = [ header['col'] for header in data.get('header_groups', [[]])[0] if not header['hidden'] ] cols_work = [t for t in cols] # copy if 'ticket' in cols_work: cols_work[cols_work.index( 'ticket')] = 'id' # replace 'ticket' to 'id' text += '||= href =||= %s\n' % ' =||= '.join(cols_work) for groupindex, row_group in data.get('row_groups', []): text += '|| group: %s\n' % groupindex for row in row_group: row = row['cell_groups'][0] ticket = {} for value in row: ticket[value['header']['col']] = value['value'] ticket['href'] = get_resource_url( self.env, Resource('ticket', ticket.get('ticket', 0)), self.env.href) text += '|| %s || %s\n' % (ticket['href'], ' || '.join( [self.formatter(col, ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def _process_delete(self, req, ticket): reminder_id = req.args.get('reminder') db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( "SELECT id, time, author, origin, description FROM ticketreminder WHERE id=%s", (reminder_id, )) reminder = cursor.fetchone() if not reminder: add_warning(req, "Could not find reminder to delete.") req.redirect(get_resource_url(self.env, ticket.resource, req.href)) if req.method == "POST": cursor.execute("DELETE FROM ticketreminder WHERE id=%s", (reminder_id, )) db.commit() add_notice(req, "Reminder has been deleted.") req.redirect( get_resource_url(self.env, ticket.resource, req.href) + "#reminders") # Python 2.5 compatibility kwargs = { 'delete_button': False, } data = { 'ticket': ticket, 'formatted_reminder': self._format_reminder(req, ticket, *reminder, **kwargs), } return ("ticket_reminder_delete.html", data, None)
def test_product_neighborhood_wiki(self): target = resource.Neighborhood('product', u'xü').child(self.resource) self.assertEquals(u"TestPage", resource.get_resource_description(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_name(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_shortname(self.env, target)) self.assertEquals(u"TestPage", resource.get_resource_summary(self.env, target)) self.assertEquals( 'http://example.org/trac.cgi/products/x%C3%BC/wiki/TestPage?version=2', resource.get_resource_url(self.env, target, self.env.href))