示例#1
0
    def process_request(self, req):
        from tractags.api import TagEngine
        from trac.web.chrome import add_stylesheet

        add_stylesheet(req, 'tags/css/tractags.css')

        pagename = req.args.get('page', 'WikiStart')
        action = req.args.get('action', 'view')

        engine = TagEngine(self.env)
        wikitags = engine.tagspace.wiki
        tags = list(wikitags.get_tags([pagename]))
        tags.sort()

        if action == 'edit':
            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
        elif action == 'view':
            hdf_tags = []
            for tag in tags:
                href, title = engine.get_tag_link(tag)
                hdf_tags.append({'name': tag, 'href': href, 'title': title})
            req.hdf['tags'] = hdf_tags
        result = WikiModule.process_request(self, req)
        if result is None:
            return None
        if result[0] == 'wiki.cs':
            return 'tagswiki.cs', None
        return result
示例#2
0
    def set_password(self, user, password):
        import re

        if len(user) < 3:
            raise TracError("user name must be at least 3 characters long")
        if not re.match(r"^\w+$", user):
            raise TracError("user name must consist only of alpha-numeric characters")
        if user not in self.get_users():
            from trac.wiki.model import WikiPage

            db = self.env.get_db_cnx()
            page = WikiPage(self.env, user, db=db)
            # User creation with existing page
            if page.exists:
                raise TracError('wiki page "%s" already exists' % user)
            else:
                from tractags.api import TagEngine

                tagspace = TagEngine(self.env).tagspace.wiki

                tagspace.add_tags(None, user, ["user"])
                page.text = """= %(user)s =\n\n[[ListTagged(%(user)s)]]\n\n[[TagIt(user)]]""" % {"user": user}
                page.save(user, "New user %s registered" % user, None)
                self.env.log.debug("New user %s registered" % user)
        HtPasswdStore.set_password(self, user, password)
示例#3
0
 def screenshot_changed(self, screenshot, old_screenshot):
     # Add tags to screenshot.
     old_screenshot.update(screenshot)
     tags = TagEngine(self.env).tagspace.screenshots
     tag_names = self._get_tags(old_screenshot)
     tags.replace_tags(None, old_screenshot['id'],
                       list(sets.Set(tag_names)))
示例#4
0
    def process_request(self, req):
        from tractags.api import TagEngine
        from trac.web.chrome import add_stylesheet

        add_stylesheet(req, 'tags/css/tractags.css')

        pagename = req.args.get('page', 'WikiStart')
        action = req.args.get('action', 'view')

        engine = TagEngine(self.env)
        wikitags = engine.tagspace.wiki
        tags = list(wikitags.get_tags([pagename]))
        tags.sort()

        if action == 'edit':
            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
        elif action == 'view':
            hdf_tags = []
            for tag in tags:
                href, title = engine.get_tag_link(tag)
                hdf_tags.append({'name': tag,
                                 'href': href,
                                 'title': title})
            req.hdf['tags'] = hdf_tags
        result = WikiModule.process_request(self, req)
        if result is None:
            return None
        if result[0] == 'wiki.cs':
            return 'tagswiki.cs', None
        return result
示例#5
0
    def set_password(self, user, password):
        import re
        if len(user) < 3:
            raise TracError('user name must be at least 3 characters long')
        if not re.match(r'^\w+$', user):
            raise TracError(
                'user name must consist only of alpha-numeric characters')
        if user not in self.get_users():
            from trac.wiki.model import WikiPage
            db = self.env.get_db_cnx()
            page = WikiPage(self.env, user, db=db)
            # User creation with existing page
            if page.exists:
                raise TracError('wiki page "%s" already exists' % user)
            else:
                from tractags.api import TagEngine
                tagspace = TagEngine(self.env).tagspace.wiki

                tagspace.add_tags(None, user, ['user'])
                page.text = '''= %(user)s =\n\n[[ListTagged(%(user)s)]]\n\n[[TagIt(user)]]''' % {
                    'user': user
                }
                page.save(user, 'New user %s registered' % user, None)
                self.env.log.debug("New user %s registered" % user)
        HtPasswdStore.set_password(self, user, password)
示例#6
0
    def render_listtags(self, req, *tags, **kwargs):
        """ List tags. For backwards compatibility, can accept a list of tags.
            This will simply call ListTagged. Optional keyword arguments are
            tagspace=wiki, tagspaces=(wiki, ticket, ...) and shownames=true. """
        if tags:
            # Backwards compatibility
            return self.render_listtagged(req, *tags, **kwargs)

        page = self._current_page(req)
        engine = TagEngine(self.env)

        showpages = kwargs.get('showpages', None) or kwargs.get('shownames', 'false')

        if 'tagspace' in kwargs:
            tagspaces = [kwargs['tagspace']]
        else:
            tagspaces = kwargs.get('tagspaces', []) or \
                        list(TagEngine(self.env).tagspaces)

        out = StringIO()
        out.write('<ul class="listtags">\n')
        tag_details = {}
        for tag, names in sorted(engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems()):
            href, title = engine.get_tag_link(tag)
            htitle = wiki_to_oneliner(title, self.env)
            out.write('<li><a href="%s" title="%s">%s</a> %s <span class="tagcount">(%i)</span>' % (href, title, tag, htitle, len(names)))
            if showpages == 'true':
                out.write('\n')
                out.write(self.render_listtagged(req, tag, tagspaces=tagspaces))
                out.write('</li>\n')

        out.write('</ul>\n')

        return out.getvalue()
示例#7
0
 def _page_titles(self, pages):
     """ Extract page titles, if possible. """
     titles = {}
     tagspace = TagEngine(self.env).tagspace.wiki
     for pagename in pages:
         href, link, title = tagspace.name_details(pagename)
         titles[pagename] = title
     return titles
示例#8
0
 def _page_titles(self, pages):
     """ Extract page titles, if possible. """
     titles = {}
     tagspace = TagEngine(self.env).tagspace.wiki
     for pagename in pages:
         href, link, title = tagspace.name_details(pagename)
         titles[pagename] = title
     return titles
示例#9
0
    def _update_tags(self, req, page):
        newtags = set([t.strip() for t in
                      _tag_split.split(req.args.get('tags')) if t.strip()])
        wikitags = TagEngine(self.env).tagspace.wiki
        oldtags = wikitags.get_tags([page.name])

        if oldtags != newtags:
            wikitags.replace_tags(req, page.name, newtags)
示例#10
0
    def render_listtagged(self, req, *tags, **kwargs):
        """ List tagged objects. Optionally accepts a list of tags to match
            against.  The special tag '''. (dot)''' inserts the current Wiki page name.

            `[[ListTagged(<tag>, ...)]]`

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`operation=intersection|union`||The set operation to perform on the discovered objects.||
            ||`showheadings=true|false`||List objects under the tagspace they occur in.||
        """

        if 'tagspace' in kwargs:
            tagspaces = [kwargs.get('tagspace', None)]
        else:
            tagspaces = kwargs.get('tagspaces', '') or \
                        list(TagEngine(self.env).tagspaces)
        showheadings = kwargs.get('showheadings', 'false')
        operation = kwargs.get('operation', 'intersection')
        if operation not in ('union', 'intersection'):
            raise TracError("Invalid tag set operation '%s'" % operation)

        engine = TagEngine(self.env)
        page_name = req.hdf.get('wiki.page_name')
        if page_name:
            tags = [tag == '.' and page_name or tag for tag in tags]

        taginfo = {}
        out = StringIO()
        out.write('<ul class="listtagged">')
        # Cull empty names
        tagged_names = [(tagspace, names) for tagspace, names in
                        engine.get_tagged_names(tags=tags, tagspaces=tagspaces,
                            operation=operation, detailed=True).iteritems()
                        if names]
        for tagspace, tagspace_names in sorted(tagged_names):
            if showheadings == 'true':
                out.write('<lh>%s tags</lh>' % tagspace)
            for name, tags in sorted(tagspace_names.iteritems()):
                if tagspace == 'wiki' and unicode(name).startswith('tags/'): continue
                tags = sorted(tags)
                taginfo = self._tag_details(taginfo, tags)
                href, link, title = engine.name_details(tagspace, name)
                htitle = wiki_to_oneliner(title, self.env)
                name_tags = ['<a href="%s" title="%s">%s</a>'
                              % (taginfo[tag][0], taginfo[tag][1], tag)
                              for tag in tags]
                if not name_tags:
                    name_tags = ''
                else:
                    name_tags = ' (' + ', '.join(sorted(name_tags)) + ')'
                out.write('<li>%s %s%s</li>\n' %
                          (link, htitle, name_tags))
        out.write('</ul>')

        return out.getvalue()
示例#11
0
    def render_tagcloud(self,
                        req,
                        smallest=10,
                        biggest=20,
                        tagspace=None,
                        tagspaces=[]):
        """ Display a summary of all tags, with the font size reflecting the
            number of pages the tag applies to. Font size ranges from 10 to 22
            pixels, but this can be overridden by the smallest=n and biggest=n
            macro parameters. By default, all tagspaces are displayed, but this
            can be overridden with tagspaces=(wiki, ticket) or tagspace=wiki."""
        smallest = int(smallest)
        biggest = int(biggest)
        engine = TagEngine(self.env)
        # Get wiki tagspace
        if tagspace:
            tagspaces = [tagspace]
        else:
            tagspaces = tagspaces or engine.tagspaces
        cloud = {}

        for tag, names in engine.get_tags(tagspaces=tagspaces,
                                          detailed=True).iteritems():
            cloud[tag] = len(names)

        tags = cloud.keys()

        # No tags?
        if not tags: return ''

        # by_count maps tag counts to an index in the set of counts
        by_count = list(set(cloud.values()))
        by_count.sort()
        by_count = dict([(c, float(i)) for i, c in enumerate(by_count)])

        taginfo = self._tag_details({}, tags)
        tags.sort()
        rlen = float(biggest - smallest)
        tlen = float(len(by_count))
        scale = 1.0
        if tlen:
            scale = rlen / tlen
        out = StringIO()
        out.write('<ul class="tagcloud">\n')
        last = tags[-1]
        for tag in tags:
            if tag == last:
                cls = ' class="last"'
            else:
                cls = ''
            out.write(
                '<li%s><a rel="tag" title="%s" style="font-size: %ipx" href="%s">%s</a> <span class="tagcount">(%i)</span></li>\n'
                % (cls, taginfo[tag][1],
                   smallest + int(by_count[cloud[tag]] * scale),
                   taginfo[tag][0], tag, cloud[tag]))
        out.write('</ul>\n')
        return out.getvalue()
示例#12
0
    def render_listtagged(self, req, *tags, **kwargs):
        """ List tagged objects. Takes a list of tags to match against.
            The special tag '.' inserts the current Wiki page name.

            Optional keyword arguments are tagspace=wiki,
            tagspaces=(wiki, title, ...) and showheadings=true.

            By default displays the intersection of objects matching each tag.
            By passing operation=union this can be modified to display
            the union of objects matching each tag.
        """

        if 'tagspace' in kwargs:
            tagspaces = [kwargs.get('tagspace', None)]
        else:
            tagspaces = kwargs.get('tagspaces', '') or \
                        list(TagEngine(self.env).tagspaces)
        showheadings = kwargs.get('showheadings', 'false')
        operation = kwargs.get('operation', 'intersection')
        if operation not in ('union', 'intersection'):
            raise TracError("Invalid tag set operation '%s'" % operation)

        engine = TagEngine(self.env)
        page_name = req.hdf.get('wiki.page_name')
        if page_name:
            tags = [tag == '.' and page_name or tag for tag in tags]

        taginfo = {}
        out = StringIO()
        out.write('<ul class="listtagged">')
        for tagspace, tagspace_names in sorted(
                engine.get_tagged_names(tags=tags,
                                        tagspaces=tagspaces,
                                        operation=operation,
                                        detailed=True).iteritems()):
            if showheadings == 'true':
                out.write('<lh>%s tags</lh>' % tagspace)
            for name, tags in sorted(tagspace_names.iteritems()):
                if tagspace == 'wiki' and unicode(name).startswith('tags/'):
                    continue
                tags = sorted(tags)
                taginfo = self._tag_details(taginfo, tags)
                href, link, title = engine.name_details(tagspace, name)
                htitle = wiki_to_oneliner(title, self.env)
                name_tags = [
                    '<a href="%s" title="%s">%s</a>' %
                    (taginfo[tag][0], taginfo[tag][1], tag) for tag in tags
                ]
                if not name_tags:
                    name_tags = ''
                else:
                    name_tags = ' (' + ', '.join(sorted(name_tags)) + ')'
                out.write('<li>%s %s%s</li>\n' % (link, htitle, name_tags))
        out.write('</ul>')

        return out.getvalue()
示例#13
0
    def _update_tags(self, req, page):
        newtags = set([
            t.strip() for t in _tag_split.split(req.args.get('tags'))
            if t.strip()
        ])
        wikitags = TagEngine(self.env).tagspace.wiki
        oldtags = wikitags.get_tags([page.name])

        if oldtags != newtags:
            wikitags.replace_tags(req, page.name, newtags)
示例#14
0
    def render_tagcloud(self, req, smallest=10, biggest=20, tagspace=None, tagspaces=[]):
        """ Display a summary of all tags, with the font size reflecting the
            number of pages the tag applies to. Font size ranges from 10 to 22
            pixels, but this can be overridden by the smallest=n and biggest=n
            macro parameters. By default, all tagspaces are displayed, but this
            can be overridden with tagspaces=(wiki, ticket) or tagspace=wiki."""
        smallest = int(smallest)
        biggest = int(biggest)
        engine = TagEngine(self.env)
        # Get wiki tagspace
        if tagspace:
            tagspaces = [tagspace]
        else:
            tagspaces = tagspaces or engine.tagspaces
        cloud = {}

        for tag, names in engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems():
            cloud[tag] = len(names)

        tags = cloud.keys()

        # No tags?
        if not tags: return ''

        # by_count maps tag counts to an index in the set of counts
        by_count = list(set(cloud.values()))
        by_count.sort()
        by_count = dict([(c, float(i)) for i, c in enumerate(by_count)])

        taginfo = self._tag_details({}, tags)
        tags.sort()
        rlen = float(biggest - smallest)
        tlen = float(len(by_count))
        scale = 1.0
        if tlen:
            scale = rlen / tlen
        out = StringIO()
        out.write('<ul class="tagcloud">\n')
        last = tags[-1]
        for tag in tags:
            if tag == last:
                cls = ' class="last"'
            else:
                cls = ''
            out.write('<li%s><a rel="tag" title="%s" style="font-size: %ipx" href="%s">%s</a> <span class="tagcount">(%i)</span></li>\n' % (
                       cls,
                       taginfo[tag][1],
                       smallest + int(by_count[cloud[tag]] * scale),
                       taginfo[tag][0],
                       tag,
                       cloud[tag]))
        out.write('</ul>\n')
        return out.getvalue()
示例#15
0
 def setUp(self):
     self.env = EnvironmentStub(default_data=True)
     self.env.path = '/'
     self.tag_engine = TagEngine(self.env)
     self.tag_engine.upgrade_environment(self.env.get_db_cnx())
     # Insert some test tickets
     from trac.ticket.model import Ticket
     for id in (1, 2, 3):
         ticket = Ticket(self.env)
         ticket['summary'] = 'Test ticket %i' % id
         ticket['description'] = 'Test ticket %i description' % id
         ticket.insert()
示例#16
0
    def getDetails(self, req, hack):
        """ Fetch hack details. Returns dict with name, dependencies and
            description. """
        from tractags.api import TagEngine

        wikitags = TagEngine(self.env).tagspace.wiki
        tags = wikitags.get_tags(hack)
        types = self.getTypes()
        hacks = wikitags.get_tagged_names(types)

        dependencies = hacks.intersection(tags)
        href, htmllink, description = wikitags.name_details(hack)
        return {"name": hack, "dependencies": tuple(dependencies), "description": description}
示例#17
0
    def render_listtagged(self, req, *tags, **kwargs):
        """ List tagged objects. Takes a list of tags to match against.
            The special tag '.' inserts the current Wiki page name.

            Optional keyword arguments are tagspace=wiki,
            tagspaces=(wiki, title, ...) and showheadings=true.

            By default displays the intersection of objects matching each tag.
            By passing operation=union this can be modified to display
            the union of objects matching each tag.
        """

        if 'tagspace' in kwargs:
            tagspaces = [kwargs.get('tagspace', None)]
        else:
            tagspaces = kwargs.get('tagspaces', '') or \
                        list(TagEngine(self.env).tagspaces)
        showheadings = kwargs.get('showheadings', 'false')
        operation = kwargs.get('operation', 'intersection')
        if operation not in ('union', 'intersection'):
            raise TracError("Invalid tag set operation '%s'" % operation)

        engine = TagEngine(self.env)
        page_name = req.hdf.get('wiki.page_name')
        if page_name:
            tags = [tag == '.' and page_name or tag for tag in tags]

        taginfo = {}
        out = StringIO()
        out.write('<ul class="listtagged">')
        for tagspace, tagspace_names in sorted(engine.get_tagged_names(tags=tags, tagspaces=tagspaces, operation=operation, detailed=True).iteritems()):
            if showheadings == 'true':
                out.write('<lh>%s tags</lh>' % tagspace)
            for name, tags in sorted(tagspace_names.iteritems()):
                if tagspace == 'wiki' and unicode(name).startswith('tags/'): continue
                tags = sorted(tags)
                taginfo = self._tag_details(taginfo, tags)
                href, link, title = engine.name_details(tagspace, name)
                htitle = wiki_to_oneliner(title, self.env)
                name_tags = ['<a href="%s" title="%s">%s</a>'
                              % (taginfo[tag][0], taginfo[tag][1], tag)
                              for tag in tags]
                if not name_tags:
                    name_tags = ''
                else:
                    name_tags = ' (' + ', '.join(sorted(name_tags)) + ')'
                out.write('<li>%s %s%s</li>\n' %
                          (link, htitle, name_tags))
        out.write('</ul>')

        return out.getvalue()
示例#18
0
    def _wiki_view(self, req, stream):
        tags = self._page_tags(req)
        if not tags:
            return stream
        engine = TagEngine(self.env)
        add_stylesheet(req, 'tags/css/tractags.css')
        li = []
        for tag in tags:
            href, title = engine.get_tag_link(tag)
            li.append(T.li(T.a(title=title, href=href)(tag), ' '))

        insert = T.ul(class_='tags')(T.lh('Tags'), li)

        return stream | Transformer('//div[@class="buttons"]').before(insert)
示例#19
0
    def _wiki_view(self, req, stream):
        tags = self._page_tags(req)
        if not tags:
            return stream
        engine = TagEngine(self.env)
        add_stylesheet(req, 'tags/css/tractags.css')
        li = []
        for tag in tags:
            href, title = engine.get_tag_link(tag)
            li.append(T.li(T.a(title=title, href=href)(tag), ' '))

        insert = T.ul(class_='tags')(T.lh('Tags'), li)

        return stream | Transformer('//div[@class="buttons"]').before(insert)
示例#20
0
    def download_deleted(self, download):
        tags = TagEngine(self.env).tagspace.downloads

        # Prepare tag names.
        self._resolve_ids(download)
        tag_names = [download['author'], download['component'],
          download['version'], download['architecture'],
          download['platform'], download['type']]
        if download['tags']:
            tag_names.extend(download['tags'].split(' '))

        # Add tags to download.
        self.log.debug(tag_names)
        tags.remove_tags(None, download['id'], list(sets.Set(tag_names)))
示例#21
0
 def getNames(self, req, tagname):
     """ Returns all pages with tagname """
     engine = TagEngine(self.env)
     try:
         tagspaces = list()
         tagspaces.append(self.tagsystem.tagspace)
         tags = list()
         tags.append (tagname)
         names = engine.get_tagged_names(tags=tags,tagspaces=tagspaces)
         self.env.log.debug("getNames found %s for tagname %s"%(names, tagname))
         return list(names[self.tagsystem.tagspace])
     except Exception, e:
         self.env.log.debug('Error in getNames(%s): %s\n' % (tagname, str(e)))
         return None
示例#22
0
    def download_deleted(self, download):
        tags = TagEngine(self.env).tagspace.downloads

        # Prepare tag names.
        self._resolve_ids(download)
        tag_names = [
            download['author'], download['component'], download['version'],
            download['architecture'], download['platform'], download['type']
        ]
        if download['tags']:
            tag_names.extend(download['tags'].split(' '))

        # Add tags to download.
        self.log.debug(tag_names)
        tags.remove_tags(None, download['id'], list(sets.Set(tag_names)))
示例#23
0
    def getDetails(self, req, hack):
        """ Fetch hack details. Returns dict with name, dependencies and
            description. """
        from tractags.api import TagEngine
        wikitags = TagEngine(self.env).tagspace.wiki
        tags = wikitags.get_tags(hack)
        types = self.getTypes()
        hacks = wikitags.get_tagged_names(types)

        dependencies = hacks.intersection(tags)
        href, htmllink, description = wikitags.name_details(hack)
        return {
            'name': hack,
            'dependencies': tuple(dependencies),
            'description': description
        }
示例#24
0
    def _page_tags(self, req):
        pagename = req.args.get('page', 'WikiStart')

        engine = TagEngine(self.env)
        wikitags = engine.tagspace.wiki
        current_tags = list(wikitags.get_tags([pagename]))
        current_tags.sort()
        return current_tags
示例#25
0
    def _do_save(self, req, db, page):
        # This method is overridden so the user doesn't get "Page not modified"
        # exceptions when updating tags but not wiki content.
        from tractags.api import TagEngine
        if 'tags' in req.args:
            newtags = set([t.strip() for t in
                          _tag_split.split(req.args.get('tags')) if t.strip()])
            wikitags = TagEngine(self.env).tagspace.wiki
            oldtags = wikitags.get_tags([page.name])

            if oldtags != newtags:
                wikitags.replace_tags(req, page.name, newtags)
                # No changes, just redirect
                if req.args.get('text') == page.text:
                    req.redirect(self.env.href.wiki(page.name))
                    return
        return WikiModule._do_save(self, req, db, page)
示例#26
0
    def _do_save(self, req, db, page):
        # This method is overridden so the user doesn't get "Page not modified"
        # exceptions when updating tags but not wiki content.
        from tractags.api import TagEngine
        if 'tags' in req.args:
            newtags = set([t.strip() for t in
                          _tag_split.split(req.args.get('tags')) if t.strip()])
            wikitags = TagEngine(self.env).tagspace.wiki
            oldtags = wikitags.get_tags([page.name])

            if oldtags != newtags:
                wikitags.replace_tags(req, page.name, newtags)
                # No changes, just redirect
                if req.args.get('text') == page.text:
                    req.redirect(self.env.href.wiki(page.name))
                    return
        return WikiModule._do_save(self, req, db, page)
示例#27
0
 def getHacks(self, req, release, type):
     """ Fetch a list of hacks for Trac release, of type. """
     from trac.versioncontrol.api import Node
     from tractags.api import TagEngine
     repo = self.env.get_repository(req.authname)
     wikitags = TagEngine(self.env).tagspace.wiki
     repo_rev = repo.get_youngest_rev()
     releases = wikitags.get_tagged_names([release])
     types = wikitags.get_tagged_names([type])
     for plugin in releases.intersection(types):
         if plugin.startswith('tags/'): continue
         path = '%s/%s' % (plugin.lower(), release)
         rev = 0
         if repo.has_node(str(path), repo_rev):
             node = repo.get_node(path)
             rev = node.rev
         yield (plugin, rev)
示例#28
0
    def _prepare_wiki(self, req):
        from tractags.api import TagEngine
        page = req.path_info[6:] or 'WikiStart'
        engine = TagEngine(self.env)
        wikitags = engine.tagspace.wiki
        tags = list(wikitags.get_tags(page))
        tags.sort()

        action = req.args.get('action', 'view')
        if action == 'edit':
            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
        elif action == 'view':
            hdf_tags = []
            for tag in tags:
                href, title = engine.get_tag_link(tag)
                hdf_tags.append({'name': tag, 'href': href, 'title': title})
            req.hdf['tags'] = hdf_tags
示例#29
0
    def render_listtags(self, req, *tags, **kwargs):
        """ List all tags.

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`shownames=true|false`||Whether to show the objects that tags appear on ''(long)''.||
            """

        if tags:
            # Backwards compatibility
            return self.render_listtagged(req, *tags, **kwargs)

        page = self._current_page(req)
        engine = TagEngine(self.env)

        showpages = kwargs.get('showpages', None) or kwargs.get(
            'shownames', 'false')

        if 'tagspace' in kwargs:
            tagspaces = [kwargs['tagspace']]
        else:
            tagspaces = kwargs.get('tagspaces', []) or \
                        list(TagEngine(self.env).tagspaces)

        out = StringIO()
        out.write('<ul class="listtags">\n')
        tag_details = {}
        for tag, names in sorted(
                engine.get_tags(tagspaces=tagspaces,
                                detailed=True).iteritems()):
            href, title = engine.get_tag_link(tag)
            htitle = wiki_to_oneliner(title, self.env, req=req)
            out.write(
                '<li><a href="%s" title="%s">%s</a> %s <span class="tagcount">(%i)</span>'
                % (href, title, tag, htitle, len(names)))
            if showpages == 'true':
                out.write('\n')
                out.write(self.render_listtagged(req, tag,
                                                 tagspaces=tagspaces))
                out.write('</li>\n')

        out.write('</ul>\n')

        return out.getvalue()
示例#30
0
 def _tag_formatter(self, formatter, ns, target, label):
     if '?' in target:
         target, args = target.split('?')[0:2]
         args = '?' + args
     else:
         args = ''
     href, title = TagEngine(self.env).get_tag_link(target)
     return Markup('<a href="%s%s" title="%s">%s</a>' %
                   (href, args, title, label))
示例#31
0
    def _prepare_wiki(self, req):
        from tractags.api import TagEngine
        page = req.path_info[6:] or 'WikiStart'
        engine = TagEngine(self.env)
        wikitags = engine.tagspace.wiki
        tags = list(wikitags.get_tags(page))
        tags.sort()

        action = req.args.get('action', 'view')
        if action == 'edit':
            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
        elif action == 'view':
            hdf_tags = []
            for tag in tags:
                href, title = engine.get_tag_link(tag)
                hdf_tags.append({'name': tag,
                                 'href': href,
                                 'title': title})
            req.hdf['tags'] = hdf_tags
示例#32
0
    def getHacks(self, req, release, type):
        """ Fetch a list of hacks for Trac release, of type. """
        from trac.versioncontrol.api import Node
        from tractags.api import TagEngine

        repo = self.env.get_repository(req.authname)
        wikitags = TagEngine(self.env).tagspace.wiki
        repo_rev = repo.get_youngest_rev()
        releases = wikitags.get_tagged_names([release])
        types = wikitags.get_tagged_names([type])
        for plugin in releases.intersection(types):
            if plugin.startswith("tags/"):
                continue
            path = "%s/%s" % (plugin.lower(), release)
            rev = 0
            if repo.has_node(str(path), repo_rev):
                node = repo.get_node(path)
                rev = node.rev
            yield (plugin, rev)
示例#33
0
 def _format_tagged(self, target, label):
     if '?' in target:
         target, args = target.split('?')[0:2]
         args = '?' + args
     else:
         args = ''
     href, title = TagEngine(self.env).get_tag_link(target,
                                                    is_expression=True)
     return Markup('<a href="%s%s" title="%s">%s</a>' %
                   (href, args, title, label))
示例#34
0
    def render_listtags(self, req, *tags, **kwargs):
        """ List tags. For backwards compatibility, can accept a list of tags.
            This will simply call ListTagged. Optional keyword arguments are
            tagspace=wiki, tagspaces=(wiki, ticket, ...) and shownames=true. """
        if tags:
            # Backwards compatibility
            return self.render_listtagged(req, *tags, **kwargs)

        page = self._current_page(req)
        engine = TagEngine(self.env)

        showpages = kwargs.get('showpages', None) or kwargs.get(
            'shownames', 'false')

        if 'tagspace' in kwargs:
            tagspaces = [kwargs['tagspace']]
        else:
            tagspaces = kwargs.get('tagspaces', []) or \
                        list(TagEngine(self.env).tagspaces)

        out = StringIO()
        out.write('<ul class="listtags">\n')
        tag_details = {}
        for tag, names in sorted(
                engine.get_tags(tagspaces=tagspaces,
                                detailed=True).iteritems()):
            href, title = engine.get_tag_link(tag)
            htitle = wiki_to_oneliner(title, self.env)
            out.write(
                '<li><a href="%s" title="%s">%s</a> %s <span class="tagcount">(%i)</span>'
                % (href, title, tag, htitle, len(names)))
            if showpages == 'true':
                out.write('\n')
                out.write(self.render_listtagged(req, tag,
                                                 tagspaces=tagspaces))
                out.write('</li>\n')

        out.write('</ul>\n')

        return out.getvalue()
示例#35
0
    def render_listtags(self, req, *tags, **kwargs):
        """ List all tags.

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`shownames=true|false`||Whether to show the objects that tags appear on ''(long)''.||
            """

        if tags:
            # Backwards compatibility
            return self.render_listtagged(req, *tags, **kwargs)

        page = self._current_page(req)
        engine = TagEngine(self.env)

        showpages = kwargs.get('showpages', None) or kwargs.get('shownames', 'false')

        if 'tagspace' in kwargs:
            tagspaces = [kwargs['tagspace']]
        else:
            tagspaces = kwargs.get('tagspaces', []) or \
                        list(TagEngine(self.env).tagspaces)

        out = StringIO()
        out.write('<ul class="listtags">\n')
        tag_details = {}
        for tag, names in sorted(engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems()):
            href, title = engine.get_tag_link(tag)
            htitle = wiki_to_oneliner(title, self.env)
            out.write('<li><a href="%s" title="%s">%s</a> %s <span class="tagcount">(%i)</span>' % (href, title, tag, htitle, len(names)))
            if showpages == 'true':
                out.write('\n')
                out.write(self.render_listtagged(req, tag, tagspaces=tagspaces))
                out.write('</li>\n')

        out.write('</ul>\n')

        return out.getvalue()
示例#36
0
    def _initialize_tags(self, args, kwargs):
        """ Instantiate a TagEngine and get the tagged names

        Returns a list of all the pages tagged with the tags specified in
        args.  Also return a reference to the TagEngine instance

        """
        self.tags = TagEngine(self.env).tagspace.wiki
        tlist = args
        if not tlist:
            tlist = get_env_val('default_tag', config=self.env.config,
                                section='blog', convert=list_val, 
                                default='blog')
        self.log.debug('tlist: %s' % str(tlist))

        union = get_env_val('union', kwargs=kwargs, default=False, 
                            convert=bool_val)
        if union:
            blog = self.tags.get_tagged_names(tlist, operation='union')
        else:
            blog = self.tags.get_tagged_names(tlist, operation='intersection')
        return (blog, tlist)
示例#37
0
    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        from trac.log import logger_factory
        self.env.log = logger_factory(logtype='syslog',
                                      logfile=None,
                                      level='DEBUG',
                                      logid='Trac',
                                      format=None)

        self.env.path = '/'
        self.wiki_tag_rpc_engine = WikiTagRPCSystem(self.env)
        self.ticket_tag_rpc_engine = TicketTagRPCSystem(self.env)
        self.tag_engine = TagEngine(self.env)
        self.tag_engine.upgrade_environment(self.env.get_db_cnx())
        self.xml_rpc_system = XMLRPCSystem(self.env)

        # Insert some test tickets
        from trac.ticket.model import Ticket
        for id in (1, 2, 3):
            ticket = Ticket(self.env)
            ticket['summary'] = 'Test ticket %i' % id
            ticket['description'] = 'Test ticket %i description' % id
            ticket.insert()
示例#38
0
 def setUp(self):
     self.env = EnvironmentStub(default_data=True)
     from trac.log import logger_factory
     self.env.log =logger_factory(logtype='syslog', logfile=None, level='DEBUG', logid='Trac', format=None)
     
     self.env.path = '/'
     self.wiki_tag_rpc_engine = WikiTagRPCSystem(self.env)
     self.ticket_tag_rpc_engine = TicketTagRPCSystem(self.env)
     self.tag_engine = TagEngine(self.env)
     self.tag_engine.upgrade_environment(self.env.get_db_cnx())
     self.xml_rpc_system = XMLRPCSystem(self.env)
                      
     
     # Insert some test tickets
     from trac.ticket.model import Ticket
     for id in (1, 2, 3):
         ticket = Ticket(self.env)
         ticket['summary'] = 'Test ticket %i' % id
         ticket['description'] = 'Test ticket %i description' % id
         ticket.insert()
示例#39
0
def execute(hdf, template, env):
    out = StringIO()
    errors = []
    authname = hdf.getValue("trac.authname", "anonymous")
    if not template:
        raise TracError("No template page supplied")
    if authname == "anonymous":
        errors.append('You need to <a href="%s">register</a> then <a href="%s">login</a> in order to create a new hack.' % (hdf.getValue("trac.href.registration", ""), hdf.getValue("trac.href.login", "")))
    db = env.get_db_cnx()
    cursor = db.cursor()

    # Fetch meta-data from tags
    META_TAGS = set()
    from tractags.api import TagEngine
    wikitags = TagEngine(env).tagspace.wiki
    for tag in wikitags.get_tagged_names(['metatag']):
        META_TAGS.update(wikitags.get_tagged_names([tag]))
    TYPES = wikitags.get_tagged_names(['type'])
    RELEASES = wikitags.get_tagged_names(['release'])

    page_name = hdf.getValue('args.name', '')
    if not page_name.lower().endswith(hdf.getValue('args.type', '')):
        page_name += hdf.getValue('args.type', '').title()
    page_title = hdf.getValue('args.title', '')
    page_description = hdf.getValue('args.description', '')
    page_example = hdf.getValue('args.example', '')
    page_type = hdf.getValue('args.type', 'plugin')
    page_tags = get_branch_values(hdf, 'args.tags')
    page_releases = get_branch_values(hdf, 'args.releases')
    page_preview = hdf.getValue('args.previewhack', '')
    page_create = hdf.getValue('args.createhack', '')

    def write_tags(out, tags, checked = (), name = "tags", type="checkbox"):
        count = 0
        for tag in sorted(tags):
            if tag.startswith('tags/'):
                continue
            (linktext,title,desc) = getInfo(db,tag)
            link = env.href.wiki(tag)
            check = ""
            if tag in checked:
                check = " checked"
            out.write('<input type="%s" name="%s" value="%s"%s/> <a href="%s" title="%s">%s</a>&nbsp;&nbsp;\n' % (type, name, tag, check, link, title, tag))
            count += 1
            if count % 8 == 0:
                out.write("<br/>\n")
        return count

    # Validation
    if page_preview or page_create:
        try:
            fetch_page(cursor, page_name)
        except:
            pass
        else:
            errors.append("Page name %s already exists" % page_name)
        if not re.match('^([A-Z][a-z]+){2,}$', page_name): errors.append('Invalid WikiName, only alpha characters are accepted and must be CamelCase')
        if not page_name: errors.append("No WikiName provided")
        if not page_title: errors.append("No page title provided")
        if not page_type: errors.append('No page type selected')
        if not page_description: errors.append("No description provided")
        if not page_example: errors.append("No example provided")
        if not page_releases: errors.append("No releases selected")

    if page_create and not errors:
        import subprocess
        repos_dir = env.config.get('trac', 'repository_dir')
        cursor.execute("SELECT name FROM component WHERE name=%s", (page_name,))
        row = cursor.fetchone()
        if row:
            errors.append("Component '%s' already exists" % page_name)
        if subprocess.call(["svn", "ls", "%s/%s" % (SVN_LOCAL_PATH, page_name.lower())]) == 0:
            errors.append("Repository path '%s' already exists" % page_name.lower())
        if not os.access(SVN_PERMISSIONS, os.W_OK):
            errors.append("Can't write to Subversion permissions file")

        lockfile = open("/var/tmp/newhack.lock", "w")
        try:
            rv = fcntl.flock(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
            if rv:
                errors.append('Failed to acquire lock, received error code %i' % rv)
        except IOError:
            errors.append('A hack is currently being created by another user. Try again later.')

        if not errors:
            try:
                # Insert component
                cursor.execute('INSERT INTO component (name, owner) VALUES (%s, %s)', (page_name, authname))
                # Create page
                page = WikiPage(env, page_name, db = db)
                page.text = expand_vars(fetch_page(cursor, template), generate_vars(hdf))
                out.write('Created wiki page.<br>\n')
                # Creating SVN paths
                paths = ['%s/%s' % (SVN_LOCAL_PATH, page_name.lower())]
                for release in page_releases:
                    paths.append("%s/%s/%s" % (SVN_LOCAL_PATH, page_name.lower(), release))
                output = os.popen('/usr/bin/op create-hack %s "New hack %s, created by %s" %s 2>&1' % (authname, page_name, authname, ' '.join(paths))).readlines()
                if output:
                    raise Exception("Failed to create Subversion paths:\n%s" % ''.join(output))
                out.write("Created SVN layout.<br>\n")
                # Add SVN permissions
                perms = open(SVN_PERMISSIONS, "a")
                perms.write("\n[/%s]\n%s = rw\n" % (page_name.lower(), authname))
                out.write('Added SVN write permission.<br>\n')
                out.write('\nFinished.<p><h1>Hack Details</h1>\n')
                for release in page_releases:
                    svnpath = "%s%s/%s" % (SVN_URL, page_name.lower(), release)
                    out.write('The Subversion repository path for %s is <a href="%s">%s</a>.<br>\n' % (release, svnpath, svnpath))
                out.write('The page for your hack is <a href="%s">%s</a>.<br>\n' % (env.href.wiki(page_name), page_name))
                page.save(authname, 'New hack %s, created by %s' % (page_name, authname), None)
                db.commit()
                # Add tags
                env.log.debug(vars)
                tags = [page_type, authname] + page_tags + page_releases
                env.log.debug(tags)
                wikitags.replace_tags(None, page_name, tags)
                # Finish up
                rv = fcntl.flock(lockfile, fcntl.LOCK_UN)
                return out.getvalue()
            except Exception, e:
                # TODO Roll back changes to SVN_PERMISSIONS file
                db.rollback()
                rv = fcntl.flock(lockfile, fcntl.LOCK_UN)
                env.log.error(e, exc_info=True)
                raise TracError(str(e))
示例#40
0
class TagsXmlRpcTestCase(unittest.TestCase):
    test_data = (('wiki', 'WikiStart', ('foo', 'bar')),
                 ('wiki', 'SandBox', ('bar', 'war')),
                 ('ticket', 1, ('war', 'death')),
                 ('ticket', 2, ('death', 'destruction')),
                 ('ticket', 3, ('foo', 'bar', 'destruction'))
                 )

    
    
    perm=Mock(assert_permission=lambda x: True,has_permission=lambda x: True)
    
    req = Mock(perm=perm, authname='anonymous')
    def _populate_tags(self,ts):
            for tagspace, target, tags in self.test_data:
                tagspace = ts.tagspace(tagspace)
                tagspace.add_tags(self.req, target, tags)
                yield tagspace, target, tags
            
    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        from trac.log import logger_factory
        self.env.log =logger_factory(logtype='syslog', logfile=None, level='DEBUG', logid='Trac', format=None)
        
        self.env.path = '/'
        self.wiki_tag_rpc_engine = WikiTagRPCSystem(self.env)
        self.ticket_tag_rpc_engine = TicketTagRPCSystem(self.env)
        self.tag_engine = TagEngine(self.env)
        self.tag_engine.upgrade_environment(self.env.get_db_cnx())
        self.xml_rpc_system = XMLRPCSystem(self.env)
                         
        
        # Insert some test tickets
        from trac.ticket.model import Ticket
        for id in (1, 2, 3):
            ticket = Ticket(self.env)
            ticket['summary'] = 'Test ticket %i' % id
            ticket['description'] = 'Test ticket %i description' % id
            ticket.insert()
    def test_insert(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts):
            found_tags = tagspace.get_tags([target])
            self.assertEqual(found_tags, set(tags))  
              
    def test_wiki_tagspace(self):
        
        self.assertEqual(self.wiki_tag_rpc_engine.namespace, 'wiki')
        
    def test_ticket_tagspace(self):
        
        self.assertEqual(self.ticket_tag_rpc_engine.namespace, 'ticket')
        
    def test_wiki_xmlrpc_methods(self):
        self.failUnless(set(self.wiki_tag_rpc_engine.xmlrpc_methods()) != None, "No xmlrpc methods for wiki namespace")
 
    def test_ticket_xmlrpc_methods(self):
        self.failUnless(set(self.ticket_tag_rpc_engine.xmlrpc_methods()) != None, "No xmlrpc methods for ticket namespace")
        
    def test_wiki_xmlrpc_namespace(self):
        self.assertEqual(self.wiki_tag_rpc_engine.xmlrpc_namespace(), "tags.wiki")
        
    def test_ticket_xmlrpc_namespace(self):
        self.assertEqual(self.ticket_tag_rpc_engine.xmlrpc_namespace(), "tags.ticket")  
        
    def test_wiki_get_name_tags (self):
        wiki_start_tags = self.wiki_tag_rpc_engine.getTags(self.req,"WikiStart")
        self.failUnless( wiki_start_tags!= None, "Can not find any tags for mock page WikiStart")
        
        
    def test_xmlrpc_listMethods(self):
        for method in self.xml_rpc_system.all_methods(self.req):
                namespace = method.namespace.replace('.', '_')
                namespaces = {}
                if namespace not in namespaces:
                    namespaces[namespace] = {
                        'description' : wiki_to_oneliner(method.namespace_description, self.env),
                        'methods' : [],
                        'namespace' : method.namespace,
                        }
                try:
                    namespaces[namespace]['methods'].append((method.signature, wiki_to_oneliner(method.description, self.env), method.permission))
                except Exception, e:
                    self.fail('%s: %s\n' % (method.name, str(e)))
示例#41
0
 def wiki_page_deleted(self, page):
     # No point having tags on a non-existent page.
     self.env.log.debug("Removing all tags from 'wiki:%s'" % page.name)
     TagEngine(self.env).tagspace.wiki.remove_all_tags(None, page.name)
示例#42
0
 def screenshot_deleted(self, screenshot):
     # Add tags to screenshot.
     tags = TagEngine(self.env).tagspace.screenshots
     tag_names = self._get_tags(screenshot)
     tags.remove_tags(None, screenshot['id'], list(sets.Set(tag_names)))
示例#43
0
 def screenshot_changed(self, screenshot, old_screenshot):
     # Add tags to screenshot.
     old_screenshot.update(screenshot)
     tags = TagEngine(self.env).tagspace.screenshots
     tag_names = self._get_tags(old_screenshot)
     tags.replace_tags(None, old_screenshot['id'], list(sets.Set(tag_names)))
示例#44
0
    def render_tagcloud(self, req, smallest=10, biggest=20, showcount=True, tagspace=None, mincount=1, tagspaces=[]):
        """ This macro displays a [http://en.wikipedia.org/wiki/Tag_cloud tag cloud] (weighted list)
            of all tags.

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`smallest=<n>`||The lower bound of the font size for the tag cloud.||
            ||`biggest=<n>`||The upper bound of the font size for the tag cloud.||
            ||`showcount=true|false`||Show the count of objects for each tag?||
            ||`mincount=<n>`||Hide tags with a count less than `<n>`.||
            """

        smallest = int(smallest)
        biggest = int(biggest)
        mincount = int(mincount)

        engine = TagEngine(self.env)
        # Get wiki tagspace
        if tagspace:
            tagspaces = [tagspace]
        else:
            tagspaces = tagspaces or engine.tagspaces
        cloud = {}

        for tag, names in engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems():
            count = len(names)
            if count >= mincount:
                cloud[tag] = len(names)

        tags = cloud.keys()

        # No tags?
        if not tags: return ''

        # by_count maps tag counts to an index in the set of counts
        by_count = list(set(cloud.values()))
        by_count.sort()
        by_count = dict([(c, float(i)) for i, c in enumerate(by_count)])

        taginfo = self._tag_details({}, tags)
        tags.sort()
        rlen = float(biggest - smallest)
        tlen = float(len(by_count))
        scale = 1.0
        if tlen:
            scale = rlen / tlen
        out = StringIO()
        out.write('<ul class="tagcloud">\n')
        last = tags[-1]
        for tag in tags:
            if tag == last:
                cls = ' class="last"'
            else:
                cls = ''
            if showcount != 'false':
                count = ' <span class="tagcount">(%i)</span>' % cloud[tag]
            else:
                count = ''
            out.write('<li%s><a rel="tag" title="%s" style="font-size: %ipx" href="%s">%s</a>%s</li>\n' % (
                       cls,
                       taginfo[tag][1] + ' (%i)' % cloud[tag],
                       smallest + int(by_count[cloud[tag]] * scale),
                       taginfo[tag][0],
                       tag,
                       count))
        out.write('</ul>\n')
        return out.getvalue()
示例#45
0
    def render_listtagged(self, req, *tags, **kwargs):
        """ List tagged objects. Optionally accepts a list of tags to match
            against.  The special tag '''. (dot)''' inserts the current Wiki page name.

            `[[ListTagged(<tag>, ...)]]`

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`operation=intersection|union`||The set operation to perform on the discovered objects.||
            ||`showheadings=true|false`||List objects under the tagspace they occur in.||
            ||`expression=<expr>`||Match object tags against the given expression.||

            The supported expression operators are: unary - (not); binary +, -
            and | (and, and not, or). All values in the expression are treated
            as tags. Any tag not in the same form as a Python variable must be
            quoted.
            
            eg. Match all objects tagged with ticket and workflow, and not
            tagged with wiki or closed.
            
                (ticket+workflow)-(wiki|closed)

            If an expression is provided operation is ignored.
        """

        if 'tagspace' in kwargs:
            tagspaces = [kwargs.get('tagspace', None)]
        else:
            tagspaces = kwargs.get('tagspaces', '') or \
                        list(TagEngine(self.env).tagspaces)
        expression = kwargs.get('expression', None)
        showheadings = kwargs.get('showheadings', 'false')
        operation = kwargs.get('operation', 'intersection')
        if operation not in ('union', 'intersection'):
            raise TracError("Invalid tag set operation '%s'" % operation)

        engine = TagEngine(self.env)
        page_name = req.hdf.get('wiki.page_name')
        if page_name:
            tags = [tag == '.' and page_name or tag for tag in tags]

        tags = set(tags)
        taginfo = {}
        out = StringIO()
        out.write('<ul class="listtagged">\n')
        # If expression was passed as an argument, do a full walk, using the
        # expression as the predicate. Silently assumes that failed expressions
        # are normal tags.
        if expression:
            from tractags.expr import Expression
            try:
                expr = Expression(expression)
            except Exception, e:
                self.env.log.error("Invalid expression '%s'" % expression, exc_info=True)
                tags.update([x.strip() for x in re.split('[+,]', expression) if x.strip()])
                expression = None
            else:
                self.env.log.debug(expr.ast)
                tagged_names = {}
                tags.update(expr.get_tags())
                for tagspace, name, name_tags in engine.walk_tagged_names(tags=tags,
                        tagspaces=tagspaces, predicate=lambda ts, n, t: expr(t)):
                    tagged_names.setdefault(tagspace, {})[name] = name_tags
                tagged_names = [(tagspace, names) for tagspace, names in tagged_names.iteritems()]
示例#46
0
    def _do_actions(self, req, cursor, modes, component, version):
        for mode in modes:
            if mode == "get-file":
                req.perm.assert_permission("SCREENSHOTS_VIEW")

                # Get screenshot
                match = re.match(r"""^/screenshots/(\d+)/(small|medium|large)$""", req.path_info)
                if match:
                    id = match.group(1)
                    size = match.group(2)
                screenshot = self.api.get_screenshot(cursor, id)

                # Return screenshots image action.
                file = screenshot["%s_file" % (size,)]
                path = os.path.join(self.path, str(screenshot["id"]), file)
                self.log.debug("file: %s" % (file,))
                self.log.debug("path: %s" % (path,))
                type = mimetypes.guess_type(path)[0]
                req.send_file(path, type)

            elif mode == "add":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

            elif mode == "post-add":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

                # Get form values.
                new_name = Markup(req.args.get("name"))
                new_description = Markup(req.args.get("description"))
                new_author = req.authname
                file, filename = self._get_file_from_req(req)
                content = file.read()
                new_tags = req.args.get("tags")
                new_components = req.args.get("components")
                if not isinstance(new_components, list):
                    new_components = [new_components]
                new_versions = req.args.get("versions")
                if not isinstance(new_versions, list):
                    new_versions = [new_versions]

                # Check form values
                if not new_components or not new_versions:
                    raise TracError("You must select at least one component" " and version.")

                # Check correct file type.
                reg = re.compile(r"^(.*)[.](.*)$")
                result = reg.match(filename)
                if result:
                    if not result.group(2).lower() in self.ext.split(" "):
                        raise TracError("Unsupported uploaded file type.")
                else:
                    raise TracError("Unsupported uploaded file type.")

                # Prepare images filenames.
                large_filename = re.sub(reg, r"\1_large.\2", filename)
                medium_filename = re.sub(reg, r"\1_medium.\2", filename)
                small_filename = re.sub(reg, r"\1_small.\2", filename)

                # Add new screenshot.
                screenshot_time = int(time.time())
                self.api.add_screenshot(
                    cursor,
                    new_name,
                    new_description,
                    screenshot_time,
                    new_author,
                    new_tags,
                    large_filename,
                    medium_filename,
                    small_filename,
                )

                # Get inserted screenshot.
                screenshot = self.api.get_screenshot_by_time(cursor, screenshot_time)
                self.id = screenshot["id"]

                # Add components and versions to screenshot.
                for new_component in new_components:
                    self.api.add_component(cursor, screenshot["id"], new_component)
                for new_version in new_versions:
                    self.api.add_version(cursor, screenshot["id"], new_version)

                # Create screenshot tags.
                if is_tags:
                    tags = TagEngine(self.env).tagspace.screenshots
                    tag_names = new_components
                    tag_names.extend(new_versions)
                    tag_names.extend([screenshot["name"], screenshot["author"]])
                    if screenshot["tags"]:
                        tag_names.extend(screenshot["tags"].split(" "))
                    tags.replace_tags(req, screenshot["id"], tag_names)

                # Prepare file paths
                path = os.path.join(self.path, str(self.id))
                large_filepath = os.path.join(path, large_filename)
                medium_filepath = os.path.join(path, medium_filename)
                small_filepath = os.path.join(path, small_filename)
                self.log.debug("large_filepath: %s" % (large_filepath,))
                self.log.debug("medium_filepath: %s" % (medium_filepath,))
                self.log.debug("small_filepath: %s" % (small_filepath,))

                # Store uploaded image.
                try:
                    os.mkdir(path)
                    out_file = open(large_filepath, "w+")
                    out_file.write(content)
                    out_file.close()
                    os.chdir(path)
                    os.system('convert "%s" -resize 400!x300! "%s"' % (large_filename, medium_filename))
                    os.system('convert "%s" -resize 120!x90! "%s"' % (large_filename, small_filename))
                except:
                    raise TracError("Error storing file.")

            elif mode == "edit":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

            elif mode == "post-edit":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

                # Get form values.
                new_name = Markup(req.args.get("name"))
                new_description = Markup(req.args.get("description"))
                new_components = req.args.get("components")
                if not isinstance(new_components, list):
                    new_components = [new_components]
                new_versions = req.args.get("versions")
                if not isinstance(new_versions, list):
                    new_versions = [new_versions]
                new_tags = req.args.get("tags")

                # Check form values
                if not new_components or not new_versions:
                    raise TracError("You must select at least one component" " and version.")

                # Get old screenshot
                screenshot = self.api.get_screenshot(cursor, self.id)

                # Update screenshot tags.
                if is_tags:
                    tags = TagEngine(self.env).tagspace.screenshots
                    tag_names = new_components
                    tag_names.extend(new_versions)
                    tag_names.extend([new_name, screenshot["author"]])
                    if new_tags:
                        tag_names.extend(new_tags.split(" "))
                    tags.replace_tags(req, screenshot["id"], tag_names)

                # Edit screenshot.
                self.api.edit_screenshot(
                    cursor, screenshot["id"], new_name, new_description, new_tags, new_components, new_versions
                )

            elif mode == "delete":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

                # Get screenshots
                screenshots = self.api.get_screenshots(cursor, component["name"], version["name"])
                index = self._get_screenshot_index(screenshots, self.id) or 0
                screenshot = self.api.get_screenshot(cursor, self.id)

                # Delete screenshot.
                try:
                    self.api.delete_screenshot(cursor, self.id)
                    path = os.path.join(self.path, str(self.id))
                    os.remove(os.path.join(path, screenshot["large_file"]))
                    os.remove(os.path.join(path, screenshot["medium_file"]))
                    os.remove(os.path.join(path, screenshot["small_file"]))
                    os.rmdir(path)
                except:
                    pass

                # Delete screenshot tags.
                if is_tags:
                    tags = TagEngine(self.env).tagspace.screenshots
                    tag_names = screenshot["components"]
                    tag_names.extend(screenshot["versions"])
                    tag_names.extend([screenshot["name"], screenshot["author"]])
                    if screenshot["tags"]:
                        tag_names.extend(screenshot["tags"].split(" "))
                    tags.remove_tags(req, screenshot["id"], tag_names)

                # Set new screenshot id.
                if index > 1:
                    self.id = screenshots[index - 1]["id"]
                else:
                    self.id = screenshots[0]["id"]

            elif mode == "display":
                req.perm.assert_permission("SCREENSHOTS_VIEW")

                # Get screenshots of selected version and component.
                screenshots = self.api.get_screenshots(cursor, component["name"], version["name"])
                index = self._get_screenshot_index(screenshots, self.id) or 0

                # Prepare displayed screenshots.
                lenght = len(screenshots)
                previous = []
                current = []
                next = []
                if lenght > 0:
                    current.append(screenshots[index])
                if (index + 1) < lenght:
                    next.append(screenshots[index + 1])
                else:
                    next.append(no_screenshot)
                if (index + 2) < lenght:
                    next.append(screenshots[index + 2])
                else:
                    next.append(no_screenshot)
                if (index - 1) > 0:
                    previous.append(screenshots[index - 2])
                else:
                    previous.append(no_screenshot)
                if (index) > 0:
                    previous.append(screenshots[index - 1])
                else:
                    previous.append(no_screenshot)

                # Fill HDF structure
                req.hdf["screenshots.index"] = index + 1
                req.hdf["screenshots.count"] = len(screenshots)
                req.hdf["screenshots.previous"] = previous
                req.hdf["screenshots.current"] = current
                req.hdf["screenshots.next"] = next

                return "screenshots.cs", None

            elif mode == "add-display":
                req.perm.assert_permission("SCREENSHOTS_ADMIN")

                # Get screenshot
                screenshot = self.api.get_screenshot(cursor, self.id)
                self.log.debug("screenshot: %s" % (screenshot,))

                # Fill HDF structure
                req.hdf["screenshots.current"] = [screenshot]

                return "screenshot-add.cs", None
示例#47
0
    def render_macro(self, req, name, content):
        from StringIO import StringIO
        from trac.wiki import wiki_to_html
        from trac.wiki.model import WikiPage
        from trac.util import Markup
        from tractags.api import TagEngine
        import re

        tagspace = TagEngine(self.env).tagspace.wiki

        out = StringIO()
        pages = tagspace.get_tagged_names(tags=["type"])
        pages = sorted(pages)

        out.write('<form style="text-align: right; padding-top: 1em; margin-right: 5em;" method="get">')
        out.write('<span style="font-size: xx-small">')
        out.write("Show hacks for releases: ")
        releases = natsorted(tagspace.get_tagged_names(tags=["release"]))
        if "update_th_filter" in req.args:
            show_releases = req.args.get("release", ["0.12"])
            if isinstance(show_releases, basestring):
                show_releases = [show_releases]
            req.session["th_release_filter"] = ",".join(show_releases)
        else:
            show_releases = req.session.get("th_release_filter", "0.12").split(",")
        for version in releases:
            checked = version in show_releases
            out.write(
                '<input type="checkbox" name="release" value="%s"%s>%s\n'
                % (version, checked and " checked" or "", version)
            )
        out.write(
            '<input name="update_th_filter" type="submit" style="font-size: xx-small; padding: 0; border: solid 1px black" value="Update"/>'
        )
        out.write("</span>")
        out.write("</form>")
        for i, pagename in enumerate(pages):
            page = WikiPage(self.env, pagename)
            if page.text:
                topmargin = "0em"
                if i < len(pages) - 1:
                    bottommargin = "0em"
                else:
                    bottommargin = "2em"

                out.write(
                    '<fieldset style="padding: 1em; margin: %s 5em %s 5em; border: 1px solid #999;">\n'
                    % (topmargin, bottommargin)
                )
                body = page.text
                title = re.search("=+\s([^=]*)=+", body)
                if title:
                    title = title.group(1).strip()
                    body = re.sub("=+\s([^=]*)=+", "", body, 1)
                else:
                    title = pagename
                body = re.sub("\\[\\[TagIt.*", "", body)
                out.write(
                    '<legend style="color: #999;"><a href="%s">%s</a></legend>\n'
                    % (self.env.href.wiki(pagename), title)
                )
                body = wiki_to_html(body, self.env, req)
                # Dear God, the horror!
                for line in body.splitlines():
                    show = False
                    for release in show_releases:
                        self.env.log.debug(release)
                        if ">%s</a>" % release in line:
                            show = True
                            break
                    if show or not "<li>" in line:
                        out.write(line)

                out.write("</fieldset>\n")

        return out.getvalue()
示例#48
0
class TagsXmlRpcTestCase(unittest.TestCase):
    test_data = (('wiki', 'WikiStart', ('foo', 'bar')), ('wiki', 'SandBox',
                                                         ('bar', 'war')),
                 ('ticket', 1, ('war', 'death')), ('ticket', 2,
                                                   ('death', 'destruction')),
                 ('ticket', 3, ('foo', 'bar', 'destruction')))

    perm = Mock(assert_permission=lambda x: True,
                has_permission=lambda x: True)

    req = Mock(perm=perm, authname='anonymous')

    def _populate_tags(self, ts):
        for tagspace, target, tags in self.test_data:
            tagspace = ts.tagspace(tagspace)
            tagspace.add_tags(self.req, target, tags)
            yield tagspace, target, tags

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        from trac.log import logger_factory
        self.env.log = logger_factory(logtype='syslog',
                                      logfile=None,
                                      level='DEBUG',
                                      logid='Trac',
                                      format=None)

        self.env.path = '/'
        self.wiki_tag_rpc_engine = WikiTagRPCSystem(self.env)
        self.ticket_tag_rpc_engine = TicketTagRPCSystem(self.env)
        self.tag_engine = TagEngine(self.env)
        self.tag_engine.upgrade_environment(self.env.get_db_cnx())
        self.xml_rpc_system = XMLRPCSystem(self.env)

        # Insert some test tickets
        from trac.ticket.model import Ticket
        for id in (1, 2, 3):
            ticket = Ticket(self.env)
            ticket['summary'] = 'Test ticket %i' % id
            ticket['description'] = 'Test ticket %i description' % id
            ticket.insert()

    def test_insert(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts):
            found_tags = tagspace.get_tags([target])
            self.assertEqual(found_tags, set(tags))

    def test_wiki_tagspace(self):

        self.assertEqual(self.wiki_tag_rpc_engine.namespace, 'wiki')

    def test_ticket_tagspace(self):

        self.assertEqual(self.ticket_tag_rpc_engine.namespace, 'ticket')

    def test_wiki_xmlrpc_methods(self):
        self.failUnless(
            set(self.wiki_tag_rpc_engine.xmlrpc_methods()) != None,
            "No xmlrpc methods for wiki namespace")

    def test_ticket_xmlrpc_methods(self):
        self.failUnless(
            set(self.ticket_tag_rpc_engine.xmlrpc_methods()) != None,
            "No xmlrpc methods for ticket namespace")

    def test_wiki_xmlrpc_namespace(self):
        self.assertEqual(self.wiki_tag_rpc_engine.xmlrpc_namespace(),
                         "tags.wiki")

    def test_ticket_xmlrpc_namespace(self):
        self.assertEqual(self.ticket_tag_rpc_engine.xmlrpc_namespace(),
                         "tags.ticket")

    def test_wiki_get_name_tags(self):
        wiki_start_tags = self.wiki_tag_rpc_engine.getTags(
            self.req, "WikiStart")
        self.failUnless(wiki_start_tags != None,
                        "Can not find any tags for mock page WikiStart")

    def test_xmlrpc_listMethods(self):
        for method in self.xml_rpc_system.all_methods(self.req):
            namespace = method.namespace.replace('.', '_')
            namespaces = {}
            if namespace not in namespaces:
                namespaces[namespace] = {
                    'description':
                    wiki_to_oneliner(method.namespace_description, self.env),
                    'methods': [],
                    'namespace':
                    method.namespace,
                }
            try:
                namespaces[namespace]['methods'].append(
                    (method.signature,
                     wiki_to_oneliner(method.description,
                                      self.env), method.permission))
            except Exception, e:
                self.fail('%s: %s\n' % (method.name, str(e)))
示例#49
0
 def wiki_page_deleted(self, page):
     # No point having tags on a non-existent page.
     self.env.log.debug("Removing all tags from 'wiki:%s'" % page.name)
     engine = TagEngine(self.env)
     engine.tagspace.wiki.remove_all_tags(None, page.name)
     engine.flush_link_cache(page)
示例#50
0
    def _new_blog_post(self, req):
        """ Generate a new blog post

        """
        action = req.args.get('action', 'edit')
        pg_name_fmt = self.env.config.get('blog', 'page_format', 
                                          '%Y/%m/%d/%H.%M')
        wikitext = req.args.get('text', '')
        blogtitle = req.args.get('blogtitle', '')
        pagename = req.args.get('pagename', pg_name_fmt) 
        pagename = time.strftime(pagename)
        if '%@' in pagename and blogtitle: 
            urltitle = re.sub(r'[^\w]+', '-', blogtitle).lower() 
            pagename = pagename.replace('%@', urltitle) 
            while '-' in pagename and len(pagename) > 60: 
                pagename = '-'.join(pagename.split('-')[:-1]) 
            pagename = pagename.strip('-')
        if '$U' in pagename:
            pagename = pagename.replace('$U', req.authname)
        comment = req.args.get('comment', '')
        readonly = int(req.args.has_key('readonly'))
        edit_rows = int(req.args.get('edite_rows', 20))
        req_tags = req.args.get('tags', [])
        
        if req.method == 'POST':
            if action == 'edit':
                if req.args.has_key('cancel'):
                    req.redirect(self.env.href.blog())
                page = WikiPage(self.env, pagename, None)
                tags = TagEngine(self.env).tagspace.wiki
                if req.args.has_key('preview'):
                    req.hdf['blog.action'] = 'preview'
                    self._render_editor(req, page, self.env.get_db_cnx(),
                                        preview=True) 
                else:
                    titleline = ' '.join(["=", blogtitle, "=\n"])
                    if blogtitle:
                        page.text = ''.join([titleline, wikitext])
                    else:
                        page.text = wikitext
                    page.readonly = readonly
                    page.save(req.authname, comment, req.remote_addr)
#                    taglist = [x.strip() for x in req_tags.split(',') if x]
                    taglist = [t.strip() for t in 
                               _tag_split.split(req.args.get('tags')) 
                               if t.strip()]
                    tags.add_tags(req, pagename, taglist)
                    req.redirect(self.env.href.blog())
        else:
            info = {
                'title' : blogtitle,
                'pagename': pagename,
                'page_source': wikitext,
                'comment': comment,
                'readonly': readonly,
                'edit_rows': edit_rows,
                'scroll_bar_pos': req.args.get('scroll_bar_pos', '')
            }
            req.hdf['blog'] = info
            req.hdf['title'] = 'New Blog Entry'
            tlist = req.args.getlist('tag')
            if not tlist:
                tlist = [self.env.config.get('blog', 'default_tag', 'blog')]
            req.hdf['tags'] = ', '.join(tlist)
            pass
示例#51
0
class TagApiTestCase(unittest.TestCase):
    test_data = (('wiki', 'WikiStart', ('foo', 'bar')),
                 ('wiki', 'SandBox', ('bar', 'war')),
                 ('ticket', 1, ('war', 'death')),
                 ('ticket', 2, ('death', 'destruction')),
                 ('ticket', 3, ('foo', 'bar', 'destruction'))
                 )

    req = Mock(perm=Mock(assert_permission=lambda x: True),
               authname='anonymous')

    def _populate_tags(self, ts):
        for tagspace, target, tags in self.test_data:
            tagspace = ts.tagspace(tagspace)
            tagspace.add_tags(self.req, target, tags)
            yield tagspace, target, tags

    def setUp(self):
        self.env = EnvironmentStub(default_data=True)
        self.env.path = '/'
        self.tag_engine = TagEngine(self.env)
        self.tag_engine.upgrade_environment(self.env.get_db_cnx())
        # Insert some test tickets
        from trac.ticket.model import Ticket
        for id in (1, 2, 3):
            ticket = Ticket(self.env)
            ticket['summary'] = 'Test ticket %i' % id
            ticket['description'] = 'Test ticket %i description' % id
            ticket.insert()

    def test_tagspaces(self):
        tagspaces = set(self.tag_engine.tagspaces)
        self.assertEqual(tagspaces, set(('ticket', 'wiki')))

    def test_insert(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts):
            found_tags = tagspace.get_tags([target])
            self.assertEqual(found_tags, set(tags))

    def test_remove(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts):
            target_tags = tagspace.get_name_tags(target)
            tag = iter(target_tags).next()
            tagspace.remove_tags(self.req, target, (tag,))
            target_tags.discard(tag)
            self.assertEqual(tagspace.get_name_tags(target), target_tags)

    def test_remove_all(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts):
            tagspace.remove_all_tags(self.req, target)

    def test_replace(self):
        ts = self.tag_engine.tagspace
        test_set = set(('foozle', 'stick'))
        for tagspace, target, tags in self._populate_tags(ts):
            found_tags = tagspace.get_tags([target])
            tagspace.replace_tags(self.req, target, test_set)
            self.assertEqual(test_set, tagspace.get_name_tags(target))

    def test_add(self):
        ts = self.tag_engine.tagspace
        test_set = set(('foozle', 'stick'))
        for tagspace, target, tags in self._populate_tags(ts):
            found_tags = tagspace.get_tags([target])
            tagspace.add_tags(self.req, target, test_set)
            self.assertEqual(test_set.union(found_tags), tagspace.get_name_tags(target))

    def test_walk(self):
        engine = self.tag_engine
        compare_data = {}
        for tagspace, target, tags in self._populate_tags(engine.tagspace):
            compare_data.setdefault(tagspace.tagspace, {})[target] = set(tags)
        tag_data = {}
        for tagspace, name, tags in engine.walk_tagged_names():
            tag_data.setdefault(tagspace, {})[name] = tags
        self.assertEqual(compare_data, tag_data)

    def test_get_tagged_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tagged_names(tags=('foo', 'bar'), operation='union'),
                         {'wiki': set([u'WikiStart', u'SandBox']), 'ticket': set([3])})

    def test_get_tagged_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tagged_names(tags=('foo', 'bar'), operation='intersection'),
                         {'wiki': set(['WikiStart']), 'ticket': set([3])})

    def test_get_tags_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tags(names=('WikiStart', 1), operation='union'),
                         set(['death', 'bar', 'war', 'foo']))

    def test_get_tags_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tags(names=('WikiStart', 3), operation='intersection'),
                         set(['bar', 'foo']))

    def test_tagspace_get_tagged_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tagged_names(tags=('foo', 'bar'), operation='union'),
                         set([u'WikiStart', u'SandBox']))

    def test_tagspace_get_tagged_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tagged_names(tags=('bar',), operation='intersection'),
                         set([u'WikiStart', u'SandBox']))

    def test_tagspace_get_tags_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tags(names=('WikiStart', 'SandBox'), operation='union'),
                         set(['bar', 'war', 'foo']))

    def test_tagspace_get_tags_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tags(names=('WikiStart', 'SandBox'), operation='intersection'),
                         set(['bar']))

    # Detailed
    def test_detailed_get_tagged_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tagged_names(tags=('foo', 'bar'), operation='union', detailed=True),
                         {'wiki': {'WikiStart': set(('foo', 'bar')),
                                   'SandBox': set(('bar', 'war'))},
                          'ticket': {3: set(('foo', 'bar', 'destruction'))}})

    def test_detailed_get_tagged_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tagged_names(tags=('foo', 'bar'), operation='intersection', detailed=True),
                         {'wiki': {'WikiStart': set(('foo', 'bar'))},
                          'ticket': {3: set(('foo', 'bar', 'destruction'))}})

    def test_detailed_get_tags_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tags(names=('WikiStart', 1), operation='union', detailed=True),
                         {'death': set([('ticket', 1)]),
                          'bar': set([('wiki', 'WikiStart')]),
                          'war': set([('ticket', 1)]),
                          'foo': set([('wiki', 'WikiStart')])})

    def test_detailed_get_tags_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.get_tags(names=('WikiStart', 3, 'SandBox'), operation='intersection', detailed=True),
                         {'bar': set([('wiki', 'SandBox'), ('wiki', 'WikiStart'), ('ticket', 3)])})

    def test_detailed_tagspace_get_tagged_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tagged_names(tags=('foo', 'bar'), operation='union', detailed=True),
                         {'WikiStart': set(['foo', 'bar']),
                          'SandBox': set(['bar', 'war'])})

    def test_detailed_tagspace_get_tagged_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tagged_names(tags=('bar',), operation='intersection', detailed=True),
                         {'WikiStart': set(['foo', 'bar']), 'SandBox': set(['bar', 'war'])})

    def test_detailed_tagspace_get_tags_union(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tags(names=('WikiStart', 'SandBox'), operation='union', detailed=True),
                         {'foo': set(['WikiStart']),
                          'bar': set(['WikiStart', 'SandBox']),
                          'war': set(['SandBox'])})

    def test_detailed_tagspace_get_tags_intersection(self):
        ts = self.tag_engine.tagspace
        for tagspace, target, tags in self._populate_tags(ts): pass
        self.assertEqual(self.tag_engine.tagspace.wiki.get_tags(names=('WikiStart', 'SandBox'), operation='intersection', detailed=True),
                         {'bar': set(['WikiStart', 'SandBox'])})
示例#52
0
 def _tag_formatter(self, formatter, ns, target, label):
     href, title = TagEngine(self.env).get_tag_link(target)
     return Markup('<a href="%s" title="%s">%s</a>' % (href, title, label))
示例#53
0
    def render_listtagged(self, req, *tags, **kwargs):
        """ List tagged objects. Optionally accepts a list of tags to match
            against.  The special tag '''. (dot)''' inserts the current Wiki page name.

            `[[ListTagged(<tag>, ...)]]`

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`operation=intersection|union`||The set operation to perform on the discovered objects.||
            ||`showheadings=true|false`||List objects under the tagspace they occur in.||
            ||`expression=<expr>`||Match object tags against the given expression.||

            The supported expression operators are: unary - (not); binary +, -
            and | (and, and not, or). All values in the expression are treated
            as tags. Any tag not in the same form as a Python variable must be
            quoted.
            
            eg. Match all objects tagged with ticket and workflow, and not
            tagged with wiki or closed.
            
                (ticket+workflow)-(wiki|closed)

            If an expression is provided operation is ignored.
        """

        if 'tagspace' in kwargs:
            tagspaces = [kwargs.get('tagspace', None)]
        else:
            tagspaces = kwargs.get('tagspaces', '') or \
                        list(TagEngine(self.env).tagspaces)
        expression = kwargs.get('expression', None)
        showheadings = kwargs.get('showheadings', 'false')
        operation = kwargs.get('operation', 'intersection')
        if operation not in ('union', 'intersection'):
            raise TracError("Invalid tag set operation '%s'" % operation)

        engine = TagEngine(self.env)
        page_name = self._current_page(req)
        if page_name:
            tags = [tag == '.' and page_name or tag for tag in tags]

        tags = set(tags)
        taginfo = {}
        out = StringIO()
        out.write('<ul class="listtagged">\n')
        # If expression was passed as an argument, do a full walk, using the
        # expression as the predicate. Silently assumes that failed expressions
        # are normal tags.
        if expression:
            from tractags.expr import Expression
            try:
                expr = Expression(expression)
                self.env.log.debug(repr(expr))
            except Exception, e:
                self.env.log.error("Invalid expression '%s'" % expression,
                                   exc_info=True)
                tags.update([
                    x.strip() for x in re.split('[+,]', expression)
                    if x.strip()
                ])
                expression = None
            else:
                self.env.log.debug(expr.ast)
                tagged_names = {}
                tags.update(expr.get_tags())
                for tagspace, name, name_tags in engine.walk_tagged_names(
                        tags=tags,
                        tagspaces=tagspaces,
                        predicate=lambda ts, n, t: expr(t)):
                    tagged_names.setdefault(tagspace, {})[name] = name_tags
                tagged_names = [
                    (tagspace, names)
                    for tagspace, names in tagged_names.iteritems()
                ]
示例#54
0
 def wiki_page_changed(self, page, version, t, comment, author, ipnr):
     TagEngine(self.env).flush_link_cache(page)
示例#55
0
 def _tag_details(self, links, tags):
     """ Extract dictionary of tag:(href, title) for all tags. """
     for tag in tags:
         if tag not in links:
             links[tag] = TagEngine(self.env).get_tag_link(tag)
     return links
示例#56
0
 def wiki_page_version_deleted(self, page):
     # Wiki tags are not versioned. If they were, we'd delete them here.
     TagEngine(self.env).flush_link_cache(page)
示例#57
0
    def render_tagcloud(self,
                        req,
                        smallest=10,
                        biggest=20,
                        showcount=True,
                        tagspace=None,
                        mincount=1,
                        tagspaces=[],
                        **kwargs):
        """ This macro displays a [http://en.wikipedia.org/wiki/Tag_cloud tag cloud] (weighted list)
            of all tags.

            ||'''Argument'''||'''Description'''||
            ||`tagspace=<tagspace>`||Specify the tagspace the macro should operate on.||
            ||`tagspaces=(<tagspace>,...)`||Specify a set of tagspaces the macro should operate on.||
            ||`smallest=<n>`||The lower bound of the font size for the tag cloud.||
            ||`biggest=<n>`||The upper bound of the font size for the tag cloud.||
            ||`showcount=true|false`||Show the count of objects for each tag?||
            ||`mincount=<n>`||Hide tags with a count less than `<n>`.||
            """

        smallest = int(smallest)
        biggest = int(biggest)
        mincount = int(mincount)

        engine = TagEngine(self.env)
        # Get wiki tagspace
        if tagspace:
            tagspaces = [tagspace]
        else:
            tagspaces = tagspaces or engine.tagspaces
        cloud = {}

        for tag, names in engine.get_tags(tagspaces=tagspaces,
                                          detailed=True).iteritems():
            count = len(names)
            if count >= mincount:
                cloud[tag] = len(names)

        tags = cloud.keys()

        # No tags?
        if not tags: return ''

        # by_count maps tag counts to an index in the set of counts
        by_count = list(set(cloud.values()))
        by_count.sort()
        by_count = dict([(c, float(i)) for i, c in enumerate(by_count)])

        taginfo = self._tag_details({}, tags)
        tags.sort()
        rlen = float(biggest - smallest)
        tlen = float(len(by_count))
        scale = 1.0
        if tlen:
            scale = rlen / tlen
        out = StringIO()
        out.write('<ul class="tagcloud">\n')
        last = tags[-1]
        for tag in tags:
            if tag == last:
                cls = ' class="last"'
            else:
                cls = ''
            if showcount != 'false':
                count = ' <span class="tagcount">(%i)</span>' % cloud[tag]
            else:
                count = ''
            out.write(
                '<li%s><a rel="tag" title="%s" style="font-size: %ipx" href="%s">%s</a>%s</li>\n'
                % (cls, taginfo[tag][1] + ' (%i)' % cloud[tag],
                   smallest + int(by_count[cloud[tag]] * scale),
                   taginfo[tag][0], tag, count))
        out.write('</ul>\n')
        return out.getvalue()
示例#58
0
    def _generate_blog(self, req, *args, **kwargs):
        """Extract the blog pages and fill the HDF.

        *args is a list of tags to use to limit the blog scope
        **kwargs are any aditional keyword arguments that are needed
        """
        tallies = {}
        tags = TagEngine(self.env).tagspace.wiki
        try:
            union = kwargs['union']
        except KeyError:
            union = False
        # Formatting
        read_post = "[wiki:%s Read Post]"
        entries = {}
        if not len(args):
            tlist = [self.env.config.get('blog', 'default_tag', 'blog')]
        else:
            tlist = args
        if union:
            blog = tags.get_tagged_names(tlist, operation='union')
        else:
            blog = tags.get_tagged_names(tlist, operation='intersection')
        macropage = req.args.get('page', None)

        poststart, postend, default_times = self._get_time_range(req, **kwargs)
        mark_updated = self._choose_value('mark_updated', req, kwargs, 
                                          convert=bool_val)
        if not mark_updated and (not isinstance(mark_updated, bool)):
            mark_updated = bool_val(self.env.config.get('blog', 'mark_updated',
                                                         True))
        macro_bl = self.env.config.get('blog', 'macro_blacklist', '').split(',')
        macro_bl = [name.strip() for name in macro_bl if name.strip()]
        macro_bl.append('BlogShow')

        # Get the email addresses of all known users and validate the "poster"
        # BlogShow optional argument at the same time (avoids looping the user
        # list twice).
        is_poster = None
        limit_poster = self._choose_value('poster', req, kwargs, convert=None)
        email_map = {}
        for username, name, email in self.env.get_known_users():
            if email:
                email_map[username] = email
            if limit_poster != None:
                if username == limit_poster:
                    is_poster = username

                       
        num_posts = self._choose_value('num_posts', req, kwargs, convert=int)
        if num_posts and default_times:
            poststart = sys.maxint
            postend = 0
        for blog_entry in blog:
            if blog_entry == macropage:
                continue
            try:
                page = WikiPage(self.env, version=1, name=blog_entry)
                version, post_time, author, comment, ipnr = page.get_history(
                                                            ).next()
                # if we're limiting by poster, do so now so that the calendar
                # only shows the number of entries the specific poster made.
                if is_poster != None:
                    if is_poster != author:
                        continue

                self._add_to_tallies(tallies, post_time, blog_entry)
                page = WikiPage(self.env, name=blog_entry)
                version, modified, author, comment, ipnr = page.get_history(
                                                           ).next()
            except:
                self.log.debug("Error loading wiki page %s" % blog_entry, exc_info=True)
                continue
            if poststart >= post_time >= postend:       
                time_format = self.env.config.get('blog', 'date_format') \
                              or '%x %X'
                timeStr = format_datetime(post_time, format=time_format) 
                fulltext = page.text
                # remove comments in blog view:
                del_comments = re.compile('==== Comment.*\Z', re.DOTALL)
                fulltext = del_comments.sub('', fulltext)
                # remove the [[AddComment...]] tag, otherwise it would appeare
                # more than one and crew up the blog view:
                del_addcomment  = re.compile('\[\[AddComment.*\Z', re.DOTALL)
                fulltext = del_addcomment.sub('', fulltext)
                # limit length of preview:
                post_size = self._choose_value('post_size', req, kwargs, int)
                if not post_size and (not isinstance(post_size, int)):
                    post_size = int(self.env.config.get('blog', 'post_size', 
                                    1024))
                text = self._trim_page(fulltext, blog_entry, post_size)
                pagetags = [x for x in tags.get_name_tags(blog_entry) if x not in tlist]
                tagtags = []
                for i, t in enumerate(pagetags[:3]):
                    d = { 'link' : t,
                          'name' : t,
                          'last' : i == (len(pagetags[:3]) - 1),
                        }
                    tagtags.append(d)
                    continue
                # extract title from text:
                match = _title_split_match(fulltext)
                if match:
                    title = match.group(1)
                    fulltext = match.group(2)
                else: 
                    title = blog_entry
                html_text = wiki_to_html(fulltext, self.env, req)
                rss_text = Markup.escape(to_unicode(html_text))
                data = {
                        'name'      : blog_entry,
                        'title'     : title,
                        'href'      : self.env.href.wiki(blog_entry),
                        'wiki_link' : wiki_to_oneliner(read_post % 
                                                       blog_entry,
                                                       self.env),
                        'time'      : timeStr,
                        'date'      : http_date(post_time),
#                        'date'      : http_date(page.time),
                        'author'    : author,
                        'wiki_text' : wiki_to_nofloat_html(text, self.env, req,
                                                   macro_blacklist=macro_bl),
                        'rss_text'  : rss_text,
                        'comment'   : wiki_to_oneliner(comment, self.env),
                        'tags'      : {
                                        'present' : len(pagetags),
                                        'tags'    : tagtags,
                                        'more'    : len(pagetags) > 3 or 0,
                                      },
                       }
                if author:
                    # For RSS, author must be an email address
                    if author.find('@') != -1:
                        data['author.email'] = author
                    elif email_map.has_key(author):
                        data['author.email'] = email_map[author]
                
                if (modified != post_time) and mark_updated:
                    data['modified'] = 1
                    mod_str = format_datetime(modified, format=time_format)
                    data['mod_time'] = mod_str
                entries[post_time] = data
            continue
        tlist = entries.keys()
        tlist.sort()
        tlist.reverse()
        if num_posts and (num_posts <= len(tlist)):
            tlist = tlist[:num_posts]
        if tlist:
            entries[tlist[-1]]['last'] = 1
        req.hdf['blog.entries'] = [entries[x] for x in tlist]
        bloglink = self.env.config.get('blog', 'new_blog_link', 'New Blog Post')
        req.hdf['blog.newblog'] = bloglink
        hidecal = self._choose_value('hidecal', req, kwargs)
        if not hidecal:
            self._generate_calendar(req, tallies)
        req.hdf['blog.hidecal'] = hidecal
        # Insert /wiki/BlogHeader into /blog.  If the page does not exist,
        # this'll be a no-op
        blog_header = WikiPage(self.env, name='BlogHeader').text
        req.hdf['blog.header'] = Mimeview(self.env).render(req,
                                                           'text/x-trac-wiki',
                                                           blog_header)