Added check for user's roles -- disallow usage by non-subscribers.

This makes it clear from the get-go that users need to subscribe. Otherwise
they'll get unexpected errors once they try to download something.
This commit is contained in:
Sybren A. Stüvel 2016-05-10 14:52:51 +02:00
parent 6ce4399407
commit 5eaee872bf
2 changed files with 73 additions and 20 deletions

View File

@ -269,24 +269,36 @@ class BlenderCloudBrowser(bpy.types.Operator):
self.mouse_x = event.mouse_x self.mouse_x = event.mouse_x
self.mouse_y = event.mouse_y self.mouse_y = event.mouse_y
if self._state == 'BROWSING' and event.type == 'LEFTMOUSE' and event.value == 'RELEASE': left_mouse_release = event.type == 'LEFTMOUSE' and event.value == 'RELEASE'
if self._state == 'PLEASE_SUBSCRIBE' and left_mouse_release:
self.open_browser_subscribe()
self._finish(context)
return {'FINISHED'}
if self._state == 'BROWSING':
selected = self.get_clicked() selected = self.get_clicked()
if selected is None: if selected:
# No item clicked, ignore it. context.window.cursor_set('HAND')
return {'RUNNING_MODAL'}
if selected.is_folder:
self.descend_node(selected.node)
else: else:
if selected.file_desc is None: context.window.cursor_set('DEFAULT')
# This can happen when the thumbnail information isn't loaded yet.
# Just ignore the click for now.
# TODO: think of a way to handle this properly.
return {'RUNNING_MODAL'}
self.handle_item_selection(context, selected)
elif event.type in {'RIGHTMOUSE', 'ESC'}: if left_mouse_release:
if selected is None:
# No item clicked, ignore it.
return {'RUNNING_MODAL'}
if selected.is_folder:
self.descend_node(selected.node)
else:
if selected.file_desc is None:
# This can happen when the thumbnail information isn't loaded yet.
# Just ignore the click for now.
# TODO: think of a way to handle this properly.
return {'RUNNING_MODAL'}
self.handle_item_selection(context, selected)
if event.type in {'RIGHTMOUSE', 'ESC'}:
self._finish(context) self._finish(context)
return {'CANCELLED'} return {'CANCELLED'}
@ -302,6 +314,10 @@ class BlenderCloudBrowser(bpy.types.Operator):
try: try:
await pillar.check_pillar_credentials() await pillar.check_pillar_credentials()
except pillar.NotSubscribedToCloudError:
self.log.info('User not subscribed to Blender Cloud.')
self._show_subscribe_screen()
return
except pillar.CredentialsNotSyncedError: except pillar.CredentialsNotSyncedError:
self.log.info('Credentials not synced, re-syncing automatically.') self.log.info('Credentials not synced, re-syncing automatically.')
else: else:
@ -311,6 +327,10 @@ class BlenderCloudBrowser(bpy.types.Operator):
try: try:
await pillar.refresh_pillar_credentials() await pillar.refresh_pillar_credentials()
except pillar.NotSubscribedToCloudError:
self.log.info('User is not a Blender Cloud subscriber.')
self._show_subscribe_screen()
return
except pillar.UserNotLoggedInError: except pillar.UserNotLoggedInError:
self.error('User not logged in on Blender ID.') self.error('User not logged in on Blender ID.')
else: else:
@ -321,6 +341,12 @@ class BlenderCloudBrowser(bpy.types.Operator):
raise pillar.UserNotLoggedInError() raise pillar.UserNotLoggedInError()
# self._new_async_task(self._check_credentials()) # self._new_async_task(self._check_credentials())
def _show_subscribe_screen(self):
"""Shows the "You need to subscribe" screen."""
self._state = 'PLEASE_SUBSCRIBE'
bpy.context.window.cursor_set('HAND')
def descend_node(self, node): def descend_node(self, node):
"""Descends the node hierarchy by visiting this node. """Descends the node hierarchy by visiting this node.
@ -479,7 +505,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
self.log.debug('Browsing assets at project %r node %r', self.project_uuid, self.node_uuid) self.log.debug('Browsing assets at project %r node %r', self.project_uuid, self.node_uuid)
self._new_async_task(self.async_download_previews()) self._new_async_task(self.async_download_previews())
def _new_async_task(self, async_task: asyncio.coroutine, future: asyncio.Future=None): def _new_async_task(self, async_task: asyncio.coroutine, future: asyncio.Future = None):
"""Stops the currently running async task, and starts another one.""" """Stops the currently running async task, and starts another one."""
self.log.debug('Setting up a new task %r, so any existing task must be stopped', async_task) self.log.debug('Setting up a new task %r, so any existing task must be stopped', async_task)
@ -501,6 +527,7 @@ class BlenderCloudBrowser(bpy.types.Operator):
'BROWSING': self._draw_browser, 'BROWSING': self._draw_browser,
'DOWNLOADING_TEXTURE': self._draw_downloading, 'DOWNLOADING_TEXTURE': self._draw_downloading,
'EXCEPTION': self._draw_exception, 'EXCEPTION': self._draw_exception,
'PLEASE_SUBSCRIBE': self._draw_subscribe,
} }
if self._state in drawers: if self._state in drawers:
@ -643,6 +670,11 @@ class BlenderCloudBrowser(bpy.types.Operator):
blf.draw(font_id, line) blf.draw(font_id, line)
bgl.glDisable(bgl.GL_BLEND) bgl.glDisable(bgl.GL_BLEND)
def _draw_subscribe(self, context):
self._draw_text_on_colour(context,
'Click to subscribe to the Blender Cloud',
(0.0, 0.0, 0.2, 0.6))
def get_clicked(self) -> MenuItem: def get_clicked(self) -> MenuItem:
for item in self.current_display_content: for item in self.current_display_content:
@ -691,6 +723,13 @@ class BlenderCloudBrowser(bpy.types.Operator):
future=signalling_future)) future=signalling_future))
self.async_task.add_done_callback(texture_download_completed) self.async_task.add_done_callback(texture_download_completed)
def open_browser_subscribe(self):
import webbrowser
webbrowser.open_new_tab('https://cloud.blender.org/join')
self.report({'INFO'}, 'We just started a browser for you.')
# store keymaps here to access after registration # store keymaps here to access after registration
addon_keymaps = [] addon_keymaps = []

View File

@ -31,14 +31,15 @@ class UserNotLoggedInError(RuntimeError):
""" """
def __str__(self): def __str__(self):
return 'UserNotLoggedInError' return self.__class__.__name__
class CredentialsNotSyncedError(UserNotLoggedInError): class CredentialsNotSyncedError(UserNotLoggedInError):
"""Raised when the user may be logged in on Blender ID, but has no Blender Cloud token.""" """Raised when the user may be logged in on Blender ID, but has no Blender Cloud token."""
def __str__(self):
return 'CredentialsNotSyncedError' class NotSubscribedToCloudError(UserNotLoggedInError):
"""Raised when the user may be logged in on Blender ID, but has no Blender Cloud token."""
class PillarError(RuntimeError): class PillarError(RuntimeError):
@ -171,11 +172,24 @@ async def check_pillar_credentials():
if not subclient: if not subclient:
raise CredentialsNotSyncedError() raise CredentialsNotSyncedError()
pillar_user_id = subclient['subclient_user_id']
if not pillar_user_id:
raise CredentialsNotSyncedError()
try: try:
await get_project_uuid('textures') # Any query will do. db_user = await pillar_call(pillarsdk.User.find, pillar_user_id)
except pillarsdk.UnauthorizedAccess: except pillarsdk.UnauthorizedAccess:
raise CredentialsNotSyncedError() raise CredentialsNotSyncedError()
roles = db_user.roles
log.debug('User has roles %r', roles)
if not roles or not {'subscriber', 'demo'}.intersection(set(roles)):
# Delete the subclient info. This forces a re-check later, which can
# then pick up on the user's new status.
del profile.subclients[SUBCLIENT_ID]
profile.save_json()
raise NotSubscribedToCloudError()
async def refresh_pillar_credentials(): async def refresh_pillar_credentials():
"""Refreshes the authentication token on Pillar. """Refreshes the authentication token on Pillar.
@ -197,7 +211,7 @@ async def refresh_pillar_credentials():
# Test the new URL # Test the new URL
_pillar_api = None _pillar_api = None
await get_project_uuid('textures') # Any query will do. await check_pillar_credentials()
async def get_project_uuid(project_url: str) -> str: async def get_project_uuid(project_url: str) -> str: