def filter_stream(self, req, method, filename, stream, data):
        if filename != 'query.html' and filename != 'report_list.html' and \
                       filename != 'report_view.html':
            return stream

        has_query_permission = self.query_permission in \
            PermissionSystem(self.env).get_user_permissions(req.authname)

        buffer = StreamBuffer()

        def replace_query_link():
            if has_query_permission:
                return buffer
            else:
                return HTML('<div id="ctxtnav" class="nav"></div>')

        def replace_filter_box():
            if has_query_permission:
                return buffer
            else:
                return HTML('')

        return stream | Transformer('//div[@id="ctxtnav" and @class="nav"]') \
            .copy(buffer) \
            .replace(replace_query_link).end() \
            .select('//form[@id="query" and @method="post" and @action]') \
            .copy(buffer) \
            .replace(replace_filter_box)
Exemple #2
0
    def filter_stream(self, req, method, filename, stream, data):
        if not filename == 'report_list.html':
            return stream
        user = req.authname
        buffer = StreamBuffer()

        def check_report_permission():
            delimiter = '</tr>'
            reportstream = str(buffer)
            reports_raw = reportstream.split(delimiter)
            reportstream = ''
            for report in reports_raw:
                if report != None and len(report) != 0:
                    # determine the report id
                    s = report.find('/report/')
                    if s == -1:
                        continue
                    e = report.find('\"', s)
                    if e == -1:
                        continue
                    report_id = report[s + len('/report/'):e]
                    if self._has_permission(user, report_id):
                        reportstream += report
            return HTML(reportstream)
        return stream | Transformer('//tbody/tr') \
        .copy(buffer) \
        .replace(check_report_permission)
Exemple #3
0
    def filter_stream(self, req, method, filename, stream, data):
        """
        filter the stream for the roadmap (/roadmap)
        and milestones /milestone/<milestone>
        """

        if filename in ('roadmap.html', 'milestone_view.html'):
            trachours = TracHoursPlugin(self.env)

            hours = {}

            milestones = data.get('milestones')
            this_milestone = None

            if milestones is None:
                # /milestone view : only one milestone
                milestones = [ data['milestone'] ]
                this_milestone = milestones[0].name
                find_xpath = "//div[@class='milestone']//h1"
                xpath = "//div[@class='milestone']//div[@class='info']"
            else:
                # /roadmap view
                find_xpath = "//li[@class='milestone']//h2/a"
                xpath = "//li[@class='milestone']//div[@class='info']"

            for milestone in milestones:
                hours[milestone.name] = dict(totalhours=0., 
                                             estimatedhours=0.,)
            
                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute("select id from ticket where milestone=%s", (milestone.name,))
                tickets = [i[0] for i in cursor.fetchall()]

                if tickets:
                    hours[milestone.name]['date'] = Ticket(self.env, tickets[0]).time_created
                for ticket in tickets:
                    ticket = Ticket(self.env, ticket)

                    # estimated hours for the ticket
                    try:
                        estimatedhours = float(ticket['estimatedhours'])
                    except (ValueError, TypeError):
                        estimatedhours = 0.
                    hours[milestone.name]['estimatedhours'] += estimatedhours

                    # total hours for the ticket (seconds -> hours)
                    totalhours = trachours.get_total_hours(ticket.id) / 3600.0
                    hours[milestone.name]['totalhours'] += totalhours
                
                    # update date for oldest ticket
                    if ticket.time_created < hours[milestone.name]['date']:
                        hours[milestone.name]['date'] = ticket.time_created

            b = StreamBuffer()
            stream |= Transformer(find_xpath).copy(b).end().select(xpath).append(self.MilestoneMarkup(b, hours, req.href, this_milestone))

        return stream
Exemple #4
0
    def _milestone_versions(self, stream, req):
        buffer = StreamBuffer()

        def apply_version():
            return self._version_display(req, buffer.events[1][1])

        filter = Transformer('//li[@class="milestone"]/div/h2/a/em').copy(buffer).end() \
            .select('//li[@class="milestone"]//p[@class="date"]').append(apply_version)
        return stream | filter
Exemple #5
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename not in ('ticket.html', 'ticket_preview.html'):
            return stream
        ticket = data.get('ticket')
        if not (ticket and ticket.exists
                and 'TICKET_ADMIN' in req.perm(ticket.resource)):
            return stream

        # Insert "Delete" buttons for ticket description and each comment
        def delete_ticket():
            return tag.form(
                tag.div(
                    tag.input(type='hidden', name='action', value='delete'),
                    tag.input(
                        type='submit',
                        value=captioned_button(
                            req,
                            u'–',  # 'EN DASH'
                            _("Delete")),
                        title=_('Delete ticket'),
                        class_="trac-delete"),
                    class_="inlinebuttons"),
                action='#',
                method='get')

        def delete_comment():
            for event in buffer:
                cnum, cdate = event[1][1].get('id')[12:].split('-', 1)
                return tag.form(
                    tag.div(
                        tag.input(type='hidden',
                                  name='action',
                                  value='delete-comment'),
                        tag.input(type='hidden', name='cnum', value=cnum),
                        tag.input(type='hidden', name='cdate', value=cdate),
                        tag.input(
                            type='submit',
                            value=captioned_button(
                                req,
                                u'–',  # 'EN DASH'
                                _("Delete")),
                            title=_('Delete comment %(num)s', num=cnum),
                            class_="trac-delete"),
                        class_="inlinebuttons"),
                    action='#',
                    method='get')

        buffer = StreamBuffer()
        return stream | Transformer('//div[@class="description"]'
                                    '/h3[@id="comment:description"]') \
            .after(delete_ticket).end() \
            .select('//div[starts-with(@class, "change")]/@id') \
            .copy(buffer).end() \
            .select('//div[starts-with(@class, "change") and @id]'
                    '/div[@class="trac-ticket-buttons"]') \
            .prepend(delete_comment)
Exemple #6
0
 def dir_entries(self, req, stream, data, xpath_prefix=''):
     # add table cells
     b = StreamBuffer()
     xpath = "//td[@class='%s']"
     stream |= Transformer(xpath_prefix + (xpath % 'name') +
                           "/a/@href").copy(b).end().select(xpath_prefix + (
                               xpath % self.element_class)).after(
                                   self.GenerateSVNUrl(
                                       b, self.svn_base_url, self.link_text,
                                       data['path_links'][0]['href']))
     return stream
Exemple #7
0
    def filter_stream(self, req, method, filename, stream, data):

        if filename in ('milestone_view.html', ):

            buffer = StreamBuffer()
            t = Transformer('//div[@class="milestone"]/h1/text()[2]')
            t = t.copy(buffer).end()
            t = t.select('//div[@class="milestone"]/div[@class="info"]/dl')
            t = t.append(GenerateMetrixLink(buffer, req.href))
            stream |= t

        return stream
Exemple #8
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename == "attachment.html":
            if data["mode"] == "new" and data[
                    "attachment"].parent_realm == "ticket":
                stream |= Transformer("//fieldset").after(
                    self._generate_attachmentflags_fieldset(readonly=False))
            elif data["mode"] == "list" and data["attachments"] and data[
                    "attachments"]["parent"].realm == "ticket":
                stream = self._filter_obsolete_attachments_from_stream(
                    stream, data["attachments"]["attachments"])
            elif data["mode"] == "view" and data[
                    "attachment"].parent_realm == "ticket":
                flags = AttachmentFlags(self.env, data["attachment"])
                if 'TICKET_MODIFY' in req.perm or get_reporter_id(
                        req) == data["attachment"].author:
                    stream |= Transformer("//div[@id='preview']").after(
                        self._generate_attachmentflags_fieldset(
                            readonly=False, current_flags=flags, form=True))
                else:
                    stream |= Transformer("//div[@id='preview']").after(
                        self._generate_attachmentflags_fieldset(
                            current_flags=flags))

        if filename == "ticket.html":
            if "attachments" in data:
                stream = self._filter_obsolete_attachments_from_stream(
                    stream, data["attachments"]["attachments"])
            stream |= Transformer("//label[@for='field-patch']").wrap('strike')

            buffer = StreamBuffer()
            #stream |= Transformer("//input[@id='field-patch']").attr('disabled','disabled')
            # Copy a checked box to buffer then disable original
            stream |= Transformer('//input[@id="field-patch" and (@checked)]')\
                .copy(buffer).after(buffer).attr("disabled","disabled")
            # Change new element to hidden field instead of checkbox and
            # remove check
            stream |= Transformer('//input[@id="field-patch" and (@checked) \
                and not (@disabled)]'                                     ).attr("type","hidden") \
                .attr("checked", None).attr("id", None)

            # Disable any unchecked fields
            # NOTE: if the box was checked and copied, the id is removed so the
            # hidden field will not be disabled here.
            stream |= Transformer('//input[@id="field-patch" \
                and not (@checked)]').attr("disabled", "disabled")

        if filename == "query.html":
            # Filter the patch field from the Trac 1.0 batch modify utility
            stream |= Transformer(
                "//select[@id='add_batchmod_field']/option[@value='patch']"
            ).remove()
        return stream
Exemple #9
0
    def _customize_View(self, stream):

        filter = Transformer('.//div [@id="banner"]')
        stream = stream | filter.wrap(self.css_banner_top2)

        buffer = StreamBuffer()
        stream = stream | Transformer('.//div [@id="banner"]').copy(buffer) \
              .end().select('.//div [@id="top2"]') \
              .after(tag.div(id_='top1')(buffer))

        filter = Transformer('.//div [@id="mainnav"]')
        stream = stream | filter.wrap(self.css_banner_top4)

        buffer = StreamBuffer()
        stream = stream | Transformer('.//div [@id="mainnav"]').copy(buffer) \
              .end().select('.//div [@id="top4"]') \
              .after(tag.div(id_='top3')(buffer))

        filter = Transformer('.//div [@id="top3"]')
        stream = stream | filter.after(tag.div(id_='right')(tag.p()))

        filter = Transformer('.//div [@id="right"]')
        stream = stream | filter. \
            append(tag.div(class_='wiki-toc')(tag.h4(_('Table of Contents'))))

        # just for the menu / TOC
        filter = Transformer('.//div [@class="wiki-toc"]')

        if self.anchors and self.keylist:
            for key in self.keylist:
                stream = stream | filter.append(
                    tag.a(key,
                          href='#' + self.anchors.get(key),
                          onclick="scrollup();") + tag.br())
        filter = Transformer('.//div [@id="main"]')
        stream = stream | filter.wrap(self.css_left)

        return stream
Exemple #10
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename != 'ticket.html':
            return stream
        ticket = data.get('ticket')
        if not (ticket and ticket.exists
                and 'TICKET_ADMIN' in req.perm(ticket.resource)):
            return stream

        # Insert "Delete" buttons for ticket description and each comment
        def delete_ticket():
            return tag.form(tag.div(tag.input(type='hidden',
                                              name='action',
                                              value='delete'),
                                    tag.input(type='submit',
                                              value=_('Delete'),
                                              title=_('Delete ticket')),
                                    class_='inlinebuttons'),
                            action='#',
                            method='get')

        def delete_comment():
            for event in buffer:
                cnum = event[1][1].get('id')[12:]
                return tag.form(tag.div(tag.input(type='hidden',
                                                  name='action',
                                                  value='delete-comment'),
                                        tag.input(type='hidden',
                                                  name='cnum',
                                                  value=cnum),
                                        tag.input(type='submit',
                                                  value=_('Delete'),
                                                  title=_(
                                                      'Delete comment %(num)s',
                                                      num=cnum)),
                                        class_='inlinebuttons'),
                                action='#',
                                method='get')

        buffer = StreamBuffer()
        return stream | Transformer('//div[@class="description"]'
                                    '/h3[@id="comment:description"]') \
            .after(delete_ticket).end() \
            .select('//div[@class="change"]/@id') \
            .copy(buffer).end() \
            .select('//div[@class="change" and @id]/h3[@class="change"]') \
            .after(delete_comment)
Exemple #11
0
    def filter_stream(self, req, method, filename, stream, data):
        if not filename == 'report_list.html':
            return stream
        stream_buffer = StreamBuffer()

        from pkg_resources import parse_version
        if parse_version(trac_version) < parse_version('1.0'):
            delimiter = '</tr>'
            selector = '//tbody/tr'
        else:
            delimiter = '</div>'
            selector = '//div[@class="reports"]/div'

        def check_report_permission():
            report_stream = str(stream_buffer)
            reports_raw = report_stream.split(delimiter)
            report_stream = ''
            for row in reports_raw:
                if row is not None and len(row) != 0 and 'View report' in row:
                    # determine the report id
                    s = row.find('/report/')
                    if s == -1:
                        continue
                    e = row.find('\"', s)
                    if e == -1:
                        continue
                    report_id = row[s+len('/report/'):e]
                    if self._has_permission(req.authname, report_id):
                        report_stream += row
                    else:
                        self.log.debug("Removing report %s from list because "
                                       "%s doesn't have permission to view" %
                                       (report_id, req.authname))
                elif 'View report' in row:
                    report_stream += row
            return HTML(report_stream)
        return stream | Transformer(selector) \
            .copy(stream_buffer) \
            .replace(check_report_permission)
    def _apply(self, select, with_attrs=False):
        buffer = StreamBuffer()
        events = buffer.events

        class Trace(object):
            last = None
            trace = []

            def __call__(self, stream):
                for event in stream:
                    if events and hash(tuple(events)) != self.last:
                        self.last = hash(tuple(events))
                        self.trace.append(list(events))
                    yield event

        trace = Trace()
        output = _transform(FOOBAR, getattr(Transformer(select), self.operation)
                                    (buffer).apply(trace), with_attrs=with_attrs)
        simplified = []
        for interval in trace.trace:
            simplified.append(_simplify([(None, e) for e in interval],
                                         with_attrs=with_attrs))
        return output, simplified
Exemple #13
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename == 'ticket.html' and req.authname != 'anonymous':
            ticket = data.get('ticket')
            if req.perm.has_permission('TICKET_ADMIN'):
                self.log.debug(
                    "TicketChangePlugin adding 'Change' links for ticket %s" %
                    ticket.id)
                buffer = StreamBuffer()

                def insert_change_link():
                    cnum = list(buffer)[0][1][1][0][1]
                    return tag(
                        " ",
                        tag.a("Change",
                              href=("../ticketchangecomment/%s?cnum=%s" %
                                    (ticket.id, cnum))))

                filter = Transformer(
                    "//div[@class='change']/div[@class='inlinebuttons']/input[@name='replyto']/@value"
                )
                return stream | filter.copy(buffer).end() \
                              .select("//div[@class='change']/div[@class='inlinebuttons']/input[@value='Reply']") \
                              .after(insert_change_link)
        return stream
Exemple #14
0
    def filter_stream(self, req, method, filename, stream, data):
        """
        filter the stream for the roadmap (/roadmap)
        and milestones /milestone/<milestone>
        """

        if filename in ('roadmap.html', 'milestone_view.html') and \
                'TICKET_VIEW_HOURS' in req.perm:
            trac_hours = TracHoursPlugin(self.env)

            hours = {}

            milestones = data.get('milestones')
            this_milestone = None

            if milestones is None:
                # /milestone view : only one milestone
                milestones = [data['milestone']]
                this_milestone = milestones[0].name
                find_xpath = "//div[@class='milestone']/h1"
                xpath = "//div[@class='milestone']/div[1]"
            else:
                # /roadmap view
                find_xpath = "//*[@class='milestone']//h2/a"
                xpath = "//*[@class='milestone']/div[1]"

            for milestone in milestones:
                hours[milestone.name] = dict(
                    totalhours=0.,
                    estimatedhours=0.,
                )

                tickets = [
                    tid for tid, in self.env.db_query(
                        """
                    SELECT id FROM ticket WHERE milestone=%s
                    """, (milestone.name, ))
                ]

                if tickets:
                    hours[milestone.name]['date'] = \
                        Ticket(self.env, tickets[0])['time']
                for ticket in tickets:
                    ticket = Ticket(self.env, ticket)

                    # estimated hours for the ticket
                    try:
                        estimated_hours = float(ticket['estimatedhours'])
                    except (ValueError, TypeError):
                        estimated_hours = 0.
                    hours[milestone.name]['estimatedhours'] += estimated_hours

                    # total hours for the ticket (seconds -> hours)
                    total_hours = trac_hours.get_total_hours(
                        ticket.id) / 3600.0
                    hours[milestone.name]['totalhours'] += total_hours

                    # update date for oldest ticket
                    if ticket['time'] < hours[milestone.name]['date']:
                        hours[milestone.name]['date'] = ticket['time']

            b = StreamBuffer()
            stream |= Transformer(find_xpath).copy(b).end().select(xpath). \
                append(
                self.MilestoneMarkup(b, hours, req.href, this_milestone))

        return stream
Exemple #15
0
    def filter_stream(self, req, method, filename, stream, data):
        #remove matches from custom queries due to the fact ticket permissions are checked after this stream is manipulated so the count cannot be updated.
        if filename == "query.html":
            stream |= Transformer(
                '//div[@class="query"]/h1/span[@class="numrows"]/text()'
            ).replace("")

        if filename == "ticket.html":
            for field, e in self.enchants.items():
                disabled = e["disable"]
                hidden = e["hide"]
                #permissions are set for field
                if e["permission"] != "" and not hidden and not (
                        disabled or disabled and e["ondenial"] == "hide"):
                    self.env.log.debug("Permissions %s" % e["permission"])
                    #default set to denied
                    denied = True
                    #iterate through permissions
                    for perm in (x.strip()
                                 for x in e["permission"].split(',')):
                        self.env.log.debug("Checking permission %s" % perm)
                        #user has permission no denied
                        if perm and perm in req.perm(
                                data.get("ticket").resource):
                            self.env.log.debug("Has %s permission" % perm)
                            denied = False
                    #if denied is true hide/disable dpending on denial setting
                    if denied:
                        denial = self.config.get('blackmagic',
                                                 '%s.ondenial' % field, None)
                        if denial:
                            if denial == "disable":
                                disabled = True
                            elif denial == "hide":
                                hidden = True
                            else:
                                disabled = True
                        else:
                            disabled = True

                #hide fields
                if hidden:
                    #replace th and td in previews with empty tags
                    stream = stream | Transformer(
                        '//th[@id="h_%s"]' % field).replace(tag.th(" "))
                    stream = stream | Transformer(
                        '//td[@headers="h_%s"]' % field).replace(tag.td(" "))
                    #replace labels and fields with blank space
                    stream = stream | Transformer(
                        '//label[@for="field-%s"]' % field).replace(" ")
                    stream = stream | Transformer(
                        '//*[@id="field-%s"]' % field).replace(" ")

                #change label
                if e["label"] is not None:
                    stream |= Transformer('//th[@id="h_%s"]/text()' %
                                          field).replace(e["label"] + ":")
                    stream = stream | Transformer(
                        '//label[@for="field-%s"]/text()' %
                        field).replace(e["label"] + ":")

                if disabled:
                    buffer = StreamBuffer()
                    #copy input to buffer then disable original
                    stream |= Transformer(
                        '//*[@id="field-%s" and (@checked) and @type="checkbox"]'
                        % field).copy(buffer).after(buffer).attr(
                            "disabled", "disabled")
                    #change new element to hidden field instead of checkbox and remove check
                    stream |= Transformer(
                        '//*[@id="field-%s" and not (@disabled) and (@checked) and @type="checkbox"]'
                        % field).attr("type",
                                      "hidden").attr("checked",
                                                     None).attr("id", None)
                    #disable non-check boxes / unchecked check boxes
                    stream = stream | Transformer(
                        '//*[@id="field-%s" and not (@checked)]' % field).attr(
                            "disabled", "disabled")

                    if not self.gray_disabled:
                        #cut label content into buffer then append it into the label with a strike tag around it
                        stream = stream | Transformer(
                            '//label[@for="field-%s"]/text()' %
                            field).cut(buffer).end().select(
                                '//label[@for="field-%s"]/' % field).append(
                                    tag.strike(buffer))
                    else:
                        #cut label and replace with coloured span
                        stream = stream | Transformer(
                            '//label[@for="field-%s"]/text()' %
                            field).cut(buffer).end().select(
                                '//label[@for="field-%s"]/' % field).append(
                                    tag.span(
                                        buffer,
                                        style="color:%s" % self.gray_disabled))

                if self.config.get('blackmagic', '%s.notice' % field, None):
                    stream = stream | Transformer(
                        '//*[@id="field-%s"]' % field
                    ).after(tag.br() + tag.small()(tag.em()(Markup(
                        self.config.get('blackmagic', '%s.notice' % field)))))

                tip = self.config.get('blackmagic', '%s.tip' % field, None)
                if tip:
                    stream = stream | Transformer(
                        '//div[@id="banner"]').before(
                            tag.script(type="text/javascript",
                                       src=req.href.chrome(
                                           "blackmagic", "js",
                                           "wz_tooltip.js"))())

                    stream = stream | Transformer(
                        '//*[@id="field-%s"]' % field).attr(
                            "onmouseover",
                            "Tip('%s')" % tip.replace(r"'", r"\'"))

        return stream
Exemple #16
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename not in ('ticket.html', 'ticket.rss'):
            return stream

        ticket_id = req.args.get('id')
        if not ticket_id:
            return stream

        # determine the username of the current user
        user = req.authname

        # determine if the user has the permission to see private comments
        perms = PermissionSystem(self.env)
        has_private_permission = \
            self.private_comment_permission in perms.get_user_permissions(user)

        # Remove private comments from Ticket Page
        if filename == 'ticket.html':
            buf = StreamBuffer()

            def check_comments():
                delimiter = '<div xmlns="http://www.w3.org/1999/xhtml" ' + \
                            'class="change" id="trac-change-'

                comment_stream = str(buf)
                # split the comment_stream to get single comments
                comments_raw = comment_stream.split(delimiter)
                comment_stream = ''

                for comment in comments_raw:
                    if comment is None or len(comment) < 1:
                        continue

                    # determine comment id
                    find = comment.find('">')
                    if find == -1:
                        continue
                    comment_id = comment[:find]

                    # concat the delimiter and the comment again
                    comment_code = delimiter + comment

                    # if the user has the permission to see the comment
                    # the comment_code will be appended to the comment_stream
                    comment_private = self._is_comment_private(
                        ticket_id, comment_id)

                    if comment_private:
                        comment_code = comment_code.replace(
                            '<span class="threading">',
                            '<span class="threading"> <span class="%s">'
                            'this comment is private</span>' %
                            str(self.css_class_private_comment_marker))

                    if has_private_permission or not comment_private:
                        comment_stream += comment_code

                return HTML(comment_stream)

            # filter all comments
            stream |= Transformer('//div[@class="change" and @id]') \
                .copy(buf).replace(check_comments)

            # if the user has the private comment permission the checkboxes
            # to change the private value will be added
            if has_private_permission:
                comment_box = tag.label(
                    _("Private Comment:"),
                    tag.input(type='checkbox', name='private_comment'))
                stream |= Transformer('//h2[@id="trac-add-comment"]') \
                    .after(comment_box)
                # Trac 1.0 and later:
                # stream |= Transformer(
                #   '//div[@id="trac-add-comment"]//fieldset').prepend(input)

        # Remove private comments from ticket RSS feed
        if filename == 'ticket.rss':
            comments = self._get_all_private_comments(ticket_id)

            self.log.debug("Private Comments for Ticket %d: %s" %
                           (ticket_id, comments))

            for comment_id in comments:
                stream |= Transformer('//item[%d]' % comment_id).remove()

        return stream