Ejemplo n.º 1
0
    def __init__(self):
        # TRANSLATOR: Keep macro doc style formatting here, please.
        self.doc_cloud = _("""Display a tag cloud.

    Show a tag cloud for all tags on resources matching query.

    Usage:

    {{{
    [[TagCloud(query,caseless_sort=<bool>,mincount=<n>)]]
    }}}
    caseless_sort::
      Whether the tag cloud should be sorted case-sensitive.
    mincount::
      Optional integer threshold to hide tags with smaller count.

    See tags documentation for the query syntax.
    """)
        self.doc_listtagged = _("""List tagged resources.

    Usage:

    {{{
    [[ListTagged(query)]]
    }}}

    See tags documentation for the query syntax.
    """)
Ejemplo n.º 2
0
class TicketTagProvider(DefaultTagProvider):
    """[main] Tag provider using ticket fields as sources of tags.

    Relevant ticket data is initially copied to plugin's own tag db store for
    more efficient regular access, that matters especially when working with
    large ticket quantities, kept current using ticket change listener events.

    Currently does NOT support custom fields.
    """

    implements(ITicketChangeListener)

#    custom_fields = ListOption('tags', 'custom_ticket_fields',
#        doc=_("List of custom ticket fields to expose as tags."))

    fields = ListOption('tags', 'ticket_fields', 'keywords',
        doc=_("List of ticket fields to expose as tags."))

    ignore_closed_tickets = BoolOption('tags', 'ignore_closed_tickets', True,
        _("Do not collect tags from closed tickets."))

    map = {'view': 'TICKET_VIEW', 'modify': 'TICKET_CHGPROP'}
    realm = 'ticket'
    use_cache = False

    def __init__(self):
        try:
            self._fetch_tkt_tags()
        except self.env.db_exc.IntegrityError, e:
            self.log.warn('tags for ticket already exist: %s', to_unicode(e))
        cfg = self.config
        cfg_key = 'permission_policies'
        default_policies = cfg.defaults().get('trac', {}).get(cfg_key)
        self.fast_permcheck = all(p in default_policies for
                                  p in cfg.get('trac', cfg_key))
Ejemplo n.º 3
0
    def __init__(self):
        # TRANSLATOR: Keep macro doc style formatting here, please.
        self.doc_cloud = _("""Display a tag cloud.

    Show a tag cloud for all tags on resources matching query.

    Usage:

    {{{
    [[TagCloud(query,caseless_sort=<bool>,mincount=<n>)]]
    }}}
    caseless_sort::
      Whether the tag cloud should be sorted case-sensitive.
    mincount::
      Optional integer threshold to hide tags with smaller count.

    See tags documentation for the query syntax.
    """)
        self.doc_listtagged = _("""List tagged resources.

    Usage:

    {{{
    [[ListTagged(query)]]
    }}}

    See tags documentation for the query syntax.
    """)
Ejemplo n.º 4
0
    def _paginate(self, req, results):
        self.query = req.args.get('q', None)
        current_page = as_int(req.args.get('listtagged_page'), 1)
        items_per_page = as_int(req.args.get('listtagged_per_page'), None)
        if items_per_page is None:
            items_per_page = self.items_per_page
        result = Paginator(results, current_page - 1, items_per_page)

        pagedata = []
        shown_pages = result.get_shown_pages(21)
        for page in shown_pages:
            page_href = self.get_href(req, items_per_page, page)
            pagedata.append([page_href, None, str(page),
                             _("Page %(num)d", num=page)])

        attributes = ['href', 'class', 'string', 'title']
        result.shown_pages = [dict(zip(attributes, p)) for p in pagedata]

        result.current_page = {'href': None, 'class': 'current',
                               'string': str(result.page + 1), 'title': None}

        if result.has_next_page:
            next_href = self.get_href(req, items_per_page, current_page + 1)
            add_link(req, 'next', next_href, _('Next Page'))

        if result.has_previous_page:
            prev_href = self.get_href(req, items_per_page, current_page - 1)
            add_link(req, 'prev', prev_href, _('Previous Page'))
        return result
Ejemplo n.º 5
0
    def _paginate(self, req, results):
        self.query = req.args.get('q', None)
        current_page = as_int(req.args.get('listtagged_page'), 1)
        items_per_page = as_int(req.args.get('listtagged_per_page'), None)
        if items_per_page is None:
            items_per_page = self.items_per_page
        result = Paginator(results, current_page - 1, items_per_page)

        pagedata = []
        shown_pages = result.get_shown_pages(21)
        for page in shown_pages:
            page_href = self.get_href(req, items_per_page, page)
            pagedata.append(
                [page_href, None,
                 str(page),
                 _("Page %(num)d", num=page)])

        attributes = ['href', 'class', 'string', 'title']
        result.shown_pages = [dict(zip(attributes, p)) for p in pagedata]

        result.current_page = {
            'href': None,
            'class': 'current',
            'string': str(result.page + 1),
            'title': None
        }

        if result.has_next_page:
            next_href = self.get_href(req, items_per_page, current_page + 1)
            add_link(req, 'next', next_href, _('Next Page'))

        if result.has_previous_page:
            prev_href = self.get_href(req, items_per_page, current_page - 1)
            add_link(req, 'prev', prev_href, _('Previous Page'))
        return result
Ejemplo n.º 6
0
 def _wiki_edit(self, req, stream):
     # TRANSLATOR: Label text for link to '/tags'.
     link = tag.a(_("view all tags"), href=req.href.tags())
     # TRANSLATOR: ... (view all tags)
     insert = tag(Markup(_("Tag under: (%(tags_link)s)", tags_link=link)))
     insert(
         tag.br(),
         tag.input(id='tags', type='text', name='tags', size='50',
             value=req.args.get('tags', ' '.join(self._page_tags(req))))
     )
     insert = tag.div(tag.label(insert), class_='field')
     return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
Ejemplo n.º 7
0
 def _wiki_edit(self, req, stream):
     # TRANSLATOR: Label text for link to '/tags'.
     link = tag.a(_("view all tags"), href=req.href.tags())
     # TRANSLATOR: ... (view all tags)
     insert = tag(Markup(_("Tag under: (%(tags_link)s)", tags_link=link)))
     insert(
         tag.br(),
         tag.input(id='tags', type='text', name='tags', size='50',
             value=req.args.get('tags', ' '.join(self._page_tags(req))))
     )
     insert = tag.div(tag.label(insert), class_='field')
     return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
Ejemplo n.º 8
0
def render_tag_changes(old_tags, new_tags):
    old_tags = split_into_tags(old_tags or '')
    new_tags = split_into_tags(new_tags or '')
    added = sorted(new_tags - old_tags)
    added = added and \
            tagn_("%(tags)s added", "%(tags)s added",
                  len(added), tags=builder.em(', '.join(added)))
    removed = sorted(old_tags - new_tags)
    removed = removed and \
              tagn_("%(tags)s removed", "%(tags)s removed",
                    len(removed), tags=builder.em(', '.join(removed)))
    # TRANSLATOR: How to delimit added and removed tags.
    delim = added and removed and _("; ")
    return builder(builder.strong(_("Tags")), ' ', added, delim, removed)
Ejemplo n.º 9
0
def render_tag_changes(old_tags, new_tags):
        old_tags = split_into_tags(old_tags or '')
        new_tags = split_into_tags(new_tags or '')
        added = sorted(new_tags - old_tags)
        added = added and \
                tagn_("%(tags)s added", "%(tags)s added",
                      len(added), tags=builder.em(', '.join(added)))
        removed = sorted(old_tags - new_tags)
        removed = removed and \
                  tagn_("%(tags)s removed", "%(tags)s removed",
                        len(removed), tags=builder.em(', '.join(removed)))
        # TRANSLATOR: How to delimit added and removed tags.
        delim = added and removed and _("; ")
        return builder(builder.strong(_("Tags")), ' ', added,
                       delim, removed)
Ejemplo n.º 10
0
    def render_admin_panel(self, req, cat, page, version):
        req.perm.require('TAGS_ADMIN')
        data = {}
        tag_system = TagSystem(self.env)
        if req.method == 'POST':
            # Replace Tag
            allow_delete = req.args.get('allow_delete')
            new_tag = req.args.get('tag_new_name').strip()
            new_tag = not new_tag == u'' and new_tag or None
            if not (allow_delete or new_tag):
                data['error'] = _("""Selected current tag(s) and either
                                  new tag or delete approval are required""")
            else:
                comment = req.args.get('comment', u'')
                old_tags = req.args.get('tag_name')
                if old_tags:
                    # Provide list regardless of single or multiple selection.
                    old_tags = isinstance(old_tags, list) and old_tags or \
                               [old_tags]
                    tag_system.replace_tag(req, old_tags, new_tag, comment,
                                           allow_delete)
                data['selected'] = new_tag

        all_tags = sorted(tag_system.get_all_tags(req, '-dummy'))
        data['tags'] = all_tags
        try:
            Chrome(self.env).add_textarea_grips(req)
        except AttributeError:
            # Element modifiers unavailable before Trac 0.12, skip gracefully.
            pass
        return 'admin_tag_change.html', data
Ejemplo n.º 11
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"))
Ejemplo n.º 12
0
    def parse_terminal(self, tokens):
        """Parse a terminal token.

        >>> q = Query('')
        >>> q.parse_terminal(q._tokenise('foo'))
        ("foo")
        """

        if not tokens:
            raise InvalidQuery(_("Unexpected end of string"))
        if tokens[0][0] in (QueryNode.TERM, QueryNode.OR):
            token = tokens.pop(0)[1]
            if token[0] in ('"', "'"):
                token = re.sub(r'\\(.)', r'\1', token[1:-1])
            return QueryNode(QueryNode.TERM, value=token)
        raise InvalidQuery(_("Expected terminal, got '%s'") % tokens[0][1])
Ejemplo n.º 13
0
    def parse_terminal(self, tokens):
        """Parse a terminal token.

        >>> q = Query('')
        >>> q.parse_terminal(q._tokenise('foo'))
        ("foo")
        """

        if not tokens:
            raise InvalidQuery(_("Unexpected end of string"))
        if tokens[0][0] in (QueryNode.TERM, QueryNode.OR):
            token = tokens.pop(0)[1]
            if token[0] in ('"', "'"):
                token = re.sub(r'\\(.)', r'\1', token[1:-1])
            return QueryNode(QueryNode.TERM, value=token)
        raise InvalidQuery(_("Expected terminal, got '%s'") % tokens[0][1])
Ejemplo n.º 14
0
    def render_admin_panel(self, req, cat, page, version):
        req.perm.require("TAGS_ADMIN")
        data = {}
        tag_system = TagSystem(self.env)
        if req.method == "POST":
            # Replace Tag
            allow_delete = req.args.get("allow_delete")
            new_tag = req.args.get("tag_new_name").strip()
            new_tag = not new_tag == u"" and new_tag or None
            if not (allow_delete or new_tag):
                data["error"] = _(
                    """Selected current tag(s) and either
                                  new tag or delete approval are required"""
                )
            else:
                comment = req.args.get("comment", u"")
                old_tags = req.args.get("tag_name")
                if old_tags:
                    # Provide list regardless of single or multiple selection.
                    old_tags = isinstance(old_tags, list) and old_tags or [old_tags]
                    tag_system.replace_tag(req, old_tags, new_tag, comment, allow_delete)
                data["selected"] = new_tag

        all_tags = sorted(tag_system.get_all_tags(req, "-dummy"))
        data["tags"] = all_tags
        try:
            Chrome(self.env).add_textarea_grips(req)
        except AttributeError:
            # Element modifiers unavailable before Trac 0.12, skip gracefully.
            pass
        return "admin_tag_change.html", data
Ejemplo n.º 15
0
    def post_process_request(self, req, template, data, content_type):
        if data and req.path_info == '/timeline' and \
                'TAGS_VIEW' in req.perm(Resource('tags')):

            def realm_handler(_, node, context):
                return query.match(node, [context.realm])

            query_str = req.args.getfirst(self.key)
            if query_str is None and req.args.get('format') != 'rss':
                query_str = req.session.get('timeline.%s' % self.key)
            else:
                query_str = (query_str or '').strip()
                # Record tag query expression between visits.
                req.session['timeline.%s' % self.key] = query_str

            if data.get('events') and query_str:
                tag_system = TagSystem(self.env)
                try:
                    query = Query(query_str,
                                  attribute_handlers={'realm': realm_handler})
                except InvalidQuery as e:
                    add_warning(req, _("Tag query syntax error: %s" % e))
                else:
                    all_realms = tag_system.get_taggable_realms(req.perm)
                    query_realms = set()
                    for m in REALM_RE.finditer(query.as_string()):
                        query_realms.add(m.group(1))
                    # Don't care about resources from non-taggable realms.
                    realms = not query_realms and all_realms or \
                             query_realms.intersection(all_realms)
                    events = []
                    self.log.info("Filtering timeline events by tags '%s'",
                                   query_str)
                    for event in data['events']:
                        resource = resource_from_event(event)
                        if resource and resource.realm in realms:
                            # Shortcut view permission checks here.
                            tags = tag_system.get_tags(None, resource)
                            if query(tags, context=resource):
                                events.append(event)
                    # Overwrite with filtered list.
                    data['events'] = events
            if query_str:
                # Add current value for next form rendering.
                data[self.key] = query_str
            elif self.key in req.session:
                del req.session[self.key]

            filter_lst = []
            # xpath = '//form[@id="prefs"]/div[1]'
            xform = JTransformer('form#prefs > div:nth-of-type(1)')
            insert = builder(Markup('<br />'), tag_("matching tags "),
                             builder.input(type='text', name=self.key,
                                           value=data.get(self.key)))
            filter_lst.append(xform.append(Markup(insert)))
            add_script_data(req, {'tags_filter': filter_lst})
            add_script(req, 'tags/js/tags_jtransform.js')

        return template, data, content_type
Ejemplo n.º 16
0
    def _paginate(self, req, results, realms):
        query = req.args.get('q', None)
        current_page = as_int(req.args.get('listtagged_page'), 1, min=1)
        items_per_page = as_int(req.args.get('listtagged_per_page'),
                                self.items_per_page)
        if items_per_page < 1:
            items_per_page = self.items_per_page
        try:
            result = Paginator(results, current_page - 1, items_per_page)
        except (AssertionError, TracError) as e:
            # AssertionError raised in Trac < 1.0.10, TracError otherwise
            self.log.warn("ListTagged macro: %s", e)
            current_page = 1
            result = Paginator(results, current_page - 1, items_per_page)

        pagedata = []
        shown_pages = result.get_shown_pages(21)
        for page in shown_pages:
            page_href = self.get_href(req, realms, query, items_per_page, page)
            pagedata.append(
                [page_href, None,
                 str(page),
                 _("Page %(num)d", num=page)])

        attributes = ['href', 'class', 'string', 'title']
        result.shown_pages = [dict(zip(attributes, p)) for p in pagedata]

        result.current_page = {
            'href': None,
            'class': 'current',
            'string': str(result.page + 1),
            'title': None
        }

        if result.has_next_page:
            next_href = self.get_href(req, realms, query, items_per_page,
                                      current_page + 1)
            add_link(req, 'next', next_href, _('Next Page'))

        if result.has_previous_page:
            prev_href = self.get_href(req, realms, query, items_per_page,
                                      current_page - 1)
            add_link(req, 'prev', prev_href, _('Previous Page'))
        return result
Ejemplo n.º 17
0
 def environment_needs_upgrade(self, db=None):
     schema_ver = self.get_schema_version()
     if schema_ver == db_default.schema_version:
         return False
     elif schema_ver > db_default.schema_version:
         raise TracError(_("A newer plugin version has been installed "
                           "before, but downgrading is unsupported."))
     self.log.info("TracTags database schema version is %d, should be %d",
                   schema_ver, db_default.schema_version)
     return True
Ejemplo n.º 18
0
 def environment_needs_upgrade(self, db):
     schema_ver = self.get_schema_version(db)
     if schema_ver == db_default.schema_version:
         return False
     elif schema_ver > db_default.schema_version:
         raise TracError(_("""A newer plugin version has been installed
                           before, but downgrading is unsupported."""))
     self.log.info("TracTags database schema version is %d, should be %d"
                   % (schema_ver, db_default.schema_version))
     return True
Ejemplo n.º 19
0
    def render_cloud(self, req, cloud, renderer=None, caseless_sort=False,
                     mincount=None, realms=()):
        """Render a tag cloud.

        :cloud: Dictionary of {object: count} representing the cloud.
        :param renderer: A callable with signature (tag, count, percent)
                         used to render the cloud objects.
        :param caseless_sort: Boolean, whether tag cloud should be sorted
                              case-sensitive.
        :param mincount: Integer threshold to hide tags with smaller count.
        """
        min_px = 10.0
        max_px = 30.0
        scale = 1.0

        if renderer is None:
            def default_renderer(tag, count, percent):
                href = self.get_href(req, realms, tag=Resource('tag', tag))
                return builder.a(tag, rel='tag', title='%i' % count,
                                 href=href, style='font-size: %ipx'
                                 % int(min_px + percent * (max_px - min_px)))
            renderer = default_renderer

        # A LUT from count to n/len(cloud)
        size_lut = dict([(c, float(i)) for i, c in
                         enumerate(sorted(set([r for r in cloud.values()])))])
        if size_lut:
            scale = 1.0 / len(size_lut)

        if caseless_sort:
            # Preserve upper-case precedence within similar tags.
            items = reversed(sorted(cloud.iteritems(),
                                    key=lambda t: t[0].lower(), reverse=True))
        else:
            items = sorted(cloud.iteritems())
        ul = li = None
        for i, (tag, count) in enumerate(items):
            percent = size_lut[count] * scale
            if mincount and count < as_int(mincount, 1):
                # Tag count is too low.
                continue
            if ul:
                # Found new tag for cloud; now add previously prepared one. 
                ul('\n', li)
            else:
                # Found first tag for cloud; now create the list.
                ul = builder.ul(class_='tagcloud')
            # Prepare current tag entry.
            li = builder.li(renderer(tag, count, percent))
        if li:
            # All tags checked; mark latest tag as last one (no tailing colon).
            li(class_='last')
            ul('\n', li, '\n')
        return ul and ul or _("No tags found")
Ejemplo n.º 20
0
    def render_cloud(self, req, cloud, renderer=None, caseless_sort=False,
                     mincount=None, realms=()):
        """Render a tag cloud.

        :cloud: Dictionary of {object: count} representing the cloud.
        :param renderer: A callable with signature (tag, count, percent)
                         used to render the cloud objects.
        :param caseless_sort: Boolean, whether tag cloud should be sorted
                              case-sensitive.
        :param mincount: Integer threshold to hide tags with smaller count.
        """
        min_px = 10.0
        max_px = 30.0
        scale = 1.0

        if renderer is None:
            def default_renderer(tag, count, percent):
                href = self.get_href(req, realms, tag=Resource('tag', tag))
                return builder.a(tag, rel='tag', title='%i' % count,
                                 href=href, style='font-size: %ipx'
                                 % int(min_px + percent * (max_px - min_px)))
            renderer = default_renderer

        # A LUT from count to n/len(cloud)
        size_lut = dict([(c, float(i)) for i, c in
                         enumerate(sorted(set([r for r in cloud.values()])))])
        if size_lut:
            scale = 1.0 / len(size_lut)

        if caseless_sort:
            # Preserve upper-case precedence within similar tags.
            items = reversed(sorted(cloud.iteritems(),
                                    key=lambda t: t[0].lower(), reverse=True))
        else:
            items = sorted(cloud.iteritems())
        ul = li = None
        for i, (tag, count) in enumerate(items):
            percent = size_lut[count] * scale
            if mincount and count < as_int(mincount, 1):
                # Tag count is too low.
                continue
            if ul:
                # Found new tag for cloud; now add previously prepared one.
                ul('\n', li)
            else:
                # Found first tag for cloud; now create the list.
                ul = builder.ul(class_='tagcloud')
            # Prepare current tag entry.
            li = builder.li(renderer(tag, count, percent))
        if li:
            # All tags checked; mark latest tag as last one (no tailing colon).
            li(class_='last')
            ul('\n', li, '\n')
        return ul and ul or _("No tags found")
Ejemplo n.º 21
0
    def upgrade_environment(self, db):
        """Each schema version should have its own upgrade module, named
        upgrades/dbN.py, where 'N' is the version number (int).
        """
        db_mgr = DatabaseManager(self.env)
        schema_ver = self.get_schema_version(db)

        cursor = db.cursor()
        # Is this a new installation?
        if not schema_ver:
            # Perform a single-step install: Create plugin schema and
            # insert default data into the database.
            connector = db_mgr._get_connector()[0]
            for table in db_default.schema:
                for stmt in connector.to_sql(table):
                    cursor.execute(stmt)
            for table, cols, vals in db_default.get_data(db):
                cursor.executemany(
                    "INSERT INTO %s (%s) VALUES (%s)" %
                    (table, ','.join(cols), ','.join(['%s' for c in cols])),
                    vals)
        else:
            # Perform incremental upgrades.
            for i in range(schema_ver + 1, db_default.schema_version + 1):
                name = 'db%i' % i
                try:
                    upgrades = __import__('tractags.upgrades', globals(),
                                          locals(), [name])
                    script = getattr(upgrades, name)
                except AttributeError:
                    raise TracError(
                        _(
                            "No upgrade module for version %(num)i "
                            "(%(version)s.py)",
                            num=i,
                            version=name))
                script.do_upgrade(self.env, i, cursor)
        cursor.execute(
            """
            UPDATE system
               SET value=%s
             WHERE name='tags_version'
            """, (db_default.schema_version, ))
        self.log.info("Upgraded TracTags db schema from version %d to %d" %
                      (schema_ver, db_default.schema_version))

        TicketTagProvider(self.env)._fetch_tkt_tags(db)
        self.log.info("Synchronized ticket attributes to tags table")

        db.commit()
Ejemplo n.º 22
0
class TicketTagProvider(DefaultTagProvider):
    """A tag provider using ticket fields as sources of tags.

    Relevant ticket data is initially copied to plugin's own tag db store for
    more efficient regular access, that matters especially when working with
    large ticket quantities, kept current using ticket change listener events.

    Currently does NOT support custom fields.
    """

    implements(ITicketChangeListener)

    #    custom_fields = ListOption('tags', 'custom_ticket_fields',
    #        doc=_("List of custom ticket fields to expose as tags."))

    fields = ListOption('tags',
                        'ticket_fields',
                        'keywords',
                        doc=_("List of ticket fields to expose as tags."))

    ignore_closed_tickets = BoolOption(
        'tags', 'ignore_closed_tickets', True,
        _("Do not collect tags from closed tickets."))

    map = {'view': 'TICKET_VIEW', 'modify': 'TICKET_CHGPROP'}
    realm = 'ticket'
    use_cache = False

    def __init__(self):
        db = self.env.get_db_cnx()
        try:
            self._fetch_tkt_tags(db)
            db.commit()
        except get_db_exc(self.env).IntegrityError, e:
            self.log.warn('tags for ticket already exist: %s', to_unicode(e))
            db.rollback()
        except:
Ejemplo n.º 23
0
    def render_admin_panel(self, req, cat, page, version):
        req.perm.require('TAGS_ADMIN')

        realms = [p.get_taggable_realm() for p in self.tag_providers
                  if (not hasattr(p, 'check_permission') or \
                      p.check_permission(req.perm, 'view'))]
        # Check request for enabled filters, or use default.
        if [r for r in realms if r in req.args] == []:
            for realm in realms:
                req.args[realm] = 'on'
        checked_realms = [r for r in realms if r in req.args]
        data = dict(checked_realms=checked_realms,
                    tag_realms=list(
                        dict(name=realm, checked=realm in checked_realms)
                        for realm in realms))

        tag_system = TagSystem(self.env)
        if req.method == 'POST':
            # Replace Tag
            allow_delete = req.args.get('allow_delete')
            new_tag = req.args.get('tag_new_name').strip()
            new_tag = not new_tag == u'' and new_tag or None
            if not (allow_delete or new_tag):
                data['error'] = _("Selected current tag(s) and either "
                                  "new tag or delete approval are required")
            else:
                comment = req.args.get('comment', u'')
                old_tags = req.args.get('tag_name')
                if old_tags:
                    # Provide list regardless of single or multiple selection.
                    old_tags = isinstance(old_tags, list) and old_tags or \
                               [old_tags]
                    tag_system.replace_tag(req,
                                           old_tags,
                                           new_tag,
                                           comment,
                                           allow_delete,
                                           filter=checked_realms)
                data['selected'] = new_tag

        query = ' or '.join(['realm:%s' % r for r in checked_realms])
        all_tags = sorted(tag_system.get_all_tags(req, query))
        data['tags'] = all_tags
        try:
            Chrome(self.env).add_textarea_grips(req)
        except AttributeError:
            # Element modifiers unavailable before Trac 0.12, skip gracefully.
            pass
        return 'admin_tag_change.html', data
Ejemplo n.º 24
0
    def post_process_request(self, req, template, data, content_type):
        if data and req.path_info == '/timeline' and \
                'TAGS_VIEW' in req.perm(Resource('tags')):

            def realm_handler(_, node, context):
                return query.match(node, [context.realm])

            query_str = req.args.get(self.key)
            if query_str is None and req.args.get('format') != 'rss':
                query_str = req.session.get('timeline.%s' % self.key)
            else:
                query_str = (query_str or '').strip()
                # Record tag query expression between visits.
                req.session['timeline.%s' % self.key] = query_str

            if data.get('events') and query_str:
                tag_system = TagSystem(self.env)
                try:
                    query = Query(query_str,
                                  attribute_handlers=dict(realm=realm_handler)
                            )
                except InvalidQuery, e:
                    add_warning(req, _("Tag query syntax error: %s"
                                       % to_unicode(e)))
                else:
                    all_realms = tag_system.get_taggable_realms(req.perm)
                    query_realms = set()
                    for m in REALM_RE.finditer(query.as_string()):
                        query_realms.add(m.group(1))
                    # Don't care about resources from non-taggable realms.
                    realms = not query_realms and all_realms or \
                             query_realms.intersection(all_realms)
                    events = []
                    self.log.debug("Filtering timeline events by tags '%s'",
                                   query_str)
                    for event in data['events']:
                        resource = event['data'][0]
                        if resource.realm in realms:
                            # Shortcut view permission checks here.
                            tags = tag_system.get_tags(None, resource)
                            if query(tags, context=resource):
                                events.append(event)
                    # Overwrite with filtered list.
                    data['events'] = events
            if query_str:
                # Add current value for next form rendering.
                data[self.key] = query_str
            elif self.key in req.session:
                del req.session[self.key]
Ejemplo n.º 25
0
    def _post_process_request_history(self, req, data):
        history = []
        page_histories = data.get('history', [])
        resource = data['resource']
        tags_histories = tag_changes(self.env, resource)

        for page_history in page_histories:
            while tags_histories and \
                    tags_histories[0][0] >= page_history['date']:
                tags_history = tags_histories.pop(0)
                date = tags_history[0]
                author = tags_history[1]
                old_tags = split_into_tags(tags_history[2] or '')
                new_tags = split_into_tags(tags_history[3] or '')
                added = sorted(new_tags - old_tags)
                added = added and \
                        tagn_("%(tags)s added", "%(tags)s added",
                              len(added), tags=tag.em(', '.join(added)))
                removed = sorted(old_tags - new_tags)
                removed = removed and \
                          tagn_("%(tags)s removed", "%(tags)s removed",
                                len(removed), tags=tag.em(', '.join(removed)))
                # TRANSLATOR: How to delimit added and removed tags.
                delim = added and removed and _("; ")
                comment = tag(tag.strong(_("Tags")), ' ', added, delim,
                              removed)
                url = req.href(resource.realm, resource.id,
                               version=page_history['version'],
                               tags_version=to_utimestamp(date))
                history.append({'version': '*', 'url': url, 'date': date,
                                'author': author, 'comment': comment,
                                'ipnr': ''})
            history.append(page_history)

        data.update(dict(history=history,
                         wiki_to_oneliner=self._wiki_to_oneliner))
Ejemplo n.º 26
0
    def post_process_request(self, req, template, data, content_type):
        if data and req.path_info == '/timeline' and \
                'TAGS_VIEW' in req.perm(Resource('tags')):

            def realm_handler(_, node, context):
                return query.match(node, [context.realm])

            query_str = req.args.get(self.key)
            if query_str is None and req.args.get('format') != 'rss':
                query_str = req.session.get('timeline.%s' % self.key)
            else:
                query_str = (query_str or '').strip()
                # Record tag query expression between visits.
                req.session['timeline.%s' % self.key] = query_str

            if data.get('events') and query_str:
                tag_system = TagSystem(self.env)
                try:
                    query = Query(query_str,
                                  attribute_handlers=dict(realm=realm_handler))
                except InvalidQuery, e:
                    add_warning(
                        req, _("Tag query syntax error: %s" % to_unicode(e)))
                else:
                    all_realms = tag_system.get_taggable_realms(req.perm)
                    query_realms = set()
                    for m in REALM_RE.finditer(query.as_string()):
                        query_realms.add(m.group(1))
                    # Don't care about resources from non-taggable realms.
                    realms = not query_realms and all_realms or \
                             query_realms.intersection(all_realms)
                    events = []
                    self.log.debug("Filtering timeline events by tags '%s'" %
                                   query_str)
                    for event in data['events']:
                        resource = event['data'][0]
                        if resource.realm in realms:
                            # Shortcut view permission checks here.
                            tags = tag_system.get_tags(None, resource)
                            if query(tags, context=resource):
                                events.append(event)
                    # Overwrite with filtered list.
                    data['events'] = events
            if query_str:
                # Add current value for next form rendering.
                data[self.key] = query_str
            elif self.key in req.session:
                del req.session[self.key]
Ejemplo n.º 27
0
    def render_admin_panel(self, req, cat, page, version):
        req.perm.require('TAGS_ADMIN')

        tag_system = TagSystem(self.env)
        all_realms = tag_system.get_taggable_realms(req.perm)
        # Check request for enabled filters, or use default.
        if not [r for r in all_realms if r in req.args]:
            for realm in all_realms:
                req.args[realm] = 'on'
        checked_realms = [r for r in all_realms if r in req.args]
        data = dict(checked_realms=checked_realms,
                    tag_realms=list(
                        dict(name=realm, checked=realm in checked_realms)
                        for realm in all_realms))

        if req.method == 'POST':
            # Replace Tag
            allow_delete = req.args.get('allow_delete')
            new_tag = req.args.get('tag_new_name').strip()
            new_tag = not new_tag == u'' and new_tag or None
            if not (allow_delete or new_tag):
                add_warning(
                    req,
                    _("Selected current tag(s) and either "
                      "new tag or delete approval are required"))
            else:
                comment = req.args.get('comment', u'')
                old_tags = req.args.getlist('tag_name')
                if old_tags:
                    tag_system.replace_tag(req,
                                           old_tags,
                                           new_tag,
                                           comment,
                                           allow_delete,
                                           filter=checked_realms)
                data['selected'] = new_tag
            req.redirect(req.href.admin('tags', 'replace'))

        query = ' or '.join('realm:%s' % r for r in checked_realms)
        all_tags = sorted(tag_system.get_all_tags(req, query))
        data['tags'] = all_tags
        chrome = Chrome(self.env)
        chrome.add_textarea_grips(req)
        if hasattr(chrome, 'jenv'):
            return 'admin_tag_change.html', data, None
        else:
            return 'admin_tag_change.html', data
Ejemplo n.º 28
0
    def _wiki_view(self, req, stream):
        add_stylesheet(req, 'tags/css/tractags.css')
        tags = self._page_tags(req)
        if not tags:
            return stream
        li = []
        for tag_ in tags:
            resource = Resource('tag', tag_)
            anchor = render_resource_link(self.env, web_context(req, resource),
                                          resource)
            anchor = anchor(rel='tag')
            li.append(tag.li(anchor, ' '))

        # TRANSLATOR: Header label text for tag list at wiki page bottom.
        insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li)
        return stream | (
            Transformer('//div[contains(@class,"wikipage")]').after(insert))
Ejemplo n.º 29
0
    def _wiki_view(self, req, stream):
        add_stylesheet(req, 'tags/css/tractags.css')
        tags = self._page_tags(req)
        if not tags:
            return stream
        li = []
        for tag_ in tags:
            resource = Resource('tag', tag_)
            anchor = render_resource_link(self.env,
                Context.from_request(req, resource), resource)
            anchor = anchor(rel='tag')
            li.append(tag.li(anchor, ' '))

        # TRANSLATOR: Header label text for tag list at wiki page bottom.
        insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li)
        return stream | (Transformer('//div[contains(@class,"wikipage")]')
                         .after(insert))
Ejemplo n.º 30
0
 def _post_process_request_wiki_edit(self, req):
     tags = ' '.join(self._page_tags(req))
     # TRANSLATOR: Label text for link to '/tags'.
     link = tag.a(_("view all tags"), href=req.href.tags())
     # TRANSLATOR: ... (view all tags)
     insert = tag(
         tag_("Tag under: (%(tags_link)s)", tags_link=link), tag.br(),
         tag.input(id='tags',
                   type='text',
                   name='tags',
                   size='50',
                   value=req.args.get('tags', tags)))
     insert = tag.div(tag.label(insert), class_='field')
     filter_lst = []
     # xpath = //div[@id="changeinfo1"]
     xform = JTransformer('div#changeinfo1')
     filter_lst.append(xform.append(Markup(insert)))
     self._add_jtransform(req, filter_lst)
Ejemplo n.º 31
0
    def upgrade_environment(self, db):
        """Each schema version should have its own upgrade module, named
        upgrades/dbN.py, where 'N' is the version number (int).
        """
        db_mgr = DatabaseManager(self.env)
        schema_ver = self.get_schema_version(db)

        cursor = db.cursor()
        # Is this a new installation?
        if not schema_ver:
            # Perform a single-step install: Create plugin schema and
            # insert default data into the database.
            connector = db_mgr._get_connector()[0]
            for table in db_default.schema:
                for stmt in connector.to_sql(table):
                    cursor.execute(stmt)
            for table, cols, vals in db_default.get_data(db):
                cursor.executemany("INSERT INTO %s (%s) VALUES (%s)" % (table,
                                   ','.join(cols),
                                   ','.join(['%s' for c in cols])), vals)
        else:
            # Perform incremental upgrades.
            for i in range(schema_ver + 1, db_default.schema_version + 1):
                name  = 'db%i' % i
                try:
                    upgrades = __import__('tractags.upgrades', globals(),
                                          locals(), [name])
                    script = getattr(upgrades, name)
                except AttributeError:
                    raise TracError(_("No upgrade module for version %(num)i "
                                      "(%(version)s.py)", num=i, version=name))
                script.do_upgrade(self.env, i, cursor)
        cursor.execute("""
            UPDATE system
               SET value=%s
             WHERE name='tags_version'
            """, (db_default.schema_version,))
        self.log.info("Upgraded TracTags db schema from version %d to %d"
                      % (schema_ver, db_default.schema_version))

        TicketTagProvider(self.env)._fetch_tkt_tags(db)
        self.log.info("Synchronized ticket attributes to tags table")

        db.commit()
Ejemplo n.º 32
0
    def render_admin_panel(self, req, cat, page, version):
        req.perm.require('TAGS_ADMIN')

        tag_system = TagSystem(self.env)
        all_realms = tag_system.get_taggable_realms(req.perm)
        # Check request for enabled filters, or use default.
        if not [r for r in all_realms if r in req.args]:
            for realm in all_realms:
                req.args[realm] = 'on'
        checked_realms = [r for r in all_realms if r in req.args]
        data = dict(checked_realms=checked_realms,
                    tag_realms=list(dict(name=realm,
                                         checked=realm in checked_realms)
                                    for realm in all_realms))

        if req.method == 'POST':
            # Replace Tag
            allow_delete = req.args.get('allow_delete')
            new_tag = req.args.get('tag_new_name').strip()
            new_tag = not new_tag == u'' and new_tag or None
            if not (allow_delete or new_tag):
                data['error'] = _("Selected current tag(s) and either "
                                  "new tag or delete approval are required")
            else:
                comment = req.args.get('comment', u'')
                old_tags = req.args.get('tag_name')
                if old_tags:
                    # Provide list regardless of single or multiple selection.
                    old_tags = isinstance(old_tags, list) and old_tags or \
                               [old_tags]
                    tag_system.replace_tag(req, old_tags, new_tag, comment,
                                           allow_delete, filter=checked_realms)
                data['selected'] = new_tag

        query = ' or '.join(['realm:%s' % r for r in checked_realms])
        all_tags = sorted(tag_system.get_all_tags(req, query))
        data['tags'] = all_tags
        try:
            Chrome(self.env).add_textarea_grips(req)
        except AttributeError:
            # Element modifiers unavailable before Trac 0.12, skip gracefully.
            pass
        return 'admin_tag_change.html', data
Ejemplo n.º 33
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())

        query = target
        # Pop realms from query expression.
        all_realms = self.tag_system.get_taggable_realms(formatter.perm)
        realms = query_realms(target, all_realms)
        if realms:
            kwargs = dict((realm, 'on') for realm in realms)
            target = re.sub('(^|\W)realm:\S+(\W|$)', ' ', target).strip()
        else:
            kwargs = {}

        tag_res = Resource('tag', target)
        if 'TAGS_VIEW' not in formatter.perm(tag_res):
            return tag.span(label,
                            class_='forbidden tags',
                            title=_("no permission to view tags"))

        context = formatter.context
        href = self.tag_system.get_resource_url(tag_res, context.href, kwargs)
        if all_realms and (target in self.tag_system.get_all_tags(
                formatter.req) or not iter_is_empty(
                    self.tag_system.query(formatter.req, query))):
            # At least one tag provider is available and tag exists or
            # tags query yields at least one match.
            if label:
                return tag.a(label, href=href)
            return render_resource_link(self.env, context, tag_res)

        return tag.a(label + '?',
                     href=href,
                     class_='missing tags',
                     rel='nofollow')
Ejemplo n.º 34
0
 def parse(self, tokens):
     left = self.parse_unary(tokens)
     while tokens:
         if tokens[0][0] == QueryNode.ENDSUB:
             return left
         if tokens[0][0] == QueryNode.OR:
             tokens.pop(0)
             return QueryNode(QueryNode.OR, left=left,
                              right=self.parse(tokens))
         elif tokens[0][0] == QueryNode.ATTR:
             tokens.pop(0)
             if left.type is not QueryNode.TERM:
                 raise InvalidQuery(_("Attribute must be a word"))
             left = QueryNode(QueryNode.ATTR, left=left,
                              right=self.parse_unary(tokens))
         else:
             return QueryNode(QueryNode.AND, left=left,
                              right=self.parse(tokens))
     return left
Ejemplo n.º 35
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())

        query = target
        # Pop realms from query expression.
        all_realms = self.tag_system.get_taggable_realms(formatter.perm)
        realms = query_realms(target, all_realms)
        if realms:
            kwargs = dict((realm, 'on') for realm in realms)
            target = re.sub('(^|\W)realm:\S+(\W|$)', ' ', target).strip()
        else:
            kwargs = {}

        tag_res = Resource('tag', target)
        if 'TAGS_VIEW' not in formatter.perm(tag_res):
            return tag.span(label, class_='forbidden tags',
                            title=_("no permission to view tags"))

        context = formatter.context
        href = self.tag_system.get_resource_url(tag_res, context.href, kwargs)
        if all_realms and (
                target in self.tag_system.get_all_tags(formatter.req) or
                not iter_is_empty(self.tag_system.query(formatter.req,
                                                        query))):
            # At least one tag provider is available and tag exists or
            # tags query yields at least one match.
            if label:
                return tag.a(label, href=href)
            return render_resource_link(self.env, context, tag_res)

        return tag.a(label+'?', href=href, class_='missing tags',
                     rel='nofollow')
Ejemplo n.º 36
0
    def _post_process_request_wiki_view(self, req):
        add_stylesheet(req, 'tags/css/tractags.css')
        tags = self._page_tags(req)
        if not tags:
            return
        li = []
        for t in tags:
            resource = Resource('tag', t)
            anchor = render_resource_link(self.env, web_context(req, resource),
                                          resource)
            anchor = anchor(rel='tag')
            li.append(tag.li(anchor, ' '))

        # TRANSLATOR: Header label text for tag list at wiki page bottom.
        insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li)

        filter_lst = []
        # xpath = //div[contains(@class,"wikipage")]
        xform = JTransformer('div[class*=wikipage]')
        filter_lst.append(xform.after(Markup(insert)))

        self._add_jtransform(req, filter_lst)
        return
Ejemplo n.º 37
0
    def parse_unary(self, tokens):
        """Parse a unary operator. Currently only NOT.

        >>> q = Query('')
        >>> q.parse_unary(q._tokenise('-foo'))
        (not
          ("foo")
          nil)
        """
        if not tokens:
            return None
        if tokens[0][0] == QueryNode.BEGINSUB:
            tokens.pop(0)
            if tokens[0][0] == QueryNode.ENDSUB:
                return None
            node = self.parse(tokens)
            if not tokens or tokens[0][0] != QueryNode.ENDSUB:
                raise InvalidQuery(_("Expected ) at end of sub-expression"))
            tokens.pop(0)
            return node
        if tokens[0][0] == QueryNode.NOT:
            tokens.pop(0)
            return QueryNode(QueryNode.NOT, left=self.parse_terminal(tokens))
        return self.parse_terminal(tokens)
Ejemplo n.º 38
0
    def parse_unary(self, tokens):
        """Parse a unary operator. Currently only NOT.

        >>> q = Query('')
        >>> q.parse_unary(q._tokenise('-foo'))
        (not
          ("foo")
          nil)
        """
        if not tokens:
            return None
        if tokens[0][0] == QueryNode.BEGINSUB:
            tokens.pop(0)
            if tokens[0][0] == QueryNode.ENDSUB:
                return None
            node = self.parse(tokens)
            if not tokens or tokens[0][0] != QueryNode.ENDSUB:
                raise InvalidQuery(_("Expected ) at end of sub-expression"))
            tokens.pop(0)
            return node
        if tokens[0][0] == QueryNode.NOT:
            tokens.pop(0)
            return QueryNode(QueryNode.NOT, left=self.parse_terminal(tokens))
        return self.parse_terminal(tokens)
Ejemplo n.º 39
0
 def _invalid_handler(self, name, node, context):
     raise InvalidQuery(_("Invalid attribute '%s'") % name)
Ejemplo n.º 40
0
    def process_request(self, req):
        req.perm.require('TAGS_VIEW')

        match = re.match(r'/tags/?(.*)', req.path_info)
        tag_id = match.group(1) and match.group(1) or None
        query = req.args.get('q', '')

        # Consider only providers, that are permitted for display.
        tag_system = TagSystem(self.env)
        all_realms = tag_system.get_taggable_realms(req.perm)
        if not (tag_id or query) or [r for r in all_realms
                                     if r in req.args] == []:
            for realm in all_realms:
                if not realm in self.exclude_realms:
                    req.args[realm] = 'on'
        checked_realms = [r for r in all_realms if r in req.args]
        if query:
            # Add permitted realms from query expression.
            checked_realms.extend(query_realms(query, all_realms))
        realm_args = dict(zip([r for r in checked_realms],
                              ['on' for r in checked_realms]))
        # Switch between single tag and tag query expression mode.
        if tag_id and not re.match(r"""(['"]?)(\S+)\1$""", tag_id, re.UNICODE):
            # Convert complex, invalid tag ID's --> query expression.
            req.redirect(req.href.tags(realm_args, q=tag_id))
        elif query:
            single_page = re.match(r"""(['"]?)(\S+)\1$""", query, re.UNICODE)
            if single_page:
                # Convert simple query --> single tag.
                req.redirect(req.href.tags(single_page.group(2), realm_args))

        data = dict(page_title=_("Tags"), checked_realms=checked_realms)
        # Populate the TagsQuery form field.
        data['tag_query'] = tag_id and tag_id or query
        data['tag_realms'] = list(dict(name=realm,
                                       checked=realm in checked_realms)
                                  for realm in all_realms)
        if tag_id:
            data['tag_page'] = WikiPage(self.env,
                                        tag_system.wiki_page_prefix + tag_id)
        if query or tag_id:
            macro = 'ListTagged'
            # TRANSLATOR: The meta-nav link label.
            add_ctxtnav(req, _("Back to Cloud"), req.href.tags())
            args = "%s,format=%s,cols=%s" % \
                   (tag_id and tag_id or query, self.default_format,
                    self.default_cols)
            data['mincount'] = None
        else:
            macro = 'TagCloud'
            mincount = as_int(req.args.get('mincount', None),
                              self.cloud_mincount)
            args = mincount and "mincount=%s" % mincount or None
            data['mincount'] = mincount
        formatter = Formatter(self.env, Context.from_request(req,
                                                             Resource('tag')))
        self.env.log.debug("%s macro arguments: %s", macro,
                           args and args or '(none)')
        macros = TagWikiMacros(self.env)
        try:
            # Query string without realm throws 'NotImplementedError'.
            data['tag_body'] = checked_realms and \
                               macros.expand_macro(formatter, macro, args,
                                                   realms=checked_realms) \
                               or ''
        except InvalidQuery, e:
            data['tag_query_error'] = to_unicode(e)
            data['tag_body'] = macros.expand_macro(formatter, 'TagCloud', '')
Ejemplo n.º 41
0
    def expand_macro(self, formatter, name, content, realms=[]):
        """Evaluate macro call and render results.

        Calls from web-UI come with pre-processed realm selection.
        """
        env = self.env
        req = formatter.req
        tag_system = TagSystem(env)

        all_realms = tag_system.get_taggable_realms()
        if not all_realms:
            # Tag providers are required, no result without at least one.
            return ''
        args, kw = parse_args(content)

        query = args and args[0].strip() or None
        if not realms:
            # Check macro arguments for realms (typical wiki macro call).
            realms = 'realm' in kw and kw['realm'].split('|') or []
        if query:
            # Add realms from query expression.
            realms.extend(query_realms(query, all_realms))
            # Remove redundant realm selection for performance.
            if set(realms) == all_realms:
                query = re.sub('(^|\W)realm:\S+(\W|$)', ' ', query).strip()
        if name == 'TagCloud':
            # Set implicit 'all tagged realms' as default.
            if not realms:
                realms = all_realms
            if query:
                all_tags = Counter()
                # Require per resource query including view permission checks.
                for resource, tags in tag_system.query(req, query):
                    all_tags.update(tags)
            else:
                # Allow faster per tag query, side steps permission checks.
                all_tags = tag_system.get_all_tags(req, realms=realms)
            mincount = 'mincount' in kw and kw['mincount'] or None
            return self.render_cloud(req,
                                     all_tags,
                                     caseless_sort=self.caseless_sort,
                                     mincount=mincount,
                                     realms=realms)
        elif name == 'ListTagged':
            if content and _OBSOLETE_ARGS_RE.search(content):
                data = {'warning': 'obsolete_args'}
            else:
                data = {'warning': None}
            context = formatter.context
            # Use TagsQuery arguments (most likely wiki macro calls).
            cols = 'cols' in kw and kw['cols'] or self.default_cols
            format = 'format' in kw and kw['format'] or self.default_format
            if not realms:
                # Apply ListTagged defaults to macro call w/o realm.
                realms = list(set(all_realms) - set(self.exclude_realms))
                if not realms:
                    return ''
            query = '(%s) (%s)' % (query or '', ' or '.join(
                ['realm:%s' % (r) for r in realms]))
            query_result = tag_system.query(req, query)
            excludes = [
                exc.strip() for exc in kw.get('exclude', '').split(':')
                if exc.strip()
            ]
            if excludes and query_result:
                filtered_result = [(resource, tags)
                                   for resource, tags in query_result
                                   if not any(
                                       fnmatchcase(resource.id, exc)
                                       for exc in excludes)]
                query_result = filtered_result
            if not query_result:
                return ''

            def _link(resource):
                if resource.realm == 'tag':
                    # Keep realm selection in tag links.
                    return builder.a(resource.id,
                                     href=self.get_href(req,
                                                        realms,
                                                        tag=resource))
                elif resource.realm == 'ticket':
                    # Return resource link including ticket status dependend
                    #   class to allow for common Trac ticket link style.
                    ticket = Ticket(env, resource.id)
                    return builder.a('#%s' % ticket.id,
                                     class_=ticket['status'],
                                     href=formatter.href.ticket(ticket.id),
                                     title=shorten_line(ticket['summary']))
                return render_resource_link(env, context, resource, 'compact')

            if format == 'table':
                cols = [
                    col for col in cols.split('|')
                    if col in self.supported_cols
                ]
                # Use available translations from Trac core.
                try:
                    labels = TicketSystem(env).get_ticket_field_labels()
                    labels['id'] = _('Id')
                except AttributeError:
                    # Trac 0.11 neither has the attribute nor uses i18n.
                    labels = {'id': 'Id', 'description': 'Description'}
                labels['realm'] = _('Realm')
                labels['tags'] = _('Tags')
                headers = [{'label': labels.get(col)} for col in cols]
                data.update({'cols': cols, 'headers': headers})

            try:
                results = sorted(
                    query_result,
                    key=lambda r: embedded_numbers(to_unicode(r[0].id)))
            except (InvalidQuery, InvalidTagRealm), e:
                return system_message(_("ListTagged macro error"), e)
            results = self._paginate(req, results, realms)
            rows = []
            for resource, tags in results:
                desc = tag_system.describe_tagged_resource(req, resource)
                tags = sorted(tags)
                wiki_desc = format_to_oneliner(env, context, desc)
                if tags:
                    rendered_tags = [
                        _link(Resource('tag', tag)) for tag in tags
                    ]
                    if 'oldlist' == format:
                        resource_link = _link(resource)
                    else:
                        resource_link = builder.a(wiki_desc,
                                                  href=get_resource_url(
                                                      env, resource,
                                                      context.href))
                        if 'table' == format:
                            cells = []
                            for col in cols:
                                if col == 'id':
                                    cells.append(_link(resource))
                                # Don't duplicate links to resource in both.
                                elif col == 'description' and 'id' in cols:
                                    cells.append(wiki_desc)
                                elif col == 'description':
                                    cells.append(resource_link)
                                elif col == 'realm':
                                    cells.append(resource.realm)
                                elif col == 'tags':
                                    cells.append(
                                        builder([(tag, ' ')
                                                 for tag in rendered_tags]))
                            rows.append({'cells': cells})
                            continue
                rows.append({
                    'desc': wiki_desc,
                    'rendered_tags': None,
                    'resource_link': _link(resource)
                })
            data.update({
                'format': format,
                'paginator': results,
                'results': rows,
                'tags_url': req.href('tags')
            })

            # Work around a bug in trac/templates/layout.html, that causes a
            # TypeError for the wiki macro call, if we use add_link() alone.
            add_stylesheet(req, 'common/css/search.css')

            return Chrome(env).render_template(req, 'listtagged_results.html',
                                               data, 'text/html', True)
Ejemplo n.º 42
0
    def expand_macro(self, formatter, name, content):
        env = self.env
        req = formatter.req
        args, kw = parse_args(content)

        # Use macro arguments (most likely wiki macro calls).
        realms = 'realm' in kw and kw['realm'].split('|') or []
        tag_system = TagSystem(env)
        all_realms = [p.get_taggable_realm()
                      for p in tag_system.tag_providers]
        self.all_realms = all_realms
        self.realms = realms

        if name == 'TagCloud':
            args.append(' or '.join(['realm:%s' % r for r in realms]))
            all_tags = tag_system.get_all_tags(req, ' '.join(args))
            mincount = 'mincount' in kw and kw['mincount'] or None
            return self.render_cloud(req, all_tags,
                                     caseless_sort=self.caseless_sort,
                                     mincount=mincount)
        elif name == 'ListTagged':
            if _OBSOLETE_ARGS_RE.search(content):
                data = {'warning': 'obsolete_args'}
            else:
                data = {'warning': None}
            context=formatter.context
            # Use TagsQuery arguments (most likely wiki macro calls).
            cols = 'cols' in kw and kw['cols'] or self.default_cols
            format = 'format' in kw and kw['format'] or self.default_format
            query = args and args[0].strip() or None
            if query and not realms:
                # First read query arguments (most likely a web-UI call).
                for realm in all_realms:
                    if re.search('(^|\W)realm:%s(\W|$)' % (realm), query):
                        realms = realms and realms.append(realm) or [realm]
            if not realms:
                # Apply ListTagged defaults to macro call w/o realm.
                realms = list(set(all_realms)-set(self.exclude_realms))
            if not realms:
                return ''
            else:
                self.query = query
                self.realms = realms
            query = '(%s) (%s)' % (query or '', ' or '.join(['realm:%s' % (r)
                                                             for r in realms]))
            env.log.debug('LISTTAGGED_QUERY: ' + query)
            query_result = tag_system.query(req, query)
            if not query_result:
                return ''

            def _link(resource):
                if resource.realm == 'tag':
                    # Keep realm selection in tag links.
                    return builder.a(resource.id,
                                     href=self.get_href(req, tag=resource))
                elif resource.realm == 'ticket':
                    # Return resource link including ticket status dependend
                    #   class to allow for common Trac ticket link style.
                    ticket = Ticket(env, resource.id)
                    return builder.a('#%s' % ticket.id,
                                     class_=ticket['status'],
                                     href=formatter.href.ticket(ticket.id),
                                     title=shorten_line(ticket['summary']))
                return render_resource_link(env, context, resource, 'compact')

            if format == 'table':
                cols = [col for col in cols.split('|')
                        if col in self.supported_cols]
                # Use available translations from Trac core.
                try:
                    labels = TicketSystem(env).get_ticket_field_labels()
                    labels['id'] = _('Id')
                except AttributeError:
                    # Trac 0.11 neither has the attribute nor uses i18n.
                    labels = {'id': 'Id', 'description': 'Description'}
                labels['realm'] = _('Realm')
                labels['tags'] = _('Tags')
                headers = [{'label': labels.get(col)}
                           for col in cols]
                data.update({'cols': cols,
                             'headers': headers})

            results = sorted(query_result, key=lambda r: \
                             embedded_numbers(to_unicode(r[0].id)))
            results = self._paginate(req, results)
            rows = []
            for resource, tags in results:
                desc = tag_system.describe_tagged_resource(req, resource)
                tags = sorted(tags)
                if tags:
                    rendered_tags = [_link(Resource('tag', tag))
                                     for tag in tags]
                    if 'oldlist' == format:
                        resource_link = _link(resource)
                    else:
                        desc = desc or \
                               get_resource_description(env, resource,
                                                        context=context)
                        resource_link = builder.a(desc, href=get_resource_url(
                                                  env, resource, context.href))
                        if 'table' == format:
                            cells = []
                            for col in cols:
                                if col == 'id':
                                    cells.append(_link(resource))
                                # Don't duplicate links to resource in both.
                                elif col == 'description' and 'id' in cols:
                                    cells.append(desc)
                                elif col == 'description':
                                    cells.append(resource_link)
                                elif col == 'realm':
                                    cells.append(resource.realm)
                                elif col == 'tags':
                                    cells.append(
                                        builder([(tag, ' ')
                                                 for tag in rendered_tags]))
                            rows.append({'cells': cells})
                            continue
                rows.append({'desc': desc,
                             'rendered_tags': None,
                             'resource_link': _link(resource)})
            data.update({'format': format,
                         'paginator': results,
                         'results': rows,
                         'tags_url': req.href('tags')})

            # Work around a bug in trac/templates/layout.html, that causes a
            # TypeError for the wiki macro call, if we use add_link() alone.
            add_stylesheet(req, 'common/css/search.css')

            return Chrome(env).render_template(
                req, 'listtagged_results.html', data, 'text/html', True)
Ejemplo n.º 43
0
        if items_per_page < 1:
            items_per_page = self.items_per_page
        try:
            result = Paginator(results, current_page - 1, items_per_page)
        except (AssertionError, TracError), e:
            # AssertionError raised in Trac < 1.0.10, TracError otherwise
            self.log.warn("ListTagged macro: %s", e)
            current_page = 1
            result = Paginator(results, current_page - 1, items_per_page)

        pagedata = []
        shown_pages = result.get_shown_pages(21)
        for page in shown_pages:
            page_href = self.get_href(req, realms, query, items_per_page, page)
            pagedata.append([page_href, None, str(page),
                             _("Page %(num)d", num=page)])

        attributes = ['href', 'class', 'string', 'title']
        result.shown_pages = [dict(zip(attributes, p)) for p in pagedata]

        result.current_page = {'href': None, 'class': 'current',
                               'string': str(result.page + 1), 'title': None}

        if result.has_next_page:
            next_href = self.get_href(req, realms, query, items_per_page,
                                      current_page + 1)
            add_link(req, 'next', next_href, _('Next Page'))

        if result.has_previous_page:
            prev_href = self.get_href(req, realms, query, items_per_page,
                                      current_page - 1)
Ejemplo n.º 44
0
 def get_admin_panels(self, req):
     if 'TAGS_ADMIN' in req.perm:
         yield ('tags', _('Tag System'), 'replace', _('Replace'))
Ejemplo n.º 45
0
    def expand_macro(self, formatter, name, content):
        env = self.env
        req = formatter.req
        args, kw = parse_args(content)

        # Use macro arguments (most likely wiki macro calls).
        realms = 'realm' in kw and kw['realm'].split('|') or []
        tag_system = TagSystem(env)
        all_realms = [p.get_taggable_realm() for p in tag_system.tag_providers]
        self.all_realms = all_realms
        self.realms = realms

        if name == 'TagCloud':
            args.append(' or '.join(['realm:%s' % r for r in realms]))
            all_tags = tag_system.get_all_tags(req, ' '.join(args))
            mincount = 'mincount' in kw and kw['mincount'] or None
            return self.render_cloud(req,
                                     all_tags,
                                     caseless_sort=self.caseless_sort,
                                     mincount=mincount)
        elif name == 'ListTagged':
            if _OBSOLETE_ARGS_RE.search(content):
                data = {'warning': 'obsolete_args'}
            else:
                data = {'warning': None}
            context = formatter.context
            # Use TagsQuery arguments (most likely wiki macro calls).
            cols = 'cols' in kw and kw['cols'] or self.default_cols
            format = 'format' in kw and kw['format'] or self.default_format
            query = args and args[0].strip() or None
            if query and not realms:
                # First read query arguments (most likely a web-UI call).
                for realm in all_realms:
                    if re.search('(^|\W)realm:%s(\W|$)' % (realm), query):
                        realms = realms and realms.append(realm) or [realm]
            if not realms:
                # Apply ListTagged defaults to macro call w/o realm.
                realms = list(set(all_realms) - set(self.exclude_realms))
            if not realms:
                return ''
            else:
                self.query = query
                self.realms = realms
            query = '(%s) (%s)' % (query or '', ' or '.join(
                ['realm:%s' % (r) for r in realms]))
            env.log.debug('LISTTAGGED_QUERY: ' + query)
            query_result = tag_system.query(req, query)
            if not query_result:
                return ''

            def _link(resource):
                if resource.realm == 'tag':
                    # Keep realm selection in tag links.
                    return builder.a(resource.id,
                                     href=self.get_href(req, tag=resource))
                elif resource.realm == 'ticket':
                    # Return resource link including ticket status dependend
                    #   class to allow for common Trac ticket link style.
                    ticket = Ticket(env, resource.id)
                    return builder.a('#%s' % ticket.id,
                                     class_=ticket['status'],
                                     href=formatter.href.ticket(ticket.id),
                                     title=shorten_line(ticket['summary']))
                return render_resource_link(env, context, resource, 'compact')

            if format == 'table':
                cols = [
                    col for col in cols.split('|')
                    if col in self.supported_cols
                ]
                # Use available translations from Trac core.
                try:
                    labels = TicketSystem(env).get_ticket_field_labels()
                    labels['id'] = _('Id')
                except AttributeError:
                    # Trac 0.11 neither has the attribute nor uses i18n.
                    labels = {'id': 'Id', 'description': 'Description'}
                labels['realm'] = _('Realm')
                labels['tags'] = _('Tags')
                headers = [{'label': labels.get(col)} for col in cols]
                data.update({'cols': cols, 'headers': headers})

            results = sorted(query_result, key=lambda r: \
                             embedded_numbers(to_unicode(r[0].id)))
            results = self._paginate(req, results)
            rows = []
            for resource, tags in results:
                desc = tag_system.describe_tagged_resource(req, resource)
                tags = sorted(tags)
                if tags:
                    rendered_tags = [
                        _link(Resource('tag', tag)) for tag in tags
                    ]
                    if 'oldlist' == format:
                        resource_link = _link(resource)
                    else:
                        desc = desc or \
                               get_resource_description(env, resource,
                                                        context=context)
                        resource_link = builder.a(desc,
                                                  href=get_resource_url(
                                                      env, resource,
                                                      context.href))
                        if 'table' == format:
                            cells = []
                            for col in cols:
                                if col == 'id':
                                    cells.append(_link(resource))
                                # Don't duplicate links to resource in both.
                                elif col == 'description' and 'id' in cols:
                                    cells.append(desc)
                                elif col == 'description':
                                    cells.append(resource_link)
                                elif col == 'realm':
                                    cells.append(resource.realm)
                                elif col == 'tags':
                                    cells.append(
                                        builder([(tag, ' ')
                                                 for tag in rendered_tags]))
                            rows.append({'cells': cells})
                            continue
                rows.append({
                    'desc': desc,
                    'rendered_tags': None,
                    'resource_link': _link(resource)
                })
            data.update({
                'format': format,
                'paginator': results,
                'results': rows,
                'tags_url': req.href('tags')
            })

            # Work around a bug in trac/templates/layout.html, that causes a
            # TypeError for the wiki macro call, if we use add_link() alone.
            add_stylesheet(req, 'common/css/search.css')

            return Chrome(env).render_template(req, 'listtagged_results.html',
                                               data, 'text/html', True)
Ejemplo n.º 46
0
 def get_admin_panels(self, req):
     if 'TAGS_ADMIN' in req.perm:
         yield 'tags', _('Tag System'), 'replace', _('Replace')
Ejemplo n.º 47
0
 def get_timeline_filters(self, req):
     if 'TAGS_VIEW' in req.perm('tags'):
         yield ('tags', _("Tag changes"))
Ejemplo n.º 48
0
 def get_timeline_filters(self, req):
     if 'TAGS_VIEW' in req.perm('tags'):
         yield ('tags', _("Tag changes"))
Ejemplo n.º 49
0
    def process_request(self, req):
        req.perm.require('TAGS_VIEW')

        match = re.match(r'/tags/?(.*)', req.path_info)
        tag_id = match.group(1) and match.group(1) or None
        query = req.args.get('q', '')

        # Consider only providers, that are permitted for display.
        tag_system = TagSystem(self.env)
        all_realms = tag_system.get_taggable_realms(req.perm)
        if not (tag_id or query) or [r for r in all_realms if r in req.args
                                     ] == []:
            for realm in all_realms:
                if not realm in self.exclude_realms:
                    req.args[realm] = 'on'
        checked_realms = [r for r in all_realms if r in req.args]
        if query:
            # Add permitted realms from query expression.
            checked_realms.extend(query_realms(query, all_realms))
        realm_args = dict(
            zip([r for r in checked_realms], ['on' for r in checked_realms]))
        # Switch between single tag and tag query expression mode.
        if tag_id and not re.match(r"""(['"]?)(\S+)\1$""", tag_id, re.UNICODE):
            # Convert complex, invalid tag ID's --> query expression.
            req.redirect(req.href.tags(realm_args, q=tag_id))
        elif query:
            single_page = re.match(r"""(['"]?)(\S+)\1$""", query, re.UNICODE)
            if single_page:
                # Convert simple query --> single tag.
                req.redirect(req.href.tags(single_page.group(2), realm_args))

        data = dict(page_title=_("Tags"), checked_realms=checked_realms)
        # Populate the TagsQuery form field.
        data['tag_query'] = tag_id and tag_id or query
        data['tag_realms'] = list(
            dict(name=realm, checked=realm in checked_realms)
            for realm in all_realms)
        if tag_id:
            data['tag_page'] = WikiPage(self.env,
                                        tag_system.wiki_page_prefix + tag_id)
        if query or tag_id:
            macro = 'ListTagged'
            # TRANSLATOR: The meta-nav link label.
            add_ctxtnav(req, _("Back to Cloud"), req.href.tags())
            args = "%s,format=%s,cols=%s" % \
                   (tag_id and tag_id or query, self.default_format,
                    self.default_cols)
            data['mincount'] = None
        else:
            macro = 'TagCloud'
            mincount = as_int(req.args.get('mincount', None),
                              self.cloud_mincount)
            args = mincount and "mincount=%s" % mincount or None
            data['mincount'] = mincount
        formatter = Formatter(self.env,
                              Context.from_request(req, Resource('tag')))
        self.env.log.debug("%s macro arguments: %s" %
                           (macro, args and args or '(none)'))
        macros = TagWikiMacros(self.env)
        try:
            # Query string without realm throws 'NotImplementedError'.
            data['tag_body'] = checked_realms and \
                               macros.expand_macro(formatter, macro, args,
                                                   realms=checked_realms) \
                               or ''
        except InvalidQuery, e:
            data['tag_query_error'] = to_unicode(e)
            data['tag_body'] = macros.expand_macro(formatter, 'TagCloud', '')
Ejemplo n.º 50
0
    def expand_macro(self, formatter, name, content, realms=[]):
        """Evaluate macro call and render results.

        Calls from web-UI come with pre-processed realm selection.
        """
        env = self.env
        req = formatter.req
        tag_system = TagSystem(env)

        all_realms = tag_system.get_taggable_realms()
        if not all_realms:
            # Tag providers are required, no result without at least one.
            return ''
        args, kw = parse_args(content)

        query = args and args[0].strip() or None
        if not realms:
            # Check macro arguments for realms (typical wiki macro call).
            realms = 'realm' in kw and kw['realm'].split('|') or []
        if query:
            # Add realms from query expression.
            realms.extend(query_realms(query, all_realms))
            # Remove redundant realm selection for performance.
            if set(realms) == all_realms:
                query = re.sub('(^|\W)realm:\S+(\W|$)', ' ', query).strip()
        if name == 'TagCloud':
            # Set implicit 'all tagged realms' as default.
            if not realms:
                realms = all_realms
            if query:
                all_tags = Counter()
                # Require per resource query including view permission checks.
                for resource, tags in tag_system.query(req, query):
                    all_tags.update(tags)
            else:
                # Allow faster per tag query, side steps permission checks.
                all_tags = tag_system.get_all_tags(req, realms=realms)
            mincount = 'mincount' in kw and kw['mincount'] or None
            return self.render_cloud(req, all_tags,
                                     caseless_sort=self.caseless_sort,
                                     mincount=mincount, realms=realms)
        elif name == 'ListTagged':
            if content and _OBSOLETE_ARGS_RE.search(content):
                data = {'warning': 'obsolete_args'}
            else:
                data = {'warning': None}
            context = formatter.context
            # Use TagsQuery arguments (most likely wiki macro calls).
            cols = 'cols' in kw and kw['cols'] or self.default_cols
            format = 'format' in kw and kw['format'] or self.default_format
            if not realms:
                # Apply ListTagged defaults to macro call w/o realm.
                realms = list(set(all_realms)-set(self.exclude_realms))
                if not realms:
                    return ''
            query = '(%s) (%s)' % (query or '', ' or '.join(['realm:%s' % (r)
                                                             for r in realms]))
            query_result = tag_system.query(req, query)
            excludes = [exc.strip()
                        for exc in kw.get('exclude', '' ).split(':')
                        if exc.strip()]
            if excludes and query_result:
                filtered_result = [(resource, tags)
                                   for resource, tags in query_result
                                   if not any(fnmatchcase(resource.id, exc)
                                              for exc in excludes)]
                query_result = filtered_result
            if not query_result:
                return ''

            def _link(resource):
                if resource.realm == 'tag':
                    # Keep realm selection in tag links.
                    return builder.a(resource.id,
                                     href=self.get_href(req, realms,
                                                        tag=resource))
                elif resource.realm == 'ticket':
                    # Return resource link including ticket status dependend
                    #   class to allow for common Trac ticket link style.
                    ticket = Ticket(env, resource.id)
                    return builder.a('#%s' % ticket.id,
                                     class_=ticket['status'],
                                     href=formatter.href.ticket(ticket.id),
                                     title=shorten_line(ticket['summary']))
                return render_resource_link(env, context, resource, 'compact')

            if format == 'table':
                cols = [col for col in cols.split('|')
                        if col in self.supported_cols]
                # Use available translations from Trac core.
                try:
                    labels = TicketSystem(env).get_ticket_field_labels()
                    labels['id'] = _('Id')
                except AttributeError:
                    # Trac 0.11 neither has the attribute nor uses i18n.
                    labels = {'id': 'Id', 'description': 'Description'}
                labels['realm'] = _('Realm')
                labels['tags'] = _('Tags')
                headers = [{'label': labels.get(col)}
                           for col in cols]
                data.update({'cols': cols,
                             'headers': headers})

            results = sorted(query_result, key=lambda r: \
                             embedded_numbers(to_unicode(r[0].id)))
            results = self._paginate(req, results, realms)
            rows = []
            for resource, tags in results:
                desc = tag_system.describe_tagged_resource(req, resource)
                tags = sorted(tags)
                wiki_desc = format_to_oneliner(env, context, desc)
                if tags:
                    rendered_tags = [_link(Resource('tag', tag))
                                     for tag in tags]
                    if 'oldlist' == format:
                        resource_link = _link(resource)
                    else:
                        resource_link = builder.a(wiki_desc,
                                                  href=get_resource_url(
                                                  env, resource, context.href))
                        if 'table' == format:
                            cells = []
                            for col in cols:
                                if col == 'id':
                                    cells.append(_link(resource))
                                # Don't duplicate links to resource in both.
                                elif col == 'description' and 'id' in cols:
                                    cells.append(wiki_desc)
                                elif col == 'description':
                                    cells.append(resource_link)
                                elif col == 'realm':
                                    cells.append(resource.realm)
                                elif col == 'tags':
                                    cells.append(
                                        builder([(tag, ' ')
                                                 for tag in rendered_tags]))
                            rows.append({'cells': cells})
                            continue
                rows.append({'desc': wiki_desc,
                             'rendered_tags': None,
                             'resource_link': _link(resource)})
            data.update({'format': format,
                         'paginator': results,
                         'results': rows,
                         'tags_url': req.href('tags')})

            # Work around a bug in trac/templates/layout.html, that causes a
            # TypeError for the wiki macro call, if we use add_link() alone.
            add_stylesheet(req, 'common/css/search.css')

            return Chrome(env).render_template(
                req, 'listtagged_results.html', data, 'text/html', True)
Ejemplo n.º 51
0
    def process_request(self, req):
        req.perm.require("TAGS_VIEW")

        match = re.match(r"/tags/?(.*)", req.path_info)
        tag_id = match.group(1) and match.group(1) or None
        query = req.args.get("q", "")

        realms = [
            p.get_taggable_realm()
            for p in self.tag_providers
            if (not hasattr(p, "check_permission") or p.check_permission(req.perm, "view"))
        ]
        if not (tag_id or query) or [r for r in realms if r in req.args] == []:
            for realm in realms:
                if not realm in self.exclude_realms:
                    req.args[realm] = "on"
        checked_realms = [r for r in realms if r in req.args]
        realm_args = dict(zip([r for r in checked_realms], ["on" for r in checked_realms]))
        if tag_id and not re.match(r"""(['"]?)(\S+)\1$""", tag_id, re.UNICODE):
            # Convert complex, invalid tag ID's to query expression.
            req.redirect(req.href.tags(realm_args, q=tag_id))
        elif query:
            single_page = re.match(r"""(['"]?)(\S+)\1$""", query, re.UNICODE)
            if single_page:
                # Convert simple query for single tag ID.
                req.redirect(req.href.tags(single_page.group(2), realm_args))

        data = dict(page_title=_("Tags"), checked_realms=checked_realms)
        # Populate the TagsQuery form field.
        data["tag_query"] = tag_id and tag_id or query
        data["tag_realms"] = list(dict(name=realm, checked=realm in checked_realms) for realm in realms)
        if tag_id:
            page_name = tag_id
            page = WikiPage(self.env, page_name)
            data["tag_page"] = page

        macros = TagWikiMacros(self.env)
        if query or tag_id:
            # TRANSLATOR: The meta-nav link label.
            add_ctxtnav(req, _("Back to Cloud"), req.href.tags())
            macro = "ListTagged"
            args = "%s,format=%s,cols=%s,realm=%s" % (
                tag_id and tag_id or query,
                self.default_format,
                self.default_cols,
                "|".join(checked_realms),
            )
            data["mincount"] = None
        else:
            macro = "TagCloud"
            mincount = as_int(req.args.get("mincount", None), self.cloud_mincount)
            args = "mincount=%s,realm=%s" % (mincount, "|".join(checked_realms))
            data["mincount"] = mincount
        formatter = Formatter(self.env, Context.from_request(req, Resource("tag")))
        self.env.log.debug("Tag macro arguments: %s", args)
        try:
            # Query string without realm throws 'NotImplementedError'.
            data["tag_body"] = len(checked_realms) > 0 and macros.expand_macro(formatter, macro, args) or ""
        except InvalidQuery, e:
            data["tag_query_error"] = to_unicode(e)
            data["tag_body"] = macros.expand_macro(formatter, "TagCloud", "")
Ejemplo n.º 52
0
 def get_admin_panels(self, req):
     if "TAGS_ADMIN" in req.perm:
         yield ("tags", _("Tag System"), "replace", _("Replace"))
Ejemplo n.º 53
0
 def _invalid_handler(self, name, node, context):
     raise InvalidQuery(_("Invalid attribute '%s'") % name)