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()))
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)
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
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)
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)
def assert_privilege(expr): """Like the `require_privilege` decorator but for asserting.""" if not get_request().user.has_privilege(expr): raise Forbidden()