Beispiel #1
0
    def get_user_setting(self, sid):
        """Returns tuple of (value, authenticated).

        Value is always True or None.  This will work with Genshi template
        checkbox logic.
        """
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("""
                SELECT value, authenticated
                  FROM session_attribute
                 WHERE sid=%s
                   AND name=%s
            """, (sid, self._attr_name()))
            row = cursor.fetchone()
            if row:
                dists, v = decode(row[0])
                value = as_bool(v)
                authenticated = as_bool(row[1])
            else:
                dists = self.default['dists']
                value = as_bool(self.default['value'])
                authenticated = False

            # We use None here so that Genshi templates check their checkboxes
            # properly and without confusion.
            return dists, value and True or None, authenticated
    def check_permission(self, action, username, resource, perm):
        """Check that the action can be performed by username on the resource."""

        # To prevent recursion
        if action in self.get_permission_actions():
            return
        # To prevent recursion when used together with sensitive tickets
        if action == 'SENSITIVE_VIEW':
            return

        # Check whether we're dealing with a ticket resource
        while resource:
            if resource.realm == 'ticket':
                break
            resource = resource.parent
        
        if resource and resource.realm == 'ticket' and resource.id is not None:
            component_permission = 'COMPONENT_VIEW' # Default just to make check logic simpler
            bypass = False
            try:
                ticket = model.Ticket(self.env, int(resource.id))
                should_check_permissions = not self.ticket_field_name or ticket.values.get(self.ticket_field_name, 0)
                if as_bool(should_check_permissions):
                    if 'component' in ticket.values and ticket['component'] and self._get_permission_name(ticket['component']) in self.get_permission_actions():
                        component_permission = self._get_permission_name(ticket['component'])
                    bypass = self._get_bypass(ticket, username)
            except ResourceNotFound:
                should_check_permissions = 1 # Fail safe to prevent a race condition

            if as_bool(should_check_permissions):
                if component_permission not in perm and 'COMPONENT_VIEW' not in perm and not bypass:
                    return False
Beispiel #3
0
    def check_permission(self, action, username, resource, perm):
        # We add the 'SENSITIVE_VIEW' pre-requisite for any action
        # other than 'SENSITIVE_VIEW' itself, as this would lead
        # to recursion.
        if action == 'SENSITIVE_VIEW':
            return
        
        # Check whether we're dealing with a ticket resource
        while resource:
            if resource.realm == 'ticket':
                break
            resource = resource.parent

        if resource and resource.realm == 'ticket' and resource.id is not None:
            bypass = False
            try:
                ticket = Ticket(self.env, int(resource.id))
                sensitive = ticket['sensitive']
                if as_bool(sensitive):
                    bypass = self.bypass_sensitive_view(ticket, username)
            except ResourceNotFound:
                sensitive = 1  # Fail safe to prevent a race condition.

            if as_bool(sensitive):
                if 'SENSITIVE_VIEW' not in perm and not bypass:
                    return False
    def check_permission(self, action, username, resource, perm):
        # We add the 'SENSITIVE_VIEW' pre-requisite for any action
        # other than 'SENSITIVE_VIEW' itself, as this would lead
        # to recursion.
        if action == 'SENSITIVE_VIEW':
            return

        # Check whether we're dealing with a ticket resource
        while resource:
            if resource.realm == 'ticket':
                break
            resource = resource.parent

        if resource and resource.realm == 'ticket' and resource.id is not None:
            bypass = False
            try:
                ticket = Ticket(self.env, int(resource.id))
                sensitive = ticket['sensitive']
                if as_bool(sensitive):
                    bypass = self.bypass_sensitive_view(ticket, username)
            except ResourceNotFound:
                sensitive = 1  # Fail safe to prevent a race condition.

            if as_bool(sensitive):
                if 'SENSITIVE_VIEW' not in perm and not bypass:
                    return False
Beispiel #5
0
    def expand_macro(self, formatter, name, text):

        req = formatter.req
        context = formatter.context
        resource = context.resource

        # Process the arguments.
        args, kwargs = parse_args(text)

        if 'ticket' not in kwargs and len(args)>0:
            kwargs['ticket'] = args[0]
        elif 'ticket' not in kwargs and not len(args):
            kwargs['ticket'] = str( WikiPage(self.env, resource).name )   # This seems to provide the correct ticket id.

        try:
            kwargs['ticket'] = int( kwargs.get('ticket').lstrip('#') )
        except ValueError:
            raise TracError('No ticket id supplied or it is not valid integer value.')

        ticket = Ticket( self.env, kwargs['ticket'] )

        self.childtickets = {}    # { parent -> children } - 1:n

        db = self.env.get_db_cnx() 
        cursor = db.cursor() 
        cursor.execute("SELECT ticket,value FROM ticket_custom WHERE name='parent'")
        for child,parent in cursor.fetchall():
            if parent and re.match('#\d+',parent):
                self.childtickets.setdefault( int(parent.lstrip('#')), [] ).append(child)

        # First ticket has no indentation.
        ticket['indent'] = '0'

        # List of tickets that will be displayed.
        if as_bool( kwargs.get('root') ):
            self.tickets = [ ticket, ]
        else:
            self.tickets = []

        # Do this neater!
        self.indent_children(ticket)

        def ticket_anchor(t):
            return tag.a( '#%s' % t.id, class_=t['status'], href=req.href.ticket(int(t.id)), title="%s : %s : %s" % (t['type'],t['owner'],t['status']))

        def_list = tag.dl(
                [( tag.dt(ticket_anchor(t),style='padding-left: %spx;' % (t['indent']*20)), tag.dd("%s" % t['summary'])) for t in self.tickets],
                class_='wiki compact',
                )

        if as_bool( kwargs.get('border') ):
            return tag.fieldset(
                    def_list,
                    tag.legend('Ticket Child Tree (#%s)' % ticket.id),
                    class_='description',
                    )
        else:
            return tag.div(def_list)
Beispiel #6
0
    def expand_macro(self, formatter, name, content):
        args, kwargs = parse_args(content)
        format = kwargs.get('format', 'compact')
        glob = kwargs.get('glob', '*')
        order = kwargs.get('order')
        desc = as_bool(kwargs.get('desc', 0))

        rm = RepositoryManager(self.env)
        all_repos = dict(rdata for rdata in rm.get_all_repositories().items()
                         if fnmatchcase(rdata[0], glob))

        if format == 'table':
            repo = self._render_repository_index(formatter.context, all_repos,
                                                 order, desc)

            add_stylesheet(formatter.req, 'common/css/browser.css')
            wiki_format_messages = self.config['changeset'] \
                                       .getbool('wiki_format_messages')
            data = {'repo': repo, 'order': order, 'desc': 1 if desc else None,
                    'reponame': None, 'path': '/', 'stickyrev': None,
                    'wiki_format_messages': wiki_format_messages}
            from trac.web.chrome import Chrome
            return Chrome(self.env).render_template(
                    formatter.req, 'repository_index.html', data, None,
                    fragment=True)

        def get_repository(reponame):
            try:
                return rm.get_repository(reponame)
            except TracError:
                return

        all_repos = [(reponame, get_repository(reponame))
                     for reponame in all_repos]
        all_repos = sorted(((reponame, repos) for reponame, repos in all_repos
                            if repos
                            and not as_bool(repos.params.get('hidden'))
                            and repos.is_viewable(formatter.perm)),
                           reverse=desc)

        def repolink(reponame, repos):
            label = reponame or _('(default)')
            return Markup(tag.a(label,
                          title=_('View repository %(repo)s', repo=label),
                          href=formatter.href.browser(repos.reponame or None)))

        if format == 'list':
            return tag.dl([
                tag(tag.dt(repolink(reponame, repos)),
                    tag.dd(repos.params.get('description')))
                for reponame, repos in all_repos])
        else: # compact
            return Markup(', ').join([repolink(reponame, repos)
                                      for reponame, repos in all_repos])
 def _do_remove_managed(self, name, delete):
     rm = RepositoryManager(self.env)
     repository = rm.get_repository(name)
     if not repository:
         raise AdminCommandError(
             _('Repository "%(name)s" does not exists', name=name))
     rm.remove(repository, as_bool(delete))
Beispiel #8
0
 def pre_process_request(self, req, handler):
     from trac.web.chrome import Chrome, add_warning
     if handler is not Chrome(self.env):
         for repo_info in self.get_all_repositories().values():
             if not as_bool(repo_info.get('sync_per_request')):
                 continue
             start = time.time()
             repo_name = repo_info['name'] or '(default)'
             try:
                 repo = self.get_repository(repo_info['name'])
                 repo.sync()
             except TracError as e:
                 add_warning(req,
                     _("Can't synchronize with repository \"%(name)s\" "
                       "(%(error)s). Look in the Trac log for more "
                       "information.", name=repo_name,
                       error=to_unicode(e)))
             except Exception as e:
                 add_warning(req,
                     _("Failed to sync with repository \"%(name)s\": "
                       "%(error)s; repository information may be out of "
                       "date. Look in the Trac log for more information "
                       "including mitigation strategies.",
                       name=repo_name, error=to_unicode(e)))
                 self.log.error(
                     "Failed to sync with repository \"%s\"; You may be "
                     "able to reduce the impact of this issue by "
                     "configuring the sync_per_request option; see "
                     "http://trac.edgewall.org/wiki/TracRepositoryAdmin"
                     "#ExplicitSync for more detail: %s", repo_name,
                     exception_to_unicode(e, traceback=True))
             self.log.info("Synchronized '%s' repository in %0.2f seconds",
                           repo_name, time.time() - start)
     return handler
Beispiel #9
0
 def _do_set(self, section, option, value):
     self.config.set(section, option, value)
     if section == 'components' and as_bool(value):
         self.config.set_defaults(component=option)
     self.config.save()
     if section == 'inherit' and option == 'file':
         self.config.parse_if_needed(force=True)  # Full reload
Beispiel #10
0
 def set_user_setting(self, session, value=None, dists=('email',),
                      save=True):
     """Sets session attribute to 1 or 0."""
     session[self._attr_name()] = \
         encode(dists, '1' if as_bool(value) else '0')
     if save:
         session.save()
Beispiel #11
0
 def _do_set(self, section, option, value):
     self.config.set(section, option, value)
     if section == 'components' and as_bool(value):
         self.config.set_defaults(component=option)
     self.config.save()
     if section == 'inherit' and option == 'file':
         self.config.parse_if_needed(force=True)  # Full reload
Beispiel #12
0
    def process_request(self, req):
        presel = req.args.get('preselected')
        if presel and (presel + '/').startswith(req.href.browser() + '/'):
            req.redirect(presel)

        path = req.args.get('path', '/')
        rev = req.args.get('rev', '')
        if rev.lower() in ('', 'head'):
            rev = None
        format = req.args.get('format')
        order = req.args.get('order', 'name').lower()
        desc = 'desc' in req.args
        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'

        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == '/'
        if show_index:
            if repos and (as_bool(all_repositories[''].get('hidden'))
                          or not repos.is_viewable(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found",
                                     repo=reponame))

        if reponame and reponame != repos.reponame: # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path)
                         + ('?' + qs if qs else ''))
        reponame = repos.reponame if repos else None

        # Find node for the requested path/rev
        context = web_context(req)
        node = None
        changeset = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset, e:
                raise ResourceNotFound(e, _('Invalid changeset number'))
            if node:
                try:
                    # use changeset instance to retrieve branches and tags
                    changeset = repos.get_changeset(node.rev)
                except NoSuchChangeset:
                    pass

            context = context.child(repos.resource.child('source', path,
                                                   version=rev_or_latest))
            display_rev = repos.display_rev
Beispiel #13
0
 def pre_process_request(self, req, handler):
     from trac.web.chrome import Chrome, add_warning
     if handler is not Chrome(self.env):
         for repo_info in self.get_all_repositories().values():
             if not as_bool(repo_info.get('sync_per_request')):
                 continue
             start = time.time()
             repo_name = repo_info['name'] or '(default)'
             try:
                 repo = self.get_repository(repo_info['name'])
                 repo.sync()
             except TracError as e:
                 add_warning(req,
                     _("Can't synchronize with repository \"%(name)s\" "
                       "(%(error)s). Look in the Trac log for more "
                       "information.", name=repo_name,
                       error=to_unicode(e)))
             except Exception as e:
                 add_warning(req,
                     _("Failed to sync with repository \"%(name)s\": "
                       "%(error)s; repository information may be out of "
                       "date. Look in the Trac log for more information "
                       "including mitigation strategies.",
                       name=repo_name, error=to_unicode(e)))
                 self.log.error(
                     "Failed to sync with repository \"%s\"; You may be "
                     "able to reduce the impact of this issue by "
                     "configuring the sync_per_request option; see "
                     "http://trac.edgewall.org/wiki/TracRepositoryAdmin"
                     "#ExplicitSync for more detail: %s", repo_name,
                     exception_to_unicode(e, traceback=True))
             self.log.info("Synchronized '%s' repository in %0.2f seconds",
                           repo_name, time.time() - start)
     return handler
Beispiel #14
0
    def getbool(self, name, default=None):
        """Return the value as a boolean. Raise an `HTTPBadRequest`
        exception if an exception occurs while converting the value to
        a boolean.

        :param name: the name of the request parameter
        :keyword default: the value to return if the parameter is not
                          specified.

        :since: 1.2
        """
        if name not in self:
            return default
        value = self[name]
        if isinstance(value, list):
            raise HTTPBadRequest(
                tag_("Invalid value for request argument "
                     "%(name)s.",
                     name=tag.em(name)))
        value = as_bool(value, None)
        if value is None:
            raise HTTPBadRequest(
                tag_("Invalid value for request argument "
                     "%(name)s.",
                     name=tag.em(name)))
        return value
Beispiel #15
0
    def custom_fields(self):
        """Return the list of custom ticket fields available for tickets."""
        fields = TicketFieldList()
        config = self.ticket_custom_section
        for name in [
                option for option, value in config.options()
                if '.' not in option
        ]:
            field = {
                'name':
                name,
                'custom':
                True,
                'type':
                config.get(name),
                'order':
                config.getint(name + '.order', 0),
                'label':
                config.get(name + '.label')
                or name.replace("_", " ").strip().capitalize(),
                'value':
                config.get(name + '.value', '')
            }
            if field['type'] == 'select' or field['type'] == 'radio':
                field['options'] = config.getlist(name + '.options', sep='|')
                if not field['options']:
                    continue
                if '' in field['options'] or \
                        field['name'] in self.allowed_empty_fields:
                    field['optional'] = True
                    if '' in field['options']:
                        field['options'].remove('')
            elif field['type'] == 'checkbox':
                field['value'] = '1' if as_bool(field['value']) else '0'
            elif field['type'] == 'text':
                field['format'] = config.get(name + '.format', 'plain')
                field['max_size'] = config.getint(name + '.max_size', 0)
            elif field['type'] == 'textarea':
                field['format'] = config.get(name + '.format', 'plain')
                field['max_size'] = config.getint(name + '.max_size', 0)
                field['height'] = config.getint(name + '.rows')
            elif field['type'] == 'time':
                field['format'] = config.get(name + '.format', 'datetime')

            if field['name'] in self.reserved_field_names:
                self.log.warning(
                    'Field name "%s" is a reserved name '
                    '(ignoring)', field['name'])
                continue
            if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', field['name']):
                self.log.warning(
                    'Invalid name for custom field: "%s" '
                    '(ignoring)', field['name'])
                continue

            fields.append(field)

        fields.sort(key=lambda f: (f['order'], f['name']))
        return fields
Beispiel #16
0
    def _render_repository_index(self, context, all_repositories, order, desc):
        # Color scale for the age column
        timerange = custom_colorizer = None
        if self.color_scale:
            custom_colorizer = self.get_custom_colorizer()

        rm = RepositoryManager(self.env)
        repositories = []
        for reponame, repoinfo in all_repositories.iteritems():
            if not reponame or as_bool(repoinfo.get('hidden')):
                continue
            try:
                repos = rm.get_repository(reponame)
            except TracError as err:
                entry = (reponame, repoinfo, None, None,
                         exception_to_unicode(err), None)
            else:
                if repos:
                    if not repos.is_viewable(context.perm):
                        continue
                    try:
                        youngest = repos.get_changeset(repos.youngest_rev)
                    except NoSuchChangeset:
                        youngest = None
                    if self.color_scale and youngest:
                        if not timerange:
                            timerange = TimeRange(youngest.date)
                        else:
                            timerange.insert(youngest.date)
                    raw_href = self._get_download_href(context.href, repos,
                                                       None, None)
                    entry = (reponame, repoinfo, repos, youngest, None,
                             raw_href)
                else:
                    entry = (reponame, repoinfo, None, None, u"\u2013", None)
            if entry[4] is not None:  # Check permission in case of error
                root = Resource('repository', reponame).child('source', '/')
                if 'BROWSER_VIEW' not in context.perm(root):
                    continue
            repositories.append(entry)

        # Ordering of repositories
        if order == 'date':
            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return (youngest.date if youngest else to_datetime(0),
                        embedded_numbers(reponame.lower()))
        elif order == 'author':
            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return (youngest.author.lower() if youngest else '',
                        embedded_numbers(reponame.lower()))
        else:
            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return embedded_numbers(reponame.lower())

        repositories = sorted(repositories, key=repo_order, reverse=desc)

        return {'repositories' : repositories,
                'timerange': timerange, 'colorize_age': custom_colorizer}
Beispiel #17
0
    def _render_repository_index(self, context, all_repositories, order, desc):
        # Color scale for the age column
        timerange = custom_colorizer = None
        if self.color_scale:
            custom_colorizer = self.get_custom_colorizer()

        rm = RepositoryManager(self.env)
        repositories = []
        for reponame, repoinfo in all_repositories.iteritems():
            if not reponame or as_bool(repoinfo.get("hidden")):
                continue
            try:
                repos = rm.get_repository(reponame)
            except TracError as err:
                entry = (reponame, repoinfo, None, None, exception_to_unicode(err), None)
            else:
                if repos:
                    if not repos.is_viewable(context.perm):
                        continue
                    try:
                        youngest = repos.get_changeset(repos.youngest_rev)
                    except NoSuchChangeset:
                        youngest = None
                    if self.color_scale and youngest:
                        if not timerange:
                            timerange = TimeRange(youngest.date)
                        else:
                            timerange.insert(youngest.date)
                    raw_href = self._get_download_href(context.href, repos, None, None)
                    entry = (reponame, repoinfo, repos, youngest, None, raw_href)
                else:
                    entry = (reponame, repoinfo, None, None, u"\u2013", None)
            if entry[4] is not None:  # Check permission in case of error
                root = Resource("repository", reponame).child(self.realm, "/")
                if "BROWSER_VIEW" not in context.perm(root):
                    continue
            repositories.append(entry)

        # Ordering of repositories
        if order == "date":

            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return (youngest.date if youngest else to_datetime(0), embedded_numbers(reponame.lower()))

        elif order == "author":

            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return (youngest.author.lower() if youngest else "", embedded_numbers(reponame.lower()))

        else:

            def repo_order((reponame, repoinfo, repos, youngest, err, href)):
                return embedded_numbers(reponame.lower())

        repositories = sorted(repositories, key=repo_order, reverse=desc)

        return {"repositories": repositories, "timerange": timerange, "colorize_age": custom_colorizer}
Beispiel #18
0
    def process_request(self, req):
        req.perm.require('BROWSER_VIEW')

        presel = req.args.get('preselected')
        if presel and (presel + '/').startswith(req.href.browser() + '/'):
            req.redirect(presel)

        path = req.args.get('path', '/')
        rev = req.args.get('rev', '')
        if rev.lower() in ('', 'head'):
            rev = None
        format = req.args.get('format')
        order = req.args.get('order', 'name').lower()
        desc = req.args.has_key('desc')
        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'

        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == '/'
        if show_index:
            if repos and (as_bool(all_repositories[''].get('hidden'))
                          or not repos.is_viewable(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found",
                                     repo=reponame))

        if reponame and reponame != repos.reponame: # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path)
                         + ('?' + qs if qs else ''))
        reponame = repos.reponame if repos else None

        # Find node for the requested path/rev
        context = web_context(req)
        node = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset, e:
                raise ResourceNotFound(e.message,
                                       _('Invalid changeset number'))

            context = context.child(repos.resource.child('source', path,
                                                   version=rev_or_latest))
            display_rev = repos.display_rev
Beispiel #19
0
    def get_subscriptions(self):
        """Generates tuples of (distributor, sid, authenticated, email).

        Tuples are suitable for yielding from IAnnouncementSubscriber's
        subscriptions method.
        """
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("""
                SELECT sid, authenticated, value
                  FROM session_attribute
                 WHERE name=%s
            """, (self._attr_name(),))
            for result in cursor.fetchall():
                dists, val = decode(result[2])
                for dist in dists:
                    if as_bool(val):
                        authenticated = as_bool(result[1])
                        yield (dist, result[0], authenticated, None)
Beispiel #20
0
    def getbool(self, key, default=''):
        """Return the value of the specified option as boolean.
        
        This method returns `True` if the option value is one of "yes", "true",
        "enabled", "on", or non-zero numbers, ignoring case. Otherwise `False`
        is returned.

        Valid default input is a string or a bool. Returns a bool.
        """
        return as_bool(self.get(key, default))
Beispiel #21
0
    def getbool(self, key, default=''):
        """Return the value of the specified option as boolean.

        This method returns `True` if the option value is one of "yes",
        "true", "enabled", "on", or non-zero numbers, ignoring case.
        Otherwise `False` is returned.

        Valid default input is a string or a bool. Returns a bool.
        """
        return as_bool(self.get(key, default))
Beispiel #22
0
    def process_request(self, req):
        req.perm.require('BROWSER_VIEW')

        presel = req.args.get('preselected')
        if presel and (presel + '/').startswith(req.href.browser() + '/'):
            req.redirect(presel)

        path = req.args.get('path', '/')
        rev = req.args.get('rev', '')
        if rev in ('', 'HEAD'):
            rev = None
        order = req.args.get('order', 'name').lower()
        desc = req.args.has_key('desc')
        xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest'
        
        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == '/'
        if show_index:
            if repos and (as_bool(all_repositories[''].get('hidden'))
                          or not repos.can_view(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found",
                                     repo=reponame))

        if reponame and reponame != repos.reponame: # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path)
                         + (qs and '?' + qs or ''))
        reponame = repos and repos.reponame or None
        
        # Find node for the requested path/rev
        context = Context.from_request(req)
        node = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset, e:
                raise ResourceNotFound(e.message,
                                       _('Invalid changeset number'))

            context = context(repos.resource.child('source', path,
                                                   version=rev_or_latest))
            display_rev = repos.display_rev
Beispiel #23
0
 def get_ticket_group_stats(self, ticket_ids):
     stat = TicketGroupStats(self.drilldown_label, self.sum_label)
     for group in self._get_groups(ticket_ids):
         stat.add_interval(title=group.get('label', group['name']),
                           count=group.get('total', 0),
                           qry_args=group.get('query_args', {}),
                           css_class=group.get('css_class', group['name']),
                           overall_completion=as_bool(
                               group.get('overall_completion')))
     stat.refresh_calcs()
     return stat
Beispiel #24
0
 def get_ticket_group_stats(self, ticket_ids):
     stat = TicketGroupStats(self.drilldown_label, self.sum_label)
     for group in self._get_groups(ticket_ids):
         stat.add_interval(
             title=group.get('label', group['name']),
             count=group.get('total', 0),
             qry_args=group.get('query_args', {}),
             css_class=group.get('css_class', group['name']),
             overall_completion=as_bool(group.get('overall_completion')))
     stat.refresh_calcs()
     return stat
Beispiel #25
0
 def _get_repository_data_from_request(self, req, prefix=''):
     """Fill a dict with common repository data for create/fork/modify
     actions.
     """
     directory = req.args.get(prefix + 'dir')
     if self.restrict_dir or not directory:
         directory = req.args.get(prefix + 'name')
     return {'name': req.args.get(prefix + 'name'),
             'type': req.args.get(prefix + 'type'),
             'dir': normalize_whitespace(directory),
             'owner': req.args.get(prefix + 'owner', req.authname),
             'inherit_readers': as_bool(req.args.get('inherit_readers'))}
Beispiel #26
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info['name'] = reponame
     info['hidden'] = as_bool(info.get('hidden'))
     info['editable'] = editable
     if 'alias' not in info:
         if info.get('dir') is not None:
             info['prettydir'] = breakable_path(info['dir']) or ''
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
         except InvalidRepository, e:
             info['error'] = e
         except TracError:
             pass  # Probably "unsupported connector"
Beispiel #27
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info['name'] = reponame
     info['hidden'] = as_bool(info.get('hidden'))
     info['editable'] = editable
     if 'alias' not in info:
         if info.get('dir') is not None:
             info['prettydir'] = breakable_path(info['dir']) or ''
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
         except InvalidRepository, e:
             info['error'] = e
         except TracError:
             pass  # Probably "unsupported connector"
Beispiel #28
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info["name"] = reponame
     info["hidden"] = as_bool(info.get("hidden"))
     info["sync_per_request"] = as_bool(info.get("sync_per_request"))
     info["editable"] = editable
     if "alias" not in info:
         if info.get("dir") is not None:
             info["prettydir"] = breakable_path(info["dir"]) or ""
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
         except InvalidRepository as e:
             info["error"] = e
         except TracError:
             pass  # Probably "unsupported connector"
         else:
             youngest_rev = repos.get_youngest_rev()
             info["rev"] = youngest_rev
             try:
                 info["display_rev"] = repos.display_rev(youngest_rev)
             except NoSuchChangeset:
                 pass
     return info
Beispiel #29
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info['name'] = reponame
     info['hidden'] = as_bool(info.get('hidden'))
     info['sync_per_request'] = as_bool(info.get('sync_per_request'))
     info['editable'] = editable
     if 'alias' not in info:
         if info.get('dir') is not None:
             info['prettydir'] = breakable_path(info['dir']) or ''
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
         except InvalidRepository as e:
             info['error'] = e
         except TracError:
             pass  # Probably "unsupported connector"
         else:
             youngest_rev = repos.get_youngest_rev()
             info['rev'] = youngest_rev
             try:
                 info['display_rev'] = repos.display_rev(youngest_rev)
             except NoSuchChangeset:
                 pass
     return info
Beispiel #30
0
    def as_bool(self, key, default=None):
        """Return the value as a boolean. Return `default` if
        if an exception is raised while converting the value to a
        boolean.

        :param key: the name of the session attribute
        :keyword default: the value to return if the parameter is not
                          specified or an exception occurs converting
                          the value to a boolean.

        :since: 1.2
        """
        if key not in self:
            return default
        return as_bool(self[key], default)
Beispiel #31
0
    def as_bool(self, name, default=None):
        """Return the value as a boolean. Return `default` if
        if an exception is raised while converting the value to a
        boolean.

        :param name: the name of the request parameter
        :keyword default: the value to return if the parameter is not
                          specified or an exception occurs converting
                          the value to a boolean.

        :since: 1.2
        """
        if name not in self:
            return default
        return as_bool(self.getfirst(name), default)
Beispiel #32
0
 def validate_ticket(self, req, ticket):
     if not self.limit_sensitivity:
         return []
     sensitive = 1
     try:
         sensitive = ticket['sensitive']
     except:
         pass
     if as_bool(sensitive):
         if req.authname is 'anonymous':
             return [(None, 'Sorry, you cannot create or update a sensitive ticket without at least logging in first')]
         if self.bypass_sensitive_view(ticket, req.authname):
             return []
         req.perm(ticket.resource).require('SENSITIVE_VIEW')
     return []
Beispiel #33
0
 def _do_set(self, reponame, key, value):
     if key not in self.repository_attrs:
         raise AdminCommandError(_('Invalid key "%(key)s"', key=key))
     if key == 'dir':
         value = os.path.abspath(value)
     if key in ('hidden', 'sync_per_request'):
         value = '1' if as_bool(value) else None
     self.modify_repository(reponame, {key: value})
     if not reponame:
         reponame = '(default)'
     if key == 'dir':
         printout(_('You should now run "repository resync %(name)s".',
                    name=reponame))
     elif key == 'type':
         printout(_('You may have to run "repository resync %(name)s".',
                    name=reponame))
Beispiel #34
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info['name'] = reponame
     if info.get('dir') is not None:
         info['prettydir'] = breakable_path(info['dir']) or ''
     info['hidden'] = as_bool(info.get('hidden'))
     info['editable'] = editable
     if not info.get('alias'):
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
             youngest_rev = repos.get_youngest_rev()
             info['rev'] = youngest_rev
             info['display_rev'] = repos.display_rev(youngest_rev)
         except Exception:
             pass
     return info
Beispiel #35
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info['name'] = reponame
     if info.get('dir') is not None:
         info['prettydir'] = breakable_path(info['dir']) or ''
     info['hidden'] = as_bool(info.get('hidden'))
     info['editable'] = editable
     if not info.get('alias'):
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
             youngest_rev = repos.get_youngest_rev()
             info['rev'] = youngest_rev
             info['display_rev'] = repos.display_rev(youngest_rev)
         except Exception:
             pass
     return info
Beispiel #36
0
 def _extend_info(self, reponame, info, editable):
     """Extend repository info for rendering."""
     info["name"] = reponame
     if info.get("dir") is not None:
         info["prettydir"] = breakable_path(info["dir"]) or ""
     info["hidden"] = as_bool(info.get("hidden"))
     info["editable"] = editable
     if not info.get("alias"):
         try:
             repos = RepositoryManager(self.env).get_repository(reponame)
             youngest_rev = repos.get_youngest_rev()
             info["rev"] = youngest_rev
             info["display_rev"] = repos.display_rev(youngest_rev)
         except Exception:
             pass
     return info
Beispiel #37
0
 def _do_set(self, reponame, key, value):
     if key not in self.repository_attrs:
         raise AdminCommandError(_('Invalid key "%(key)s"', key=key))
     if key == 'dir':
         value = os.path.abspath(value)
     if key in ('hidden', 'sync_per_request'):
         value = '1' if as_bool(value) else None
     self.modify_repository(reponame, {key: value})
     if not reponame:
         reponame = '(default)'
     if key == 'dir':
         printout(_('You should now run "repository resync %(name)s".',
                    name=reponame))
     elif key == 'type':
         printout(_('You may have to run "repository resync %(name)s".',
                    name=reponame))
 def validate_ticket(self, req, ticket):
     if not self.limit_sensitivity:
         return []
     sensitive = 1
     try:
         sensitive = ticket['sensitive']
     except:
         pass
     if as_bool(sensitive):
         if req.authname is 'anonymous':
             return [(
                 None,
                 'Sorry, you cannot create or update a sensitive ticket without at least logging in first'
             )]
         if self.bypass_sensitive_view(ticket, req.authname):
             return []
         req.perm(ticket.resource).require('SENSITIVE_VIEW')
     return []
Beispiel #39
0
    def _render_list(self, req):
        """Render the list of available reports."""
        sort = req.args.get('sort', 'report')
        asc = as_bool(req.args.get('asc', 1))
        format = req.args.get('format')

        rows = self.env.db_query("""
                SELECT id, title, description FROM report ORDER BY %s %s
                """ % ('title' if sort == 'title' else 'id',
                       '' if asc else 'DESC'))
        rows = [(id, title, description) for id, title, description in rows
                if 'REPORT_VIEW' in req.perm('report', id)]

        if format == 'rss':
            data = {'rows': rows}
            return 'report_list.rss', data, 'application/rss+xml'
        elif format == 'csv':
            self._send_csv(req, ['report', 'title', 'description'],
                           rows, mimetype='text/csv',
                           filename='reports.csv')
        elif format == 'tab':
            self._send_csv(req, ['report', 'title', 'description'],
                           rows, '\t', mimetype='text/tab-separated-values',
                           filename='reports.tsv')

        def report_href(**kwargs):
            return req.href.report(sort=req.args.get('sort'),
                                   asc='1' if asc else '0', **kwargs)

        add_link(req, 'alternate',
                 auth_link(req, report_href(format='rss')),
                 _('RSS Feed'), 'application/rss+xml', 'rss')
        add_link(req, 'alternate', report_href(format='csv'),
                 _('Comma-delimited Text'), 'text/plain')
        add_link(req, 'alternate', report_href(format='tab'),
                 _('Tab-delimited Text'), 'text/plain')

        reports = [(id, title, description,
                    'REPORT_MODIFY' in req.perm('report', id),
                    'REPORT_DELETE' in req.perm('report', id))
                   for id, title, description in rows]
        data = {'reports': reports, 'sort': sort, 'asc': asc}

        return 'report_list.html', data, None
Beispiel #40
0
    def _convert_value(self, value, option=None):
        """ Converts a config value into a string so that it can be used by Genshi
            without needing to convert or escape anything.
        """
        if option is not None:
            option_type = option.__class__.__name__
            if option_type == 'BoolOption':
                if as_bool(str(value)):
                    return 'true'
                else:
                    return 'false'
            elif (option_type == 'ListOption'
                  or option_type == 'OrderedExtensionsOption'
                  ) and type(value).__name__ == 'list':
                return unicode(option.sep).join(value)

        if value is None:
            return ''

        return unicode(value)
Beispiel #41
0
def parse_subscriber_config(rawsubscriptions):
    """Given a list of options from [notification-subscriber]"""

    required_attrs = {
        'distributor': 'email',
        'priority': 100,
        'adverb': 'always',
        'format': 'text/plain',
    }
    optional_attrs = {}
    known_attrs = required_attrs.copy()
    known_attrs.update(optional_attrs)

    byname = defaultdict(dict)
    for option, value in rawsubscriptions:
        parts = option.split('.', 1)
        name = parts[0]
        if len(parts) == 1:
            byname[name].update({'name': name, 'class': value.strip()})
        else:
            attribute = parts[1]
            known = known_attrs.get(attribute)
            if known is None or isinstance(known, basestring):
                pass
            elif isinstance(known, int):
                value = int(value)
            elif isinstance(known, bool):
                value = as_bool(value)
            elif isinstance(known, list):
                value = to_list(value)
            byname[name][attribute] = value

    byclass = defaultdict(list)
    for name, attributes in byname.items():
        for key, value in required_attrs.items():
            attributes.setdefault(key, value)
        byclass[attributes['class']].append(attributes)
    for values in byclass.values():
        values.sort(key=lambda value: (value['priority'], value['name']))

    return byclass
Beispiel #42
0
def parse_subscriber_config(rawsubscriptions):
    """Given a list of options from [notification-subscriber]"""

    required_attrs = {
        'distributor': 'email',
        'priority': 100,
        'adverb': 'always',
        'format': 'text/plain',
    }
    optional_attrs = {}
    known_attrs = required_attrs.copy()
    known_attrs.update(optional_attrs)

    byname = defaultdict(dict)
    for option, value in rawsubscriptions:
        parts = option.split('.', 1)
        name = parts[0]
        if len(parts) == 1:
            byname[name].update({'name': name, 'class': value.strip()})
        else:
            attribute = parts[1]
            known = known_attrs.get(attribute)
            if known is None or isinstance(known, basestring):
                pass
            elif isinstance(known, int):
                value = int(value)
            elif isinstance(known, bool):
                value = as_bool(value)
            elif isinstance(known, list):
                value = to_list(value)
            byname[name][attribute] = value

    byclass = defaultdict(list)
    for name, attributes in byname.items():
        for key, value in required_attrs.items():
            attributes.setdefault(key, value)
        byclass[attributes['class']].append(attributes)
    for values in byclass.values():
        values.sort(key=lambda value: (value['priority'], value['name']))

    return byclass
Beispiel #43
0
    def get_user_setting(self, sid):
        """Returns tuple of (value, authenticated)."""
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("""
                SELECT value, authenticated
                  FROM session_attribute
                 WHERE sid=%s
                   AND name=%s
            """, (sid, self._attr_name()))
            row = cursor.fetchone()
            if row:
                pair = decode(row[0])
                authenticated = as_bool(row[1])
            else:
                pair = (self.default['dists'], self.default['value'])
                authenticated = False

            # We use None here so that Genshi templates check their checkboxes
            # properly and without confusion.
            return pair + (authenticated,)
Beispiel #44
0
    def _render_repository_index(self, context, all_repositories, order, desc):
        # Color scale for the age column
        timerange = custom_colorizer = None
        if self.color_scale:
            custom_colorizer = self.get_custom_colorizer()

        rm = RepositoryManager(self.env)
        repositories = []
        for reponame, repoinfo in all_repositories.iteritems():
            if not reponame or as_bool(repoinfo.get('hidden')):
                continue
            try:
                repos = rm.get_repository(reponame)
            except TracError, err:
                entry = (reponame, repoinfo, None, None,
                         exception_to_unicode(err), None)
            else:
                if repos:
                    if not repos.is_viewable(context.perm):
                        continue
                    try:
                        youngest = repos.get_changeset(repos.youngest_rev)
                    except NoSuchChangeset:
                        youngest = None
                    if self.color_scale and youngest:
                        if not timerange:
                            timerange = TimeRange(youngest.date)
                        else:
                            timerange.insert(youngest.date)
                    raw_href = self._get_download_href(context.href, repos,
                                                       None, None)
                    entry = (reponame, repoinfo, repos, youngest, None,
                             raw_href)
                else:
                    entry = (reponame, repoinfo, None, None, u"\u2013", None)
            if entry[4] is not None:  # Check permission in case of error
                root = Resource('repository', reponame).child('source', '/')
                if 'BROWSER_VIEW' not in context.perm(root):
                    continue
            repositories.append(entry)
Beispiel #45
0
    def _render_repository_index(self, context, all_repositories, order, desc):
        # Color scale for the age column
        timerange = custom_colorizer = None
        if self.color_scale:
            custom_colorizer = self.get_custom_colorizer()

        rm = RepositoryManager(self.env)
        repositories = []
        for reponame, repoinfo in all_repositories.iteritems():
            if not reponame or as_bool(repoinfo.get('hidden')):
                continue
            try:
                repos = rm.get_repository(reponame)
            except TracError, err:
                entry = (reponame, repoinfo, None, None,
                         exception_to_unicode(err), None)
            else:
                if repos:
                    if not repos.is_viewable(context.perm):
                        continue
                    try:
                        youngest = repos.get_changeset(repos.youngest_rev)
                    except NoSuchChangeset:
                        youngest = None
                    if self.color_scale and youngest:
                        if not timerange:
                            timerange = TimeRange(youngest.date)
                        else:
                            timerange.insert(youngest.date)
                    raw_href = self._get_download_href(context.href, repos,
                                                       None, None)
                    entry = (reponame, repoinfo, repos, youngest, None,
                             raw_href)
                else:
                    entry = (reponame, repoinfo, None, None, u"\u2013", None)
            if entry[4] is not None:  # Check permission in case of error
                root = Resource('repository', reponame).child('source', '/')
                if 'BROWSER_VIEW' not in context.perm(root):
                    continue
            repositories.append(entry)
    def __init__(self):
        self.section = 'multiproject-files'
        # logic is a mapping from configuration_key to
        # tuple (default_value, value_getter, strip_value)
        _as_bool = lambda ignored_key, value: as_bool(value)
        self.logic = {
            'default_downloads_directory':
            ('downloads', self._get_directory, True),
            'sys_dav_root': ('/var/www/trac/webdav', self._get_abspath, True),
            'url_dav_path': ('dav', self._get_relative_url, True),
            'downloads_dir_customizable': ('True', _as_bool, True),
        }

        values = {}
        self.defaults = {}
        value = None
        options = {}
        try:
            items = Configuration.instance().config_parser.items(self.section)
            for item in items:
                options[item[0]] = item[1]
        except NoSectionError:
            options = {}

        for key, logic in self.logic.items():
            default_val, handler, do_strip = logic
            self.defaults[key] = default_val
            if key not in options:
                value = handler(key, default_val)
            else:
                value = options[key].strip() if do_strip else options[key]
                value = handler(key, value)
            values[key] = value

        self.default_downloads_directory = values[
            'default_downloads_directory']
        self.sys_dav_root = values['sys_dav_root']
        self.url_dav_path = values['url_dav_path']
        self.downloads_dir_customizable = values['downloads_dir_customizable']
Beispiel #47
0
    def get_subscriptions(self, match):
        """Generates tuples of (distributor, sid, authenticated, email).

        `match` should is passed the string value of the setting and should
        return true or false depending on whether the subscription matches.

        Tuples are suitable for yielding from IAnnouncementSubscriber's
        subscriptions method.
        """
        with self.env.db_query as db:
            cursor = db.cursor()
            cursor.execute("""
                SELECT sid, authenticated, value
                  FROM session_attribute
                 WHERE name=%s
            """, (self._attr_name(),))
            for result in cursor.fetchall():
                dists, val = decode(result[2])
                for dist in dists:
                    if match(dist, val):
                        authenticated = as_bool(result[1])
                        yield (dist, result[0], authenticated, None)
Beispiel #48
0
def parse_subscriber_config(rawsubscriptions):
    """Given a list of options from [notification-subscriber]"""

    required_attrs = {
        'distributor': 'email',
        'priority': 100,
        'adverb': 'always',
        'format': 'text/plain',
    }
    optional_attrs = {}
    known_attrs = required_attrs.copy()
    known_attrs.update(optional_attrs)

    byname = defaultdict(dict)
    for option, value in rawsubscriptions:
        parts = option.split('.')
        name = parts[0]
        if len(parts) == 1:
            byname[name]['name'] = name
            byname[name]['class'] = value.strip()
        else:
            attribute = parts[1]
            if attribute not in known_attrs.keys or \
                    isinstance(known_attrs[attribute], str):
                byname[name][attribute] = value
            elif isinstance(known_attrs[attribute], int):
                byname[name][attribute] = int(value)
            elif isinstance(known_attrs[attribute], bool):
                byname[name][attribute] = as_bool(value)
            elif isinstance(known_attrs[attribute], list):
                byname[name][attribute] = to_list(value)

    byclass = defaultdict(list)
    for name, attributes in byname.items():
        for key, val in required_attrs.items():
            attributes.setdefault(key, val)
        byclass[attributes['class']].append(attributes)

    return byclass
Beispiel #49
0
    def __init__(self):
        self.section = 'multiproject-files'
        # logic is a mapping from configuration_key to
        # tuple (default_value, value_getter, strip_value)
        _as_bool = lambda ignored_key, value: as_bool(value)
        self.logic = {
            'default_downloads_directory': ('downloads', self._get_directory, True),
            'sys_dav_root': ('/var/www/trac/webdav', self._get_abspath, True),
            'url_dav_path': ('dav', self._get_relative_url, True),
            'downloads_dir_customizable': ('True', _as_bool, True),
        }

        values = {}
        self.defaults = {}
        value = None
        options = {}
        try:
            items = Configuration.instance().config_parser.items(self.section)
            for item in items:
                options[item[0]] = item[1]
        except NoSectionError:
            options = {}

        for key, logic in self.logic.items():
            default_val, handler, do_strip = logic
            self.defaults[key] = default_val
            if key not in options:
                value = handler(key, default_val)
            else:
                value = options[key].strip() if do_strip else options[key]
                value = handler(key, value)
            values[key] = value

        self.default_downloads_directory = values['default_downloads_directory']
        self.sys_dav_root = values['sys_dav_root']
        self.url_dav_path = values['url_dav_path']
        self.downloads_dir_customizable = values['downloads_dir_customizable']
Beispiel #50
0
 def normalize(self, value):
     if value not in (True, False):
         value = as_bool(value)
     return self.dumps(value)
Beispiel #51
0
    def process_request(self, req):
        presel = req.args.get("preselected")
        if presel and (presel + "/").startswith(req.href.browser() + "/"):
            req.redirect(presel)

        path = req.args.get("path", "/")
        rev = req.args.get("rev", "")
        if rev.lower() in ("", "head"):
            rev = None
        format = req.args.get("format")
        order = req.args.get("order", "name").lower()
        desc = "desc" in req.args

        rm = RepositoryManager(self.env)
        all_repositories = rm.get_all_repositories()
        reponame, repos, path = rm.get_repository_by_path(path)

        # Repository index
        show_index = not reponame and path == "/"
        if show_index:
            if repos and (as_bool(all_repositories[""].get("hidden")) or not repos.is_viewable(req.perm)):
                repos = None

        if not repos and reponame:
            raise ResourceNotFound(_("Repository '%(repo)s' not found", repo=reponame))

        if reponame and reponame != repos.reponame:  # Redirect alias
            qs = req.query_string
            req.redirect(req.href.browser(repos.reponame or None, path) + ("?" + qs if qs else ""))
        reponame = repos.reponame if repos else None

        # Find node for the requested path/rev
        context = web_context(req)
        node = None
        changeset = None
        display_rev = lambda rev: rev
        if repos:
            try:
                if rev:
                    rev = repos.normalize_rev(rev)
                # If `rev` is `None`, we'll try to reuse `None` consistently,
                # as a special shortcut to the latest revision.
                rev_or_latest = rev or repos.youngest_rev
                node = get_existing_node(req, repos, path, rev_or_latest)
            except NoSuchChangeset as e:
                raise ResourceNotFound(e, _("Invalid changeset number"))
            if node:
                try:
                    # use changeset instance to retrieve branches and tags
                    changeset = repos.get_changeset(node.rev)
                except NoSuchChangeset:
                    pass

            context = context.child(repos.resource.child(self.realm, path, version=rev_or_latest))
            display_rev = repos.display_rev

        # Prepare template data
        path_links = get_path_links(req.href, reponame, path, rev, order, desc)

        repo_data = dir_data = file_data = None
        if show_index:
            repo_data = self._render_repository_index(context, all_repositories, order, desc)
        if node:
            if not node.is_viewable(req.perm):
                raise PermissionError("BROWSER_VIEW" if node.isdir else "FILE_VIEW", node.resource, self.env)
            if node.isdir:
                if format in ("zip",):  # extension point here...
                    self._render_zip(req, context, repos, node, rev)
                    # not reached
                dir_data = self._render_dir(req, repos, node, rev, order, desc)
            elif node.isfile:
                file_data = self._render_file(req, context, repos, node, rev)

        if not repos and not (repo_data and repo_data["repositories"]):
            # If no viewable repositories, check permission instead of
            # repos.is_viewable()
            req.perm.require("BROWSER_VIEW")
            if show_index:
                raise ResourceNotFound(_("No viewable repositories"))
            else:
                raise ResourceNotFound(_("No node %(path)s", path=path))

        quickjump_data = properties_data = None
        if node and not req.is_xhr:
            properties_data = self.render_properties("browser", context, node.get_properties())
            quickjump_data = list(repos.get_quickjump_entries(rev))

        data = {
            "context": context,
            "reponame": reponame,
            "repos": repos,
            "repoinfo": all_repositories.get(reponame or ""),
            "path": path,
            "rev": node and node.rev,
            "stickyrev": rev,
            "display_rev": display_rev,
            "changeset": changeset,
            "created_path": node and node.created_path,
            "created_rev": node and node.created_rev,
            "properties": properties_data,
            "path_links": path_links,
            "order": order,
            "desc": 1 if desc else None,
            "repo": repo_data,
            "dir": dir_data,
            "file": file_data,
            "quickjump_entries": quickjump_data,
            "wiki_format_messages": self.config["changeset"].getbool("wiki_format_messages"),
            "xhr": req.is_xhr,  # Remove in 1.3.1
        }
        if req.is_xhr:  # render and return the content only
            return "dir_entries.html", data, None

        if dir_data or repo_data:
            add_script(req, "common/js/expand_dir.js")
            add_script(req, "common/js/keyboard_nav.js")

        # Links for contextual navigation
        if node:
            if node.isfile:
                prev_rev = repos.previous_rev(rev=node.created_rev, path=node.created_path)
                if prev_rev:
                    href = req.href.browser(reponame, node.created_path, rev=prev_rev)
                    add_link(req, "prev", href, _("Revision %(num)s", num=display_rev(prev_rev)))
                if rev is not None:
                    add_link(req, "up", req.href.browser(reponame, node.created_path))
                next_rev = repos.next_rev(rev=node.created_rev, path=node.created_path)
                if next_rev:
                    href = req.href.browser(reponame, node.created_path, rev=next_rev)
                    add_link(req, "next", href, _("Revision %(num)s", num=display_rev(next_rev)))
                prevnext_nav(req, _("Previous Revision"), _("Next Revision"), _("Latest Revision"))
            else:
                if path != "/":
                    add_link(req, "up", path_links[-2]["href"], _("Parent directory"))
                add_ctxtnav(
                    req, tag.a(_("Last Change"), href=req.href.changeset(node.created_rev, reponame, node.created_path))
                )
            if node.isfile:
                annotate = data["file"]["annotate"]
                if annotate:
                    add_ctxtnav(
                        req,
                        _("Normal"),
                        title=_("View file without annotations"),
                        href=req.href.browser(reponame, node.created_path, rev=rev),
                    )
                if annotate != "blame":
                    add_ctxtnav(
                        req,
                        _("Blame"),
                        title=_(
                            "Annotate each line with the last " "changed revision " "(this can be time consuming...)"
                        ),
                        href=req.href.browser(reponame, node.created_path, rev=rev, annotate="blame"),
                    )
            add_ctxtnav(req, _("Revision Log"), href=req.href.log(reponame, path, rev=rev))
            path_url = repos.get_path_url(path, rev)
            if path_url:
                if path_url.startswith("//"):
                    path_url = req.scheme + ":" + path_url
                add_ctxtnav(req, _("Repository URL"), href=path_url)

        add_stylesheet(req, "common/css/browser.css")
        return "browser.html", data, None
Beispiel #52
0
    def expand_macro(self, formatter, name, content):
        args, kwargs = parse_args(content)
        format = kwargs.get("format", "compact")
        glob = kwargs.get("glob", "*")
        order = kwargs.get("order")
        desc = as_bool(kwargs.get("desc", 0))

        rm = RepositoryManager(self.env)
        all_repos = dict(rdata for rdata in rm.get_all_repositories().items() if fnmatchcase(rdata[0], glob))

        if format == "table":
            repo = self._render_repository_index(formatter.context, all_repos, order, desc)

            add_stylesheet(formatter.req, "common/css/browser.css")
            wiki_format_messages = self.config["changeset"].getbool("wiki_format_messages")
            data = {
                "repo": repo,
                "order": order,
                "desc": 1 if desc else None,
                "reponame": None,
                "path": "/",
                "stickyrev": None,
                "wiki_format_messages": wiki_format_messages,
            }
            from trac.web.chrome import Chrome

            return Chrome(self.env).render_template(formatter.req, "repository_index.html", data, None, fragment=True)

        def get_repository(reponame):
            try:
                return rm.get_repository(reponame)
            except TracError:
                return

        all_repos = [(reponame, get_repository(reponame)) for reponame in all_repos]
        all_repos = sorted(
            (
                (reponame, repos)
                for reponame, repos in all_repos
                if repos and not as_bool(repos.params.get("hidden")) and repos.is_viewable(formatter.perm)
            ),
            reverse=desc,
        )

        def repolink(reponame, repos):
            label = reponame or _("(default)")
            return Markup(
                tag.a(
                    label,
                    title=_("View repository %(repo)s", repo=label),
                    href=formatter.href.browser(repos.reponame or None),
                )
            )

        if format == "list":
            return tag.dl(
                [
                    tag(tag.dt(repolink(reponame, repos)), tag.dd(repos.params.get("description")))
                    for reponame, repos in all_repos
                ]
            )
        else:  # compact
            return Markup(", ").join([repolink(reponame, repos) for reponame, repos in all_repos])
Beispiel #53
0
    def get_ticket_group_stats(self, ticket_ids):
        total_cnt = len(ticket_ids)
        all_statuses = set(TicketSystem(self.env).get_all_status())
        status_cnt = {}
        for s in all_statuses:
            status_cnt[s] = 0
        if total_cnt:
            for status, count in self.env.db_query("""
                    SELECT status, count(status) FROM ticket
                    WHERE id IN (%s) GROUP BY status
                    """ % ",".join(str(x) for x in sorted(ticket_ids))):
                status_cnt[status] = count

        stat = TicketGroupStats(_('ticket status'), _('tickets'))
        remaining_statuses = set(all_statuses)
        groups =  self._get_ticket_groups()
        catch_all_group = None
        # we need to go through the groups twice, so that the catch up group
        # doesn't need to be the last one in the sequence
        for group in groups:
            status_str = group['status'].strip()
            if status_str == '*':
                if catch_all_group:
                    raise TracError(_(
                        "'%(group1)s' and '%(group2)s' milestone groups "
                        "both are declared to be \"catch-all\" groups. "
                        "Please check your configuration.",
                        group1=group['name'], group2=catch_all_group['name']))
                catch_all_group = group
            else:
                group_statuses = set([s.strip()
                                      for s in status_str.split(',')]) \
                                      & all_statuses
                if group_statuses - remaining_statuses:
                    raise TracError(_(
                        "'%(groupname)s' milestone group reused status "
                        "'%(status)s' already taken by other groups. "
                        "Please check your configuration.",
                        groupname=group['name'],
                        status=', '.join(group_statuses - remaining_statuses)))
                else:
                    remaining_statuses -= group_statuses
                group['statuses'] = group_statuses
        if catch_all_group:
            catch_all_group['statuses'] = remaining_statuses
        for group in groups:
            group_cnt = 0
            query_args = {}
            for s, cnt in status_cnt.iteritems():
                if s in group['statuses']:
                    group_cnt += cnt
                    query_args.setdefault('status', []).append(s)
            for arg in [kv for kv in group.get('query_args', '').split(',')
                        if '=' in kv]:
                k, v = [a.strip() for a in arg.split('=', 1)]
                query_args.setdefault(k, []).append(v)
            stat.add_interval(group.get('label', group['name']),
                              group_cnt, query_args,
                              group.get('css_class', group['name']),
                              as_bool(group.get('overall_completion')))
        stat.refresh_calcs()
        return stat