Files
blender-cloud/cloud/__init__.py
Sybren A. Stüvel 19ccffa4ae Cache the homepage template context.
This requires pillar-python-sdk c8eec9fa9d8a198df198538a38ca1ad2367bb3e6
or newer.
2017-09-19 13:45:10 +02:00

129 lines
3.7 KiB
Python

import logging
import flask
from werkzeug.local import LocalProxy
from pillar.api.utils import authorization
from pillar.extension import PillarExtension
EXTENSION_NAME = 'cloud'
ROLES_TO_BE_SUBSCRIBER = {'demo', 'subscriber', 'admin'} # TODO: get rid of this, use 'subscriber' cap
class CloudExtension(PillarExtension):
has_context_processor = True
def __init__(self):
self._log = logging.getLogger('%s.CloudExtension' % __name__)
@property
def name(self):
return EXTENSION_NAME
def flask_config(self):
"""Returns extension-specific defaults for the Flask configuration.
Use this to set sensible default values for configuration settings
introduced by the extension.
:rtype: dict
"""
# Just so that it registers the management commands.
from . import cli
return {}
def eve_settings(self):
"""Returns extensions to the Eve settings.
Currently only the DOMAIN key is used to insert new resources into
Eve's configuration.
:rtype: dict
"""
return {}
def blueprints(self):
"""Returns the list of top-level blueprints for the extension.
These blueprints will be mounted at the url prefix given to
app.load_extension().
:rtype: list of flask.Blueprint objects.
"""
from . import routes
import cloud.stats.routes
return [
routes.blueprint,
cloud.stats.routes.blueprint,
]
@property
def template_path(self):
import os.path
return os.path.join(os.path.dirname(__file__), 'templates')
@property
def static_path(self):
import os.path
return os.path.join(os.path.dirname(__file__), 'static')
def context_processor(self):
return {
'current_user_is_subscriber': authorization.user_has_cap('subscriber')
}
def setup_app(self, app):
"""Links certain roles to the subscriber role.
This means that users who get the subscriber role also get this linked
role, and when the subscriber role is revoked, the linked role is also
revoked.
"""
from pillar.api.service import signal_user_changed_role
from . import routes
signal_user_changed_role.connect(self._user_changed_role)
routes.setup_app(app)
def _user_changed_role(self, sender, user: dict):
from pillar.api import service
linked_roles = {'flamenco-user', 'attract-user'}
link_to = {'subscriber', 'demo'}
user_roles = set(user.get('roles', []))
# Determine what to do
has_linked_roles = not (linked_roles - user_roles)
has_link_to = bool(link_to.intersection(user_roles))
action = ''
if has_link_to and not has_linked_roles:
self._log.info('Granting roles %s to user %s', linked_roles, user['_id'])
action = 'grant'
elif not has_link_to and has_linked_roles:
self._log.info('Revoking roles %s from user %s', linked_roles, user['_id'])
action = 'revoke'
if not action:
return
# Avoid infinite loops while we're changing the user's roles.
service.signal_user_changed_role.disconnect(self._user_changed_role)
try:
if linked_roles:
service.do_badger(action, roles=linked_roles, user_id=user['_id'])
finally:
service.signal_user_changed_role.connect(self._user_changed_role)
def _get_current_cloud():
"""Returns the Cloud extension of the current application."""
return flask.current_app.pillar_extensions[EXTENSION_NAME]
current_cloud = LocalProxy(_get_current_cloud)
"""Cloud extension of the current app."""