def expand_macro(self, formatter, name, content): args, kw = parse_args(content) prefix = args[0].strip() if args else None hideprefix = args and len(args) > 1 and args[1].strip() == 'hideprefix' minsize = _arg_as_int(kw.get('min', 1), 'min', min=1) minsize_group = max(minsize, 2) depth = _arg_as_int(kw.get('depth', -1), 'depth', min=-1) format = kw.get('format', '') def parse_list(name): return [inc.strip() for inc in kw.get(name, '').split(':') if inc.strip()] includes = parse_list('include') or ['*'] excludes = parse_list('exclude') wiki = formatter.wiki resource = formatter.resource if prefix and resource and resource.realm == 'wiki': prefix = wiki.resolve_relative_name(prefix, resource.id) start = prefix.count('/') if prefix else 0 if hideprefix: omitprefix = lambda page: page[len(prefix):] else: omitprefix = lambda page: page pages = sorted(page for page in wiki.get_pages(prefix) if (depth < 0 or depth >= page.count('/') - start) and 'WIKI_VIEW' in formatter.perm('wiki', page) and any(fnmatchcase(page, inc) for inc in includes) and not any(fnmatchcase(page, exc) for exc in excludes)) if format == 'compact': return tag( separated((tag.a(wiki.format_page_name(omitprefix(p)), href=formatter.href.wiki(p)) for p in pages), ', ')) # the function definitions for the different format styles # the different page split formats, each corresponding to its rendering def split_pages_group(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted at Camel Case word boundaries, numbers and '/'. """ page_paths = [] for page in pages: path = [elt.strip() for elt in self.SPLIT_RE.split( self.NUM_SPLIT_RE.sub(r" \1 ", wiki.format_page_name(omitprefix(page), split=True)))] page_paths.append(([elt for elt in path if elt], page)) return page_paths def split_pages_hierarchy(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted according to the '/' hierarchy. """ return [(wiki.format_page_name(omitprefix(page)).split("/"), page) for page in pages] # the different tree structures, each corresponding to its rendering def tree_group(entries): """Transform a flat list of entries into a tree structure. `entries` is a list of `(path_elements, page_name)` pairs Return a list organized in a tree structure, in which: - a leaf is a page name - a node is a `(key, nodes)` pairs, where: - `key` is the leftmost of the path elements, common to the grouped (path element, page_name) entries - `nodes` is a list of nodes or leaves """ groups = [] for key, grouper in groupby(entries, lambda (elts, name): elts[0] if elts else ''): # remove key from path_elements in grouped entries for further # grouping grouped_entries = [(path_elements[1:], page_name) for path_elements, page_name in grouper] if key and len(grouped_entries) >= minsize_group: subnodes = tree_group(sorted(grouped_entries)) if len(subnodes) == 1: subkey, subnodes = subnodes[0] node = (key + subkey, subnodes) groups.append(node) elif self.SPLIT_RE.match(key): for elt in subnodes: if isinstance(elt, tuple): subkey, subnodes = elt elt = (key + subkey, subnodes) groups.append(elt) else: node = (key, subnodes) groups.append(node) else: for path_elements, page_name in grouped_entries: groups.append(page_name) return groups
def _format_ctxtnav(self, items): """Prepare context navigation items for display on login page.""" return list(separated(items, '|'))
def render_ticket_action_control(self, req, ticket, action): self.log.debug('render_ticket_action_control: action "%s"', action) this_action = self.actions[action] status = this_action['newstate'] operations = this_action['operations'] ticket_owner = ticket._old.get('owner', ticket['owner']) ticket_status = ticket._old.get('status', ticket['status']) author = get_reporter_id(req, 'author') author_info = partial(Chrome(self.env).authorinfo, req, resource=ticket.resource) format_author = partial(Chrome(self.env).format_author, req, resource=ticket.resource) formatted_current_owner = author_info(ticket_owner) exists = ticket_status is not None ticket_system = TicketSystem(self.env) control = [] # default to nothing hints = [] if 'reset_workflow' in operations: control.append(_("from invalid state")) hints.append(_("Current state no longer exists")) if 'del_owner' in operations: hints.append(_("The ticket will be disowned")) if 'set_owner' in operations or 'may_set_owner' in operations: owners = self.get_allowed_owners(req, ticket, this_action) if 'set_owner' in operations: default_owner = author elif 'may_set_owner' in operations: if not exists: default_owner = ticket_system.default_owner else: default_owner = ticket_owner or None if owners is not None and default_owner not in owners: owners.insert(0, default_owner) else: # Protect against future modification for case that another # operation is added to the outer conditional raise AssertionError(operations) id = 'action_%s_reassign_owner' % action if not owners: owner = req.args.get(id, default_owner) control.append( tag_("to %(owner)s", owner=tag.input(type='text', id=id, name=id, value=owner))) if not exists or ticket_owner is None: hints.append(_("The owner will be the specified user")) else: hints.append(tag_("The owner will be changed from " "%(current_owner)s to the specified " "user", current_owner=formatted_current_owner)) elif len(owners) == 1: owner = tag.input(type='hidden', id=id, name=id, value=owners[0]) formatted_new_owner = author_info(owners[0]) control.append(tag_("to %(owner)s", owner=tag(formatted_new_owner, owner))) if not exists or ticket_owner is None: hints.append(tag_("The owner will be %(new_owner)s", new_owner=formatted_new_owner)) elif ticket['owner'] != owners[0]: hints.append(tag_("The owner will be changed from " "%(current_owner)s to %(new_owner)s", current_owner=formatted_current_owner, new_owner=formatted_new_owner)) else: selected_owner = req.args.get(id, default_owner) control.append(tag_("to %(owner)s", owner=tag.select( [tag.option(label, value=value if value is not None else '', selected=(value == selected_owner or None)) for label, value in sorted((format_author(owner), owner) for owner in owners)], id=id, name=id))) if not exists or ticket_owner is None: hints.append(_("The owner will be the selected user")) else: hints.append(tag_("The owner will be changed from " "%(current_owner)s to the selected user", current_owner=formatted_current_owner)) elif 'set_owner_to_self' in operations: formatted_author = author_info(author) if not exists or ticket_owner is None: hints.append(tag_("The owner will be %(new_owner)s", new_owner=formatted_author)) elif ticket_owner != author: hints.append(tag_("The owner will be changed from " "%(current_owner)s to %(new_owner)s", current_owner=formatted_current_owner, new_owner=formatted_author)) elif ticket_status != status: hints.append(tag_("The owner will remain %(current_owner)s", current_owner=formatted_current_owner)) if 'set_resolution' in operations: resolutions = [r.name for r in Resolution.select(self.env)] if 'set_resolution' in this_action: valid_resolutions = set(resolutions) resolutions = this_action['set_resolution'] if any(x not in valid_resolutions for x in resolutions): raise ConfigurationError(_( "Your workflow attempts to set a resolution but uses " "undefined resolutions (configuration issue, please " "contact your Trac admin).")) if not resolutions: raise ConfigurationError(_( "Your workflow attempts to set a resolution but none is " "defined (configuration issue, please contact your Trac " "admin).")) id = 'action_%s_resolve_resolution' % action if len(resolutions) == 1: resolution = tag.input(type='hidden', id=id, name=id, value=resolutions[0]) control.append(tag_("as %(resolution)s", resolution=tag(resolutions[0], resolution))) hints.append(tag_("The resolution will be set to %(name)s", name=resolutions[0])) else: selected_option = req.args.get(id, ticket_system.default_resolution) control.append(tag_("as %(resolution)s", resolution=tag.select( [tag.option(x, value=x, selected=(x == selected_option or None)) for x in resolutions], id=id, name=id))) hints.append(_("The resolution will be set")) if 'del_resolution' in operations: hints.append(_("The resolution will be deleted")) if 'leave_status' in operations: control.append(tag_("as %(status)s", status=ticket_status)) if len(operations) == 1: hints.append(tag_("The owner will remain %(current_owner)s", current_owner=formatted_current_owner) if ticket_owner else _("The ticket will remain with no owner")) elif not operations: if status != '*': if ticket['status'] is None: hints.append(tag_("The status will be '%(name)s'", name=status)) else: hints.append(tag_("Next status will be '%(name)s'", name=status)) return (this_action['label'], tag(separated(control, ' ')), tag(separated(hints, '. ', '.') if hints else ''))
def expand_macro(self, formatter, name, content): args, kw = parse_args(content) prefix = args and args[0].strip() or None hideprefix = args and len(args) > 1 and args[1].strip() == 'hideprefix' minsize = max(int(kw.get('min', 2)), 2) depth = int(kw.get('depth', -1)) start = prefix and prefix.count('/') or 0 format = kw.get('format', '') if hideprefix: omitprefix = lambda page: page[len(prefix):] else: omitprefix = lambda page: page wiki = formatter.wiki pages = sorted(page for page in wiki.get_pages(prefix) \ if (depth < 0 or depth >= page.count('/') - start) and 'WIKI_VIEW' in formatter.perm('wiki', page)) if format == 'compact': return tag( separated((tag.a(wiki.format_page_name(omitprefix(p)), href=formatter.href.wiki(p)) for p in pages), ', ')) # the function definitions for the different format styles # the different page split formats, each corresponding to its rendering def split_pages_group(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted at Camel Case word boundaries, numbers and '/'. """ page_paths = [] for page in pages: path = [elt.rstrip('/').strip() for elt in self.SPLIT_RE.split( wiki.format_page_name(omitprefix(page), split=True))] page_paths.append(([elt for elt in path if elt], page)) return page_paths def split_pages_hierarchy(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted according to the '/' hierarchy. """ return [(wiki.format_page_name(omitprefix(page)).split("/"), page) for page in pages] # create the group hierarchy (same for group and hierarchy formats) def split_in_groups(entries): """Transform a flat list of entries into a tree structure. `entries` is a list of `(path_elements, page_name)` pairs Return a list organized in a tree structure, in which: - a leaf is a page name - a node is a `(key, nodes)` pairs, where: - `key` is the leftmost of the path elements, common to the grouped (path element, page_name) entries - `nodes` is a list of nodes or leaves """ groups = [] for key, grouper in groupby(entries, lambda (elts, name): elts and elts[0] or ''): # remove key from path_elements in grouped entries for further # grouping grouped_entries = [(path_elements[1:], page_name) for path_elements, page_name in grouper] if key and len(grouped_entries) >= minsize: subnodes = split_in_groups(sorted(grouped_entries)) if len(subnodes) == 1: subkey, subnodes = subnodes[0] node = (key + subkey, subnodes) # FIXME else: node = (key, subnodes) groups.append(node) else: for path_elements, page_name in grouped_entries: groups.append(page_name) return groups
def render_ticket_action_control(self, req, ticket, action): self.log.debug('render_ticket_action_control: action "%s"', action) this_action = self.actions[action] status = this_action['newstate'] operations = this_action['operations'] current_owner = ticket._old.get('owner', ticket['owner']) author = get_reporter_id(req, 'author') format_author = partial(Chrome(self.env).format_author, req) formatted_current_owner = format_author(current_owner or _("(none)")) control = [] # default to nothing hints = [] if 'reset_workflow' in operations: control.append(_("from invalid state")) hints.append(_("Current state no longer exists")) if 'del_owner' in operations: hints.append(_("The ticket will be disowned")) if 'set_owner' in operations: id = 'action_%s_reassign_owner' % action if 'set_owner' in this_action: owners = [x.strip() for x in this_action['set_owner'].split(',')] elif self.config.getbool('ticket', 'restrict_owner'): perm = PermissionSystem(self.env) owners = perm.get_users_with_permission('TICKET_MODIFY') owners.sort() else: owners = None if owners is None: owner = req.args.get(id, author) control.append(tag_("to %(owner)s", owner=tag.input(type='text', id=id, name=id, value=owner))) hints.append(_("The owner will be changed from " "%(current_owner)s to the specified user", current_owner=formatted_current_owner)) elif len(owners) == 1: owner = tag.input(type='hidden', id=id, name=id, value=owners[0]) formatted_new_owner = format_author(owners[0]) control.append(tag_("to %(owner)s", owner=tag(formatted_new_owner, owner))) if ticket['owner'] != owners[0]: hints.append(_("The owner will be changed from " "%(current_owner)s to %(selected_owner)s", current_owner=formatted_current_owner, selected_owner=formatted_new_owner)) else: selected_owner = req.args.get(id, req.authname) control.append(tag_("to %(owner)s", owner=tag.select( [tag.option(x, value=x, selected=(x == selected_owner or None)) for x in owners], id=id, name=id))) hints.append(_("The owner will be changed from " "%(current_owner)s to the selected user", current_owner=formatted_current_owner)) elif 'set_owner_to_self' in operations and \ ticket._old.get('owner', ticket['owner']) != author: hints.append(_("The owner will be changed from %(current_owner)s " "to %(authname)s", current_owner=formatted_current_owner, authname=format_author(author))) if 'set_resolution' in operations: if 'set_resolution' in this_action: resolutions = [x.strip() for x in this_action['set_resolution'].split(',')] else: resolutions = [r.name for r in Resolution.select(self.env)] if not resolutions: raise TracError(_("Your workflow attempts to set a resolution " "but none is defined (configuration issue, " "please contact your Trac admin).")) id = 'action_%s_resolve_resolution' % action if len(resolutions) == 1: resolution = tag.input(type='hidden', id=id, name=id, value=resolutions[0]) control.append(tag_("as %(resolution)s", resolution=tag(resolutions[0], resolution))) hints.append(_("The resolution will be set to %(name)s", name=resolutions[0])) else: selected_option = req.args.get(id, TicketSystem(self.env).default_resolution) control.append(tag_("as %(resolution)s", resolution=tag.select( [tag.option(x, value=x, selected=(x == selected_option or None)) for x in resolutions], id=id, name=id))) hints.append(_("The resolution will be set")) if 'del_resolution' in operations: hints.append(_("The resolution will be deleted")) if 'leave_status' in operations: control.append(_("as %(status)s", status= ticket._old.get('status', ticket['status']))) if len(operations) == 1: hints.append(_("The owner will remain %(current_owner)s", current_owner=formatted_current_owner) if current_owner else _("The ticket will remain with no owner")) else: if status != '*': hints.append(_("Next status will be '%(name)s'", name=status)) return (this_action.get('name', action), tag(separated(control, ' ')), '. '.join(hints) + '.' if hints else '')
def render_ticket_action_control(self, req, ticket, action): self.log.debug('render_ticket_action_control: action "%s"', action) this_action = self.actions[action] status = this_action['newstate'] operations = this_action['operations'] current_owner = ticket._old.get('owner', ticket['owner']) author = get_reporter_id(req, 'author') author_info = partial(Chrome(self.env).authorinfo, req, resource=ticket.resource) formatted_current_owner = author_info(current_owner) exists = ticket._old.get('status', ticket['status']) is not None control = [] # default to nothing hints = [] if 'reset_workflow' in operations: control.append(_("from invalid state")) hints.append(_("Current state no longer exists")) if 'del_owner' in operations: hints.append(_("The ticket will be disowned")) if 'set_owner' in operations or 'may_set_owner' in operations: if 'set_owner' in this_action: owners = self._to_users(this_action['set_owner'], ticket) elif self.config.getbool('ticket', 'restrict_owner'): perm = PermissionSystem(self.env) owners = perm.get_users_with_permission('TICKET_MODIFY') owners = [ user for user in owners if 'TICKET_MODIFY' in PermissionCache( self.env, user, ticket.resource) ] owners = sorted(owners) else: owners = None if 'set_owner' in operations: default_owner = author elif 'may_set_owner' in operations: if not exists: default_owner = TicketSystem(self.env).default_owner else: default_owner = ticket._old.get('owner', ticket['owner'] or None) if owners is not None and default_owner not in owners: owners.insert(0, default_owner) else: # Protect against future modification for case that another # operation is added to the outer conditional raise AssertionError(operations) id = 'action_%s_reassign_owner' % action if not owners: owner = req.args.get(id, default_owner) control.append( tag_("to %(owner)s", owner=tag.input(type='text', id=id, name=id, value=owner))) if not exists or current_owner is None: hints.append(_("The owner will be the specified user")) else: hints.append( tag_( "The owner will be changed from " "%(current_owner)s to the specified " "user", current_owner=formatted_current_owner)) elif len(owners) == 1: owner = tag.input(type='hidden', id=id, name=id, value=owners[0]) formatted_new_owner = author_info(owners[0]) control.append( tag_("to %(owner)s", owner=tag(formatted_new_owner, owner))) if not exists or current_owner is None: hints.append( tag_("The owner will be %(new_owner)s", new_owner=formatted_new_owner)) elif ticket['owner'] != owners[0]: hints.append( tag_( "The owner will be changed from " "%(current_owner)s to %(new_owner)s", current_owner=formatted_current_owner, new_owner=formatted_new_owner)) else: selected_owner = req.args.get(id, default_owner) control.append( tag_("to %(owner)s", owner=tag.select([ tag.option(x if x is not None else _("(none)"), value=x if x is not None else '', selected=(x == selected_owner or None)) for x in owners ], id=id, name=id))) if not exists or current_owner is None: hints.append(_("The owner will be the selected user")) else: hints.append( tag_( "The owner will be changed from " "%(current_owner)s to the selected user", current_owner=formatted_current_owner)) elif 'set_owner_to_self' in operations and \ ticket._old.get('owner', ticket['owner']) != author: formatted_author = author_info(author) if not exists or current_owner is None: hints.append( tag_("The owner will be %(new_owner)s", new_owner=formatted_author)) else: hints.append( tag_( "The owner will be changed from " "%(current_owner)s to %(new_owner)s", current_owner=formatted_current_owner, new_owner=formatted_author)) if 'set_resolution' in operations: if 'set_resolution' in this_action: resolutions = this_action['set_resolution'] else: resolutions = [r.name for r in Resolution.select(self.env)] if not resolutions: raise TracError( _("Your workflow attempts to set a resolution " "but none is defined (configuration issue, " "please contact your Trac admin).")) id = 'action_%s_resolve_resolution' % action if len(resolutions) == 1: resolution = tag.input(type='hidden', id=id, name=id, value=resolutions[0]) control.append( tag_("as %(resolution)s", resolution=tag(resolutions[0], resolution))) hints.append( tag_("The resolution will be set to %(name)s", name=resolutions[0])) else: selected_option = req.args.get( id, TicketSystem(self.env).default_resolution) control.append( tag_( "as %(resolution)s", resolution=tag.select([ tag.option(x, value=x, selected=(x == selected_option or None)) for x in resolutions ], id=id, name=id))) hints.append(_("The resolution will be set")) if 'del_resolution' in operations: hints.append(_("The resolution will be deleted")) if 'leave_status' in operations: control.append( tag_("as %(status)s", status=ticket._old.get('status', ticket['status']))) if len(operations) == 1: hints.append( tag_("The owner will remain %(current_owner)s", current_owner=formatted_current_owner) if current_owner else _("The ticket will remain with no owner" )) else: if ticket['status'] is None: hints.append(tag_("The status will be '%(name)s'", name=status)) elif status != '*': hints.append( tag_("Next status will be '%(name)s'", name=status)) return (this_action['label'], tag(separated(control, ' ')), tag(separated(hints, '. ', '.') if hints else ''))
def render_property_diff(env, req, ticket, field, old, new, resource_new=None): "Version for Trac 0.12" 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(env, resource_new, req.href, action='diff') # TRANSLATOR: modified ('diff') (link) diff = tag.a(_("diff"), href=href) rendered = tag_("modified (%(diff)s)", diff=diff) # per name special rendering of diffs old_list, new_list = None, None render_elt = lambda x: x sep = ', ' if field == 'cc': chrome = Chrome(env) old_list, new_list = chrome.cc_list(old), chrome.cc_list(new) if not (Chrome(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.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 tagn_("%(items)s added", "%(items)s added", len(added), items=separated(added, sep)) remvd = remvd and tagn_("%(items)s removed", "%(items)s removed", len(remvd), items=separated(remvd, sep)) if added or remvd: rendered = tag(added, added and remvd and _("; "), remvd) return rendered if field in ('reporter', 'owner'): if not (Chrome(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 # The `wtag_` is the `tag_` from tracwatchlist.translation, e.g. # using its translation domain. if field == 'attachment': rendered = wtag_("%(value)s added", value=tag.em(new)) # changed 'if' to 'elif': elif old and not new: rendered = tag_("%(value)s deleted", value=tag.em(old)) elif new and not old: rendered = tag_("set to %(value)s", value=tag.em(new)) elif old and new: rendered = tag_("changed from %(old)s to %(new)s", old=tag.em(old), new=tag.em(new)) return rendered
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