diff --git a/pillar/application/modules/blender_cloud/home_project.py b/pillar/application/modules/blender_cloud/home_project.py index 50aee78c..be4ed46f 100644 --- a/pillar/application/modules/blender_cloud/home_project.py +++ b/pillar/application/modules/blender_cloud/home_project.py @@ -3,7 +3,7 @@ import logging from bson import ObjectId from eve.methods.put import put_internal from eve.methods.get import get -from flask import Blueprint, g, current_app +from flask import Blueprint, g, current_app, request from werkzeug import exceptions as wz_exceptions from application.modules import projects @@ -60,14 +60,24 @@ def create_home_project(user_id): @blueprint.route('/home-project') @authorization.require_login(require_roles={u'subscriber', u'demo'}) def home_project(): - user_id = g.current_user['user_id'] + """Fetches the home project, creating it if necessary. + Eve projections are supported, but at least the following fields must be present: + 'permissions', 'category', 'user' + """ + user_id = g.current_user['user_id'] roles = g.current_user.get('roles', ()) + log.debug('Possibly creating home project for user %s with roles %s', user_id, roles) if not HOME_PROJECT_USERS.intersection(roles): log.debug('User %s is not a subscriber, not creating home project.', user_id) return 'No home project', 404 + # Create the home project before we do the Eve query. This costs an extra round-trip + # to the database, but makes it easier to do projections correctly. + if not has_home_project(user_id): + create_home_project(user_id) + resp, _, _, status, _ = get('projects', category=u'home', user=user_id) if status != 200: return utils.jsonify(resp), status @@ -75,8 +85,10 @@ def home_project(): if resp['_items']: project = resp['_items'][0] else: - log.debug('Home project for user %s not found', user_id) - project = create_home_project(user_id) + log.warning('Home project for user %s not found, while we just created it! Could be ' + 'due to projections and other arguments on the query string: %s', + user_id, request.query_string) + return 'No home project', 404 return utils.jsonify(project), status diff --git a/tests/test_bcloud_home_project.py b/tests/test_bcloud_home_project.py index 2ddaf076..7a8cf7bd 100644 --- a/tests/test_bcloud_home_project.py +++ b/tests/test_bcloud_home_project.py @@ -58,9 +58,7 @@ class HomeProjectTest(AbstractPillarTest): self.assertEqual(json_proj['_etag'], db_proj['_etag']) @responses.activate - def test_autocreate_home_project_after_getting_subscriber_role(self): - from application.modules.blender_cloud import home_project - + def test_autocreate_home_project_with_subscriber_role(self): # Implicitly create user by token validation. self.mock_blenderid_validate_happy() resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')}) @@ -77,13 +75,13 @@ class HomeProjectTest(AbstractPillarTest): self.assertEqual('home', json_proj['category']) @responses.activate - def test_autocreate_home_project_after_getting_demo_role(self): + def test_autocreate_home_project_with_demo_role(self): # Implicitly create user by token validation. self.mock_blenderid_validate_happy() resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')}) self.assertEqual(200, resp.status_code, resp) - # Grant demo role, which should also should allow creation fo the home project. + # Grant demo role, which should allow creation of the home project. self.badger(TEST_EMAIL_ADDRESS, 'demo', 'grant') resp = self.client.get('/bcloud/home-project', @@ -93,6 +91,20 @@ class HomeProjectTest(AbstractPillarTest): json_proj = json.loads(resp.data) self.assertEqual('home', json_proj['category']) + @responses.activate + def test_autocreate_home_project_with_succubus_role(self): + # Implicitly create user by token validation. + self.mock_blenderid_validate_happy() + resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')}) + self.assertEqual(200, resp.status_code, resp) + + # Grant demo role, which should NOT allow creation fo the home project. + self.badger(TEST_EMAIL_ADDRESS, 'succubus', 'grant') + + resp = self.client.get('/bcloud/home-project', + headers={'Authorization': self.make_header('token')}) + self.assertEqual(403, resp.status_code) + def test_has_home_project(self): from application.modules.blender_cloud import home_project from application.utils.authentication import validate_token @@ -106,3 +118,28 @@ class HomeProjectTest(AbstractPillarTest): self.assertFalse(home_project.has_home_project(user_id)) home_project.create_home_project(user_id) self.assertTrue(home_project.has_home_project(user_id)) + + @responses.activate + def test_home_project_projections(self): + """Getting the home project should support projections.""" + + # Implicitly create user by token validation. + self.mock_blenderid_validate_happy() + resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')}) + self.assertEqual(200, resp.status_code, resp) + + # Grant subscriber role, and fetch the home project. + self.badger(TEST_EMAIL_ADDRESS, 'subscriber', 'grant') + + resp = self.client.get('/bcloud/home-project', + query_string={'projection': json.dumps( + {'permissions': 1, + 'category': 1, + 'user': 1})}, + headers={'Authorization': self.make_header('token')}) + self.assertEqual(200, resp.status_code, resp.data) + + json_proj = json.loads(resp.data) + self.assertNotIn('name', json_proj) + self.assertNotIn('node_types', json_proj) + self.assertEqual('home', json_proj['category'])