From 1d687d5c01ff1b4494300df3dceffd9b8962ee77 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Fri, 10 Mar 2017 15:36:30 +0100 Subject: [PATCH] Introducing Cloud extension We use a Pillar extension to register Blender Cloud specific endpoints. --- cloud/__init__.py | 71 +++++++++++ cloud/cli.py | 40 ++++++ cloud/routes.py | 11 ++ cloud/templates/about.html | 252 +++++++++++++++++++++++++++++++++++++ manage.py | 33 +---- cloud.py => runserver.py | 3 + runserver.wsgi | 3 + 7 files changed, 381 insertions(+), 32 deletions(-) create mode 100644 cloud/__init__.py create mode 100755 cloud/cli.py create mode 100644 cloud/routes.py create mode 100644 cloud/templates/about.html rename cloud.py => runserver.py (81%) diff --git a/cloud/__init__.py b/cloud/__init__.py new file mode 100644 index 0000000..c7e3015 --- /dev/null +++ b/cloud/__init__.py @@ -0,0 +1,71 @@ +import logging + +import flask +from werkzeug.local import LocalProxy +from pillar.extension import PillarExtension + +EXTENSION_NAME = 'cloud' + + +class CloudExtension(PillarExtension): + 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 + return [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 _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.""" diff --git a/cloud/cli.py b/cloud/cli.py new file mode 100755 index 0000000..67dcbb8 --- /dev/null +++ b/cloud/cli.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +import logging +from flask import current_app +from flask_script import Manager + +from pillar.cli import manager + +log = logging.getLogger(__name__) + +manager_cloud = Manager( + current_app, usage="Blender Cloud scripts") + + +@manager_cloud.command +def reconcile_subscribers(): + """For every user, check their subscription status with the store.""" + from pillar.auth.subscriptions import fetch_user + + users_coll = current_app.data.driver.db['users'] + unsubscribed_users = [] + for user in users_coll.find({'roles': 'subscriber'}): + print('Processing %s' % user['email']) + print(' Checking subscription') + user_store = fetch_user(user['email']) + if user_store['cloud_access'] == 0: + print(' Removing subscriber role') + users_coll.update( + {'_id': user['_id']}, + {'$pull': {'roles': 'subscriber'}}) + unsubscribed_users.append(user['email']) + + if not unsubscribed_users: + return + + print('The following users have been unsubscribed') + for user in unsubscribed_users: + print(user) + +manager.add_command("cloud", manager_cloud) diff --git a/cloud/routes.py b/cloud/routes.py new file mode 100644 index 0000000..3d84c8f --- /dev/null +++ b/cloud/routes.py @@ -0,0 +1,11 @@ +import logging + +from flask import Blueprint, render_template + +blueprint = Blueprint('cloud', __name__) +log = logging.getLogger(__name__) + + +@blueprint.route('/about') +def about(): + return render_template('about.html') diff --git a/cloud/templates/about.html b/cloud/templates/about.html new file mode 100644 index 0000000..9c16876 --- /dev/null +++ b/cloud/templates/about.html @@ -0,0 +1,252 @@ +{% extends 'layout.html' %} +{% block page_title %}Welcome{% endblock %} +{% block body %} +
+ +
+
+
+

+ Launch at SXSW March 9th, 2014 +

+
+ First happy cloud video and crowdfunding for Cosmos Laundromat Pilot. +
+
+
+ +
+
+
+
+ +
+
+

+ Gooseberry | Cosmos Laundromat March 10th, 2015 +

+
+ Weekly folders with updates for subscribers. Initial development of Attract, which will become the new cloud some months later on. +
+
+
+
+
+

+ Glass Half October 30th, 2015 +

+
+ Introducing integrated blogs in Blender Cloud projects. Glass Half is the first project fully developed on the new Blender Cloud. It's also the first and only project to have share its animation dailies! But the biggest outcome from Glass Half was definitely Flexirig. +
+
+
+ +
+
+
+
+ +
+
+

+ Art Gallery November 19th, 2015 +

+
+ Learn by example. Introducing a place for amazing artwork to be shared, along with its blendfiles and breakdowns. +
+
+
+
+
+

+ Blender Institute Podcast November 24th, 2015 +

+
+ With so much going on in the Cloud at at the studio. The Blender Institute Podcast was born! Sharing our daily studio work, Blender community news, and interacting with the awesome Blender Cloud subscribers. +
+
+
+ +
+
+
+
+ +
+
+

+ Blenrig December 1st, 2015 +

+
+ The most powerful and versatile rigging framework for Blender, used and tested through Cosmos Laundromat and the Caminandes series, is now part of Blender Cloud! +
+
+
+
+
+

+ Texture Library December 23rd, 2015 +

+
+ The biggest source for CC0/Public Domain textures on the interwebs goes live. First as beta, as a quick gift right before Xmas 2015! +
+
+
+ +
+
+
+
+ +
+
+

+ Character Library January 5th, 2016 +

+
+ High-quality, animation-ready characters collection from all the Blender Institute open projects, plus a brand new one: Vincent! +
+
+
+
+
+

+ Caminandes: Llamigos January 30th, 2016 +

+
+ The third episode of the Caminandes series was completely done -and sponsored! through Blender Cloud. It's also the only project til date to have nicely edited Weekly video reports. +
+
+
+ +
+
+
+
+ +
+
+

+ Sybren March 1st, 2016 +

+
+ Dr. Sybren Stüvel starts working at the Blender Institute! +
+
+
+
+
+

+ Private Projects May 3rd, 2016 +

+
+ Create your own private projects on Blender Cloud. +
+
+
+ +
+
+
+
+ +
+
+

+ Project Sharing May 9th, 2016 +

+
+ Team work! Share your projects with other Blender Cloud subscribers. +
+
+
+
+
+

+ Blender Cloud add-on with Texture Library May 11th, 2016 +

+
+ Browse the textures from within Blender! +
+
+
+ +
+
+
+
+ +
+
+

+ Private Texture Libraries May 23rd, 2016 +

+
+ Create your own private textures library and browse it in Blender with our add-on. +
+
+
+
+
+

+ Blender Sync June 30th, 2016 +

+
+ Sync your Blender preferences across multiple devices. +
+
+
+ +
+
+
+
+ +
+
+

+ Image Sharing July 14th, 2016 +

+
+ Quickly share renders and Blender screenshots within Blender with our add-on. +
+
+
+
+
+

+ HDRI Library July 27th, 2016 +

+
+ High-dynamic range images are now available on Blender Cloud! With their own special viewer. Also available via the Blender Cloud add-on. +
+
+
+ +
+
+
+
+ +
+
+

+ Toon Character Workflow December 6th, 2016 +

+
+ YouTube star Dillon Gu joins Blender Cloud for a new tutorial series that will guide you from the basics to a finished toon-shaded character. +
+
+
+
+
+ +{% endblock body%} \ No newline at end of file diff --git a/manage.py b/manage.py index 5828ee0..b7c1f98 100755 --- a/manage.py +++ b/manage.py @@ -1,38 +1,7 @@ #!/usr/bin/env python -import logging -from flask import current_app from pillar import cli -from pillar.cli import manager_maintenance -from cloud import app - -log = logging.getLogger(__name__) - - -@manager_maintenance.command -def reconcile_subscribers(): - """For every user, check their subscription status with the store.""" - from pillar.auth.subscriptions import fetch_user - - users_coll = current_app.data.driver.db['users'] - unsubscribed_users = [] - for user in users_coll.find({'roles': 'subscriber'}): - print('Processing %s' % user['email']) - print(' Checking subscription') - user_store = fetch_user(user['email']) - if user_store['cloud_access'] == 0: - print(' Removing subscriber role') - users_coll.update( - {'_id': user['_id']}, - {'$pull': {'roles': 'subscriber'}}) - unsubscribed_users.append(user['email']) - - if not unsubscribed_users: - return - - print('The following users have been unsubscribed') - for user in unsubscribed_users: - print(user) +from runserver import app cli.manager.app = app cli.manager.run() diff --git a/cloud.py b/runserver.py similarity index 81% rename from cloud.py rename to runserver.py index 2c0e3ca..debbedc 100755 --- a/cloud.py +++ b/runserver.py @@ -3,13 +3,16 @@ from pillar import PillarServer from attract import AttractExtension from flamenco import FlamencoExtension +from cloud import CloudExtension attract = AttractExtension() flamenco = FlamencoExtension() +cloud = CloudExtension() app = PillarServer('.') app.load_extension(attract, '/attract') app.load_extension(flamenco, '/flamenco') +app.load_extension(cloud, None) app.process_extensions() if __name__ == '__main__': diff --git a/runserver.wsgi b/runserver.wsgi index 8ecf6c4..1bcaaac 100644 --- a/runserver.wsgi +++ b/runserver.wsgi @@ -4,13 +4,16 @@ import sys from pillar import PillarServer from attract import AttractExtension from flamenco import FlamencoExtension +from cloud import CloudExtension sys.path.append('/data/git/blender-cloud') attract = AttractExtension() flamenco = FlamencoExtension() +cloud = CloudExtension() application = PillarServer(dirname(abspath(__file__))) application.load_extension(attract, '/attract') application.load_extension(flamenco, '/flamenco') +application.load_extension(cloud, None) application.process_extensions()