2017-03-10 15:36:30 +01:00
|
|
|
import logging
|
|
|
|
|
|
|
|
import flask
|
|
|
|
from werkzeug.local import LocalProxy
|
2017-06-14 16:26:29 +02:00
|
|
|
|
2019-04-03 15:54:37 +02:00
|
|
|
import pillarsdk
|
|
|
|
import pillar.auth
|
2017-06-14 16:26:29 +02:00
|
|
|
from pillar.api.utils import authorization
|
2017-03-10 15:36:30 +01:00
|
|
|
from pillar.extension import PillarExtension
|
|
|
|
|
|
|
|
EXTENSION_NAME = 'cloud'
|
|
|
|
|
|
|
|
|
|
|
|
class CloudExtension(PillarExtension):
|
2017-06-14 16:26:29 +02:00
|
|
|
has_context_processor = True
|
2017-11-30 15:30:08 +01:00
|
|
|
user_roles = {'subscriber-pro', 'has_subscription'}
|
|
|
|
user_roles_indexable = {'subscriber-pro', 'has_subscription'}
|
|
|
|
|
|
|
|
user_caps = {
|
|
|
|
'has_subscription': {'can-renew-subscription'},
|
|
|
|
}
|
2017-06-14 16:26:29 +02:00
|
|
|
|
2017-03-10 15:36:30 +01:00
|
|
|
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
|
|
|
|
|
2017-11-30 15:45:40 +01:00
|
|
|
return {
|
|
|
|
'EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER': 'https://store.blender.org/api/',
|
|
|
|
'EXTERNAL_SUBSCRIPTIONS_TIMEOUT_SECS': 10,
|
2017-12-01 19:06:16 +01:00
|
|
|
'BLENDER_ID_WEBHOOK_USER_CHANGED_SECRET': 'oos9wah1Zoa0Yau6ahThohleiChephoi',
|
2018-09-19 11:34:13 +02:00
|
|
|
'NODE_TAGS': ['animation', 'modeling', 'rigging', 'sculpting', 'shading', 'texturing', 'lighting',
|
2018-09-19 16:15:31 +02:00
|
|
|
'character-pipeline', 'effects', 'video-editing', 'digital-painting', 'production-design',
|
|
|
|
'walk-through'],
|
2017-11-30 15:45:40 +01:00
|
|
|
}
|
2017-03-10 15:36:30 +01:00
|
|
|
|
|
|
|
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
|
2017-03-17 09:40:50 +01:00
|
|
|
import cloud.stats.routes
|
|
|
|
return [
|
|
|
|
routes.blueprint,
|
|
|
|
cloud.stats.routes.blueprint,
|
|
|
|
]
|
2017-03-10 15:36:30 +01:00
|
|
|
|
|
|
|
@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')
|
|
|
|
|
2017-06-14 16:26:29 +02:00
|
|
|
def context_processor(self):
|
|
|
|
return {
|
2017-08-22 16:40:05 +02:00
|
|
|
'current_user_is_subscriber': authorization.user_has_cap('subscriber')
|
2017-06-14 16:26:29 +02:00
|
|
|
}
|
|
|
|
|
2019-04-03 15:54:37 +02:00
|
|
|
def is_cloud_project(self, project):
|
|
|
|
"""Returns whether the project is set up for Blender Cloud.
|
|
|
|
|
|
|
|
Requires the presence of the 'cloud' key in extension_props
|
|
|
|
"""
|
|
|
|
|
|
|
|
try:
|
|
|
|
pprops = project.extension_props[EXTENSION_NAME]
|
|
|
|
except AttributeError:
|
|
|
|
self._log.warning("is_cloud_project: Project url=%r doesn't have any "
|
|
|
|
"extension properties.", project['url'])
|
|
|
|
if self._log.isEnabledFor(logging.DEBUG):
|
|
|
|
import pprint
|
|
|
|
self._log.debug('Project: %s', pprint.pformat(project.to_dict()))
|
|
|
|
return False
|
|
|
|
except KeyError:
|
|
|
|
# Not set up for Blender Cloud
|
|
|
|
return False
|
|
|
|
|
|
|
|
if pprops is None:
|
|
|
|
self._log.debug("is_cloud_project: Project url=%r doesn't have Blender Cloud"
|
|
|
|
" extension properties.", project['url'])
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
@property
|
|
|
|
def has_project_settings(self) -> bool:
|
|
|
|
# Only available for admins
|
|
|
|
return pillar.auth.current_user.has_cap('admin')
|
|
|
|
|
|
|
|
def project_settings(self, project: pillarsdk.Project, **template_args: dict) -> flask.Response:
|
|
|
|
"""Renders the project settings page for this extension.
|
|
|
|
|
|
|
|
Set YourExtension.has_project_settings = True and Pillar will call this function.
|
|
|
|
|
|
|
|
:param project: the project for which to render the settings.
|
|
|
|
:param template_args: additional template arguments.
|
|
|
|
:returns: a Flask HTTP response
|
|
|
|
"""
|
|
|
|
|
|
|
|
from cloud.routes import project_settings
|
|
|
|
|
|
|
|
return project_settings(project, **template_args)
|
|
|
|
|
2017-07-11 12:40:13 +02:00
|
|
|
def setup_app(self, app):
|
2017-12-21 15:26:23 +01:00
|
|
|
from . import routes, webhooks, eve_hooks, email
|
2017-07-11 12:40:13 +02:00
|
|
|
|
2017-09-19 13:45:10 +02:00
|
|
|
routes.setup_app(app)
|
2017-12-01 19:06:16 +01:00
|
|
|
app.register_api_blueprint(webhooks.blueprint, '/webhooks')
|
2017-12-21 15:26:23 +01:00
|
|
|
eve_hooks.setup_app(app)
|
|
|
|
email.setup_app(app)
|
2017-07-11 12:40:13 +02:00
|
|
|
|
2017-03-10 15:36:30 +01:00
|
|
|
|
|
|
|
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."""
|