Beispiel #1
0
 def get_forums(self, req, cursor, order_by = 'ORDER BY subject ASC'):
     columns = ('id', 'name', 'author', 'time', 'moderators', 'group',
       'subject', 'description', 'topics', 'replies', 'lastreply',
       'lasttopic')
     sql = "SELECT id, name, author, time, moderators, forum_group," \
       " subject, description, (SELECT COUNT(id) FROM topic t WHERE" \
       " t.forum = forum.id) AS topics, (SELECT COUNT(id) FROM message m" \
       " WHERE m.forum = forum.id) AS replies, (SELECT MAX(time) FROM" \
       " message m WHERE m.forum = forum.id) AS lasttopic, (SELECT" \
       " MAX(time) FROM topic t WHERE t.forum = forum.id) AS lastreply" \
       " FROM forum " + order_by
     self.log.debug(sql)
     cursor.execute(sql)
     forums = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['moderators'] = wiki_to_oneliner(row['moderators'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(row['lastreply'])
         else:
             row['lastreply'] = 'No replies'
         if row['lasttopic']:
             row['lasttopic'] = pretty_timedelta(row['lasttopic'])
         else:
             row['lasttopic'] = 'No topics'
         row['time'] = format_datetime(row['time'])
         forums.append(row)
     return forums
Beispiel #2
0
    def get_groups(self, req, cursor, order_by='id', desc=False):
        # Get count of forums without group
        sql = "SELECT COUNT(f.id) FROM forum f WHERE f.forum_group = 0"
        self.log.debug(sql)
        cursor.execute(sql)
        no_group_forums = 0
        for row in cursor:
            no_group_forums = row[0]
        groups = [{
            'id': 0,
            'name': 'None',
            'description': 'No Group',
            'forums': no_group_forums
        }]

        # Get forum groups
        if order_by != 'forum':
            order_by = 'g.' + order_by
        columns = ('id', 'name', 'description', 'forums')
        sql = "SELECT g.id, g.name, g.description, f.forums FROM " \
          " forum_group g LEFT JOIN (SELECT COUNT(id) AS forums, " \
          " forum_group FROM forum GROUP BY forum_group) f ON g.id = " \
          " f.forum_group ORDER BY " + order_by + (" ASC",
          " DESC")[bool(desc)]
        self.log.debug(sql)
        cursor.execute(sql)
        for row in cursor:
            row = dict(zip(columns, row))
            row['name'] = wiki_to_oneliner(row['name'], self.env)
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            groups.append(row)
        return groups
Beispiel #3
0
 def get_forums(self, req, cursor, order_by='ORDER BY subject ASC'):
     columns = ('id', 'name', 'author', 'time', 'moderators', 'group',
                'subject', 'description', 'topics', 'replies', 'lastreply',
                'lasttopic')
     sql = "SELECT id, name, author, time, moderators, forum_group," \
       " subject, description, (SELECT COUNT(id) FROM topic t WHERE" \
       " t.forum = forum.id) AS topics, (SELECT COUNT(id) FROM message m" \
       " WHERE m.forum = forum.id) AS replies, (SELECT MAX(time) FROM" \
       " message m WHERE m.forum = forum.id) AS lasttopic, (SELECT" \
       " MAX(time) FROM topic t WHERE t.forum = forum.id) AS lastreply" \
       " FROM forum " + order_by
     self.log.debug(sql)
     cursor.execute(sql)
     forums = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['moderators'] = wiki_to_oneliner(row['moderators'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(row['lastreply'])
         else:
             row['lastreply'] = 'No replies'
         if row['lasttopic']:
             row['lasttopic'] = pretty_timedelta(row['lasttopic'])
         else:
             row['lasttopic'] = 'No topics'
         row['time'] = format_datetime(row['time'])
         forums.append(row)
     return forums
Beispiel #4
0
    def get_groups(self, req, cursor, order_by = 'id', desc = False):
        # Get count of forums without group
        sql = "SELECT COUNT(f.id) FROM forum f WHERE f.forum_group = 0"
        self.log.debug(sql)
        cursor.execute(sql)
        no_group_forums = 0
        for row in cursor:
            no_group_forums = row[0]
        groups = [{'id' : 0, 'name' : 'None', 'description' : 'No Group',
          'forums' : no_group_forums}]

        # Get forum groups
        if order_by != 'forum':
            order_by = 'g.' + order_by
        columns = ('id', 'name', 'description', 'forums')
        sql = "SELECT g.id, g.name, g.description, f.forums FROM " \
          " forum_group g LEFT JOIN (SELECT COUNT(id) AS forums, " \
          " forum_group FROM forum GROUP BY forum_group) f ON g.id = " \
          " f.forum_group ORDER BY " + order_by + (" ASC",
          " DESC")[bool(desc)]
        self.log.debug(sql)
        cursor.execute(sql)
        for row in cursor:
            row = dict(zip(columns, row))
            row['name'] = wiki_to_oneliner(row['name'], self.env)
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            groups.append(row)
        return groups
Beispiel #5
0
    def get_groups(self, req, cursor, order_by='ORDER BY id ASC'):
        # Get count of forums without group
        sql = "SELECT COUNT(id) FROM forum WHERE forum_group = 0"
        self.log.debug(sql)
        cursor.execute(sql)
        no_group_forums = 0
        for row in cursor:
            no_group_forums = row[0]
        groups = [{
            'id': 0,
            'name': 'None',
            'description': 'No Group',
            'forums': no_group_forums
        }]

        # Get forum groups
        columns = ('id', 'name', 'description', 'forums')
        sql = "SELECT id, name, description, (SELECT COUNT(id) FROM forum f" \
          " WHERE f.forum_group = forum_group.id) FROM forum_group " + order_by
        self.log.debug(sql)
        cursor.execute(sql)
        for row in cursor:
            row = dict(zip(columns, row))
            row['name'] = wiki_to_oneliner(row['name'], self.env)
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            groups.append(row)
        return groups
Beispiel #6
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'changeset' in filters:
            format = req.args.get('format')
            wiki_format = self.wiki_format_messages
            show_files = self.timeline_show_files
            db = self.env.get_db_cnx()
            repos = self.env.get_repository(req.authname)
            for chgset in repos.get_changesets(start, stop):
                message = chgset.message or '--'
                if wiki_format:
                    shortlog = wiki_to_oneliner(message, self.env, db,
                                                shorten=True)
                else:
                    shortlog = shorten_line(message)

                if format == 'rss':
                    title = Markup('Changeset [%s]: %s', chgset.rev, shortlog)
                    href = req.abs_href.changeset(chgset.rev)
                    if wiki_format:
                        message = wiki_to_html(message, self.env, req, db,
                                               absurls=True)
                    else:
                        message = html.PRE(message)
                else:
                    title = Markup('Changeset <em>[%s]</em> by %s', chgset.rev,
                                   chgset.author)
                    href = req.href.changeset(chgset.rev)

                    if wiki_format:
                        if self.timeline_long_messages:
                            message = wiki_to_html(message, self.env, req, db,
                                                   absurls=True)
                        else:
                            message = wiki_to_oneliner(message, self.env, db,
                                                       shorten=True)
                    else:
                        message = shortlog

                if show_files and req.perm.has_permission('BROWSER_VIEW'):
                    files = []
                    for chg in chgset.get_changes():
                        if show_files > 0 and len(files) >= show_files:
                            files.append(html.LI(Markup('&hellip;')))
                            break
                        files.append(html.LI(html.DIV(class_=chg[2]),
                                             chg[0] or '/'))
                    message = html.UL(files, class_="changes") + message

                yield 'changeset', href, title, chgset.date, chgset.author,\
                      message
Beispiel #7
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'changeset' in filters:
            format = req.args.get('format')
            wiki_format = self.wiki_format_messages
            show_files = self.timeline_show_files
            db = self.env.get_db_cnx()
            repos = self.env.get_repository(req.authname)
            for chgset in repos.get_changesets(start, stop):
                message = chgset.message or '--'
                if wiki_format:
                    shortlog = wiki_to_oneliner(message, self.env, db,
                                                shorten=True)
                else:
                    shortlog = shorten_line(message)

                if format == 'rss':
                    title = Markup(u'변경사항 [%s]: %s', chgset.rev, shortlog)
                    href = req.abs_href.changeset(chgset.rev)
                    if wiki_format:
                        message = wiki_to_html(message, self.env, req, db,
                                               absurls=True)
                    else:
                        message = html.PRE(message)
                else:
                    title = Markup(u'변경사항 <em>[%s]</em> : %s에 의해 수정됨', chgset.rev,
                                   chgset.author)
                    href = req.href.changeset(chgset.rev)

                    if wiki_format:
                        if self.timeline_long_messages:
                            message = wiki_to_html(message, self.env, req, db,
                                                   absurls=True)
                        else:
                            message = wiki_to_oneliner(message, self.env, db,
                                                       shorten=True)
                    else:
                        message = shortlog

                if show_files and req.perm.has_permission('BROWSER_VIEW'):
                    files = []
                    for chg in chgset.get_changes():
                        if show_files > 0 and len(files) >= show_files:
                            files.append(html.LI(Markup('&hellip;')))
                            break
                        files.append(html.LI(html.DIV(class_=chg[2]),
                                             chg[0] or '/'))
                    message = html.UL(files, class_="changes") + message

                yield 'changeset', href, title, chgset.date, chgset.author,\
                      message
Beispiel #8
0
 def get_timeline_events(self, req, start, stop, filters):
     if 'codereview' in filters:
         crp = CodeReviewPool(self.env)
         for t, author, text, cr_id, status, version, message in \
             crp.get_codereviews_by_time(to_timestamp(start), to_timestamp(stop)):
             if status == str_status["NoNeedToReview"]:
                 continue
             elif status == str_status["CompletelyReview"]:
                 title = Markup(
                     'CodeReview : [ <em title="%s" >%s</em> ] completed by %s'
                     % (message, cr_id, author))
             elif version == 1:
                 title = Markup(
                     'CodeReview : [ <em title="%s" >%s</em> ] created by %s'
                     % (message, cr_id, author))
             else:
                 title = Markup(
                     'CodeReview : [ <em title="%s" >%s</em> ] edited by %s'
                     % (message, cr_id, author))
             href = "%s/%s" % (self.env.href.CodeReview(), cr_id)
             text = wiki_to_oneliner(text,
                                     self.env,
                                     self.env.get_db_cnx(),
                                     shorten=True,
                                     req=req)
             yield 'codereview', href, title, t, author, text
Beispiel #9
0
def get_changes(env, repos, revs, full=None, req=None, format=None):
    db = env.get_db_cnx()
    changes = {}
    for rev in revs:
        changeset = repos.get_changeset(rev)
        message = changeset.message or '--'
        files = None
        if format == 'changelog':
            files = [change[0] for change in changeset.get_changes()]
        elif message:
            if not full:
                message = wiki_to_oneliner(message, env, db,
                                           shorten=True)
            else:
                message = wiki_to_html(message, env, req, db,
                                       absurls=(format == 'rss'),
                                       escape_newlines=True)
        if not message:
            message = '--'
        changes[rev] = {
            'date_seconds': changeset.date,
            'date': format_datetime(changeset.date),
            'age': pretty_timedelta(changeset.date),
            'author': changeset.author or 'anonymous',
            'message': message,
            'shortlog': shorten_line(message),
            'files': files
        }
    return changes
Beispiel #10
0
def attachment_to_hdf(env, req, db, attachment):
    """
    This function have been removed from 0.11, this is copied from 0.10, then modified to 
    work with 0.11
    """
    if not db:
        db = env.get_db_cnx()
    hdf = {
        'filename':
        attachment.filename,
        'description':
        wiki_to_oneliner(attachment.description, env, db, req=req),
        'author':
        attachment.author,
        'ipnr':
        attachment.ipnr,
        'size':
        pretty_size(attachment.size),
        'time':
        format_datetime(attachment.date),
        'age':
        pretty_timedelta(attachment.date),
        'href':
        AttachmentModule(env).get_resource_url(attachment.resource, req.href)
    }
    return hdf
Beispiel #11
0
    def get_timeline_events(self, req, start, stop, filters):
        self.log.debug("start: %s, stop: %s, filters: %s" % (start, stop,
          filters))
        if 'downloads' in filters:
            # Create database context
            db = self.env.get_db_cnx()
            cursor = db.cursor()

            # Get API component.
            api = self.env[DownloadsApi]

            format = req.args.get('format')
            self.log.debug("format: %s" % (format))

            # Get message events
            for download in api.get_new_downloads(req, cursor, start, stop):
                kind = 'newticket'

                title = Markup("New download <em>%s</em> created by %s" %
                  (download['file'], download['author']))
                time = download['time']
                author = download['author']

                if format == 'rss':
                    href = req.abs_href.downloads(download['id'])
                    message = wiki_to_html(download['description'], self.env,
                      req)
                else:
                    href = req.href.downloads(download['id'])
                    message = wiki_to_oneliner(download['description'], self.env)

                yield kind, href, title, time, author, message
Beispiel #12
0
    def get_downloads(self, req, cursor, order_by = 'id', desc = False):
        columns = ('id', 'file', 'description', 'size', 'time', 'count',
          'author', 'tags', 'component', 'version', 'architecture', 'platform',
          'type')
        sql = "SELECT id, file, description, size, time, count, author, tags," \
          " component, version, architecture, platform, type FROM download " \
          "ORDER BY " + order_by + (" ASC", " DESC")[bool(desc)]
        self.log.debug(sql)
        cursor.execute(sql)
        downloads = []
        for row in cursor:
            row = dict(zip(columns, row))
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            row['size'] = pretty_size(row['size'])
            row['time'] = pretty_timedelta(row['time'])
            row['count'] = row['count'] or 0
            downloads.append(row)

        # Replace field ids with apropriate objects.
        for download in downloads:
            download['architecture'] = self.get_architecture(cursor,
              download['architecture'])
            download['platform'] = self.get_platform(cursor,
              download['platform'])
            download['type'] = self.get_type(cursor, download['type'])
        return downloads
Beispiel #13
0
 def get_timeline_events(self, req, start, stop, filters):
     if 'milestone' in filters:
         format = req.args.get('format')
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute(
             "SELECT completed,name,description FROM milestone "
             "WHERE completed>=%s AND completed<=%s", (
                 start,
                 stop,
             ))
         for completed, name, description in cursor:
             title = Markup('Milestone <em>%s</em> completed', name)
             if format == 'rss':
                 href = req.abs_href.milestone(name)
                 message = wiki_to_html(description,
                                        self.env,
                                        req,
                                        db,
                                        absurls=True)
             else:
                 href = req.href.milestone(name)
                 message = wiki_to_oneliner(description,
                                            self.env,
                                            db,
                                            shorten=True)
             yield 'milestone', href, title, completed, None, message or '--'
Beispiel #14
0
    def get_messages(self,
                     req,
                     cursor,
                     topic,
                     time,
                     order_by='ORDER BY time ASC'):
        columns = ('id', 'replyto', 'time', 'author', 'body')
        sql = "SELECT id, replyto, time, author, body FROM message WHERE" \
          " topic = %s " + order_by
        self.log.debug(sql % (topic, ))
        cursor.execute(sql, (topic, ))
        messagemap = {}
        messages = []
        for row in cursor:
            row = dict(zip(columns, row))
            row['author'] = wiki_to_oneliner(row['author'], self.env)
            row['body'] = wiki_to_html(row['body'], self.env, req)
            if int(row['time']) > time:
                row['new'] = True
            row['time'] = format_datetime(row['time'])
            messagemap[row['id']] = row

            # Add top-level messages to the main list, in order of time
            if row['replyto'] == -1:
                messages.append(row)

        # Second pass, add replies
        for message in messagemap.values():
            if message['replyto'] != -1:
                parent = messagemap[message['replyto']]
                if 'replies' in parent:
                    parent['replies'].append(message)
                else:
                    parent['replies'] = [message]
        return messages
Beispiel #15
0
    def get_messages(self, req, cursor, topic, time, order_by = 'ORDER BY time ASC'):
        columns = ('id', 'replyto', 'time', 'author', 'body')
        sql = "SELECT id, replyto, time, author, body FROM message WHERE" \
          " topic = %s " + order_by
        self.log.debug(sql % (topic,))
        cursor.execute(sql, (topic,))
        messagemap = {}
        messages = []
        for row in cursor:
            row = dict(zip(columns, row))
            row['author'] = wiki_to_oneliner(row['author'], self.env)
            row['body'] = wiki_to_html(row['body'], self.env, req)
            if int(row['time']) > time:
                row['new'] = True
            row['time'] = format_datetime(row['time'])
            messagemap[row['id']] = row

            # Add top-level messages to the main list, in order of time
            if row['replyto'] == -1:
                messages.append(row)

        # Second pass, add replies
        for message in messagemap.values():
            if message['replyto'] != -1:
                parent = messagemap[message['replyto']]
                if 'replies' in parent:
                    parent['replies'].append(message)
                else:
                    parent['replies'] = [message]
        return messages;
Beispiel #16
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()
Beispiel #17
0
    def get_downloads(self, req, cursor, order_by='id', desc=False):
        columns = ('id', 'file', 'description', 'size', 'time', 'count',
                   'author', 'tags', 'component', 'version', 'architecture',
                   'platform', 'type')
        sql = "SELECT id, file, description, size, time, count, author, tags," \
          " component, version, architecture, platform, type FROM download " \
          "ORDER BY " + order_by + (" ASC", " DESC")[bool(desc)]
        self.log.debug(sql)
        cursor.execute(sql)
        downloads = []
        for row in cursor:
            row = dict(zip(columns, row))
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            row['size'] = pretty_size(row['size'])
            row['time'] = pretty_timedelta(row['time'])
            row['count'] = row['count'] or 0
            downloads.append(row)

        # Replace field ids with apropriate objects.
        for download in downloads:
            download['architecture'] = self.get_architecture(
                cursor, download['architecture'])
            download['platform'] = self.get_platform(cursor,
                                                     download['platform'])
            download['type'] = self.get_type(cursor, download['type'])
        return downloads
Beispiel #18
0
    def get_messages(self, req, cursor, topic_id, time, order_by = 'time', desc = False):
        order_by = 'm.' + order_by
        columns = ('id', 'replyto', 'time', 'author', 'body')
        sql = "SELECT m.id, m.replyto, m.time, m.author, m.body FROM message m WHERE" \
          " m.topic = %s ORDER BY " + order_by + (" ASC", " DESC")[bool(desc)]
        self.log.debug(sql % (topic_id,))
        cursor.execute(sql, (topic_id,))
        messagemap = {}
        messages = []
        for row in cursor:
            row = dict(zip(columns, row))
            row['author'] = wiki_to_oneliner(row['author'], self.env)
            row['body'] = wiki_to_html(row['body'], self.env, req, None, False, True)
            if int(row['time']) > time:
                row['new'] = True
            row['time'] = format_datetime(row['time'])
            messagemap[row['id']] = row

            # Add top-level messages to the main list, in order of time
            if row['replyto'] == -1:
                messages.append(row)

        # Second pass, add replies
        for message in messagemap.values():
            if message['replyto'] != -1:
                parent = messagemap[message['replyto']]
                if 'replies' in parent:
                    parent['replies'].append(message)
                else:
                    parent['replies'] = [message]
        return messages;
Beispiel #19
0
    def get_timeline_events(self, req, start, stop, filters):
        self.log.debug("start: %s, stop: %s, filters: %s" % (start, stop, filters))
        if "downloads" in filters:
            # Create database context
            db = self.env.get_db_cnx()
            cursor = db.cursor()

            #  Get API component.
            api = self.env[DownloadsApi]

            format = req.args.get("format")
            self.log.debug("format: %s" % (format))

            # Get message events
            for download in api.get_new_downloads(req, cursor, start, stop):
                kind = "newticket"

                title = Markup("New download <em>%s</em> created by %s" % (download["file"], download["author"]))
                time = download["time"]
                author = download["author"]

                if format == "rss":
                    href = req.abs_href.downloads(download["id"])
                    message = wiki_to_html(download["description"], self.env, req)
                else:
                    href = req.href.downloads(download["id"])
                    message = wiki_to_oneliner(download["description"], self.env)

                yield kind, href, title, time, author, message
Beispiel #20
0
 def get_topics(self, req, cursor, forum_id, order_by = 'time', desc = False):
     if not order_by in ('replies', 'lastreply',):
         order_by = 't.' + order_by
     columns = ('id', 'forum', 'time', 'subject', 'body', 'author',
       'replies', 'lastreply')
     sql = "SELECT t.id, t.forum, t.time, t.subject, t.body, t.author," \
       " m.replies, m.lastreply FROM topic t LEFT JOIN (SELECT COUNT(id)" \
       " AS replies, MAX(time) AS lastreply, topic FROM message GROUP BY" \
       " topic) m ON t.id = m.topic WHERE t.forum = %s ORDER BY " \
       + order_by + (" ASC", " DESC")[bool(desc)]
     self.log.debug(sql % (forum_id,))
     cursor.execute(sql, (forum_id,))
     topics = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         row['body'] = wiki_to_html(row['body'], self.env, req)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(float(row['lastreply']))
         else:
             row['lastreply'] = 'No replies'
         if not row['replies']:
             row['replies'] = 0
         row['time'] = format_datetime(row['time'])
         topics.append(row)
     return topics
Beispiel #21
0
 def get_topics(self, req, cursor, forum_id, order_by='time', desc=False):
     if not order_by in (
             'replies',
             'lastreply',
     ):
         order_by = 't.' + order_by
     columns = ('id', 'forum', 'time', 'subject', 'body', 'author',
                'replies', 'lastreply')
     sql = "SELECT t.id, t.forum, t.time, t.subject, t.body, t.author," \
       " m.replies, m.lastreply FROM topic t LEFT JOIN (SELECT COUNT(id)" \
       " AS replies, MAX(time) AS lastreply, topic FROM message GROUP BY" \
       " topic) m ON t.id = m.topic WHERE t.forum = %s ORDER BY " \
       + order_by + (" ASC", " DESC")[bool(desc)]
     self.log.debug(sql % (forum_id, ))
     cursor.execute(sql, (forum_id, ))
     topics = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         row['body'] = wiki_to_html(row['body'], self.env, req)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(float(row['lastreply']))
         else:
             row['lastreply'] = 'No replies'
         if not row['replies']:
             row['replies'] = 0
         row['time'] = format_datetime(row['time'])
         topics.append(row)
     return topics
Beispiel #22
0
    def get_timeline_events(self, req, start, stop, filters):
        format = req.args.get('format')

        status_map = {
            'new': ('newticket', u'créé'),
            'reopened': ('newticket', u'réouvert'),
            'closed': ('closedticket', u'fermé'),
            'edit': ('editedticket', u'mis à jour')
        }

        href = format == 'rss' and req.abs_href or req.href

        def produce(
            (id, t, author, type, summary), status, fields, comment, cid):
            if status == 'edit':
                if 'ticket_details' in filters:
                    info = u''
                    if len(fields) > 0:
                        info = u', '.join([u'<i>%s</i>' % f for f in \
                                          fields.keys()]) + u' modifié<br />'
                else:
                    return None
            elif 'ticket' in filters:
                if status == 'closed' and fields.has_key('resolution'):
                    info = fields['resolution']
                    if info and comment:
                        info = '%s: ' % info
                else:
                    info = ''
            else:
                return None
            kind, verb = status_map[status]
            if format == 'rss':
                title = u'Ticket #%s (%s %s): %s' % \
                        (id, translate(self.env, type).lower(), verb, summary)
            else:
                title = Markup(
                    u'Ticket <em title="%s">#%s</em> (%s) %s par %s', summary,
                    id, translate(self.env, type), verb, author)
            ticket_href = href.ticket(id)
            if cid:
                ticket_href += '#comment:' + cid
            if status == 'new':
                message = unicode(summary)
            else:
                message = Markup(info)
                if comment:
                    if format == 'rss':
                        message += wiki_to_html(comment,
                                                self.env,
                                                req,
                                                db,
                                                absurls=True)
                    else:
                        message += wiki_to_oneliner(comment,
                                                    self.env,
                                                    db,
                                                    shorten=True)
            return kind, ticket_href, title, t, author, message
Beispiel #23
0
    def _prepare_message_list(self, req, cursor, topic):
        # Get form values.
        new_author = req.args.get('author')
        new_subject = req.args.get('subject')
        new_body = req.args.get('body')

        # Get time when topic was visited from session.
        visited = eval(req.session.get('visited-topics') or '{}')
        if visited.has_key(topic['id']):
            visit_time = int(visited[topic['id']])
        else:
            visit_time = 0

        # Update this topic visit time and save to session.
        visited[topic['id']] = int(time.time())
        req.session['visited-topics'] = to_unicode(visited)

        # Mark new topic.
        if int(topic['time']) > visit_time:
            topic['new'] = True

        # Prepare display of topic
        if new_author:
            req.hdf['discussion.author'] = wiki_to_oneliner(new_author,
              self.env)
        if new_subject:
            req.hdf['discussion.subject'] = wiki_to_oneliner(new_subject,
              self.env)
        if new_body:
            req.hdf['discussion.body'] = wiki_to_html(new_body, self.env, req)

        # Prepare display of messages
        display = req.session.get('message-list-display') or \
          self.default_display
        req.hdf['discussion.display'] = display
        if display == 'flat-asc':
            req.hdf['discussion.messages'] = self.get_flat_messages(req, cursor,
              topic['id'], visit_time)
        elif display == 'flat-desc' or display == 'flat':
            req.hdf['discussion.messages'] = self.get_flat_messages(req, cursor,
              topic['id'], visit_time, 'ORDER BY time DESC')
        elif display == 'tree' or display == '':
            req.hdf['discussion.messages'] = self.get_messages(req, cursor,
             topic['id'], visit_time)
        else:
            raise TracError('Unsupported display mode: %s' % (display))
Beispiel #24
0
    def _prepare_message_list(self, req, cursor, topic):
        # Get form values.
        new_author = req.args.get('author')
        new_subject = req.args.get('subject')
        new_body = req.args.get('body')

        # Get time when topic was visited from session.
        visited = eval(req.session.get('visited-topics') or '{}')
        if visited.has_key(topic['id']):
            visit_time = int(visited[topic['id']])
        else:
            visit_time = 0

        # Update this topic visit time and save to session.
        visited[topic['id']] = int(time.time())
        req.session['visited-topics'] = to_unicode(visited)

        # Mark new topic.
        if int(topic['time']) > visit_time:
            topic['new'] = True

        # Prepare display of topic
        if new_author:
            req.hdf['discussion.author'] = wiki_to_oneliner(
                new_author, self.env)
        if new_subject:
            req.hdf['discussion.subject'] = wiki_to_oneliner(
                new_subject, self.env)
        if new_body:
            req.hdf['discussion.body'] = wiki_to_html(new_body, self.env, req)

        # Prepare display of messages
        display = req.session.get('message-list-display') or \
          self.default_display
        req.hdf['discussion.display'] = display
        if display == 'flat-asc':
            req.hdf['discussion.messages'] = self.get_flat_messages(
                req, cursor, topic['id'], visit_time)
        elif display == 'flat-desc' or display == 'flat':
            req.hdf['discussion.messages'] = self.get_flat_messages(
                req, cursor, topic['id'], visit_time, 'ORDER BY time DESC')
        elif display == 'tree' or display == '':
            req.hdf['discussion.messages'] = self.get_messages(
                req, cursor, topic['id'], visit_time)
        else:
            raise TracError('Unsupported display mode: %s' % (display))
Beispiel #25
0
    def render_discussion(self, req):
        # Get request mode
        group, forum, topic, message = self._get_items(req)
        modes = self._get_modes(req, group, forum, topic, message)
        self.log.debug('modes: %s' % modes)

        # Determine moderator rights.
        if forum:
            is_moderator = (req.authname in forum['moderators']) or \
              req.perm.has_permission('DISCUSSION_ADMIN')
        else:
            is_moderator = req.perm.has_permission('DISCUSSION_ADMIN')

        # Perform mode actions
        self._do_action(req, modes, group, forum, topic, message, is_moderator)

        # Add CSS styles
        add_stylesheet(req, 'common/css/wiki.css')
        add_stylesheet(req, 'discussion/css/discussion.css')
        add_stylesheet(req, 'discussion/css/admin.css')

        add_link(req, 'alternate', '/timeline?discussion=on&amp;max=50&amp;daysback=90&amp;format=rss', 'POPFile forums', 'application/rss+xml')

        # Fill up HDF structure and return template
        req.hdf['discussion.authname'] = req.authname
        req.hdf['discussion.is_moderator'] = is_moderator
        title = 'POPFile Forums'
        if group:
            group['name'] = wiki_to_oneliner(group['name'], self.env)
            group['description'] = wiki_to_oneliner(group['description'],
              self.env)
            req.hdf['discussion.group'] = group
        if forum:
            forum['name'] = wiki_to_oneliner(forum['name'], self.env)
            forum['description'] = wiki_to_oneliner(forum['description'],
              self.env)
            forum['subject'] = wiki_to_oneliner(forum['subject'], self.env)
            forum['time'] = format_datetime(forum['time'])
            req.hdf['discussion.forum'] = forum
            title = 'POPFile ' + forum['name'] + ' Forum'
        if topic:
            topic['subject'] = wiki_to_oneliner(topic['subject'], self.env)
            topic['author'] = wiki_to_oneliner(topic['author'], self.env)
            topic['body'] = wiki_to_html(topic['body'], self.env, req, None, False, True)
            topic['time'] = format_datetime(topic['time'])
            req.hdf['discussion.topic'] = topic
        if message:
            message['author'] = wiki_to_oneliner(message['author'], self.env)
            message['body'] = wiki_to_html(message['body'], self.env, req, None, False, True)
            message['time'] = format_datetime(message['time'])
            req.hdf['discussion.message'] = message
        req.hdf['discussion.mode'] = modes[-1]
        req.hdf['discussion.time'] = format_datetime(time.time())
        req.hdf['title'] = title

        return modes[-1] + '.cs', None
Beispiel #26
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()
Beispiel #27
0
 def get_screenshots(self, cursor, component, version):
     columns = ('id', 'name', 'description', 'time', 'author', 'tags',
                'large_file', 'medium_file', 'small_file')
     sql = "SELECT s.id, s.name, s.description, s.time, s.author, s.tags," \
       " s.large_file, s.medium_file, s.small_file FROM screenshot s," \
       " screenshot_component c, screenshot_version v WHERE c.component" \
       " = %s AND v.version = %s AND s.id = c.screenshot AND s.id =" \
       " v.screenshot;"
     self.log.debug(sql % (component, version))
     cursor.execute(sql, (component, version))
     screenshots = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['name'] = wiki_to_oneliner(row['name'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         screenshots.append(row)
     return screenshots
Beispiel #28
0
 def get_screenshots(self, cursor, component, version):
     columns = ('id', 'name', 'description', 'time', 'author', 'tags',
       'large_file', 'medium_file', 'small_file')
     sql = "SELECT s.id, s.name, s.description, s.time, s.author, s.tags," \
       " s.large_file, s.medium_file, s.small_file FROM screenshot s," \
       " screenshot_component c, screenshot_version v WHERE c.component" \
       " = %s AND v.version = %s AND s.id = c.screenshot AND s.id =" \
       " v.screenshot;"
     self.log.debug(sql % (component, version))
     cursor.execute(sql, (component, version))
     screenshots = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['name'] = wiki_to_oneliner(row['name'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         screenshots.append(row)
     return screenshots
Beispiel #29
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()
    def get_task_markup(self, req, ticket, task):
        if not task:
            return ''

        ticket_text = 'ticket #' + str(task['ticket'])
        if task['ticket'] == ticket:
            ticket_text = 'this ticket'
        timedelta = pretty_timedelta(task['starttime'], None);

        return '<li>%s</li>' % wiki_to_oneliner('You have been working on %s for %s' % (ticket_text, timedelta), self.env, req=req)
Beispiel #31
0
    def get_timeline_events(self, req, start, stop, filters):
        format = req.args.get('format')

        status_map = {
            'new': ('newticket', u'créé'),
            'reopened': ('newticket', u'réouvert'),
            'closed': ('closedticket', u'fermé'),
            'edit': ('editedticket', u'mis à jour')
        }

        href = format == 'rss' and req.abs_href or req.href

        def produce((id, t, author, type, summary), status, fields, comment,
                    cid):
            if status == 'edit':
                if 'ticket_details' in filters:
                    info = u''
                    if len(fields) > 0:
                        info = u', '.join([u'<i>%s</i>' % f for f in \
                                          fields.keys()]) + u' modifié<br />'
                else:
                    return None
            elif 'ticket' in filters:
                if status == 'closed' and fields.has_key('resolution'):
                    info = fields['resolution']
                    if info and comment:
                        info = '%s: ' % info
                else:
                    info = ''
            else:
                return None
            kind, verb = status_map[status]
            if format == 'rss':
                title = u'Ticket #%s (%s %s): %s' % \
                        (id, translate(self.env, type).lower(), verb, summary)
            else:
                title = Markup(
                    u'Ticket <em title="%s">#%s</em> (%s) %s par %s', summary,
                    id, translate(self.env, type), verb, author)
            ticket_href = href.ticket(id)
            if cid:
                ticket_href += '#comment:' + cid
            if status == 'new':
                message = unicode(summary)
            else:
                message = Markup(info)
                if comment:
                    if format == 'rss':
                        message += wiki_to_html(
                            comment, self.env, req, db, absurls=True)
                    else:
                        message += wiki_to_oneliner(
                            comment, self.env, db, shorten=True)
            return kind, ticket_href, title, t, author, message
Beispiel #32
0
    def render_discussion(self, req, cursor):
        # Get request mode
        group, forum, topic, message = self._get_items(req, cursor)
        modes = self._get_modes(req, group, forum, topic, message)
        self.log.debug('modes: %s' % modes)

        # Determine moderator rights.
        if forum:
            is_moderator = (req.authname in forum['moderators']) or \
              req.perm.has_permission('DISCUSSION_ADMIN')
        else:
            is_moderator = req.perm.has_permission('DISCUSSION_ADMIN')

        # Perform mode actions
        self._do_action(req, cursor, modes, group, forum, topic, message,
                        is_moderator)

        # Add CSS styles
        add_stylesheet(req, 'common/css/wiki.css')
        add_stylesheet(req, 'discussion/css/discussion.css')
        add_stylesheet(req, 'discussion/css/admin.css')

        # Fill up HDF structure and return template
        req.hdf['discussion.authname'] = req.authname
        req.hdf['discussion.is_moderator'] = is_moderator
        if group:
            group['name'] = wiki_to_oneliner(group['name'], self.env)
            group['description'] = wiki_to_oneliner(group['description'],
                                                    self.env)
            req.hdf['discussion.group'] = group
        if forum:
            forum['name'] = wiki_to_oneliner(forum['name'], self.env)
            forum['description'] = wiki_to_oneliner(forum['description'],
                                                    self.env)
            forum['subject'] = wiki_to_oneliner(forum['subject'], self.env)
            forum['time'] = format_datetime(forum['time'])
            req.hdf['discussion.forum'] = forum
        if topic:
            topic['subject'] = wiki_to_oneliner(topic['subject'], self.env)
            topic['author'] = wiki_to_oneliner(topic['author'], self.env)
            topic['body'] = wiki_to_html(topic['body'], self.env, req)
            topic['time'] = format_datetime(topic['time'])
            req.hdf['discussion.topic'] = topic
        if message:
            message['author'] = wiki_to_oneliner(message['author'], self.env)
            message['body'] = wiki_to_html(message['body'], self.env, req)
            message['time'] = format_datetime(message['time'])
            req.hdf['discussion.message'] = message
        req.hdf['discussion.mode'] = modes[-1]
        req.hdf['discussion.time'] = format_datetime(time.time())
        return modes[-1] + '.cs', None
Beispiel #33
0
 def get_forums(self, req, cursor, order_by = 'subject', desc = False):
     if not order_by in ('topics', 'replies', 'lasttopic', 'lastreply'):
         order_by = 'f.' + order_by
     columns = ('id', 'name', 'author', 'time', 'moderators', 'group',
       'subject', 'description', 'topics', 'replies', 'lasttopic',
       'lastreply')
     sql = "SELECT f.id, f.name, f.author, f.time, f.moderators, " \
       "f.forum_group, f.subject, f.description, ta.topics, ta.replies, " \
       "ta.lasttopic, ta.lastreply FROM forum f LEFT JOIN (SELECT " \
       "COUNT(t.id) AS topics, MAX(t.time) AS lasttopic, SUM(ma.replies) " \
       "AS replies, MAX(ma.lastreply) AS lastreply, t.forum AS forum FROM " \
       " topic t LEFT JOIN (SELECT COUNT(m.id) AS replies, MAX(m.time) AS " \
       "lastreply, m.topic AS topic FROM message m GROUP BY m.topic) ma ON " \
       "t.id = ma.topic GROUP BY forum) ta ON f.id = ta.forum ORDER BY " + \
       order_by + (" ASC", " DESC")[bool(desc)]
     self.log.debug(sql)
     cursor.execute(sql)
     forums = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['moderators'] = wiki_to_oneliner(row['moderators'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(float(row['lastreply']))
         else:
             row['lastreply'] = 'No replies'
         if row['lasttopic']:
             self.log.debug('lasttopic: %s' % row['lasttopic'])
             row['lasttopic'] = pretty_timedelta(float(row['lasttopic']))
         else:
             row['lasttopic'] = 'No topics'
         if not row['topics']:
             row['topics'] = 0
         if not row['replies']:
             row['replies'] = 0
         else:
             # SUM on PosgreSQL returns float number.
             row['replies'] = int(row['replies'])
         row['time'] = format_datetime(row['time'])
         forums.append(row)
     return forums
Beispiel #34
0
    def render_discussion(self, req, cursor):
        # Get request mode
        group, forum, topic, message = self._get_items(req, cursor)
        modes = self._get_modes(req, group, forum, topic, message)
        self.log.debug('modes: %s' % modes)

        # Determine moderator rights.
        if forum:
            is_moderator = (req.authname in forum['moderators']) or \
              req.perm.has_permission('DISCUSSION_ADMIN')
        else:
            is_moderator = req.perm.has_permission('DISCUSSION_ADMIN')

        # Perform mode actions
        self._do_action(req, cursor, modes, group, forum, topic, message,
          is_moderator)

        # Add CSS styles
        add_stylesheet(req, 'common/css/wiki.css')
        add_stylesheet(req, 'discussion/css/discussion.css')
        add_stylesheet(req, 'discussion/css/admin.css')

        # Fill up HDF structure and return template
        req.hdf['discussion.authname'] = req.authname
        req.hdf['discussion.is_moderator'] = is_moderator
        if group:
            group['name'] = wiki_to_oneliner(group['name'], self.env)
            group['description'] = wiki_to_oneliner(group['description'],
              self.env)
            req.hdf['discussion.group'] = group
        if forum:
            forum['name'] = wiki_to_oneliner(forum['name'], self.env)
            forum['description'] = wiki_to_oneliner(forum['description'],
              self.env)
            forum['subject'] = wiki_to_oneliner(forum['subject'], self.env)
            forum['time'] = format_datetime(forum['time'])
            req.hdf['discussion.forum'] = forum
        if topic:
            topic['subject'] = wiki_to_oneliner(topic['subject'], self.env)
            topic['author'] = wiki_to_oneliner(topic['author'], self.env)
            topic['body'] = wiki_to_html(topic['body'], self.env, req)
            topic['time'] = format_datetime(topic['time'])
            req.hdf['discussion.topic'] = topic
        if message:
            message['author'] = wiki_to_oneliner(message['author'], self.env)
            message['body'] = wiki_to_html(message['body'], self.env, req)
            message['time'] = format_datetime(message['time'])
            req.hdf['discussion.message'] = message
        req.hdf['discussion.mode'] = modes[-1]
        req.hdf['discussion.time'] = format_datetime(time.time())
        return modes[-1] + '.cs', None
Beispiel #35
0
 def get_forums(self, req, cursor, asc=0, order_by='subject'):
     if not order_by in ('topics', 'replies', 'lasttopic', 'lastreply'):
         order_by = 'f.' + order_by
     columns = ('id', 'name', 'author', 'time', 'moderators', 'group',
                'subject', 'description', 'topics', 'replies', 'lasttopic',
                'lastreply')
     sql = "SELECT f.id, f.name, f.author, f.time, f.moderators, " \
       "f.forum_group, f.subject, f.description, ta.topics, ta.replies, " \
       "ta.lasttopic, ta.lastreply FROM forum f LEFT JOIN (SELECT " \
       "COUNT(t.id) AS topics, MAX(t.time) AS lasttopic, SUM(ma.replies) " \
       "AS replies, MAX(ma.lastreply) AS lastreply, t.forum AS forum FROM " \
       " topic t LEFT JOIN (SELECT COUNT(m.id) AS replies, MAX(m.time) AS " \
       "lastreply, m.topic AS topic FROM message m GROUP BY m.topic) ma ON " \
       "t.id = ma.topic GROUP BY forum) ta ON f.id = ta.forum ORDER BY " + \
       order_by + (" DESC", " ASC")[int(asc)]
     self.log.debug(sql)
     cursor.execute(sql)
     forums = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['moderators'] = wiki_to_oneliner(row['moderators'], self.env)
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(float(row['lastreply']))
         else:
             row['lastreply'] = 'No replies'
         if row['lasttopic']:
             self.log.debug('lasttopic: %s' % row['lasttopic'])
             row['lasttopic'] = pretty_timedelta(float(row['lasttopic']))
         else:
             row['lasttopic'] = 'No topics'
         if not row['topics']:
             row['topics'] = 0
         if not row['replies']:
             row['replies'] = 0
         else:
             # SUM on PosgreSQL returns float number.
             row['replies'] = int(row['replies'])
         row['time'] = format_datetime(row['time'])
         forums.append(row)
     return forums
Beispiel #36
0
 def get_types(self, req, cursor, order_by='id', desc=False):
     columns = ('id', 'name', 'description')
     sql = "SELECT id, name, description FROM download_type ORDER BY " + \
       order_by + (" ASC", " DESC")[bool(desc)]
     self.log.debug(sql)
     cursor.execute(sql)
     types = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         types.append(row)
     return types
Beispiel #37
0
 def _get_messages(self, req, cursor):
     cursor.execute("SELECT id, author, time, title, body FROM guestbook"
       " ORDER BY time")
     columns = ['id', 'author', 'time', 'title', 'body']
     messages = []
     for message in cursor:
         message = dict(zip(columns, message))
         message['time'] =  format_datetime(message['time'])
         message['title'] = wiki_to_oneliner(message['title'], self.env)
         message['body'] = wiki_to_html(message['body'], self.env, req)
         messages.append(message)
     return messages
Beispiel #38
0
 def _get_messages(self, req, cursor):
     cursor.execute("SELECT id, author, time, title, body FROM guestbook"
                    " ORDER BY time")
     columns = ['id', 'author', 'time', 'title', 'body']
     messages = []
     for message in cursor:
         message = dict(zip(columns, message))
         message['time'] = format_datetime(message['time'])
         message['title'] = wiki_to_oneliner(message['title'], self.env)
         message['body'] = wiki_to_html(message['body'], self.env, req)
         messages.append(message)
     return messages
Beispiel #39
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'ticket_details' in filters:
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute(
                "SELECT tc.time,tc.ticket,t.type,tc.field, "
                "       tc.oldvalue,tc.newvalue,tc.author,t.summary "
                "FROM ticket_change tc"
                "   INNER JOIN ticket t ON t.id = tc.ticket "
                "AND tc.time>=%s AND tc.time<=%s ORDER BY tc.time" %
                (start, stop))
            previous_update = None
            updates = []
            ticket_change = False
            for time, id, type, field, oldvalue, newvalue, author, summary in cursor:
                if not previous_update or (time, id,
                                           author) != previous_update[:3]:
                    if previous_update and not ticket_change:
                        updates.append(
                            (previous_update, field_changes, comment))
                    ticket_change = False
                    field_changes = []
                    comment = ''
                    previous_update = (time, id, author, type, summary)
                if field == 'comment':
                    comment = newvalue
                elif field == 'status' and newvalue in ['reopened', 'closed']:
                    ticket_change = True
                else:
                    field_changes.append(field)
            if previous_update and not ticket_change:
                updates.append((previous_update, field_changes, comment))

            absurls = req.args.get('format') == 'rss'  # Kludge
            for (t, id, author, type,
                 summary), field_changes, comment in updates:
                if absurls:
                    href = self.env.abs_href.ticket(id)
                else:
                    href = self.env.href.ticket(id)
                title = util.Markup(
                    'Ticket <em title="%s">#%s</em> (%s) '
                    'updated by %s', summary, id, type, author)
                message = util.Markup()
                if len(field_changes) > 0:
                    message = util.Markup(', '.join(field_changes) + \
                                          ' changed.<br />')
                message += wiki_to_oneliner(comment,
                                            self.env,
                                            db,
                                            shorten=True,
                                            absurls=absurls)
                yield 'editedticket', href, title, t, author, message
Beispiel #40
0
 def get_types(self, req, cursor, order_by = 'id', desc = False):
     columns = ('id', 'name', 'description')
     sql = "SELECT id, name, description FROM download_type ORDER BY " + \
       order_by + (" ASC", " DESC")[bool(desc)]
     self.log.debug(sql)
     cursor.execute(sql)
     types = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['description'] = wiki_to_oneliner(row['description'],
           self.env)
         types.append(row)
     return types
Beispiel #41
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()
Beispiel #42
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'changeset' in filters:
            format = req.args.get('format')
            show_files = int(
                self.config.get('timeline', 'changeset_show_files'))
            db = self.env.get_db_cnx()
            repos = self.env.get_repository()
            authzperm = SubversionAuthorizer(self.env, req.authname)
            rev = repos.youngest_rev
            while rev:
                if not authzperm.has_permission_for_changeset(rev):
                    rev = repos.previous_rev(rev)
                    continue

                chgset = repos.get_changeset(rev)
                if chgset.date < start:
                    return
                if chgset.date < stop:
                    message = chgset.message or '--'
                    if format == 'rss':
                        title = util.Markup('Changeset <em>[%s]</em>: %s',
                                            chgset.rev,
                                            util.shorten_line(message))
                        href = self.env.abs_href.changeset(chgset.rev)
                        message = wiki_to_html(message,
                                               self.env,
                                               req,
                                               db,
                                               absurls=True)
                    else:
                        title = util.Markup('Changeset <em>[%s]</em> by %s',
                                            chgset.rev, chgset.author)
                        href = self.env.href.changeset(chgset.rev)
                        message = wiki_to_oneliner(message,
                                                   self.env,
                                                   db,
                                                   shorten=True)
                    if show_files:
                        files = []
                        for chg in chgset.get_changes():
                            if show_files > 0 and len(files) >= show_files:
                                files.append('...')
                                break
                            files.append('<span class="%s">%s</span>' %
                                         (chg[2], util.escape(chg[0])))
                        message = '<span class="changes">' + ', '.join(files) +\
                                  '</span>: ' + message
                    yield 'changeset', href, title, chgset.date, chgset.author,\
                          util.Markup(message)
                rev = repos.previous_rev(rev)
Beispiel #43
0
 def get_components(self, req, cursor):
     columns = ('name', 'description')
     sql = "SELECT name, description FROM component"
     self.log.debug(sql)
     cursor.execute(sql)
     components = []
     id = 0
     for row in cursor:
         row = dict(zip(columns, row))
         row['description'] = wiki_to_oneliner(row['description'], self.env)
         id = id + 1
         row['id'] = id
         components.append(row)
     return components
Beispiel #44
0
def attachment_to_hdf(env, db, req, attachment):
    from trac.wiki import wiki_to_oneliner
    if not db:
        db = env.get_db_cnx()
    hdf = {
        'filename': attachment.filename,
        'description': wiki_to_oneliner(attachment.description, env, db),
        'author': util.escape(attachment.author),
        'ipnr': attachment.ipnr,
        'size': util.pretty_size(attachment.size),
        'time': time.strftime('%c', time.localtime(attachment.time)),
        'href': attachment.href()
    }
    return hdf
Beispiel #45
0
    def get_groups(self, req, cursor, order_by = 'ORDER BY id ASC'):
        # Get count of forums without group
        sql = "SELECT COUNT(id) FROM forum WHERE forum_group = 0"
        self.log.debug(sql)
        cursor.execute(sql)
        no_group_forums = 0
        for row in cursor:
            no_group_forums = row[0]
        groups = [{'id' : 0, 'name' : 'None', 'description' : 'No Group',
          'forums' : no_group_forums}]

        # Get forum groups
        columns = ('id', 'name', 'description', 'forums')
        sql = "SELECT id, name, description, (SELECT COUNT(id) FROM forum f" \
          " WHERE f.forum_group = forum_group.id) FROM forum_group " + order_by
        self.log.debug(sql)
        cursor.execute(sql)
        for row in cursor:
            row = dict(zip(columns, row))
            row['name'] = wiki_to_oneliner(row['name'], self.env)
            row['description'] = wiki_to_oneliner(row['description'], self.env)
            groups.append(row)
        return groups
Beispiel #46
0
def get_changes(env, repos, revs, full=None, req=None, format=None):
    db = env.get_db_cnx()
    changes = {}
    for rev in revs:
        try:
            changeset = repos.get_changeset(rev)
        except NoSuchChangeset:
            changes[rev] = {}
            continue

        wiki_format = env.config['changeset'].getbool('wiki_format_messages')
        message = changeset.message or '--'
        absurls = (format == 'rss')
        if wiki_format:
            shortlog = wiki_to_oneliner(message,
                                        env,
                                        db,
                                        shorten=True,
                                        absurls=absurls)
        else:
            shortlog = Markup.escape(shorten_line(message))

        if full:
            if wiki_format:
                message = wiki_to_html(message,
                                       env,
                                       req,
                                       db,
                                       absurls=absurls,
                                       escape_newlines=True)
            else:
                message = html.PRE(message)
        else:
            message = shortlog

        if format == 'rss':
            if isinstance(shortlog, Markup):
                shortlog = shortlog.plaintext(keeplinebreaks=False)
            message = unicode(message)

        changes[rev] = {
            'date_seconds': changeset.date,
            'date': format_datetime(changeset.date),
            'age': pretty_timedelta(changeset.date),
            'author': changeset.author or 'anonymous',
            'message': message,
            'shortlog': shortlog,
        }
    return changes
Beispiel #47
0
 def get_components(self, cursor):
     columns = ('name', 'description')
     sql = "SELECT name, description FROM component"
     self.log.debug(sql)
     cursor.execute(sql)
     components = []
     id = 0
     for row in cursor:
         row = dict(zip(columns, row))
         row['description'] = wiki_to_oneliner(row['description'],
           self.env)
         id = id + 1
         row['id'] = id
         components.append(row)
     return components
Beispiel #48
0
 def get_timeline_events(self, req, start, stop, filters):
     if 'codereview' in filters:
         crp = CodeReviewPool(self.env)
         for t, author, text, cr_id, status, version, message in crp.get_codereviews_by_time(start, stop):
             if status == str_status["NoNeedToReview"]:
                 continue
             elif status == str_status["CompletelyReview"]:
                 title = Markup('CodeReview : [ <em title="%s" >%s</em> ] completed by %s', message, cr_id, author)
             elif version == 1:
                 title = Markup('CodeReview : [ <em title="%s" >%s</em> ] created by %s', message, cr_id, author)
             else:
                 title = Markup('CodeReview : [ <em title="%s" >%s</em> ] edited by %s', message, cr_id, author)
             href = "%s/%s" % (self.env.href.CodeReview(), cr_id)
             text = wiki_to_oneliner(text, self.env, self.env.get_db_cnx(), shorten=True)
             yield 'codereview', href, title, t, author, text
Beispiel #49
0
 def get_flat_messages(self, req, cursor, topic, time, order_by =
   'ORDER BY time ASC'):
     columns = ('id', 'replyto', 'time', 'author', 'body')
     sql = "SELECT id, replyto, time, author, body FROM message WHERE" \
       " topic = %s " + order_by
     self.log.debug(sql % (topic,))
     cursor.execute(sql, (topic,))
     messages = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         row['body'] = wiki_to_html(row['body'], self.env, req)
         if int(row['time']) > time:
             row['new'] = True
         row['time'] = format_datetime(row['time'])
         messages.append(row)
     return messages
Beispiel #50
0
 def get_flat_messages(self, req, cursor, topic_id, time, order_by =
   'ORDER BY time ASC'):
     columns = ('id', 'replyto', 'time', 'author', 'body')
     sql = "SELECT m.id, m.replyto, m.time, m.author, m.body FROM message m" \
       " WHERE m.topic = %s " + order_by
     self.log.debug(sql % (topic_id,))
     cursor.execute(sql, (topic_id,))
     messages = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         row['body'] = wiki_to_html(row['body'], self.env, req, None, False, True)
         if int(row['time']) > time:
             row['new'] = True
         row['time'] = format_datetime(row['time'])
         messages.append(row)
     return messages
Beispiel #51
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()
Beispiel #52
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'ticket_details' in filters:
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute("SELECT tc.time,tc.ticket,t.type,tc.field, "
                           "       tc.oldvalue,tc.newvalue,tc.author,t.summary "
                           "FROM ticket_change tc"
                           "   INNER JOIN ticket t ON t.id = tc.ticket "
                           "AND tc.time>=%s AND tc.time<=%s ORDER BY tc.time"
                           % (start, stop))
            previous_update = None
            updates = []
            ticket_change = False
            for time,id,type,field,oldvalue,newvalue,author,summary in cursor:
                if not previous_update or (time,id,author) != previous_update[:3]:
                    if previous_update and not ticket_change:
                        updates.append((previous_update,field_changes,comment))
                    ticket_change = False
                    field_changes = []
                    comment = ''
                    previous_update = (time,id,author,type,summary)
                if field == 'comment':
                    comment = newvalue
                elif field == 'status' and newvalue in ['reopened', 'closed']:
                    ticket_change = True
                else:
                    field_changes.append(field)
            if previous_update and not ticket_change:
                updates.append((previous_update,field_changes,comment))

            absurls = req.args.get('format') == 'rss' # Kludge
            for (t,id,author,type,summary),field_changes,comment in updates:
                if absurls:
                    href = self.env.abs_href.ticket(id)
                else:
                    href = self.env.href.ticket(id) 
                title = util.Markup('Ticket <em title="%s">#%s</em> (%s) '
                                    'updated by %s', summary, id, type, author)
                message = util.Markup()
                if len(field_changes) > 0:
                    message = util.Markup(', '.join(field_changes) + \
                                          ' changed.<br />')
                message += wiki_to_oneliner(comment, self.env, db,
                                            shorten=True, absurls=absurls)
                yield 'editedticket', href, title, t, author, message
Beispiel #53
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'changeset' in filters:
            format = req.args.get('format')
            show_files = int(self.config.get('timeline',
                                             'changeset_show_files'))
            db = self.env.get_db_cnx()
            repos = self.env.get_repository()
            authzperm = SubversionAuthorizer(self.env, req.authname)
            rev = repos.youngest_rev
            while rev:
                if not authzperm.has_permission_for_changeset(rev):
                    rev = repos.previous_rev(rev)
                    continue

                chgset = repos.get_changeset(rev)
                if chgset.date < start:
                    return
                if chgset.date < stop:
                    message = chgset.message or '--'
                    if format == 'rss':
                        title = util.Markup('Changeset <em>[%s]</em>: %s',
                                            chgset.rev,
                                            util.shorten_line(message))
                        href = self.env.abs_href.changeset(chgset.rev)
                        message = wiki_to_html(message, self.env, req, db,
                                               absurls=True)
                    else:
                        title = util.Markup('Changeset <em>[%s]</em> by %s',
                                            chgset.rev, chgset.author)
                        href = self.env.href.changeset(chgset.rev)
                        message = wiki_to_oneliner(message, self.env, db,
                                                   shorten=True)
                    if show_files:
                        files = []
                        for chg in chgset.get_changes():
                            if show_files > 0 and len(files) >= show_files:
                                files.append('...')
                                break
                            files.append('<span class="%s">%s</span>'
                                         % (chg[2], util.escape(chg[0])))
                        message = '<span class="changes">' + ', '.join(files) +\
                                  '</span>: ' + message
                    yield 'changeset', href, title, chgset.date, chgset.author,\
                          util.Markup(message)
                rev = repos.previous_rev(rev)
Beispiel #54
0
def attachment_to_hdf(env, req, db, attachment):
    """
    This function have been removed from 0.11, this is copied from 0.10, then modified to 
    work with 0.11
    """
    if not db:
        db = env.get_db_cnx()
    hdf = {
        'filename': attachment.filename,
        'description': wiki_to_oneliner(attachment.description, env, db, req=req),
        'author': attachment.author,
        'ipnr': attachment.ipnr,
        'size': pretty_size(attachment.size),
        'time': format_datetime(attachment.date),
        'age': pretty_timedelta(attachment.date),
        'href': AttachmentModule(env).get_resource_url(attachment.resource, req.href)
    }
    return hdf
Beispiel #55
0
 def get_timeline_events(self, req, start, stop, filters):
     if 'milestone' in filters:
         format = req.args.get('format')
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute("SELECT completed,name,description FROM milestone "
                        "WHERE completed>=%s AND completed<=%s",
                        (start, stop,))
         for completed, name, description in cursor:
             title = Markup(u'Jalon <em>%s</em> completé', name)
             if format == 'rss':
                 href = req.abs_href.milestone(name)
                 message = wiki_to_html(description, self.env, req, db,
                                        absurls=True)
             else:
                 href = req.href.milestone(name)
                 message = wiki_to_oneliner(description, self.env, db,
                                            shorten=True)
             yield 'milestone', href, title, completed, None, message or '--'
Beispiel #56
0
 def process_request(self, req, chrome, projects):
     folders = []
     for project in projects:
         env = project["env"]
         if not req.authname:
             req.authname = "anonymous"
         try:
             repos = env.get_repository(req.authname)
         except TracError:
             continue
         try:
             change = repos.get_changeset(repos.get_youngest_rev())
             folders.append({'name': project["name"],
                         'href': project["href"]+"/browser",
                         'rev': repos.get_youngest_rev(),
                         'age': util.pretty_timedelta(change.date),
                         'author': change.author,
                         'message': wiki_to_oneliner(change.message, env, env.get_db_cnx(), shorten=True, absurls=True, req=req)})
         except Exception, e:
             pass
Beispiel #57
0
def get_changes(env, repos, revs, full=None, req=None, format=None):
    db = env.get_db_cnx()
    changes = {}
    for rev in revs:
        try:
            changeset = repos.get_changeset(rev)
        except NoSuchChangeset:
            changes[rev] = {}
            continue

        wiki_format = env.config['changeset'].getbool('wiki_format_messages')
        message = changeset.message or '--'
        absurls = (format == 'rss')
        if wiki_format:
            shortlog = wiki_to_oneliner(message, env, db,
                                        shorten=True, absurls=absurls)
        else:
            shortlog = Markup.escape(shorten_line(message))

        if full:
            if wiki_format:
                message = wiki_to_html(message, env, req, db,
                                       absurls=absurls, escape_newlines=True)
            else:
                message = html.PRE(message)
        else:
            message = shortlog

        if format == 'rss':
            if isinstance(shortlog, Markup):
                shortlog = shortlog.plaintext(keeplinebreaks=False)
            message = unicode(message)

        changes[rev] = {
            'date_seconds': changeset.date,
            'date': format_datetime(changeset.date),
            'age': pretty_timedelta(changeset.date),
            'author': changeset.author or 'anonymous',
            'message': message, 'shortlog': shortlog,
        }
    return changes
Beispiel #58
0
 def _format_description(self, template, screenshot):
     description = template.replace('$id', to_unicode(screenshot['id']))
     description = description.replace('$name', screenshot['name'])
     description = description.replace('$file',
                                       to_unicode(screenshot['file']))
     description = description.replace('$time',
                                       format_datetime(screenshot['time']))
     description = description.replace('$author', screenshot['author'])
     description = description.replace('$description',
                                       screenshot['description'])
     description = description.replace('$width',
                                       to_unicode(screenshot['width']))
     description = description.replace('$height',
                                       to_unicode(screenshot['height']))
     description = description.replace('$tags',
                                       to_unicode(screenshot['tags']))
     description = description.replace('$components',
                                       ', '.join(screenshot['components']))
     description = description.replace('$versions',
                                       ', '.join(screenshot['versions']))
     return wiki_to_oneliner(description, self.env)
Beispiel #59
0
 def get_topics(self, req, cursor, forum, order_by = 'ORDER BY time ASC'):
     columns = ('id', 'forum', 'time', 'subject', 'body', 'author',
       'replies', 'lastreply')
     sql = "SELECT id, forum, time, subject, body, author, (SELECT" \
       " COUNT(id) FROM message m WHERE m.topic = topic.id) AS replies," \
       " (SELECT MAX(time) FROM message m WHERE m.topic = topic.id) AS" \
       " lastreply FROM topic WHERE forum = %s " + order_by
     self.log.debug(sql % (forum,))
     cursor.execute(sql, (forum,))
     topics = []
     for row in cursor:
         row = dict(zip(columns, row))
         row['author'] = wiki_to_oneliner(row['author'], self.env)
         row['body'] = wiki_to_html(row['body'], self.env, req)
         if row['lastreply']:
             row['lastreply'] = pretty_timedelta(row['lastreply'])
         else:
             row['lastreply'] = 'No replies'
         row['time'] = format_datetime(row['time'])
         topics.append(row)
     return topics
Beispiel #60
0
 def _format_description(self, template, screenshot):
     description = template.replace('$id', to_unicode(screenshot['id']))
     description = description.replace('$name', screenshot['name'])
     description = description.replace('$file',
       to_unicode(screenshot['file']))
     description = description.replace('$time', format_datetime(
       screenshot['time']))
     description = description.replace('$author', screenshot['author'])
     description = description.replace('$description',
       screenshot['description'])
     description = description.replace('$width', to_unicode(
       screenshot['width']))
     description = description.replace('$height', to_unicode(
       screenshot['height']))
     description = description.replace('$tags', to_unicode(
       screenshot['tags']))
     description = description.replace('$components',
       ', '.join(screenshot['components']))
     description = description.replace('$versions',
       ', '.join(screenshot['versions']))
     return wiki_to_oneliner(description, self.env)