Exemple #1
0
 def cursor_execute(self, execute, cursor, statement, parameters,
                    context, executemany):
     start = _timer()
     try:
         return execute(cursor, statement, parameters, context)
     finally:
         from pyClanSphere.application import get_request
         from pyClanSphere.utils.debug import find_calling_context
         request = get_request()
         if request is not None:
             request.queries.append((statement, parameters, start,
                                     _timer(), find_calling_context()))
Exemple #2
0
def bind_privileges(container, privileges, user=None):
    """Binds the privileges to the container.  The privileges can be a list
    of privilege names, the container must be a set.  This is called for
    the HTTP round-trip in the form validation.
    """
    if not user:
        user = get_request().user
    app = get_application()
    notification_types = app.notification_manager.notification_types
    current_map = dict((x.name, x) for x in container)
    currently_attached = set(x.name for x in container)
    new_privileges = set(privileges)

    # remove out-dated privileges
    for name in currently_attached.difference(new_privileges):
        container.remove(current_map[name])
        # remove any privilege dependencies that are not attached to other
        # privileges
        if current_map[name].dependencies:
            for privilege in current_map[name].dependencies.iter_privileges():
                try:
                    container.remove(privilege)
                except KeyError:
                    # privilege probably already removed
                    pass

        # remove notification subscriptions that required the privilege
        # being deleted.
        for notification in user.notification_subscriptions:
            privs = notification_types[notification.notification_id].privileges
            if current_map[name] in privs.iter_privileges():
                db.session.delete(notification)
                break
            for privilege in current_map[name].dependencies:
                if privilege in privs.iter_privileges():
                    db.session.delete(notification)

    # add new privileges
    for name in new_privileges.difference(currently_attached):
        privilege = app.privileges[name]
        container.add(privilege)
        # add dependable privileges
        if privilege.dependencies:
            for privilege in privilege.dependencies.iter_privileges():
                container.add(privilege)
Exemple #3
0
def get_redirect_target(invalid_targets=(), request=None):
    """Check the request and get the redirect target if possible.
    If not this function returns just `None`.  The return value of this
    function is suitable to be passed to `_redirect`
    """
    if request is None:
        request = get_request()
    check_target = request.values.get('_redirect_target') or \
                   request.args.get('next') or \
                   request.environ.get('HTTP_REFERER')

    # if there is no information in either the form data
    # or the wsgi environment about a jump target we have
    # to use the target url
    if not check_target:
        return

    # otherwise drop the leading slash
    check_target = check_target.lstrip('/')

    site_url = request.app.cfg['site_url']
    clan_parts = urlparse(site_url)
    check_parts = urlparse(urljoin(site_url, check_target))

    # if the jump target is on a different server we probably have
    # a security problem and better try to use the target url.
    if clan_parts[:2] != check_parts[:2]:
        return

    # if the jump url is the same url as the current url we've had
    # a bad redirect before and use the target url to not create a
    # infinite redirect.
    current_parts = urlparse(urljoin(site_url, request.path))
    if check_parts[:5] == current_parts[:5]:
        return

    # if the `check_target` is one of the invalid targets we also
    # fall back.
    for invalid in invalid_targets:
        if check_parts[:5] == urlparse(urljoin(site_url, invalid))[:5]:
            return

    return check_target
Exemple #4
0
def redirect(url, code=302, allow_external_redirect=False,
             force_scheme_change=False):
    """Return a redirect response.  Like Werkzeug's redirect but this
    one checks for external redirects too.  If a redirect to an external
    target was requested `BadRequest` is raised unless
    `allow_external_redirect` was explicitly set to `True`.

    Leading slashes are ignored which makes it unsuitable to redirect
    to URLs returned from `url_for` and others.  Use `redirect_to`
    to redirect to arbitrary endpoints or `_redirect` to redirect to
    unchecked resources outside the URL root.

    By default the redirect will not change the URL scheme of the current
    request (if there is one).  This behavior can be changed by setting
    the force_scheme_change to False.
    """
    # leading slashes are ignored, if we redirect to "/foo" or "foo"
    # does not matter, in both cases we want to be below our clanwebsite root.
    url = url.lstrip('/')

    if not allow_external_redirect:
        #: check if the url is on the same server
        #: and make it an external one
        try:
            url = check_external_url(get_application(), url)
        except ValueError:
            raise BadRequest()

    # keep the current URL schema if we have an active request if we
    # should.  If https enforcement is set we suppose that the site_url
    # is already set to an https value.
    request = get_request()
    if request and not force_scheme_change and \
       not request.app.cfg['force_https']:
        url = request.environ['wsgi.url_scheme'] + ':' + url.split(':', 1)[1]

    return _redirect(url, code)
Exemple #5
0
def render_admin_response(template_name, _active_menu_item=None, **values):
    """Works pretty much like the normal `render_response` function but
    it emits some events to collect navigation items and injects that
    into the template context. This also gets the flashes messages from
    the user session and injects them into the template context after the
    plugins have provided theirs in the `before-admin-response-rendered`
    event.

    The second parameter can be the active menu item if wanted. For example
    ``'options.overview'`` would show the overview button in the options
    submenu. If the menu is a standalone menu like the dashboard (no
    child items) you can also just use ``'dashboard'`` to highlight that.
    """
    request = get_request()

    # set up the core navigation bar
    navigation_bar = [
        ('dashboard', url_for('admin/index'), _(u'Dashboard'), [])
    ]

    Access_items = []

    # set up the administration menu bar
    if request.user.has_privilege(CLAN_ADMIN):
        navigation_bar.extend([
            ('users_groups', url_for('admin/manage_users'), _(u'Users and Groups'), [
                ('users', url_for('admin/manage_users'), _(u'Users')),
                ('groups', url_for('admin/manage_groups'), _(u'Groups'))
            ])
        ])
        navigation_bar.extend([
            ('options', url_for('admin/options'), _(u'Options'), [
                ('basic', url_for('admin/basic_options'), _(u'Basic')),
                ('urls', url_for('admin/urls'), _(u'URLs')),
                ('theme', url_for('admin/theme'), _(u'Theme')),
                ('recaptcha', url_for('admin/recaptcha'), _(u'reCAPTCHA')),
                ('cache', url_for('admin/cache'), _(u'Cache')),
                ('configuration', url_for('admin/configuration'),
                 _(u'Configuration Editor'))
            ])
        ])

    # add the help item to the navigation bar
    system_items = [('help', url_for('admin/help'), _(u'Help'))]

    if request.user.has_privilege(CLAN_ADMIN):
        system_items[0:0] = [
            ('information', url_for('admin/information'),
             _(u'Information')),
            ('maintenance', url_for('admin/maintenance'),
             _(u'Maintenance')),
            ('plugins', url_for('admin/plugins'), _(u'Plugins')),
            ('log', url_for('admin/log'), _('Log'))
        ]

    navigation_bar.append(('system', system_items[0][1], _(u'System'),
                           system_items))

    signals.modify_admin_navigation_bar.send(request=request, navbar=navigation_bar)

    # find out which is the correct menu and submenu bar
    active_menu = active_submenu = None
    if _active_menu_item is not None:
        p = _active_menu_item.split('.')
        if len(p) == 1:
            active_menu = p[0]
        else:
            active_menu, active_submenu = p
    for id, url, title, subnavigation_bar in navigation_bar:
        if id == active_menu:
            break
    else:
        subnavigation_bar = []

    # if we are in maintenance_mode the user should know that, no matter
    # on which page he is.
    if request.app.cfg['maintenance_mode'] and \
                                        request.user.has_privilege(CLAN_ADMIN):
        flash(_(u'pyClanSphere is in maintenance mode. Don\'t forget to '
                u'<a href="%s">turn it off again</a> once you finish your '
                u'changes.') % url_for('admin/maintenance'))

    # check for broken plugins if we have the plugin guard enabled
    if request.app.cfg['plugin_guard']:
        plugins_to_deactivate = []
        for plugin in request.app.plugins.itervalues():
            if plugin.active and plugin.setup_error is not None:
                flash(_(u'Could not activate plugin “%(name)s”: %(error)s') % {
                    'name':     plugin.html_display_name,
                    'error':    plugin.setup_error
                })
                plugins_to_deactivate.append(plugin.name)

        if plugins_to_deactivate:
            #TODO: it's quite tricky – it needs at least two reloads to
            #      deactivate the plugin (which is in fact a application reload)
            cfg = request.app.cfg.edit()
            cfg['plugins'] = u', '.join(sorted(set(request.app.cfg['plugins']) - \
                                               set(plugins_to_deactivate)))
            cfg.commit()
            # we change the plugins inline so that the user get somewhat more
            # information
            request.app.cfg.touch()

    signals.before_admin_response_rendered.send(request=request, values=values)

    # the admin variables is pushed into the context after the event was
    # sent so that plugins can flash their messages. If we would emit the
    # event afterwards all flashes messages would appear in the request
    # after the current request.
    values['admin'] = {
        'navbar': [{
            'id':       id,
            'url':      url,
            'title':    title,
            'active':   active_menu == id
        } for id, url, title, children in navigation_bar],
        'ctxnavbar': [{
            'id':       id,
            'url':      url,
            'title':    title,
            'active':   active_submenu == id
        } for id, url, title in subnavigation_bar],
        'messages': [{
            'type':     type,
            'msg':      msg
        } for type, msg in request.session.pop('admin/flashed_messages', [])],
        'active_pane': _active_menu_item
    }
    return render_response(template_name, **values)
Exemple #6
0
def assert_privilege(expr):
    """Like the `require_privilege` decorator but for asserting."""
    if not get_request().user.has_privilege(expr):
        raise Forbidden()