Exemple #1
0
    def attach(self, req):
        path = req.path_info.split("/")
        realm, obj_id = path[3:]

        obj_resource = Resource(realm, id=obj_id)
        attachment = Attachment(self.env, obj_resource.child("attachment"))

        req.perm(attachment.resource).require("ATTACHMENT_CREATE")
        if req.method == "POST":
            self._save_attachement(req, attachment)
            pass
        return "itteco_attach_popup.html", {"resource": obj_resource}, "text/html"
Exemple #2
0
    def _render_view(self, req, db, version):

        db = self.env.get_db_cnx()
        sql = "SELECT name FROM milestone " \
              "INNER JOIN milestone_version ON (name = milestone) " \
              "WHERE version = %s " \
              "ORDER BY due"
        cursor = db.cursor()
        cursor.execute(sql, (version.name,))

        milestones = []
        tickets = []
        milestone_stats = []

        for row in cursor:
            milestone = Milestone(self.env, row[0])
            milestones.append(milestone)

            mtickets = get_tickets_for_milestone(self.env, db, milestone.name,
                                                 'owner')
            mtickets = apply_ticket_permissions(self.env, req, mtickets)
            tickets += mtickets
            stat = get_ticket_stats(self.milestone_stats_provider, mtickets)
            milestone_stats.append(milestone_stats_data(self.env, req, stat, milestone.name))

        stats = get_ticket_stats(self.version_stats_provider, tickets)
        interval_hrefs = version_interval_hrefs(self.env, req, stats,
                                                [milestone.name for milestone in milestones])

        version.resource = Resource('version', version.name)
        context = Context.from_request(req, version.resource)

        version.is_released = version.time and version.time.date() < date.today()
        version.stats = stats
        version.interval_hrefs = interval_hrefs
        version.stats_href = [] # Not implemented yet, see th:#10349
        data = {
            'context': context,
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'milestones': milestones,
            'milestone_stats': milestone_stats,
            'show_milestone_description': self.show_milestone_description # Not implemented yet
        }

        add_stylesheet(req, 'extendedversion/css/version.css')
        add_script(req, 'common/js/folding.js')
        add_ctxtnav(req, _("Back to Versions"), req.href.versions())
        return 'version_view.html', data, None
Exemple #3
0
    def test_view_build(self):
        config = BuildConfig(self.env, name='test', path='trunk')
        config.insert()
        platform = TargetPlatform(self.env, config='test', name='any')
        platform.insert()
        build = Build(self.env,
                      config='test',
                      platform=1,
                      rev=123,
                      rev_time=42,
                      status=Build.SUCCESS,
                      slave='hal')
        build.insert()

        PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW')
        req = Mock(method='GET',
                   base_path='',
                   cgi_location='',
                   path_info='/build/test/1',
                   href=Href('/trac'),
                   args={},
                   chrome={},
                   authname='joe',
                   perm=PermissionCache(self.env, 'joe'))

        root = Mock(get_entries=lambda: ['foo'],
                    get_history=lambda: [('trunk', rev, 'edit')
                                         for rev in range(123, 111, -1)])
        self.repos = Mock(get_node=lambda path, rev=None: root,
                          sync=lambda: None,
                          normalize_path=lambda path: path,
                          normalize_rev=lambda rev: rev,
                          get_changeset=lambda rev: Mock(author='joe'))
        self.repos.authz = Mock(has_permission=lambda path: True,
                                assert_permission=lambda path: None)

        module = BuildController(self.env)
        assert module.match_request(req)
        _, data, _ = module.process_request(req)

        self.assertEqual('view_build', data['page_mode'])

        from trac.resource import Resource
        self.assertEquals(Resource('build', 'test/1'),
                          data['context'].resource)

        self.assertEquals([], data['build']['attachments']['attachments'])
        self.assertEquals('/trac/attachment/build/test/1/',
                          data['build']['attachments']['attach_href'])
Exemple #4
0
    def __call__(self, realm_or_resource, id=False, version=False):
        """Convenience function for using thus:
            'WIKI_VIEW' in perm(context)
        or
            'WIKI_VIEW' in perm(realm, id, version)
        or
            'WIKI_VIEW' in perm(resource)

        """
        resource = Resource(realm_or_resource, id, version)
        if resource and self._resource and resource == self._resource:
            return self
        else:
            return PermissionCache(self.env, self.username, resource,
                                   self._cache)
Exemple #5
0
    def do_put(self, req, args):
        trac_type = AgiloTicketSystem(self.env).normalize_type(
            args.get(Key.TYPE))
        if trac_type is None:
            self.error_response(req, {}, ['Must specify a type.'])

        success, ticket_id, errors = self._create_ticket(req, args)
        if not success:
            self.error_response(req, {}, errors)

        ticket_resource = Resource('ticket')(id=ticket_id)
        if not req.perm.has_permission(Action.TICKET_VIEW, ticket_resource):
            self.error_response(req, {},
                                ['No permission to see ticket %d' % ticket_id])
        return self.get_ticket_as_json(req, ticket_id)
Exemple #6
0
def get_blog_resources(env):
    """ Returns a list of resource instances of existing blog posts (current
    version). The list is ordered by publish_time (newest first). """
    sql = "SELECT bp1.name FROM fullblog_posts bp1, " \
          "(SELECT name, max(version) AS ver FROM fullblog_posts " \
          "GROUP BY name) bp2 WHERE bp1.name = bp2.name AND " \
          "bp1.version = ver ORDER BY bp1.publish_time DESC"
    if hasattr(env, 'db_query'):
        cursor = env.db_query(sql)
    else:
        db = env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(sql)
    blog_realm = Resource('blog')
    return [blog_realm(id=post[0], version=0) for post in cursor]
Exemple #7
0
 def test_set_tags(self):
     resource = Resource('wiki', 'TaggedPage')
     self.req.perm = PermissionCache(self.env, username='******')
     # Shouldn't raise an error with appropriate permission.
     self.tag_wp.set_resource_tags(self.req, resource, self.tags)
     self.tag_wp.set_resource_tags(self.req, resource, ['tag2'])
     # Check change records.
     rows = self.env.db_query(
         """
         SELECT author,oldtags,newtags FROM tags_change
         WHERE tagspace=%s AND name=%s
         ORDER by time DESC
         """, ('wiki', 'TaggedPage'))
     self.assertEqual(rows[0], ('editor', 'tag1', 'tag2'))
     self.assertEqual(rows[1], ('editor', '', 'tag1'))
Exemple #8
0
    def _check_duplicate_id(self, req, ticket):
        if req.args.get('action') == 'resolve':
            resolution = req.args.get('action_resolve_resolve_resolution')
            if resolution == 'duplicate':
                duplicate_id = req.args.get('duplicate_id')
                if not duplicate_id:
                    yield None, "Duplicate ticket ID must be provided."

                try:
                    duplicate_ticket = self.find_ticket(duplicate_id)
                    req.perm.require('TICKET_MODIFY',
                                     Resource(duplicate_ticket.id))
                    ticket.duplicate = duplicate_ticket
                except NoSuchTicketError:
                    yield None, "Invalid duplicate ticket ID."
Exemple #9
0
    def post_process_request(self, req, template, data, content_type):
        if data and req.path_info == '/timeline' and \
                'TAGS_VIEW' in req.perm(Resource('tags')):

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

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

            if data.get('events') and query_str:
                tag_system = TagSystem(self.env)
                try:
                    query = Query(query_str,
                                  attribute_handlers=dict(realm=realm_handler))
                except InvalidQuery, e:
                    add_warning(
                        req, _("Tag query syntax error: %s" % to_unicode(e)))
                else:
                    all_realms = tag_system.get_taggable_realms(req.perm)
                    query_realms = set()
                    for m in REALM_RE.finditer(query.as_string()):
                        query_realms.add(m.group(1))
                    # Don't care about resources from non-taggable realms.
                    realms = not query_realms and all_realms or \
                             query_realms.intersection(all_realms)
                    events = []
                    self.log.debug("Filtering timeline events by tags '%s'" %
                                   query_str)
                    for event in data['events']:
                        resource = event['data'][0]
                        if resource.realm in realms:
                            # Shortcut view permission checks here.
                            tags = tag_system.get_tags(None, resource)
                            if query(tags, context=resource):
                                events.append(event)
                    # Overwrite with filtered list.
                    data['events'] = events
            if query_str:
                # Add current value for next form rendering.
                data[self.key] = query_str
            elif self.key in req.session:
                del req.session[self.key]
Exemple #10
0
 def expand_macro(self, formatter, name, content, args=None):
     # pylint: disable=too-many-function-args
     args = args or {}
     reponame = args.get('repository') or ''
     rev = args.get('revision')
     # pylint: disable=no-member
     repos = RepositoryManager(self.env).get_repository(reponame)
     try:
         changeset = repos.get_changeset(rev)
         message = changeset.message
         rev = changeset.rev
         resource = repos.resource
     except Exception:  # pylint: disable=broad-except
         message = content
         resource = Resource('repository', reponame)
     config = self.ticket_replace_section
     fields = {}
     for key, value in config.options():
         idx = key.rfind('.')
         if idx >= 0:
             prefix, attribute = key[:idx], key[idx + 1:]
             field = fields.setdefault(prefix, {})
             field[attribute] = config.get(key)
         else:
             fields[key] = {'': value}
     for prefix, field in fields.iteritems():
         if not all(k in field for k in ['pattern', 'replace']):
             self.log.warn(
                 "Ignoring [%s] %s, missing .pattern or .replace" %
                 (self.ticket_replace_section_name, key))
             continue
         subst = {'repository': reponame, 'revision': rev}
         pattern = field['pattern'].replace('$(', '%(') % subst
         replace = field['replace'].replace('$(', '%(') % subst
         message = re.sub(pattern, replace, message)
     if ChangesetModule(self.env).wiki_format_messages:
         message = '\n'.join(
             map(lambda line: "> " + line, message.split('\n')))
         return tag.div(format_to_html(self.env,
                                       formatter.context.child(
                                           'changeset',
                                           rev,
                                           parent=resource),
                                       message,
                                       escape_newlines=True),
                        class_='message')
     else:
         return tag.pre(message, class_='message')
Exemple #11
0
 def render_widget(self, name, context, options):
     """Render widget considering given options.
     """
     if name == 'WidgetDoc':
         add_stylesheet(context.req, 'dashboard/css/docs.css')
         widget_name, = self.bind_params(options,
                                         self.get_widget_params(name),
                                         'urn')
         if widget_name is not None:
             try:
                 providers = [([widget_name],
                               self.resolve_widget(widget_name))]
             except LookupError:
                 return 'widget_alert.html', {
                     'title': _('Widget documentation'),
                     'data': {
                         'msglabel': 'Alert',
                         'msgbody': 'Unknown identifier',
                         'msgdetails': [('Widget name', widget_name)]
                     }
                 }, context
         else:
             providers = [(provider.get_widgets(), provider) \
                     for provider in self.widget_providers]
         metadata = [self._prepare_doc_metadata(self.widget_metadata(wnm, p)) \
                 for widgets, p in providers for wnm in widgets]
         docs_resource = Resource('wiki', 'BloodhoundWidgets')
         insert_docs = resource_exists(self.env, docs_resource) and \
                 not (context.resource and \
                 docs_resource == context.resource)
         return 'widget_doc.html', {
             'title':
             _('Widget documentation'),
             'data': {
                 'items': metadata
             },
             'ctxtnav': [
                 tag.a(tag.i(class_='icon-info-sign'),
                       ' ',
                       _('Help'),
                       href=get_resource_url(self.env, docs_resource,
                                             context.href))
             ] if insert_docs else [],
         }, context
     else:
         raise InvalidIdentifier('Widget name MUST match any of ' +
                                 ', '.join(self.get_widgets()),
                                 title='Invalid widget identifier')
Exemple #12
0
    def get_search_results(self, req, terms, filters):
        """Overriding search results for Tickets"""
        if not 'ticket' in filters:
            return
        ticket_realm = Resource('ticket')
        with self.env.db_query as db:
            sql, args = search_to_sql(db, [
                'summary', 'keywords', 'description', 'reporter', 'cc',
                db.cast('id', 'text')
            ], terms)
            sql2, args2 = search_to_sql(db, ['newvalue'], terms)
            sql3, args3 = search_to_sql(db, ['value'], terms)
            ticketsystem = TicketSystem(self.env)
            if req.args.get('product'):
                productsql = "product='%s' AND" % req.args.get('product')
            else:
                productsql = ""

            for summary, desc, author, type, tid, ts, status, resolution in \
                    db("""SELECT summary, description, reporter, type, id,
                                 time, status, resolution
                          FROM ticket
                          WHERE (%s id IN (
                              SELECT id FROM ticket WHERE %s
                            UNION
                              SELECT ticket FROM ticket_change
                              WHERE field='comment' AND %s
                            UNION
                              SELECT ticket FROM ticket_custom WHERE %s
                          ))
                          """ % (productsql, sql, sql2, sql3),
                          args + args2 + args3):
                t = ticket_realm(id=tid)
                if 'TICKET_VIEW' in req.perm(t):
                    yield (req.href.ticket(tid),
                           tag_("%(title)s: %(message)s",
                                title=tag.span(get_resource_shortname(
                                    self.env, t),
                                               class_=status),
                                message=ticketsystem.format_summary(
                                    summary, status, resolution,
                                    type)), from_utimestamp(ts), author,
                           shorten_result(desc, terms))

        # Attachments
        for result in AttachmentModule(self.env) \
                      .get_search_results(req, ticket_realm, terms):
            yield result
Exemple #13
0
 def query(self, req, qstr='status!=closed'):
     """
     Perform a ticket query, returning a list of ticket ID's.
     All queries will use stored settings for maximum number of results per
     page and paging options. Use `max=n` to define number of results to
     receive, and use `page=n` to page through larger result sets. Using
     `max=0` will turn off paging and return all results.
     """
     q = query.Query.from_string(self.env, qstr)
     ticket_realm = Resource('ticket')
     out = []
     for t in q.execute(req):
         tid = t['id']
         if 'TICKET_VIEW' in req.perm(ticket_realm(id=tid)):
             out.append(tid)
     return out
Exemple #14
0
    def render_timeline_event(self, context, field, event):
        # Decompose event data.
        id = event[3]

        # Return apropriate content.
        resource = Resource('downloads', id)
        if field == 'url':
           if context.req.perm.has_permission('DOWNLOADS_VIEW', resource):
               return get_resource_url(self.env, resource, context.req.href)
           else:
               return '#'
        elif field == 'title':
           return tag('New download ', tag.em(get_resource_name(self.env,
             resource)), ' created')
        elif field == 'description':
           return get_resource_description(self.env, resource, 'summary')
Exemple #15
0
 def test_resource_link_ticket_context_milestone_exists(self):
     """Resource link in ticket context for viewable milestone.
     """
     milestone = Milestone(self.env)
     milestone.name = 'milestone1'
     milestone.insert()
     req = MockRequest(self.env, path_info='/ticket/1')
     resource = Resource('milestone', 'milestone1')
     context = web_context(req)
     link = render_resource_link(self.env,
                                 context,
                                 resource,
                                 format='compact')
     self.assertEqual(
         '<a class="milestone" href="/trac.cgi/milestone/'
         'milestone1" title="No date set">milestone1</a>', unicode(link))
Exemple #16
0
    def _wiki_view(self, req, stream):
        tags = self._page_tags(req)
        if not tags:
            return stream
        tag_system = TagSystem(self.env)
        add_stylesheet(req, 'tags/css/tractags.css')
        li = []
        for tag_ in tags:
            resource = Resource('tag', tag_)
            anchor = render_resource_link(self.env,
                                          Context.from_request(req, resource),
                                          resource)
            li.append(tag.li(anchor, ' '))

        insert = tag.ul(class_='tags')(tag.li('Tags', class_='header'), li)
        return stream | Transformer('//div[@class="buttons"]').before(insert)
Exemple #17
0
def email_default_context():
    class NoEmailViewPerm(MockPerm):
        def has_permission(self,
                           action,
                           realm_or_resource=None,
                           id=False,
                           version=False):
            return action != 'EMAIL_VIEW'

        __contains__ = has_permission

    context = RenderingContext(Resource('wiki', 'WikiStart'),
                               href=Href('/'),
                               perm=NoEmailViewPerm())
    context.req = None  # 1.0 FIXME .req shouldn't be required by formatter
    return context
Exemple #18
0
    def download_created(self, context, download):
        # Check proper permissions to modify tags.
        if not context.req.perm.has_permission('TAGS_MODIFY'):
            return

        # Create temporary resource.
        resource = Resource(self.realm, download['id'])

        # Delete tags of download with same ID for sure.
        tag_system = TagSystem(self.env)
        tag_system.delete_tags(context.req, resource)

        # Add tags of new download.
        new_tags = self._get_tags(download)
        self.log.debug('tags: %s' % (new_tags, ))
        tag_system.add_tags(context.req, resource, new_tags)
Exemple #19
0
 def _render_list(self, req):
     """products list"""
     products = [
         p for p in Product.select(self.env)
         if 'PRODUCT_VIEW' in req.perm(Neighborhood('product', p.prefix))
     ]
     map(
         lambda p: setattr(
             p, 'href',
             resolve_product_href(lookup_product_env(self.env, p.prefix),
                                  self.env)), products)
     data = {
         'products': products,
         'context': web_context(req, Resource('product', None))
     }
     return 'product_list.html', data, None
Exemple #20
0
    def expand_macro(self, formatter, name, content, args={}):
        reponame = args.get('repository') or ''
        rev_str = args.get('revision')
        repos = RepositoryManager(self.env).get_repository(reponame)
        rev = None
        try:
            changeset = repos.get_changeset(repos.normalize_rev(rev_str))
            message = changeset.message
            rev = repos.db_rev(changeset.rev)
            resource = repos.resource

            # add review status to commit message (
            review = CodeReview(self.env, reponame, rev)
            status = review.encode(review.status)
            message += '\n\n{{{#!html \n'
            message += '<div class="codereviewstatus">'
            message += '  <div class="system-message %s">' % status.lower()
            message += '    <p>Code review status: '
            message += '      <span>%s</span>' % review.status
            message += '    </p>'
            message += '  </div>'
            message += '</div>'
            message += '\n}}}'

        except Exception:
            message = content
            resource = Resource('repository', reponame)
        if formatter.context.resource.realm == 'ticket':
            ticket_re = CommitTicketUpdater.ticket_re
            if not any(
                    int(tkt_id) == int(formatter.context.resource.id)
                    for tkt_id in ticket_re.findall(message)):
                return tag.p(
                    "(The changeset message doesn't reference this "
                    "ticket)",
                    class_='hint')
        if ChangesetModule(self.env).wiki_format_messages:
            ctxt = formatter.context
            return tag.div(format_to_html(self.env,
                                          ctxt('changeset',
                                               rev,
                                               parent=resource),
                                          message,
                                          escape_newlines=True),
                           class_='message')
        else:
            return tag.pre(message, class_='message')
Exemple #21
0
    def filter_stream(self, req, method, filename, stream, data):
        page_name = req.args.get('page', 'WikiStart')
        planid = req.args.get('planid', '-1')

        if page_name == 'TC':
            # The root catalog does not have workflows
            return stream

        if page_name.startswith('TC') and filename == 'wiki_view.html':
            self.log.debug(">>> TestManagerWorkflowInterface - filter_stream")
            req.perm.require('TEST_VIEW')

            # Determine which object is being displayed (i.e. realm),
            # based on Wiki page name and the presence of the planid
            # request parameter.
            realm = None
            if page_name.find('_TC') >= 0:
                if not planid or planid == '-1':
                    realm = 'testcase'
                    key = {'id': page_name.rpartition('_TC')[2]}
                else:
                    realm = 'testcaseinplan'
                    key = {
                        'id': page_name.rpartition('_TC')[2],
                        'planid': planid
                    }
            else:
                if not planid or planid == '-1':
                    realm = 'testcatalog'
                    key = {'id': page_name.rpartition('_TT')[2]}
                else:
                    realm = 'testplan'
                    key = {'id': planid}

            id = get_string_from_dictionary(key)
            res = Resource(realm, id)

            rwsystem = ResourceWorkflowSystem(self.env)
            workflow_markup = rwsystem.get_workflow_markup(
                req, '..', realm, res)

            self.log.debug("<<< TestManagerWorkflowInterface - filter_stream")

            return stream | Transformer(
                '//div[contains(@class,"wikipage")]').after(workflow_markup)

        return stream
    def filter_stream(self, req, method, filename, stream, data):
        crumbs = self._get_crumbs(req.session)
        if not crumbs:
            return stream

        add_stylesheet(req, 'breadcrumbs/css/breadcrumbs.css')
        ul = []

        path = req.path_info
        if path.count('/') >= 2:
            realm, resource_id = path.split('/', 2)[1:]
            if '&' in resource_id:
                resource_id = resource_id[0:resource_id.index('&')]
            current = '/'.join((realm, resource_id))
        else:
            current = None

        offset = 0
        if crumbs and crumbs[0] == current:
            offset = 1
        for crumb in crumbs[offset: self.max_crumbs + offset]:
            realm, resource_id = crumb.split('/', 1)
            resource = Resource(realm, resource_id)

            name = get_resource_shortname(self.env, resource)

            if not resource_exists(self.env, resource):
                continue

            title = get_resource_summary(self.env, resource)
            link = req.href(realm, resource_id)

            first = ul == []
            li = tag.li(tag.a(title=title, href=link)(name))
            if first:
                li(class_="first")
            ul.append(li)

        if ul:
            last = ul.pop()
            ul.append(last(class_="last"))
            label = self.label if self.label else "Breadcrumbs:"
            insert = tag.ul(class_="nav", id="breadcrumbs")(tag.li(label), ul)
        else:
            insert = ''

        return stream | Transformer('//div[@id="metanav"]/ul').after(insert)
Exemple #23
0
    def get_timeline_events(self, req, start, stop, filters):
        if 'build' not in filters:
            return

        # Attachments (will be rendered by attachment module)
        for event in AttachmentModule(self.env).get_timeline_events(
                req, Resource('build'), start, stop):
            yield event

        start = to_timestamp(start)
        stop = to_timestamp(stop)

        add_stylesheet(req, 'bitten/bitten.css')

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "SELECT b.id,b.config,c.label,c.path, b.rev,p.name,"
            "b.stopped,b.status FROM bitten_build AS b"
            "  INNER JOIN bitten_config AS c ON (c.name=b.config) "
            "  INNER JOIN bitten_platform AS p ON (p.id=b.platform) "
            "WHERE b.stopped>=%s AND b.stopped<=%s "
            "AND b.status IN (%s, %s) ORDER BY b.stopped",
            (start, stop, Build.SUCCESS, Build.FAILURE))

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        event_kinds = {
            Build.SUCCESS: 'successbuild',
            Build.FAILURE: 'failedbuild'
        }

        for id_, config, label, path, rev, platform, stopped, status in cursor:
            if not _has_permission(req.perm, repos, path, rev=rev):
                continue
            errors = []
            if status == Build.FAILURE:
                for step in BuildStep.select(self.env,
                                             build=id_,
                                             status=BuildStep.FAILURE,
                                             db=db):
                    errors += [(step.name, error) for error in step.errors]
            display_rev = repos.normalize_rev(rev)
            yield (event_kinds[status], to_datetime(stopped, utc), None,
                   (id_, config, label, display_rev, platform, status, errors))
Exemple #24
0
    def _download_link(self, formatter, ns, params, label):
        if ns == 'download':
            if formatter.req.perm.has_permission('DOWNLOADS_VIEW'):
                # Create context.
                context = Context.from_request(formatter.req)('downloads-wiki')
                db = self.env.get_db_cnx()
                context.cursor = db.cursor()

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

                # Get download.
                if re.match(r'\d+', params):
                    download = api.get_download(context, params)
                else:
                    download = api.get_download_by_file(context, params)

                if download:
                    if formatter.req.perm.has_permission(
                            'DOWNLOADS_VIEW',
                            Resource('downloads', download['id'])):
                        # Return link to existing file.
                        return html.a(
                            label,
                            href=formatter.href.downloads(params),
                            title='%s (%s)' %
                            (download['file'], pretty_size(download['size'])))
                    else:
                        # File exists but no permission to download it.
                        html.a(
                            label,
                            href='#',
                            title='%s (%s)' %
                            (download['file'], pretty_size(download['size'])),
                            class_='missing')
                else:
                    # Return link to non-existing file.
                    return html.a(label,
                                  href='#',
                                  title='File not found.',
                                  class_='missing')
            else:
                # Return link to file to which is no permission.
                return html.a(label,
                              href='#',
                              title='No permission to file.',
                              class_='missing')
Exemple #25
0
    def refresh_project(self, project_identifier, from_date, to_date=datetime.now(datefmt.localtz),
                        afilters=None, update=False):
        """
        Will refresh a project events in cache in given date range.

        .. NOTE::

            Dates needs to be given in datefmt.localtz form

        """
        # Initialize objects
        project = Project.get(env_name=project_identifier)
        if not project:
            conf.log.warning('Project {0} is already removed from system or it cannot be found'.format(project_identifier))
            return

        e = open_environment(conf.getEnvironmentSysPath(project.env_name), use_cache=True)
        pte = ProjectTimelineEvents(e)
        providers = pte.event_providers

        project_href = Href(conf.url_projects_path + '/' + project.env_name)

        context = Context(resource=Resource(), href=project_href)
        req = self._create_dummy_req(project_identifier)
        context.req = req
        context.perm = req.perm

        # Read events from timeline
        events = []
        for provider in providers:
            try:
                # Use filters in parameter or check filters from providers
                if afilters:
                    filters = afilters
                else:
                    available_filters = provider.get_timeline_filters(req) or []
                    filters = [f[0] for f in available_filters]

                for event in provider.get_timeline_events(req, from_date, to_date, filters):
                    event_data = self._event_data(provider, event)
                    if event_data['author'] != 'trac': # Skip system events
                        events.append(CachedEvent.from_event_data(project, event_data, context, filters[0]))
            except:
                conf.log.error("Could not read timeline events for %s from %s" % (project_identifier, str(provider)))

        # Write events into sql table
        self._write_events_into_cache(events, update)
    def validate_blog_comment(self, req, postname, fields):
        if 'previewcomment' in req.args:
            return []

        blog_res = Resource('blog', postname)
        if req.perm(blog_res).has_permission('BLOG_ADMIN'):
            return []

        author = fields.get('author', '')
        changes = [(None, fields.get('comment', '')), (None, author)]
        if arity(FilterSystem.test) == 4:
            # 0.11 compatible method signature
            FilterSystem(self.env).test(req, author, changes)
        else:
            # 0.12+ compatible that adds an 'ip' argument
            FilterSystem(self.env).test(req, author, changes, req.remote_addr)
        return []
Exemple #27
0
    def _sticky_from_query(self, req, query):
        for col in ['id', 'summary', 'type'] + self._fields:
            if col not in query.rows:
                query.rows.append(col)
        query.has_more_pages = False
        query.max = 0

        if hasattr(self.env, 'get_read_db'):
            db = self.env.get_read_db()
        else:
            db = self.env.get_db_cnx()
        tickets = []
        for ticket in query.execute(req, db):
            resource = Resource('ticket', ticket['id'])
            if 'TICKET_VIEW' in req.perm(resource):
                tickets.append(ticket)
        return self._sticky(req, tickets)
Exemple #28
0
 def _render_link(self, context, name, label, extra=''):
     try:
         version = Version(self.env, name)
     except TracError:
         version = None
     # Note: the above should really not be needed, `Milestone.exists`
     # should simply be false if the milestone doesn't exist in the db
     # (related to #4130)
     href = context.href.version(name)
     if version and version.exists:
         resource = Resource('version', name)
         if 'VERSION_VIEW' in context.perm(resource):
             return tag.a(label, class_='version', href=href + extra)
     elif 'VERSION_CREATE' in context.perm('version', name):
         return tag.a(label, class_='missing version', href=href + extra,
                      rel='nofollow')
     return tag.a(label, class_='missing version')
Exemple #29
0
    def test_log_link_checking_repository_resource(self):
        self.env.config.set(
            'trac', 'permission_policies',
            'TestLogModulePermissionPolicy, DefaultPermissionPolicy')
        resource = Resource('wiki', 'WikiStart')

        req = MockRequest(self.env, authname='anonymous')
        rendered = unicode(
            format_to_oneliner(self.env, web_context(req, resource),
                               'log:mock@42-43'))
        self.assertIn(' title="No permission to view change log"', rendered)

        req = MockRequest(self.env, authname='blah')
        rendered = unicode(
            format_to_oneliner(self.env, web_context(req, resource),
                               'log:mock@42-43'))
        self.assertIn(' href="/trac.cgi/log/mock/?revs=42-43"', rendered)
Exemple #30
0
    def _wiki_view(self, req, stream):
        add_stylesheet(req, 'tags/css/tractags.css')
        tags = self._page_tags(req)
        if not tags:
            return stream
        li = []
        for tag_ in tags:
            resource = Resource('tag', tag_)
            anchor = render_resource_link(self.env, web_context(req, resource),
                                          resource)
            anchor = anchor(rel='tag')
            li.append(tag.li(anchor, ' '))

        # TRANSLATOR: Header label text for tag list at wiki page bottom.
        insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li)
        return stream | (
            Transformer('//div[contains(@class,"wikipage")]').after(insert))
Exemple #31
0
 def process_request(self, req):
     # Allow all POST requests (with a valid __FORM_TOKEN, ensuring that
     # the client has at least some permission). Additionally, allow GET
     # requests from TRAC_ADMIN for testing purposes.
     if req.method != 'POST':
         req.perm.require('TRAC_ADMIN')
         
     # @todo: Embed "tips" within the rendered output for the editor
     # (recognize TracLinks, table-stuff, macros, processors)
     # @todo: Save the content in server-side user-specific field for recovery
     
     realm = req.args.get('realm', 'wiki')
     id = req.args.get('id')
     version = req.args.get('version')
     if version is not None:
         try:
             version = int(version)
         except ValueError:
             version = None
     text = req.args.get('text', '')
     flavor = req.args.get('flavor')
     options = {}
     if 'escape_newlines' in req.args:
         options['escape_newlines'] = bool(int(req.args['escape_newlines']
                                               or 0))
     if 'shorten' in req.args:
         options['shorten'] = bool(int(req.args['shorten'] or 0))
     
     resource = Resource(realm, id=id, version=version)
     context = Context.from_request(req, resource)
     rendered = format_to_cke_html(self.env, context, text, self.code_styles, **options)
     
     # since Trac renders underlined text as `<span class="underlined">text</span>
     # instead of u-tag, we need to adjust it for compatibility's sake
     # see also discussion at Google Groups:
     # https://groups.google.com/group/trac-dev/browse_thread/thread/833206a932d1f918
     html = HTML(rendered)
     html |= Transformer('//span[@class="underline"]').rename('u').attr('class', None)
     # CKEditor renders indentation by using p style="margin-left: 40px" 
     # instead of blockquote-tag
     html |= Transformer('//blockquote/p').attr('style', 'margin-left: 40px')
     html |= Transformer('//blockquote').unwrap()
     buffer = StringIO()
     html.render(out=buffer, encoding='utf-8')
     req.send( buffer.getvalue() )
     
Exemple #32
0
    def __init__(self, name, params, log):
        """Initialize a repository.

           :param name: a unique name identifying the repository, usually a
                        type-specific prefix followed by the path to the
                        repository.
           :param params: a `dict` of parameters for the repository. Contains
                          the name of the repository under the key "name" and
                          the surrogate key that identifies the repository in
                          the database under the key "id".
           :param log: a logger instance.
        """
        self.name = name
        self.params = params
        self.reponame = params['name']
        self.id = params['id']
        self.log = log
        self.resource = Resource('repository', self.reponame)
Exemple #33
0
    def filter_stream(self, req, method, filename, stream, data):
#        self.list_namespaces()
        # generate TracLink string
        resource = None
        if filename in ['ticket.html', 'wiki_view.html', 'report_view.html', 'milestone_view.html', 'agilo_ticket_view.html'] \
                and 'context' in data:
            resource = copy(data['context'].resource)
        elif filename in ['search.html']:  # search:
            resource = Resource('search', data['query'])
        elif filename in ['browser.html']:  # source:
            resource = copy(data['context'].resource)
            if resource.parent and resource.parent.realm == 'repository':
                resource.id = '%s/%s' % (resource.parent.id, resource.id)
                resource.parent = None
        elif filename in ['revisionlog.html']:  # log:
            resource = copy(data['context'].resource)
            resource.realm = 'log'
            if resource.parent and resource.parent.realm == 'repository':
                resource.id = '%s/%s' % (resource.parent.id, resource.id)
                resource.parent = None
            revranges = data.get('revranges', None)
            rev = data.get('rev', None)
            if revranges:
                resource.version = '%s:%s' % (revranges.a, revranges.b)
            elif rev:
                resource.version = rev
        elif filename in ['attachment.html']:
            if isinstance(data['attachment'], Attachment):  # attachment:
                resource = copy(data['attachment'].resource)
            else:
                pass  # attachment list page of the ticket; no TracLinks defined
        elif filename in ['timeline.html']:  # timeline:
            resource = Resource('timeline', format_datetime(data['precisedate'], 'iso8601'))
        elif filename in ['changeset.html']:
            if data['changeset']:  # changeset:
                resource = copy(data['context'].resource)
                if resource.parent and resource.parent.realm == 'repository':
                    resource.id = '%s/%s' % (resource.id, resource.parent.id)  # OK, I know
                    resource.parent = None
                if data['restricted']:
                    resource.id = '%s/%s' % (resource.id, data['new_path'])
            else:  # diff:
                args = req.args
                old_path, new_path = args.get('old_path', ''), args.get('new_path', '')
                old_rev, new_rev = args.get('old'), args.get('new')
                if old_path == new_path:  # diff:path@1:3 style
                    resource = Resource('diff', old_path, '%s:%s' % (old_rev, new_rev))
                else:  # diff:path@1//path@3 style
                    if old_rev:
                        old_path += '@%s' % old_rev
                    if new_rev:
                        new_path += '@%s' % new_rev
                    resource = Resource('diff', '%s//%s' % (old_path, new_path))
        elif filename in ['query.html']:
            if 'report_resource' in data:
                resource = copy(data['report_resource'])
            else:
                resource = Resource('query', data['query'].to_string().replace("\n", "")[7:])
        else:
            pass

        # link hash TODO: check wiki_view for agilo
        if filename in ['browser.html', 'changeset.html', 'ticket.html', 'agilo_ticket_view.html', 'wiki_view.html']:
            add_script(req, 'traclinks/js/jquery.ba-hashchange.js')
            add_script(req, 'traclinks/js/onhashchange.js')
        #
        if resource:
            traclinks = '%s' % (resource.id)
            if resource.version != None:
                traclinks += (resource.realm == 'ticket' and '?version=%s' or '@%s') % resource.version
            parent = resource.parent
            while parent and parent.id:
                traclinks += ':%s:%s' % (parent.realm, parent.id)
                if parent.version != None:
                    traclinks += '@%s' % parent.version
                parent = parent.parent
            if ' ' in traclinks:
                traclinks = '"%s"' % traclinks  # surround quote if needed
            traclinks = '%s:%s' % (resource.realm, traclinks)
            # new ticket template
            if resource.id == None and resource.realm == 'ticket':
                query_string = unicode_urlencode(
                    [(k, v) for k, v in data['ticket'].values.iteritems()
                            if v not in (None, '')])
                traclinks = '[/newticket?%s]' % query_string

            #return stream | Transformer('//input[@id="proj-search"]').attr('placeholder', traclinks).attr('size', '50')
            _input = tag.input(value=traclinks, readonly='', style=self.style)
            div = tag.div(_input, id="banner-traclink", style="float:right")
            return stream | Transformer('//div[@id="header"]').before(div)

        return stream
Exemple #34
0
class Repository(object):
    """Base class for a repository provided by a version control system."""

    has_linear_changesets = False

    scope = '/'

    def __init__(self, name, params, log):
        """Initialize a repository.

           :param name: a unique name identifying the repository, usually a
                        type-specific prefix followed by the path to the
                        repository.
           :param params: a `dict` of parameters for the repository. Contains
                          the name of the repository under the key "name" and
                          the surrogate key that identifies the repository in
                          the database under the key "id".
           :param log: a logger instance.
        """
        self.name = name
        self.params = params
        self.reponame = params['name']
        self.id = params['id']
        self.log = log
        self.resource = Resource('repository', self.reponame)

    def close(self):
        """Close the connection to the repository."""
        raise NotImplementedError

    def get_base(self):
        """Return the name of the base repository for this repository.

        This function returns the name of the base repository to which scoped
        repositories belong. For non-scoped repositories, it returns the
        repository name.
        """
        return self.name

    def clear(self, youngest_rev=None):
        """Clear any data that may have been cached in instance properties.

        `youngest_rev` can be specified as a way to force the value
        of the `youngest_rev` property (''will change in 0.12'').
        """
        pass

    def sync(self, rev_callback=None, clean=False):
        """Perform a sync of the repository cache, if relevant.

        If given, `rev_callback` must be a callable taking a `rev` parameter.
        The backend will call this function for each `rev` it decided to
        synchronize, once the synchronization changes are committed to the
        cache. When `clean` is `True`, the cache is cleaned first.
        """
        pass

    def sync_changeset(self, rev):
        """Resync the repository cache for the given `rev`, if relevant.

        Returns a "metadata-only" changeset containing the metadata prior to
        the resync, or `None` if the old values cannot be retrieved (typically
        when the repository is not cached).
        """
        return None

    def get_quickjump_entries(self, rev):
        """Generate a list of interesting places in the repository.

        `rev` might be used to restrict the list of available locations,
        but in general it's best to produce all known locations.

        The generated results must be of the form (category, name, path, rev).
        """
        return []

    def get_path_url(self, path, rev):
        """Return the repository URL for the given path and revision.

        The returned URL can be `None`, meaning that no URL has been specified
        for the repository, an absolute URL, or a scheme-relative URL starting
        with `//`, in which case the scheme of the request should be prepended.
        """
        return None

    def get_changeset(self, rev):
        """Retrieve a Changeset corresponding to the given revision `rev`."""
        raise NotImplementedError

    def get_changeset_uid(self, rev):
        """Return a globally unique identifier for the ''rev'' changeset.

        Two changesets from different repositories can sometimes refer to
        the ''very same'' changeset (e.g. the repositories are clones).
        """

    def get_changesets(self, start, stop):
        """Generate Changeset belonging to the given time period (start, stop).
        """
        rev = self.youngest_rev
        while rev:
            chgset = self.get_changeset(rev)
            if chgset.date < start:
                return
            if chgset.date < stop:
                yield chgset
            rev = self.previous_rev(rev)

    def has_node(self, path, rev=None):
        """Tell if there's a node at the specified (path,rev) combination.

        When `rev` is `None`, the latest revision is implied.
        """
        try:
            self.get_node(path, rev)
            return True
        except TracError:
            return False

    def get_node(self, path, rev=None):
        """Retrieve a Node from the repository at the given path.

        A Node represents a directory or a file at a given revision in the
        repository.
        If the `rev` parameter is specified, the Node corresponding to that
        revision is returned, otherwise the Node corresponding to the youngest
        revision is returned.
        """
        raise NotImplementedError

    def get_oldest_rev(self):
        """Return the oldest revision stored in the repository."""
        raise NotImplementedError
    oldest_rev = property(lambda self: self.get_oldest_rev())

    def get_youngest_rev(self):
        """Return the youngest revision in the repository."""
        raise NotImplementedError
    youngest_rev = property(lambda self: self.get_youngest_rev())

    def previous_rev(self, rev, path=''):
        """Return the revision immediately preceding the specified revision.

        If `path` is given, filter out ancestor revisions having no changes
        below `path`.

        In presence of multiple parents, this follows the first parent.
        """
        raise NotImplementedError

    def next_rev(self, rev, path=''):
        """Return the revision immediately following the specified revision.

        If `path` is given, filter out descendant revisions having no changes
        below `path`.

        In presence of multiple children, this follows the first child.
        """
        raise NotImplementedError

    def parent_revs(self, rev):
        """Return a list of parents of the specified revision."""
        parent = self.previous_rev(rev)
        return [parent] if parent is not None else []

    def rev_older_than(self, rev1, rev2):
        """Provides a total order over revisions.

        Return `True` if `rev1` is an ancestor of `rev2`.
        """
        raise NotImplementedError

    def get_path_history(self, path, rev=None, limit=None):
        """Retrieve all the revisions containing this path.

        If given, `rev` is used as a starting point (i.e. no revision
        ''newer'' than `rev` should be returned).
        The result format should be the same as the one of Node.get_history()
        """
        raise NotImplementedError

    def normalize_path(self, path):
        """Return a canonical representation of path in the repos."""
        raise NotImplementedError

    def normalize_rev(self, rev):
        """Return a (unique) canonical representation of a revision.

        It's up to the backend to decide which string values of `rev`
        (usually provided by the user) should be accepted, and how they
        should be normalized. Some backends may for instance want to match
        against known tags or branch names.

        In addition, if `rev` is `None` or '', the youngest revision should
        be returned.
        """
        raise NotImplementedError

    def short_rev(self, rev):
        """Return a compact representation of a revision in the repos."""
        return self.normalize_rev(rev)

    def display_rev(self, rev):
        """Return a representation of a revision in the repos for displaying to
        the user.

        This can be a shortened revision string, e.g. for repositories using
        long hashes.
        """
        return self.normalize_rev(rev)

    def get_changes(self, old_path, old_rev, new_path, new_rev,
                    ignore_ancestry=1):
        """Generates changes corresponding to generalized diffs.

        Generator that yields change tuples (old_node, new_node, kind, change)
        for each node change between the two arbitrary (path,rev) pairs.

        The old_node is assumed to be None when the change is an ADD,
        the new_node is assumed to be None when the change is a DELETE.
        """
        raise NotImplementedError

    def is_viewable(self, perm):
        """Return True if view permission is granted on the repository."""
        return 'BROWSER_VIEW' in perm(self.resource.child('source', '/'))

    can_view = is_viewable  # 0.12 compatibility