Introducing Cloud extension
We use a Pillar extension to register Blender Cloud specific endpoints.
This commit is contained in:
71
cloud/__init__.py
Normal file
71
cloud/__init__.py
Normal file
@@ -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."""
|
40
cloud/cli.py
Executable file
40
cloud/cli.py
Executable file
@@ -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)
|
11
cloud/routes.py
Normal file
11
cloud/routes.py
Normal file
@@ -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')
|
252
cloud/templates/about.html
Normal file
252
cloud/templates/about.html
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
{% block page_title %}Welcome{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="page-header">
|
||||||
|
<div style="text-align: left" class="page-title">
|
||||||
|
<em>ABOUT</em>
|
||||||
|
<i class="pi-blender-cloud-logo"></i>
|
||||||
|
</div>
|
||||||
|
<div class="page-title-summary">
|
||||||
|
Blender Cloud means inspiration, knowledge, and tools in one place.<br>Started in 2015, it has been pushing the meaning of recurring crowdfunding ever since.<br> By subscribing to Blender Cloud you support the creation of open content, the development of high-end production tools like Blender and access a unique set of learning and creative resources.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="page-content">
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Launch at SXSW <small>March 9th, 2014</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
First happy cloud video and crowdfunding for Cosmos Laundromat Pilot.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://gooseberry.blender.org/gooseberry-campaign-launched-we-need-10k-people-to-help/"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://gooseberry.blender.org/gooseberry-campaign-launched-we-need-10k-people-to-help/"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Gooseberry | Cosmos Laundromat <small>March 10th, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Weekly folders with updates for subscribers. Initial development of Attract, which will become the new cloud some months later on.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Glass Half <small>October 30th, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
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 <a href="https://cloud.blender.org/p/glass-half/5627bb22f0e7220061109c9f">animation dailies</a>! But the biggest outcome from Glass Half was definitely <a href="https://cloud.blender.org/p/glass-half/569d6044c379cf445461293e">Flexirig</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/p/glass-half/blog/glass-half-premiere"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/new-art-gallery-with-gleb-alexandrov"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Art Gallery <small>November 19th, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Learn by example. Introducing a place for amazing artwork to be shared, along with its blendfiles and breakdowns.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Blender Institute Podcast <small>November 24th, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
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.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-blender-institute-podcast"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/p/blenrig/blog/welcome-to-the-blenrig-project"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Blenrig <small>December 1st, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
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!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Texture Library <small>December 23rd, 2015</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
The biggest source for CC0/Public Domain textures on the interwebs goes live. First as beta, as a quick gift right before Xmas 2015!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/new-texture-library"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/nraryew-the-character-lib"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Character Library <small>January 5th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
High-quality, animation-ready characters collection from all the Blender Institute open projects, plus a brand new one: Vincent!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Caminandes: Llamigos <small>January 30th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
The <a href="https://www.youtube.com/watch?v=SkVqJ1SGeL0">third episode</a> of the Caminandes series was completely done -and sponsored! through Blender Cloud. It's also the only project til date to have <a href="https://www.youtube.com/watch?v=kQH897V9bDg&list=PLI2TkLMzCSr_H6ppmzDtU0ut0RwxGvXjv">nicely edited Weekly video reports</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/p/caminandes-3/blog/caminandes-llamigos"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/welcome-sybren"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Sybren <small>March 1st, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Dr. Sybren Stüvel starts working at the Blender Institute!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Private Projects <small>May 3rd, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Create your own private projects on Blender Cloud.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/welcome-sybren"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-project-sharing"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Project Sharing <small>May 9th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Team work! Share your projects with other Blender Cloud subscribers.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Blender Cloud add-on with Texture Library <small>May 11th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Browse the textures from within Blender!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-project-sharing"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-private-texture-libraries"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Private Texture Libraries <small>May 23rd, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Create your own private textures library and browse it in Blender with our add-on.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Blender Sync <small>June 30th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Sync your Blender preferences across multiple devices.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-blender-sync"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-image-sharing"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
Image Sharing <small>July 14th, 2016</small>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
Quickly share renders and Blender screenshots within Blender with our add-on.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-the-hdri-library">HDRI Library <small>July 27th, 2016</small></a>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
High-dynamic range images are now available on Blender Cloud! With their own special viewer. Also available via the Blender Cloud add-on.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-the-hdri-library"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="page-card">
|
||||||
|
<div class="page-card-side">
|
||||||
|
<a href="https://cloud.blender.org/blog/introducing-the-hdri-library"><img src="https://placehold.it/400x200"></a>
|
||||||
|
</div>
|
||||||
|
<div class="page-card-side">
|
||||||
|
<h2 class="page-card-title">
|
||||||
|
<a href="https://cloud.blender.org/blog/new-training-toon-character-workflow">Toon Character Workflow <small>December 6th, 2016</small></a>
|
||||||
|
</h2>
|
||||||
|
<div class="page-card-summary">
|
||||||
|
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.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock body%}
|
33
manage.py
33
manage.py
@@ -1,38 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import logging
|
|
||||||
from flask import current_app
|
|
||||||
from pillar import cli
|
from pillar import cli
|
||||||
from pillar.cli import manager_maintenance
|
from runserver import app
|
||||||
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)
|
|
||||||
|
|
||||||
cli.manager.app = app
|
cli.manager.app = app
|
||||||
cli.manager.run()
|
cli.manager.run()
|
||||||
|
@@ -3,13 +3,16 @@
|
|||||||
from pillar import PillarServer
|
from pillar import PillarServer
|
||||||
from attract import AttractExtension
|
from attract import AttractExtension
|
||||||
from flamenco import FlamencoExtension
|
from flamenco import FlamencoExtension
|
||||||
|
from cloud import CloudExtension
|
||||||
|
|
||||||
attract = AttractExtension()
|
attract = AttractExtension()
|
||||||
flamenco = FlamencoExtension()
|
flamenco = FlamencoExtension()
|
||||||
|
cloud = CloudExtension()
|
||||||
|
|
||||||
app = PillarServer('.')
|
app = PillarServer('.')
|
||||||
app.load_extension(attract, '/attract')
|
app.load_extension(attract, '/attract')
|
||||||
app.load_extension(flamenco, '/flamenco')
|
app.load_extension(flamenco, '/flamenco')
|
||||||
|
app.load_extension(cloud, None)
|
||||||
app.process_extensions()
|
app.process_extensions()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
@@ -4,13 +4,16 @@ import sys
|
|||||||
from pillar import PillarServer
|
from pillar import PillarServer
|
||||||
from attract import AttractExtension
|
from attract import AttractExtension
|
||||||
from flamenco import FlamencoExtension
|
from flamenco import FlamencoExtension
|
||||||
|
from cloud import CloudExtension
|
||||||
|
|
||||||
sys.path.append('/data/git/blender-cloud')
|
sys.path.append('/data/git/blender-cloud')
|
||||||
|
|
||||||
attract = AttractExtension()
|
attract = AttractExtension()
|
||||||
flamenco = FlamencoExtension()
|
flamenco = FlamencoExtension()
|
||||||
|
cloud = CloudExtension()
|
||||||
|
|
||||||
application = PillarServer(dirname(abspath(__file__)))
|
application = PillarServer(dirname(abspath(__file__)))
|
||||||
application.load_extension(attract, '/attract')
|
application.load_extension(attract, '/attract')
|
||||||
application.load_extension(flamenco, '/flamenco')
|
application.load_extension(flamenco, '/flamenco')
|
||||||
|
application.load_extension(cloud, None)
|
||||||
application.process_extensions()
|
application.process_extensions()
|
||||||
|
Reference in New Issue
Block a user