diff --git a/CHANGELOG.md b/CHANGELOG.md index 7448484..bc6c59c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Blender Cloud changelog +## Version 1.8 (in development) + +- Distinguish between 'please subscribe' (to get a new subscription) and 'please renew' (to renew an + existing subscription). + + ## Version 1.7.5 (2017-10-06) - Sorting the project list alphabetically. diff --git a/blender_cloud/__init__.py b/blender_cloud/__init__.py index ed5e07e..1c69962 100644 --- a/blender_cloud/__init__.py +++ b/blender_cloud/__init__.py @@ -79,6 +79,7 @@ def register(): reload_mod('blendfile') reload_mod('home_project') reload_mod('utils') + reload_mod('pillar') async_loop = reload_mod('async_loop') flamenco = reload_mod('flamenco') diff --git a/blender_cloud/image_sharing.py b/blender_cloud/image_sharing.py index 03c034d..fa1e9bd 100644 --- a/blender_cloud/image_sharing.py +++ b/blender_cloud/image_sharing.py @@ -124,9 +124,8 @@ class PILLAR_OT_image_share(pillar.PillarOperatorMixin, db_user = await self.check_credentials(context, REQUIRES_ROLES_FOR_IMAGE_SHARING) self.user_id = db_user['_id'] self.log.debug('Found user ID: %s', self.user_id) - except pillar.NotSubscribedToCloudError: - self.log.exception('User not subscribed to cloud.') - self.report({'ERROR'}, 'Please subscribe to the Blender Cloud.') + except pillar.NotSubscribedToCloudError as ex: + self._log_subscription_needed(can_renew=ex.can_renew) self._state = 'QUIT' return except pillar.UserNotLoggedInError: diff --git a/blender_cloud/pillar.py b/blender_cloud/pillar.py index 43d98c6..b0bfbb5 100755 --- a/blender_cloud/pillar.py +++ b/blender_cloud/pillar.py @@ -62,7 +62,16 @@ class CredentialsNotSyncedError(UserNotLoggedInError): class NotSubscribedToCloudError(UserNotLoggedInError): - """Raised when the user may be logged in on Blender ID, but has no Blender Cloud token.""" + """Raised when the user does not have an active Cloud subscription. + + :ivar can_renew: True when the user has an inactive subscription that can be renewed, + or False when the user has no subscription at all. + """ + + def __init__(self, can_renew: bool): + super().__init__() + self.can_renew = can_renew + log.warning('Not subscribed to cloud, can_renew=%s', can_renew) class PillarError(RuntimeError): @@ -273,14 +282,15 @@ async def check_pillar_credentials(required_roles: set): except (pillarsdk.UnauthorizedAccess, pillarsdk.ResourceNotFound, pillarsdk.ForbiddenAccess): raise CredentialsNotSyncedError() - roles = db_user.roles or set() - log.debug('User has roles %r', roles) - if required_roles and not required_roles.intersection(set(roles)): + roles = set(db_user.roles or set()) + log.getChild('check_pillar_credentials').debug('user has roles %r', roles) + if required_roles and not required_roles.intersection(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() + + raise NotSubscribedToCloudError(can_renew='has_subscription' in roles) return db_user @@ -834,7 +844,6 @@ class PillarOperatorMixin: try: db_user = await check_pillar_credentials(required_roles) except NotSubscribedToCloudError: - self._log_subscription_needed() raise except CredentialsNotSyncedError: self.log.info('Credentials not synced, re-syncing automatically.') @@ -845,7 +854,6 @@ class PillarOperatorMixin: try: db_user = await refresh_pillar_credentials(required_roles) except NotSubscribedToCloudError: - self._log_subscription_needed() raise except CredentialsNotSyncedError: self.log.info('Credentials not synced after refreshing, handling as not logged in.') @@ -857,11 +865,13 @@ class PillarOperatorMixin: self.log.info('Credentials refreshed and ok.') return db_user - def _log_subscription_needed(self): - self.log.warning( - 'Please subscribe to the blender cloud at https://cloud.blender.org/join') - self.report({'INFO'}, - 'Please subscribe to the blender cloud at https://cloud.blender.org/join') + def _log_subscription_needed(self, *, can_renew: bool, level='ERROR'): + if can_renew: + msg = 'Please renew your Blender Cloud subscription at https://cloud.blender.org/renew' + else: + msg = 'Please subscribe to the blender cloud at https://cloud.blender.org/join' + self.log.warning(msg) + self.report({level}, msg) class AuthenticatedPillarOperatorMixin(PillarOperatorMixin): diff --git a/blender_cloud/settings_sync.py b/blender_cloud/settings_sync.py index 15a9d9a..0db959d 100644 --- a/blender_cloud/settings_sync.py +++ b/blender_cloud/settings_sync.py @@ -284,9 +284,8 @@ class PILLAR_OT_sync(pillar.PillarOperatorMixin, db_user = await self.check_credentials(context, REQUIRES_ROLES_FOR_SYNC) self.user_id = db_user['_id'] log.debug('Found user ID: %s', self.user_id) - except pillar.NotSubscribedToCloudError: - self.log.exception('User not subscribed to cloud.') - self.bss_report({'SUBSCRIBE'}, 'Please subscribe to the Blender Cloud.') + except pillar.NotSubscribedToCloudError as ex: + self._log_subscription_needed(can_renew=ex.can_renew) self._state = 'QUIT' return except pillar.UserNotLoggedInError: diff --git a/blender_cloud/texture_browser.py b/blender_cloud/texture_browser.py index bea2f22..0eaf5d1 100644 --- a/blender_cloud/texture_browser.py +++ b/blender_cloud/texture_browser.py @@ -311,8 +311,8 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, self.mouse_y = event.mouse_y left_mouse_release = event.type == 'LEFTMOUSE' and event.value == 'RELEASE' - if self._state == 'PLEASE_SUBSCRIBE' and left_mouse_release: - self.open_browser_subscribe() + if left_mouse_release and self._state in {'PLEASE_SUBSCRIBE', 'PLEASE_RENEW'}: + self.open_browser_subscribe(renew=self._state == 'PLEASE_RENEW') self._finish(context) return {'FINISHED'} @@ -365,9 +365,9 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, try: db_user = await self.check_credentials(context, REQUIRED_ROLES_FOR_TEXTURE_BROWSER) - except pillar.NotSubscribedToCloudError: - self.log.info('User not subscribed to Blender Cloud.') - self._show_subscribe_screen() + except pillar.NotSubscribedToCloudError as ex: + self._log_subscription_needed(can_renew=ex.can_renew, level='INFO') + self._show_subscribe_screen(can_renew=ex.can_renew) return None if db_user is None: @@ -375,10 +375,14 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, await self.async_download_previews() - def _show_subscribe_screen(self): + def _show_subscribe_screen(self, *, can_renew: bool): """Shows the "You need to subscribe" screen.""" - self._state = 'PLEASE_SUBSCRIBE' + if can_renew: + self._state = 'PLEASE_RENEW' + else: + self._state = 'PLEASE_SUBSCRIBE' + bpy.context.window.cursor_set('HAND') def descend_node(self, menu_item: MenuItem): @@ -560,6 +564,7 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, 'DOWNLOADING_TEXTURE': self._draw_downloading, 'EXCEPTION': self._draw_exception, 'PLEASE_SUBSCRIBE': self._draw_subscribe, + 'PLEASE_RENEW': self._draw_renew, } if self._state in drawers: @@ -727,6 +732,11 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, 'Click to subscribe to the Blender Cloud', (0.0, 0.0, 0.2, 0.6)) + def _draw_renew(self, context): + self._draw_text_on_colour(context, + 'Click to renew your Blender Cloud subscription', + (0.0, 0.0, 0.2, 0.6)) + def get_clicked(self) -> MenuItem: for item in self.current_display_content: @@ -807,11 +817,11 @@ class BlenderCloudBrowser(pillar.PillarOperatorMixin, future=signalling_future)) self.async_task.add_done_callback(texture_download_completed) - def open_browser_subscribe(self): + def open_browser_subscribe(self, *, renew: bool): import webbrowser - webbrowser.open_new_tab('https://cloud.blender.org/join') - + url = 'renew' if renew else 'join' + webbrowser.open_new_tab('https://cloud.blender.org/%s' % url) self.report({'INFO'}, 'We just started a browser for you.') def _scroll_smooth(self): @@ -866,9 +876,8 @@ class PILLAR_OT_switch_hdri(pillar.PillarOperatorMixin, try: db_user = await self.check_credentials(context, REQUIRED_ROLES_FOR_TEXTURE_BROWSER) user_id = db_user['_id'] - except pillar.NotSubscribedToCloudError: - self.log.exception('User not subscribed to cloud.') - self.report({'ERROR'}, 'Please subscribe to the Blender Cloud.') + except pillar.NotSubscribedToCloudError as ex: + self._log_subscription_needed(can_renew=ex.can_renew) self._state = 'QUIT' return except pillar.UserNotLoggedInError: