예제 #1
0
    def _render_editor(self, req, milestone):
        data = {
            'milestone': milestone,
            'datetime_hint': get_datetime_format_hint(req.lc_time),
            'default_due': self.get_default_due(req),
            'milestone_groups': [],
        }

        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_MODIFY')
            milestones = [
                m for m in Milestone.select(self.env)
                if m.name != milestone.name
                and 'MILESTONE_VIEW' in req.perm(m.resource)
            ]
            data['milestone_groups'] = group_milestones(
                milestones, 'TICKET_ADMIN' in req.perm)
            data['num_open_tickets'] = \
                get_num_tickets_for_milestone(self.env, milestone,
                                              exclude_closed=True)
            data['retarget_to'] = self.default_retarget_to
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')
            if milestone.name:
                add_notice(
                    req,
                    _(
                        "Milestone %(name)s does not exist. You can"
                        " create it here.",
                        name=milestone.name))

        chrome = Chrome(self.env)
        chrome.add_jquery_ui(req)
        chrome.add_wiki_toolbars(req)
        add_stylesheet(req, 'common/css/roadmap.css')
        return 'milestone_edit.html', data, None
예제 #2
0
    def render(self, context, mimetype, content, filename=None, rev=None):
        req = context.req
        content = content_to_unicode(self.env, content, mimetype)
        changes = self._diff_to_hdf(content.splitlines(),
                                    Mimeview(self.env).tab_width)
        if not changes or not any(c['diffs'] for c in changes):
            self.log.warning('Invalid unified diff content')
            return
        data = {
            'diff': {
                'style': 'inline'
            },
            'no_id': True,
            'changes': changes,
            'longcol': 'File',
            'shortcol': ''
        }

        add_script(req, 'common/js/diff.js')
        add_stylesheet(req, 'common/css/diff.css')
        return Chrome(self.env).render_template(req,
                                                'diff_div.html',
                                                data,
                                                fragment=True)
예제 #3
0
파일: chrome.py 프로젝트: starworldx/trac
    def test_add_jquery_ui_timezone_list_has_default_timezone(self):
        chrome = Chrome(self.env)
        gmt07b = timezone('GMT -7:00')
        gmt04a = timezone('GMT +4:00')

        def verify_tzprops(lc_time, tz, tz_default, tz_label):
            req = MockRequest(self.env,
                              locale=locale_en,
                              lc_time=lc_time,
                              tz=tz)
            chrome.add_jquery_ui(req)
            data = req.chrome['script_data']['jquery_ui']
            self.assertEqual(tz_default, data['default_timezone'])
            if tz_label is not None:
                self.assertIn({
                    'value': tz_default,
                    'label': tz_label
                }, data['timezone_list'])

        verify_tzprops('iso8601', utc, 0, '+00:00')
        verify_tzprops(locale_en, utc, 0, None)
        verify_tzprops('iso8601', gmt07b, -420, '-07:00')
        verify_tzprops(locale_en, gmt07b, -420, None)
        verify_tzprops('iso8601', gmt04a, 240, '+04:00')
        verify_tzprops(locale_en, gmt04a, 240, None)
        if pytz:
            # must use timezones which does not use DST
            guam = timezone('Pacific/Guam')
            monrovia = timezone('Africa/Monrovia')
            panama = timezone('America/Panama')
            verify_tzprops('iso8601', guam, 600, '+10:00')
            verify_tzprops(locale_en, guam, 600, None)
            verify_tzprops('iso8601', monrovia, 0, '+00:00')
            verify_tzprops(locale_en, monrovia, 0, None)
            verify_tzprops('iso8601', panama, -300, '-05:00')
            verify_tzprops(locale_en, panama, -300, None)
예제 #4
0
    def content(self, req, ticket):
        chrome = Chrome(self.env)
        template = chrome.load_template('image-sidebar.html')
        imagetrac = ImageTrac(self.env)
        if imagetrac:
            images = imagetrac.images(ticket, req.href)
            display = 'default'
        else:
            image = self.image(ticket)
            link = req.href('attachment', 'ticket', ticket.id, image, format='raw')
            images = dict(image=dict(original=link))
            display = 'original'

        # default ticket image
        default = None
        if self.env.is_component_enabled(DefaultTicketImage):
            default = DefaultTicketImage(self.env).default_image(ticket.id)

        # generate the template
        return template.generate(display=display, 
                                 images=images,
                                 req=req,
                                 default=default,
                                 ticket=ticket)
예제 #5
0
파일: chrome.py 프로젝트: ohanar/trac
    def test_icon_links(self):
        req = Request(abs_href=Href('http://example.org/trac.cgi'),
                      href=Href('/trac.cgi'),
                      base_path='/trac.cgi',
                      path_info='',
                      add_redirect_listener=lambda listener: None)
        chrome = Chrome(self.env)

        # No icon set in config, so no icon links
        self.env.config.set('project', 'icon', '')
        links = chrome.prepare_request(req)['links']
        assert 'icon' not in links
        assert 'shortcut icon' not in links

        # Relative URL for icon config option
        self.env.config.set('project', 'icon', 'foo.ico')
        links = chrome.prepare_request(req)['links']
        self.assertEqual('/trac.cgi/chrome/common/foo.ico',
                         links['icon'][0]['href'])
        self.assertEqual('/trac.cgi/chrome/common/foo.ico',
                         links['shortcut icon'][0]['href'])

        # URL relative to the server root for icon config option
        self.env.config.set('project', 'icon', '/favicon.ico')
        links = chrome.prepare_request(req)['links']
        self.assertEqual('/favicon.ico', links['icon'][0]['href'])
        self.assertEqual('/favicon.ico', links['shortcut icon'][0]['href'])

        # Absolute URL for icon config option
        self.env.config.set('project', 'icon',
                            'http://example.com/favicon.ico')
        links = chrome.prepare_request(req)['links']
        self.assertEqual('http://example.com/favicon.ico',
                         links['icon'][0]['href'])
        self.assertEqual('http://example.com/favicon.ico',
                         links['shortcut icon'][0]['href'])
예제 #6
0
    def test_preview_valid_xhtml(self):
        chrome = Chrome(self.env)
        module = AttachmentModule(self.env)

        def render(attachment):
            path_info = '/attachment/%s/%s/%s' % (attachment.parent_realm,
                                                  attachment.parent_id,
                                                  attachment.filename)
            req = MockRequest(self.env, path_info=path_info)
            self.assertTrue(module.match_request(req))
            template, data = module.process_request(req)
            return chrome.render_template(req, template, data,
                                          {'fragment': True})

        # empty file
        attachment = Attachment(self.env, 'parent_realm', 'parent_id')
        attachment.insert('empty', io.BytesIO(), 0, 1)
        result = render(attachment)
        self.assertIn('<strong>(The file is empty)</strong>', result)
        xml = minidom.parseString(result)

        # text file
        attachment = Attachment(self.env, 'parent_realm', 'parent_id')
        attachment.insert('foo.txt', io.BytesIO(b'text'), 4, 1)
        result = render(attachment)
        self.assertIn(
            '<tr><th id="L1"><a href="#L1">1</a></th>'
            '<td>text</td></tr>', result)
        xml = minidom.parseString(result)

        # preview unavailable
        attachment = Attachment(self.env, 'parent_realm', 'parent_id')
        attachment.insert('foo.dat', io.BytesIO(b'\x00\x00\x01\xb3'), 4, 1)
        result = render(attachment)
        self.assertIn('<strong>HTML preview not available</strong>', result)
        xml = minidom.parseString(result)
예제 #7
0
def fetch_user_data(env, req):
    acctmgr = AccountManager(env)
    guard = AccountGuard(env)
    accounts = {}
    for username in acctmgr.get_users():
        if req.perm.has_permission('ACCTMGR_USER_ADMIN'):
            url = req.href.admin('accounts', 'users', user=username)
        else:
            url = None
        accounts[username] = {'username': username, 'review_url': url}
        if guard.user_locked(username):
            accounts[username]['locked'] = True
            t_lock = guard.lock_time(username)
            if t_lock > 0:
                t_release = guard.pretty_release_time(req, username)
                accounts[username]['release_hint'] = _(
                    "Locked until %(t_release)s", t_release=t_release)
    for acct, status in get_user_attribute(env,
                                           username=None,
                                           authenticated=None).iteritems():
        account = accounts.get(acct)
        if account is not None and 1 in status:
            # Only use attributes related to authenticated
            # accounts.
            account['name'] = status[1].get('name')
            account['email'] = status[1].get('email')
            if account['email']:
                account['email'] = Chrome(env).format_author(
                    req, account['email'])
    ts_seen = last_seen(env)
    if ts_seen is not None:
        for username, last_visit in ts_seen:
            account = accounts.get(username)
            if account and last_visit:
                account['last_visit'] = to_datetime(last_visit)
    return sorted(accounts.itervalues(), key=lambda acct: acct['username'])
예제 #8
0
    def _render_admin_panel(self, req, cat, page, path_info):
        label = [gettext(each) for each in self._label]
        data = {'label_singular': label[0], 'label_plural': label[1],
                'type': self._type}

        # Detail view?
        if path_info:
            enum = self._enum_cls(self.env, path_info)
            if req.method == 'POST':
                if req.args.get('save'):
                    enum.name = req.args.get('name')
                    enum.description = req.args.get('description')
                    enum.update()
                    add_notice(req, _("Your changes have been saved."))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))
            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data.update({'view': 'detail', 'enum': enum})

        else:
            default = self.config.get('ticket', 'default_%s' % self._type)
            if req.method == 'POST':
                # Add enum
                if req.args.get('add') and req.args.get('name'):
                    enum = self._enum_cls(self.env)
                    enum.name = req.args.get('name')
                    enum.insert()
                    add_notice(req, _('The %(field)s value "%(name)s" '
                                      'has been added.',
                                      field=label[0], name=enum.name))
                    req.redirect(req.href.admin(cat, page))

                # Remove enums
                elif req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if not sel:
                        raise TracError(_("No %s selected") % self._type)
                    with self.env.db_transaction:
                        for name in sel:
                            self._enum_cls(self.env, name).delete()
                            if name == default:
                                self.config.set('ticket',
                                                'default_%s' % self._type, '')
                                self.config.save()
                    add_notice(req, _("The selected %(field)s values have "
                                      "been removed.", field=label[0]))
                    req.redirect(req.href.admin(cat, page))

                # Apply changes
                elif req.args.get('apply'):
                    # Set default value
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default %s to %s",
                                      self._type, name)
                        self.config.set('ticket', 'default_%s' % self._type,
                                        name)
                        self._save_config(req)

                    # Change enum values
                    order = {str(int(key[6:])): str(req.args.getint(key))
                             for key in req.args
                             if key.startswith('value_')}
                    values = {val: True for val in order.values()}
                    if len(order) != len(values):
                        raise TracError(_("Order numbers must be unique"))
                    changed = False
                    with self.env.db_transaction:
                        for enum in self._enum_cls.select(self.env):
                            new_value = order[enum.value]
                            if new_value != enum.value:
                                enum.value = new_value
                                enum.update()
                                changed = True

                    if changed:
                        add_notice(req, _("Your changes have been saved."))
                    req.redirect(req.href.admin(cat, page))

                # Clear default
                elif req.args.get('clear'):
                    self.log.info("Clearing default %s", self._type)
                    self.config.set('ticket', 'default_%s' % self._type, '')
                    self._save_config(req)
                    req.redirect(req.href.admin(cat, page))

            Chrome(self.env).add_jquery_ui(req)
            add_script(req, 'common/js/admin_enums.js')
            data.update(dict(enums=list(self._enum_cls.select(self.env)),
                             default=default, view='list'))

        return 'admin_enums.html', data
예제 #9
0
    def _render_admin_panel(self, req, cat, page, milestone_name):
        perm_cache = req.perm('admin', 'ticket/' + self._type)

        # Detail view
        if milestone_name:
            milestone = model.Milestone(self.env, milestone_name)
            milestone_module = MilestoneModule(self.env)
            if req.method == 'POST':
                if 'save' in req.args:
                    perm_cache.require('MILESTONE_MODIFY')
                    if milestone_module.save_milestone(req, milestone):
                        req.redirect(req.href.admin(cat, page))

                elif 'cancel' in req.args:
                    req.redirect(req.href.admin(cat, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail',
                    'milestone': milestone,
                    'default_due': milestone_module.get_default_due(req)}

        # List view
        else:
            ticket_default = self.config.get('ticket', 'default_milestone')
            retarget_default = self.config.get('milestone',
                                               'default_retarget_to')
            if req.method == 'POST':

                # Add milestone
                if 'add' in req.args and req.args.get('name'):
                    perm_cache.require('MILESTONE_CREATE')
                    name = req.args.get('name')
                    try:
                        model.Milestone(self.env, name=name)
                    except ResourceNotFound:
                        milestone = model.Milestone(self.env)
                        milestone.name = name
                        MilestoneModule(self.env).save_milestone(req,
                                                                 milestone)
                        req.redirect(req.href.admin(cat, page))
                    else:
                        add_warning(req, _('Milestone "%(name)s" already '
                                           'exists, please choose another '
                                           'name.', name=name))

                # Remove milestone
                elif 'remove' in req.args:
                    save = False
                    perm_cache.require('MILESTONE_DELETE')
                    sel = req.args.getlist('sel')
                    if not sel:
                        raise TracError(_("No milestone selected"))
                    with self.env.db_transaction:
                        for name in sel:
                            milestone = model.Milestone(self.env, name)
                            milestone.move_tickets(None, req.authname,
                                                   "Milestone deleted")
                            milestone.delete()
                            if name == ticket_default:
                                self.config.set('ticket',
                                                'default_milestone', '')
                                save = True
                            if name == retarget_default:
                                self.config.set('milestone',
                                                'default_retarget_to', '')
                                save = True
                    if save:
                        self._save_config(req)
                    add_notice(req, _("The selected milestones have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default milestone
                elif 'apply' in req.args:
                    save = False
                    name = req.args.get('ticket_default')
                    if name and name != ticket_default:
                        self.log.info("Setting default ticket "
                                      "milestone to %s", name)
                        self.config.set('ticket', 'default_milestone', name)
                        save = True
                    retarget = req.args.get('retarget_default')
                    if retarget and retarget != retarget_default:
                        self.log.info("Setting default retargeting "
                                      "milestone to %s", retarget)
                        self.config.set('milestone', 'default_retarget_to',
                                        retarget)
                        save = True
                    if save:
                        self._save_config(req)
                        req.redirect(req.href.admin(cat, page))

                # Clear default milestone
                elif 'clear' in req.args:
                    self.log.info("Clearing default ticket milestone "
                                  "and default retarget milestone")
                    self.config.set('ticket', 'default_milestone', '')
                    self.config.set('milestone', 'default_retarget_to', '')
                    self._save_config(req)
                    req.redirect(req.href.admin(cat, page))

            # Get ticket count
            num_tickets = dict(self.env.db_query("""
                    SELECT milestone, COUNT(milestone) FROM ticket
                    WHERE milestone != ''
                    GROUP BY milestone
                """))
            query_href = lambda name: req.href.query([('group', 'status'),
                                                      ('milestone', name)])

            data = {'view': 'list',
                    'milestones': model.Milestone.select(self.env),
                    'query_href': query_href,
                    'num_tickets': lambda m: num_tickets.get(m.name, 0),
                    'ticket_default': ticket_default,
                    'retarget_default': retarget_default}

        Chrome(self.env).add_jquery_ui(req)

        data.update({
            'datetime_hint': get_datetime_format_hint(req.lc_time),
        })
        return 'admin_milestones.html', data
예제 #10
0
def send_internal_error(env, req, exc_info):
    if env:
        env.log.error("Internal Server Error: %r, referrer %r%s", req,
                      req.environ.get('HTTP_REFERER'),
                      exception_to_unicode(exc_info[1], traceback=True))
    message = exception_to_unicode(exc_info[1])
    traceback = get_last_traceback()

    frames, plugins, faulty_plugins, interface_custom = [], [], [], []
    th = 'http://trac-hacks.org'
    has_admin = False
    try:
        has_admin = 'TRAC_ADMIN' in req.perm
    except Exception:
        pass

    tracker = default_tracker
    tracker_args = {}
    if has_admin and not isinstance(exc_info[1], MemoryError):
        # Collect frame and plugin information
        frames = get_frame_info(exc_info[2])
        if env:
            plugins = [
                p for p in get_plugin_info(env)
                if any(c['enabled'] for m in p['modules'].itervalues()
                       for c in m['components'].itervalues())
            ]
            match_plugins_to_frames(plugins, frames)

            # Identify the tracker where the bug should be reported
            faulty_plugins = [p for p in plugins if 'frame_idx' in p]
            faulty_plugins.sort(key=lambda p: p['frame_idx'])
            if faulty_plugins:
                info = faulty_plugins[0]['info']
                if 'trac' in info:
                    tracker = info['trac']
                elif info.get('home_page', '').startswith(th):
                    tracker = th
                    plugin_name = info.get('home_page', '').rstrip('/') \
                                                           .split('/')[-1]
                    tracker_args = {'component': plugin_name}
        interface_custom = Chrome(env).get_interface_customization_files()

    def get_description(_):
        if env and has_admin:
            sys_info = "".join("|| '''`%s`''' || `%s` ||\n" %
                               (k, v.replace('\n', '` [[br]] `'))
                               for k, v in env.get_systeminfo())
            sys_info += "|| '''`jQuery`''' || `#JQUERY#` ||\n" \
                        "|| '''`jQuery UI`''' || `#JQUERYUI#` ||\n" \
                        "|| '''`jQuery Timepicker`''' || `#JQUERYTP#` ||\n"
            enabled_plugins = "".join("|| '''`%s`''' || `%s` ||\n" %
                                      (p['name'], p['version'] or _('N/A'))
                                      for p in plugins)
            files = Chrome(env).get_interface_customization_files().items()
            interface_files = "".join("|| **%s** || %s ||\n" %
                                      (k, ", ".join("`%s`" % f for f in v))
                                      for k, v in sorted(files))
        else:
            sys_info = _("''System information not available''\n")
            enabled_plugins = _("''Plugin information not available''\n")
            interface_files = _("''Interface customization information not "
                                "available''\n")
        return _("""\
==== How to Reproduce ====

While doing a %(method)s operation on `%(path_info)s`, Trac issued an internal error.

''(please provide additional details here)''

Request parameters:
{{{
%(req_args)s
}}}

User agent: `#USER_AGENT#`

==== System Information ====
%(sys_info)s
==== Enabled Plugins ====
%(enabled_plugins)s
==== Interface Customization ====
%(interface_customization)s
==== Python Traceback ====
{{{
%(traceback)s}}}""",
                 method=req.method,
                 path_info=req.path_info,
                 req_args=pformat(req.args),
                 sys_info=sys_info,
                 enabled_plugins=enabled_plugins,
                 interface_customization=interface_files,
                 traceback=to_unicode(traceback))

    # Generate the description once in English, once in the current locale
    description_en = get_description(lambda s, **kw: safefmt(s, kw))
    try:
        description = get_description(_)
    except Exception:
        description = description_en

    data = {
        'title': 'Internal Error',
        'type': 'internal',
        'message': message,
        'traceback': traceback,
        'frames': frames,
        'shorten_line': shorten_line,
        'repr': safe_repr,
        'plugins': plugins,
        'faulty_plugins': faulty_plugins,
        'interface': interface_custom,
        'tracker': tracker,
        'tracker_args': tracker_args,
        'description': description,
        'description_en': description_en
    }

    Chrome(env).add_jquery_ui(req)
    try:
        req.send_error(exc_info, status=500, env=env, data=data)
    except RequestDone:
        pass
예제 #11
0
파일: main.py 프로젝트: wataash/trac
    def dispatch(self, req):
        """Find a registered handler that matches the request and let
        it process it.

        In addition, this method initializes the data dictionary
        passed to the the template and adds the web site chrome.
        """
        self.log.debug('Dispatching %r', req)
        chrome = Chrome(self.env)

        try:
            # Select the component that should handle the request
            chosen_handler = None
            for handler in self._request_handlers.values():
                if handler.match_request(req):
                    chosen_handler = handler
                    break
            if not chosen_handler and req.path_info in ('', '/'):
                chosen_handler = self._get_valid_default_handler(req)
            # pre-process any incoming request, whether a handler
            # was found or not
            self.log.debug("Chosen handler is %s", chosen_handler)
            chosen_handler = self._pre_process_request(req, chosen_handler)
            if not chosen_handler:
                if req.path_info.endswith('/'):
                    # Strip trailing / and redirect
                    target = unicode_quote(req.path_info.rstrip('/'))
                    if req.query_string:
                        target += '?' + req.query_string
                    req.redirect(req.href + target, permanent=True)
                raise HTTPNotFound('No handler matched request to %s',
                                   req.path_info)

            req.callbacks['chrome'] = partial(chrome.prepare_request,
                                              handler=chosen_handler)

            # Protect against CSRF attacks: we validate the form token
            # for all POST requests with a content-type corresponding
            # to form submissions
            if req.method == 'POST':
                ctype = req.get_header('Content-Type')
                if ctype:
                    ctype, options = cgi.parse_header(ctype)
                if ctype in ('application/x-www-form-urlencoded',
                             'multipart/form-data') and \
                        req.args.get('__FORM_TOKEN') != req.form_token:
                    if self.env.secure_cookies and req.scheme == 'http':
                        msg = _('Secure cookies are enabled, you must '
                                'use https to submit forms.')
                    else:
                        msg = _('Do you have cookies enabled?')
                    raise HTTPBadRequest(_('Missing or invalid form token.'
                                           ' %(msg)s', msg=msg))

            # Process the request and render the template
            resp = chosen_handler.process_request(req)
            if resp:
                template, data, metadata = \
                    self._post_process_request(req, *resp)
                if 'hdfdump' in req.args:
                    req.perm.require('TRAC_ADMIN')
                    # debugging helper - no need to render first
                    out = io.BytesIO()
                    pprint({'template': template,
                            'metadata': metadata,
                            'data': data}, out)
                    req.send(out.getvalue(), 'text/plain')
                self.log.debug("Rendering response with template %s", template)
                metadata.setdefault('iterable', chrome.use_chunked_encoding)
                content_type = metadata.get('content_type')
                output = chrome.render_template(req, template, data, metadata)
                req.send(output, content_type or 'text/html')
            else:
                self.log.debug("Empty or no response from handler. "
                               "Entering post_process_request.")
                self._post_process_request(req)
        except RequestDone:
            raise
        except Exception as e:
            # post-process the request in case of errors
            err = sys.exc_info()
            try:
                self._post_process_request(req)
            except RequestDone:
                raise
            except TracError as e2:
                self.log.warning("Exception caught while post-processing"
                                 " request: %s", exception_to_unicode(e2))
            except Exception as e2:
                if not (type(e) is type(e2) and e.args == e2.args):
                    self.log.error("Exception caught while post-processing"
                                   " request: %s",
                                   exception_to_unicode(e2, traceback=True))
            if isinstance(e, PermissionError):
                raise HTTPForbidden(e)
            if isinstance(e, ResourceNotFound):
                raise HTTPNotFound(e)
            if isinstance(e, NotImplementedError):
                tb = traceback.extract_tb(err[2])[-1]
                self.log.warning("%s caught from %s:%d in %s: %s",
                                 e.__class__.__name__, tb[0], tb[1], tb[2],
                                 to_unicode(e) or "(no message)")
                raise HTTPInternalServerError(TracNotImplementedError(e))
            if isinstance(e, TracError):
                raise HTTPInternalServerError(e)
            raise err[0], err[1], err[2]
예제 #12
0
    def process_request(self, req):
        req.perm.require('LOG_VIEW')

        mode = req.args.get('mode', 'stop_on_copy')
        path = req.args.get('path', '/')
        rev = req.args.get('rev')
        stop_rev = req.args.get('stop_rev')
        revs = req.args.get('revs')
        format = req.args.get('format')
        verbose = req.args.get('verbose')
        limit = int(req.args.get('limit') or self.default_log_limit)

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

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

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

        normpath = repos.normalize_path(path)
        # if `revs` parameter is given, then we're restricted to the
        # corresponding revision ranges.
        # If not, then we're considering all revisions since `rev`,
        # on that path, in which case `revranges` will be None.
        revranges = None
        if revs:
            try:
                revranges = Ranges(revs)
                rev = revranges.b
            except ValueError:
                pass
        rev = unicode(repos.normalize_rev(rev))
        display_rev = repos.display_rev

        # The `history()` method depends on the mode:
        #  * for ''stop on copy'' and ''follow copies'', it's `Node.history()`
        #    unless explicit ranges have been specified
        #  * for ''show only add, delete'' we're using
        #   `Repository.get_path_history()`
        cset_resource = repos.resource.child('changeset')
        show_graph = False
        if mode == 'path_history':

            def history():
                for h in repos.get_path_history(path, rev):
                    if 'CHANGESET_VIEW' in req.perm(cset_resource(id=h[1])):
                        yield h
        elif revranges:

            def history():
                prevpath = path
                expected_next_item = None
                ranges = list(revranges.pairs)
                ranges.reverse()
                for (a, b) in ranges:
                    a = repos.normalize_rev(a)
                    b = repos.normalize_rev(b)
                    while not repos.rev_older_than(b, a) and b != a:
                        node = get_existing_node(req, repos, prevpath, b)
                        node_history = list(node.get_history(2))
                        p, rev, chg = node_history[0]
                        if repos.rev_older_than(rev, a):
                            break  # simply skip, no separator
                        if 'CHANGESET_VIEW' in req.perm(cset_resource(id=rev)):
                            if expected_next_item:
                                # check whether we're continuing previous range
                                np, nrev, nchg = expected_next_item
                                if rev != nrev:  # no, we need a separator
                                    yield (np, nrev, None)
                            yield node_history[0]
                        prevpath = node_history[-1][0]  # follow copy
                        b = repos.previous_rev(rev)
                        if len(node_history) > 1:
                            expected_next_item = node_history[-1]
                        else:
                            expected_next_item = None
                if expected_next_item:
                    yield (expected_next_item[0], expected_next_item[1], None)
        else:
            show_graph = path == '/' and not verbose \
                         and not repos.has_linear_changesets

            def history():
                node = get_existing_node(req, repos, path, rev)
                for h in node.get_history():
                    if 'CHANGESET_VIEW' in req.perm(cset_resource(id=h[1])):
                        yield h

        # -- retrieve history, asking for limit+1 results
        info = []
        depth = 1
        previous_path = normpath
        count = 0
        for old_path, old_rev, old_chg in history():
            if stop_rev and repos.rev_older_than(old_rev, stop_rev):
                break
            old_path = repos.normalize_path(old_path)

            item = {
                'path': old_path,
                'rev': old_rev,
                'existing_rev': old_rev,
                'change': old_chg,
                'depth': depth,
            }

            if old_chg == Changeset.DELETE:
                item['existing_rev'] = repos.previous_rev(old_rev, old_path)
            if not (mode == 'path_history' and old_chg == Changeset.EDIT):
                info.append(item)
            if old_path and old_path != previous_path and \
                    not (mode == 'path_history' and old_path == normpath):
                depth += 1
                item['depth'] = depth
                item['copyfrom_path'] = old_path
                if mode == 'stop_on_copy':
                    break
                elif mode == 'path_history':
                    depth -= 1
            if old_chg is None:  # separator entry
                stop_limit = limit
            else:
                count += 1
                stop_limit = limit + 1
            if count >= stop_limit:
                break
            previous_path = old_path
        if info == []:
            node = get_existing_node(req, repos, path, rev)
            if repos.rev_older_than(stop_rev, node.created_rev):
                # FIXME: we should send a 404 error here
                raise TracError(
                    _(
                        "The file or directory '%(path)s' doesn't "
                        "exist at revision %(rev)s or at any previous revision.",
                        path=path,
                        rev=display_rev(rev)), _('Nonexistent path'))

        # Generate graph data
        graph = {}
        if show_graph:
            threads, vertices, columns = \
                make_log_graph(repos, (item['rev'] for item in info))
            graph.update(threads=threads,
                         vertices=vertices,
                         columns=columns,
                         colors=self.graph_colors,
                         line_width=0.04,
                         dot_radius=0.1)
            add_script(req, 'common/js/excanvas.js', ie_if='IE')
            add_script(req, 'common/js/log_graph.js')
            add_script_data(req, graph=graph)

        def make_log_href(path, **args):
            link_rev = rev
            if rev == str(repos.youngest_rev):
                link_rev = None
            params = {'rev': link_rev, 'mode': mode, 'limit': limit}
            params.update(args)
            if verbose:
                params['verbose'] = verbose
            return req.href.log(repos.reponame or None, path, **params)

        if format in ('rss', 'changelog'):
            info = [i for i in info if i['change']]  # drop separators
            if info and count > limit:
                del info[-1]
        elif info and count >= limit:
            # stop_limit reached, there _might_ be some more
            next_rev = info[-1]['rev']
            next_path = info[-1]['path']
            next_revranges = None
            if revranges:
                next_revranges = str(revranges.truncate(next_rev))
            if next_revranges or not revranges:
                older_revisions_href = make_log_href(next_path,
                                                     rev=next_rev,
                                                     revs=next_revranges)
                add_link(
                    req, 'next', older_revisions_href,
                    _('Revision Log (restarting at %(path)s, rev. %(rev)s)',
                      path=next_path,
                      rev=display_rev(next_rev)))
            # only show fully 'limit' results, use `change == None` as a marker
            info[-1]['change'] = None

        revisions = [i['rev'] for i in info]
        changes = get_changes(repos, revisions, self.log)
        extra_changes = {}

        if format == 'changelog':
            for rev in revisions:
                changeset = changes[rev]
                cs = {}
                cs['message'] = wrap(changeset.message,
                                     70,
                                     initial_indent='\t',
                                     subsequent_indent='\t')
                files = []
                actions = []
                for cpath, kind, chg, bpath, brev in changeset.get_changes():
                    files.append(bpath if chg == Changeset.DELETE else cpath)
                    actions.append(chg)
                cs['files'] = files
                cs['actions'] = actions
                extra_changes[rev] = cs

        data = {
            'context':
            web_context(req, 'source', path, parent=repos.resource),
            'reponame':
            repos.reponame or None,
            'repos':
            repos,
            'path':
            path,
            'rev':
            rev,
            'stop_rev':
            stop_rev,
            'display_rev':
            display_rev,
            'revranges':
            revranges,
            'mode':
            mode,
            'verbose':
            verbose,
            'limit':
            limit,
            'items':
            info,
            'changes':
            changes,
            'extra_changes':
            extra_changes,
            'graph':
            graph,
            'wiki_format_messages':
            self.config['changeset'].getbool('wiki_format_messages')
        }

        if format == 'changelog':
            return 'revisionlog.txt', data, 'text/plain'
        elif format == 'rss':
            data['email_map'] = Chrome(self.env).get_email_map()
            data['context'] = web_context(req,
                                          'source',
                                          path,
                                          parent=repos.resource,
                                          absurls=True)
            return 'revisionlog.rss', data, 'application/rss+xml'

        item_ranges = []
        range = []
        for item in info:
            if item['change'] is None:  # separator
                if range:  # start new range
                    range.append(item)
                    item_ranges.append(range)
                    range = []
            else:
                range.append(item)
        if range:
            item_ranges.append(range)
        data['item_ranges'] = item_ranges

        add_stylesheet(req, 'common/css/diff.css')
        add_stylesheet(req, 'common/css/browser.css')

        path_links = get_path_links(req.href, repos.reponame, path, rev)
        if path_links:
            data['path_links'] = path_links
        if path != '/':
            add_link(req, 'up', path_links[-2]['href'], _('Parent directory'))

        rss_href = make_log_href(path,
                                 format='rss',
                                 revs=revs,
                                 stop_rev=stop_rev)
        add_link(req, 'alternate', auth_link(req, rss_href), _('RSS Feed'),
                 'application/rss+xml', 'rss')
        changelog_href = make_log_href(path,
                                       format='changelog',
                                       revs=revs,
                                       stop_rev=stop_rev)
        add_link(req, 'alternate', changelog_href, _('ChangeLog'),
                 'text/plain')

        add_ctxtnav(req,
                    _('View Latest Revision'),
                    href=req.href.browser(repos.reponame or None, path))
        if 'next' in req.chrome['links']:
            next = req.chrome['links']['next'][0]
            add_ctxtnav(
                req,
                tag.span(tag.a(_('Older Revisions'), href=next['href']),
                         Markup(' &rarr;')))

        return 'revisionlog.html', data, None
예제 #13
0
    def _format_plaintext(self, event):
        """Format ticket change notification e-mail (untranslated)"""
        ticket = event.target
        newticket = event.category == 'created'
        with translation_deactivated(ticket):
            link = self.env.abs_href.ticket(ticket.id)

            changes_body = ''
            changes_descr = ''
            change_data = {}
            if not newticket and event.time:  # Ticket change
                from trac.ticket.web_ui import TicketModule
                for change in TicketModule(self.env) \
                              .grouped_changelog_entries(ticket,
                                                         when=event.time):
                    if not change['permanent']:  # attachment with same time...
                        continue
                    author = change['author']
                    change_data.update({
                        'author': self._format_author(author),
                        'comment': wrap(change['comment'], self.COLS, ' ', ' ',
                                        '\n', self.ambiwidth)
                    })
                    link += '#comment:%s' % str(change.get('cnum', ''))
                    for field, values in change['fields'].iteritems():
                        old = values['old']
                        new = values['new']
                        newv = ''
                        if field == 'description':
                            new_descr = wrap(new, self.COLS, ' ', ' ', '\n',
                                             self.ambiwidth)
                            old_descr = wrap(old, self.COLS, '> ', '> ', '\n',
                                             self.ambiwidth)
                            old_descr = old_descr.replace(2 * '\n', '\n' + '>' +
                                                          '\n')
                            cdescr = '\n'
                            cdescr += 'Old description:' + 2 * '\n' + old_descr + \
                                      2 * '\n'
                            cdescr += 'New description:' + 2 * '\n' + new_descr + \
                                      '\n'
                            changes_descr = cdescr
                        elif field == 'cc':
                            addcc, delcc = self._diff_cc(old, new)
                            chgcc = ''
                            if delcc:
                                chgcc += wrap(" * cc: %s (removed)" %
                                              ', '.join(delcc),
                                              self.COLS, ' ', ' ', '\n',
                                              self.ambiwidth) + '\n'
                            if addcc:
                                chgcc += wrap(" * cc: %s (added)" %
                                              ', '.join(addcc),
                                              self.COLS, ' ', ' ', '\n',
                                              self.ambiwidth) + '\n'
                            if chgcc:
                                changes_body += chgcc
                        else:
                            if field in ['owner', 'reporter']:
                                old = self._format_author(old)
                                new = self._format_author(new)
                            elif field in ticket.time_fields:
                                format = ticket.fields.by_name(field) \
                                                      .get('format')
                                old = self._format_time_field(old, format)
                                new = self._format_time_field(new, format)
                            newv = new
                            length = 7 + len(field)
                            spacer_old, spacer_new = ' ', ' '
                            if len(old + new) + length > self.COLS:
                                length = 5
                                if len(old) + length > self.COLS:
                                    spacer_old = '\n'
                                if len(new) + length > self.COLS:
                                    spacer_new = '\n'
                            chg = '* %s: %s%s%s=>%s%s' \
                                  % (field, spacer_old, old,
                                     spacer_old, spacer_new, new)
                            chg = chg.replace('\n', '\n' + length * ' ')
                            chg = wrap(chg, self.COLS, '', length * ' ', '\n',
                                       self.ambiwidth)
                            changes_body += ' %s%s' % (chg, '\n')
                        if newv:
                            change_data[field] = {'oldvalue': old,
                                                  'newvalue': new}

            ticket_values = ticket.values.copy()
            ticket_values['id'] = ticket.id
            ticket_values['description'] = wrap(
                ticket_values.get('description', ''), self.COLS,
                initial_indent=' ', subsequent_indent=' ', linesep='\n',
                ambiwidth=self.ambiwidth)
            ticket_values['new'] = newticket
            ticket_values['link'] = link

            data = Chrome(self.env).populate_data(None, {
                'CRLF': CRLF,
                'ticket_props': self._format_props(ticket),
                'ticket_body_hdr': self._format_hdr(ticket),
                'ticket': ticket_values,
                'changes_body': changes_body,
                'changes_descr': changes_descr,
                'change': change_data
            })
            return self._format_body(data, 'ticket_notify_email.txt')
예제 #14
0
 def test_actor_no_email_view(self):
     req = MockRequest(self.env, authname='user2')
     author = Chrome(self.env).format_author(req, '*****@*****.**')
     self.assertEqual(u'user@\u2026', author)
예제 #15
0
 def test_subject_is_none(self):
     format_author = Chrome(self.env).format_author
     self.assertEqual('(none)', format_author(None, None))
예제 #16
0
 def setUp(self):
     self.env = EnvironmentStub(path=mkdtemp())
     os.mkdir(self.env.templates_dir)
     filepath = os.path.join(self.env.templates_dir, self.filename)
     create_file(filepath, self.template)
     self.chrome = Chrome(self.env)
예제 #17
0
 def setUp(self):
     self.env = EnvironmentStub(path=tempfile.mkdtemp())
     self.chrome = Chrome(self.env)
예제 #18
0
 def test_actor_no_email_view_show_email_addresses(self):
     self.env.config.set('trac', 'show_email_addresses', True)
     req = MockRequest(self.env, authname='user2')
     author = Chrome(self.env).format_author(req, '*****@*****.**')
     self.assertEqual('*****@*****.**', author)
예제 #19
0
 def _format_author(self, author):
     return Chrome(self.env).format_author(None, author)
예제 #20
0
 def test_actor_no_email_view_no_req(self):
     author = Chrome(self.env).format_author(None, '*****@*****.**')
     self.assertEqual(u'user@\u2026', author)
예제 #21
0
    def render_property(self, name, mode, context, props):
        def sha_link(sha, label=None):
            # sha is assumed to be a non-abbreviated 40-chars sha id
            try:
                reponame = context.resource.parent.id
                repos = self.env.get_repository(reponame)
                cset = repos.get_changeset(sha)
                if label is None:
                    label = repos.display_rev(sha)

                return tag.a(label,
                             class_='changeset',
                             title=shorten_line(cset.message),
                             href=context.href.changeset(sha, repos.reponame))

            except Exception as e:
                return tag.a(sha,
                             class_='missing changeset',
                             title=to_unicode(e),
                             rel='nofollow')

        if name == 'Branches':
            branches = props[name]

            # simple non-merge commit
            return tag(*intersperse(', ', (sha_link(rev, label)
                                           for label, rev in branches)))

        elif name in ('Parents', 'Children'):
            revs = props[name]  # list of commit ids

            if name == 'Parents' and len(revs) > 1:
                # we got a merge...
                current_sha = context.resource.id
                reponame = context.resource.parent.id

                parent_links = intersperse(', ', \
                    ((sha_link(rev),
                      ' (',
                      tag.a(_("diff"),
                            title=_("Diff against this parent (show the "
                                    "changes merged from the other parents)"),
                            href=context.href.changeset(current_sha, reponame,
                                                        old=rev)),
                      ')')
                     for rev in revs))

                return tag(
                    list(parent_links), tag.br(),
                    tag.span(Markup(
                        _("Note: this is a <strong>merge"
                          "</strong> changeset, the "
                          "changes displayed below "
                          "correspond to the merge "
                          "itself.")),
                             class_='hint'), tag.br(),
                    tag.span(Markup(
                        _("Use the <code>(diff)</code> "
                          "links above to see all the "
                          "changes relative to each "
                          "parent.")),
                             class_='hint'))

            # simple non-merge commit
            return tag(*intersperse(', ', map(sha_link, revs)))

        elif name in ('git-committer', 'git-author'):
            user_, time_ = props[name]
            _str = "%s (%s)" % (Chrome(self.env).format_author(
                context.req,
                user_), format_datetime(time_, tzinfo=context.req.tz))
            return unicode(_str)

        raise TracError(_("Internal error"))
예제 #22
0
 def test_actor_has_email_view_for_resource(self):
     format_author = Chrome(self.env).format_author
     req = MockRequest(self.env, authname='user2')
     resource = Resource('wiki', 'WikiStart')
     author = format_author(req, '*****@*****.**', resource)
     self.assertEqual('*****@*****.**', author)
예제 #23
0
    def dispatch(self, req):
        """Find a registered handler that matches the request and let
        it process it.

        In addition, this method initializes the data dictionary
        passed to the the template and adds the web site chrome.
        """
        self.log.debug('Dispatching %r', req)
        chrome = Chrome(self.env)

        # Setup request callbacks for lazily-evaluated properties
        req.callbacks.update({
            'authname': self.authenticate,
            'chrome': chrome.prepare_request,
            'perm': self._get_perm,
            'session': self._get_session,
            'locale': self._get_locale,
            'lc_time': self._get_lc_time,
            'tz': self._get_timezone,
            'form_token': self._get_form_token,
            'use_xsendfile': self._get_use_xsendfile,
            'xsendfile_header': self._get_xsendfile_header,
        })

        try:
            try:
                # Select the component that should handle the request
                chosen_handler = None
                try:
                    for handler in self._request_handlers.values():
                        if handler.match_request(req):
                            chosen_handler = handler
                            break
                    if not chosen_handler and \
                            (not req.path_info or req.path_info == '/'):
                        chosen_handler = self._get_valid_default_handler(req)
                    # pre-process any incoming request, whether a handler
                    # was found or not
                    self.log.debug("Chosen handler is %s", chosen_handler)
                    chosen_handler = \
                        self._pre_process_request(req, chosen_handler)
                except TracError as e:
                    raise HTTPInternalError(e)
                if not chosen_handler:
                    if req.path_info.endswith('/'):
                        # Strip trailing / and redirect
                        target = unicode_quote(req.path_info.rstrip('/'))
                        if req.query_string:
                            target += '?' + req.query_string
                        req.redirect(req.href + target, permanent=True)
                    raise HTTPNotFound('No handler matched request to %s',
                                       req.path_info)

                req.callbacks['chrome'] = partial(chrome.prepare_request,
                                                  handler=chosen_handler)

                # Protect against CSRF attacks: we validate the form token
                # for all POST requests with a content-type corresponding
                # to form submissions
                if req.method == 'POST':
                    ctype = req.get_header('Content-Type')
                    if ctype:
                        ctype, options = cgi.parse_header(ctype)
                    if ctype in ('application/x-www-form-urlencoded',
                                 'multipart/form-data') and \
                            req.args.get('__FORM_TOKEN') != req.form_token:
                        if self.env.secure_cookies and req.scheme == 'http':
                            msg = _('Secure cookies are enabled, you must '
                                    'use https to submit forms.')
                        else:
                            msg = _('Do you have cookies enabled?')
                        raise HTTPBadRequest(
                            _('Missing or invalid form token.'
                              ' %(msg)s',
                              msg=msg))

                # Process the request and render the template
                resp = chosen_handler.process_request(req)
                if resp:
                    if len(resp) == 2:  # old Clearsilver template and HDF data
                        self.log.error(
                            "Clearsilver template are no longer "
                            "supported (%s)", resp[0])
                        raise TracError(
                            _("Clearsilver templates are no longer supported, "
                              "please contact your Trac administrator."))
                    # Genshi
                    template, data, content_type, method = \
                        self._post_process_request(req, *resp)
                    if 'hdfdump' in req.args:
                        req.perm.require('TRAC_ADMIN')
                        # debugging helper - no need to render first
                        out = io.BytesIO()
                        pprint(data, out)
                        req.send(out.getvalue(), 'text/plain')
                    self.log.debug("Rendering response from handler")
                    output = chrome.render_template(
                        req,
                        template,
                        data,
                        content_type,
                        method=method,
                        iterable=chrome.use_chunked_encoding)
                    req.send(output, content_type or 'text/html')
                else:
                    self.log.debug("Empty or no response from handler. "
                                   "Entering post_process_request.")
                    self._post_process_request(req)
            except RequestDone:
                raise
            except:
                # post-process the request in case of errors
                err = sys.exc_info()
                try:
                    self._post_process_request(req)
                except RequestDone:
                    raise
                except Exception as e:
                    self.log.error(
                        "Exception caught while post-processing"
                        " request: %s", exception_to_unicode(e,
                                                             traceback=True))
                raise err[0], err[1], err[2]
        except PermissionError as e:
            raise HTTPForbidden(e)
        except ResourceNotFound as e:
            raise HTTPNotFound(e)
        except TracError as e:
            raise HTTPInternalError(e)
예제 #24
0
 def test_actor_has_email_view_for_resource_negative(self):
     format_author = Chrome(self.env).format_author
     req = MockRequest(self.env, authname='user2')
     resource = Resource('wiki', 'TracGuide')
     author = format_author(req, '*****@*****.**', resource)
     self.assertEqual(u'user@\u2026', author)
예제 #25
0
파일: admin.py 프로젝트: skshel123/trac
    def render_admin_panel(self, req, category, page, path_info):
        # Retrieve info for all repositories
        rm = RepositoryManager(self.env)
        all_repos = rm.get_all_repositories()
        db_provider = self.env[DbRepositoryProvider]

        if path_info:
            # Detail view
            reponame = path_info if not is_default(path_info) else ''
            info = all_repos.get(reponame)
            if info is None:
                raise TracError(
                    _("Repository '%(repo)s' not found", repo=path_info))
            if req.method == 'POST':
                if req.args.get('cancel'):
                    req.redirect(req.href.admin(category, page))

                elif db_provider and req.args.get('save'):
                    # Modify repository
                    changes = {}
                    valid = True
                    for field in db_provider.repository_attrs:
                        value = normalize_whitespace(req.args.get(field))
                        if (value is not None
                            or field in ('hidden', 'sync_per_request')) \
                                and value != info.get(field):
                            changes[field] = value
                    if 'dir' in changes and not \
                            self._check_dir(req, changes['dir']):
                        valid = False
                    if valid and changes:
                        db_provider.modify_repository(reponame, changes)
                        add_notice(req, _('Your changes have been saved.'))
                        name = req.args.get('name')
                        pretty_name = name or '(default)'
                        resync = tag.code('trac-admin "%s" repository resync '
                                          '"%s"' %
                                          (self.env.path, pretty_name))
                        if 'dir' in changes:
                            msg = tag_(
                                'You should now run %(resync)s to '
                                'synchronize Trac with the repository.',
                                resync=resync)
                            add_notice(req, msg)
                        elif 'type' in changes:
                            msg = tag_(
                                'You may have to run %(resync)s to '
                                'synchronize Trac with the repository.',
                                resync=resync)
                            add_notice(req, msg)
                        if name and name != path_info and 'alias' not in info:
                            cset_added = tag.code('trac-admin "%s" changeset '
                                                  'added "%s" $REV' %
                                                  (self.env.path, pretty_name))
                            msg = tag_(
                                'You will need to update your '
                                'post-commit hook to call '
                                '%(cset_added)s with the new '
                                'repository name.',
                                cset_added=cset_added)
                            add_notice(req, msg)
                    if valid:
                        req.redirect(req.href.admin(category, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail', 'reponame': reponame}

        else:
            # List view
            if req.method == 'POST':
                # Add a repository
                if db_provider and req.args.get('add_repos'):
                    name = req.args.get('name')
                    pretty_name = name or '(default)'
                    if name in all_repos:
                        raise TracError(
                            _('The repository "%(name)s" already '
                              'exists.',
                              name=pretty_name))
                    type_ = req.args.get('type')
                    # Avoid errors when copy/pasting paths
                    dir = normalize_whitespace(req.args.get('dir', ''))
                    if name is None or type_ is None or not dir:
                        add_warning(
                            req, _('Missing arguments to add a '
                                   'repository.'))
                    elif self._check_dir(req, dir):
                        db_provider.add_repository(name, dir, type_)
                        add_notice(
                            req,
                            _('The repository "%(name)s" has been '
                              'added.',
                              name=pretty_name))
                        resync = tag.code('trac-admin "%s" repository resync '
                                          '"%s"' %
                                          (self.env.path, pretty_name))
                        msg = tag_(
                            'You should now run %(resync)s to '
                            'synchronize Trac with the repository.',
                            resync=resync)
                        add_notice(req, msg)
                        cset_added = tag.code('trac-admin "%s" changeset '
                                              'added "%s" $REV' %
                                              (self.env.path, pretty_name))
                        doc = tag.a(_("documentation"),
                                    href=req.href.wiki('TracRepositoryAdmin') +
                                    '#Synchronization')
                        msg = tag_(
                            'You should also set up a post-commit hook '
                            'on the repository to call %(cset_added)s '
                            'for each committed changeset. See the '
                            '%(doc)s for more information.',
                            cset_added=cset_added,
                            doc=doc)
                        add_notice(req, msg)

                # Add a repository alias
                elif db_provider and req.args.get('add_alias'):
                    name = req.args.get('name')
                    pretty_name = name or '(default)'
                    alias = req.args.get('alias')
                    if name is not None and alias is not None:
                        try:
                            db_provider.add_alias(name, alias)
                        except self.env.db_exc.IntegrityError:
                            raise TracError(
                                _('The alias "%(name)s" already '
                                  'exists.',
                                  name=pretty_name))
                        add_notice(
                            req,
                            _('The alias "%(name)s" has been '
                              'added.',
                              name=pretty_name))
                    else:
                        add_warning(req,
                                    _('Missing arguments to add an '
                                      'alias.'))

                # Refresh the list of repositories
                elif req.args.get('refresh'):
                    pass

                # Remove repositories
                elif db_provider and req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if sel:
                        for name in sel:
                            db_provider.remove_repository(name)
                        add_notice(
                            req,
                            _('The selected repositories have '
                              'been removed.'))
                    else:
                        add_warning(req, _('No repositories were selected.'))

                req.redirect(req.href.admin(category, page))

            data = {'view': 'list'}

        # Find repositories that are editable
        db_repos = {}
        if db_provider is not None:
            db_repos = dict(db_provider.get_repositories())

        # Prepare common rendering data
        repositories = {
            reponame: self._extend_info(reponame, info.copy(), reponame
                                        in db_repos)
            for (reponame, info) in all_repos.iteritems()
        }
        types = sorted([''] + rm.get_supported_types())
        data.update({
            'types':
            types,
            'default_type':
            rm.default_repository_type,
            'repositories':
            repositories,
            'can_add_alias':
            any('alias' not in info for info in repositories.itervalues())
        })

        return 'admin_repositories.html', data
예제 #26
0
    def test_show_full_names_false(self):
        format_author = Chrome(self.env).format_author
        self.env.config.set('trac', 'show_full_names', False)

        self.assertEqual('user1', format_author(None, 'user1'))
        self.assertEqual('user2', format_author(None, 'user2'))
예제 #27
0
    def _render_admin_panel(self, req, cat, page, version):
        # Detail view?
        if version:
            ver = model.Version(self.env, version)
            if req.method == 'POST':
                if req.args.get('save'):
                    ver.name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req, parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    else:
                        ver.time = None  # unset
                    ver.description = req.args.get('description')
                    ver.update()
                    add_notice(req, _("Your changes have been saved."))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail', 'version': ver}

        else:
            default = self.config.get('ticket', 'default_version')
            if req.method == 'POST':
                # Add Version
                if req.args.get('add') and req.args.get('name'):
                    ver = model.Version(self.env)
                    ver.name = req.args.get('name')
                    if req.args.get('time'):
                        ver.time = user_time(req, parse_date,
                                             req.args.get('time'),
                                             hint='datetime')
                    ver.insert()
                    add_notice(req, _('The version "%(name)s" has been '
                                      'added.', name=ver.name))
                    req.redirect(req.href.admin(cat, page))

                # Remove versions
                elif req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if not sel:
                        raise TracError(_("No version selected"))
                    with self.env.db_transaction:
                        for name in sel:
                            model.Version(self.env, name).delete()
                            if name == default:
                                self.config.set('ticket',
                                                'default_version', '')
                                self._save_config(req)
                    add_notice(req, _("The selected versions have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default version
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default version to %s", name)
                        self.config.set('ticket', 'default_version', name)
                        self._save_config(req)
                        req.redirect(req.href.admin(cat, page))

                # Clear default version
                elif req.args.get('clear'):
                    self.log.info("Clearing default version")
                    self.config.set('ticket', 'default_version', '')
                    self._save_config(req)
                    req.redirect(req.href.admin(cat, page))

            data = {'view': 'list',
                    'versions': list(model.Version.select(self.env)),
                    'default': default}

        Chrome(self.env).add_jquery_ui(req)
        data.update({'datetime_hint': get_datetime_format_hint(req.lc_time)})

        return 'admin_versions.html', data
예제 #28
0
    def test_format_emails(self):
        format_emails = Chrome(self.env).format_emails
        to_format = '[email protected], user2; [email protected]'

        self.assertEqual(u'user1@\u2026, user2, user3@\u2026',
                         format_emails(None, to_format))
예제 #29
0
    def _render_admin_panel(self, req, cat, page, component):
        # Detail view?
        if component:
            comp = model.Component(self.env, component)
            if req.method == 'POST':
                if req.args.get('save'):
                    comp.name = req.args.get('name')
                    comp.owner = req.args.get('owner')
                    comp.description = req.args.get('description')
                    comp.update()
                    add_notice(req, _("Your changes have been saved."))
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail', 'component': comp}

        else:
            default = self.config.get('ticket', 'default_component')
            if req.method == 'POST':
                # Add Component
                if req.args.get('add') and req.args.get('name'):
                    comp = model.Component(self.env)
                    comp.name = req.args.get('name')
                    comp.owner = req.args.get('owner')
                    comp.insert()
                    add_notice(req, _('The component "%(name)s" has been '
                                      'added.', name=comp.name))
                    req.redirect(req.href.admin(cat, page))

                # Remove components
                elif req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if not sel:
                        raise TracError(_("No component selected"))
                    with self.env.db_transaction:
                        for name in sel:
                            model.Component(self.env, name).delete()
                            if name == default:
                                self.config.set('ticket',
                                                'default_component', '')
                                self._save_config(req)
                    add_notice(req, _("The selected components have been "
                                      "removed."))
                    req.redirect(req.href.admin(cat, page))

                # Set default component
                elif req.args.get('apply'):
                    name = req.args.get('default')
                    if name and name != default:
                        self.log.info("Setting default component to %s", name)
                        self.config.set('ticket', 'default_component', name)
                        self._save_config(req)
                        req.redirect(req.href.admin(cat, page))

                # Clear default component
                elif req.args.get('clear'):
                    self.log.info("Clearing default component")
                    self.config.set('ticket', 'default_component', '')
                    self._save_config(req)
                    req.redirect(req.href.admin(cat, page))

            data = {'view': 'list',
                    'components': list(model.Component.select(self.env)),
                    'default': default}

        owners = TicketSystem(self.env).get_allowed_owners()
        if owners is not None:
            owners.insert(0, '')
        data.update({'owners': owners})

        return 'admin_components.html', data
예제 #30
0
 def test_actor_no_email_view_no_req(self):
     authorinfo = Chrome(self.env).authorinfo
     self.assertEqual(u'<span class="trac-author">user@\u2026</span>',
                      unicode(authorinfo(None, '*****@*****.**')))
     self.assertEqual(u'<span class="trac-author">User One &lt;user@\u2026&gt;</span>',
                      unicode(authorinfo(None, 'User One <*****@*****.**>')))