367 lines
18 KiB
Python
367 lines
18 KiB
Python
# -*- encoding: utf-8 -*-
|
|
|
|
|
|
import datetime
|
|
|
|
from bson import tz_util, ObjectId
|
|
|
|
from pillar.tests import AbstractPillarTest
|
|
from pillar.tests import common_test_data as ctd
|
|
from pillar.api.projects.utils import get_node_type
|
|
|
|
EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID = ObjectId('5673541534134154134513c3')
|
|
EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA = {
|
|
'_created': datetime.datetime(2015, 12, 17, 13, 22, 56, tzinfo=tz_util.utc),
|
|
'_etag': 'cc4643e98d3606f87bbfaaa200bfbae941b642f3',
|
|
'_id': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID,
|
|
'_updated': datetime.datetime(2016, 1, 7, 18, 59, 4, tzinfo=tz_util.utc),
|
|
'category': 'assets',
|
|
'description': 'Welcome to this curated collection of Blender Institute textures and image '
|
|
'resources. This collection is an on-going project, as with each project we '
|
|
'create a number of textures based on our own resources (photographs, scans, '
|
|
'etc.) or made completely from scratch. At the moment you can find all the '
|
|
'textures from the past Open Projects that were deemed re-usable. \r\n\r\n'
|
|
'People who have contributed to these textures:\r\n\r\nAndrea Weikert, Andy '
|
|
'Goralczyk, Basse Salmela, Ben Dansie, Campbell Barton, Enrico Valenza, Ian '
|
|
'Hubert, Kjartan Tysdal, Manu J\xe4rvinen, Massimiliana Pulieso, Matt Ebb, '
|
|
'Pablo Vazquez, Rob Tuytel, Roland Hess, Sarah Feldlaufer, S\xf6nke M\xe4ter',
|
|
'is_private': False,
|
|
'name': 'Unittest project',
|
|
'node_types': [
|
|
{'description': 'Group for texture node type',
|
|
'dyn_schema': {'order': {'type': 'integer'},
|
|
'status': {'allowed': ['published', 'pending'],
|
|
'type': 'string'},
|
|
'url': {'type': 'string'}},
|
|
'form_schema': {},
|
|
'name': 'group_texture',
|
|
'parent': ['group_texture', 'project']},
|
|
{'description': 'Folder node',
|
|
'dyn_schema': {'notes': {'maxlength': 256, 'type': 'string'},
|
|
'order': {'type': 'integer'},
|
|
'status': {'allowed': ['published', 'pending'],
|
|
'type': 'string'},
|
|
'url': {'type': 'string'}},
|
|
'form_schema': {},
|
|
'name': 'group',
|
|
'parent': ['group', 'project']},
|
|
{'description': 'Basic Asset Type',
|
|
'dyn_schema': {
|
|
'attachments': {'schema': {'schema': {'field': {'type': 'string'},
|
|
'files': {'schema': {
|
|
'schema': {'file': {
|
|
'data_relation': {
|
|
'embeddable': True,
|
|
'field': '_id',
|
|
'resource': 'files'},
|
|
'type': 'objectid'},
|
|
'size': {
|
|
'type': 'string'},
|
|
'slug': {
|
|
'minlength': 1,
|
|
'type': 'string'}},
|
|
'type': 'dict'},
|
|
'type': 'list'}},
|
|
'type': 'dict'},
|
|
'type': 'list'},
|
|
'categories': {'type': 'string'},
|
|
'content_type': {'type': 'string'},
|
|
'file': {'data_relation': {'embeddable': True,
|
|
'field': '_id',
|
|
'resource': 'files'},
|
|
'type': 'objectid'},
|
|
'order': {'type': 'integer'},
|
|
'status': {'allowed': ['published',
|
|
'pending',
|
|
'processing'],
|
|
'type': 'string'},
|
|
'tags': {'schema': {'type': 'string'}, 'type': 'list'}},
|
|
'form_schema': {'attachments': {'visible': False},
|
|
'content_type': {'visible': False},
|
|
'file': {'visible': False}},
|
|
'name': 'asset',
|
|
'parent': ['group']},
|
|
{'description': 'Entrypoint to a remote or local storage solution',
|
|
'dyn_schema': {'backend': {'type': 'string'},
|
|
'subdir': {'type': 'string'}},
|
|
'form_schema': {'backend': {}, 'subdir': {}},
|
|
'name': 'storage',
|
|
'parent': ['group', 'project'],
|
|
'permissions': {'groups': [{'group': ctd.EXAMPLE_ADMIN_GROUP_ID,
|
|
'methods': ['GET', 'PUT', 'POST']},
|
|
{'group': ctd.EXAMPLE_PROJECT_READONLY_GROUP_ID,
|
|
'methods': ['GET']},
|
|
{'group': ctd.EXAMPLE_PROJECT_READONLY_GROUP2_ID,
|
|
'methods': ['GET']}],
|
|
'users': [],
|
|
'world': []}},
|
|
{'description': 'Comments for asset nodes, pages, etc.',
|
|
'dyn_schema': {'confidence': {'type': 'float'},
|
|
'content': {'minlength': 5, 'type': 'string'},
|
|
'is_reply': {'type': 'boolean'},
|
|
'rating_negative': {'type': 'integer'},
|
|
'rating_positive': {'type': 'integer'},
|
|
'ratings': {'schema': {
|
|
'schema': {'is_positive': {'type': 'boolean'},
|
|
'user': {'type': 'objectid'},
|
|
'weight': {'type': 'integer'}},
|
|
'type': 'dict'},
|
|
'type': 'list'},
|
|
'status': {'allowed': ['published', 'flagged', 'edited'],
|
|
'type': 'string'}},
|
|
'form_schema': {},
|
|
'name': 'comment',
|
|
'parent': ['asset', 'comment']},
|
|
{'description': 'Container for node_type post.',
|
|
'dyn_schema': {'categories': {'schema': {'type': 'string'},
|
|
'type': 'list'},
|
|
'template': {'type': 'string'}},
|
|
'form_schema': {},
|
|
'name': 'blog',
|
|
'parent': ['project']},
|
|
{'description': 'A blog post, for any project',
|
|
'dyn_schema': {
|
|
'attachments': {'schema': {'schema': {'field': {'type': 'string'},
|
|
'files': {'schema': {
|
|
'schema': {'file': {
|
|
'data_relation': {
|
|
'embeddable': True,
|
|
'field': '_id',
|
|
'resource': 'files'},
|
|
'type': 'objectid'},
|
|
'size': {
|
|
'type': 'string'},
|
|
'slug': {
|
|
'minlength': 1,
|
|
'type': 'string'}},
|
|
'type': 'dict'},
|
|
'type': 'list'}},
|
|
'type': 'dict'},
|
|
'type': 'list'},
|
|
'category': {'type': 'string'},
|
|
'content': {'maxlength': 90000,
|
|
'minlength': 5,
|
|
'required': True,
|
|
'type': 'string'},
|
|
'status': {'allowed': ['published', 'pending'],
|
|
'default': 'pending',
|
|
'type': 'string'},
|
|
'url': {'type': 'string'}},
|
|
'form_schema': {'attachments': {'visible': False}},
|
|
'name': 'post',
|
|
'parent': ['blog']},
|
|
{'description': 'Image Texture',
|
|
'dyn_schema': {'aspect_ratio': {'type': 'float'},
|
|
'categories': {'type': 'string'},
|
|
'files': {'schema': {'schema': {
|
|
'file': {'data_relation': {'embeddable': True,
|
|
'field': '_id',
|
|
'resource': 'files'},
|
|
'type': 'objectid'},
|
|
'is_tileable': {'type': 'boolean'},
|
|
'map_type': {'allowed': ['color',
|
|
'specular',
|
|
'bump',
|
|
'normal',
|
|
'translucency',
|
|
'emission',
|
|
'alpha'],
|
|
'type': 'string'}},
|
|
'type': 'dict'},
|
|
'type': 'list'},
|
|
'is_landscape': {'type': 'boolean'},
|
|
'is_tileable': {'type': 'boolean'},
|
|
'order': {'type': 'integer'},
|
|
'resolution': {'type': 'string'},
|
|
'status': {'allowed': ['published',
|
|
'pending',
|
|
'processing'],
|
|
'type': 'string'},
|
|
'tags': {'schema': {'type': 'string'}, 'type': 'list'}},
|
|
'form_schema': {'content_type': {'visible': False},
|
|
'files': {'visible': False}},
|
|
'name': 'texture',
|
|
'parent': ['group']}],
|
|
'nodes_blog': [],
|
|
'nodes_featured': [],
|
|
'nodes_latest': [],
|
|
'permissions': {'groups': [{'group': ctd.EXAMPLE_ADMIN_GROUP_ID,
|
|
'methods': ['GET', 'POST', 'PUT', 'DELETE']}],
|
|
'users': [],
|
|
'world': ['GET']},
|
|
'status': 'published',
|
|
'summary': 'Texture collection from all Blender Institute open projects.',
|
|
'url': 'attachment-schema-update',
|
|
'picture_header': ObjectId('5673f260c379cf0007b31bc4'),
|
|
'picture_square': ObjectId('5673f256c379cf0007b31bc3'),
|
|
'user': ctd.EXAMPLE_PROJECT_OWNER_ID}
|
|
|
|
EXAMPLE_ASSET_NODE_OLD_ATTACHMENT_SCHEMA = {
|
|
'_id': ObjectId('572761099837730efe8e120d'),
|
|
'picture': ObjectId('5673f260c379cf0007b31bc4'),
|
|
'description': '',
|
|
'node_type': 'asset',
|
|
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
|
|
'properties': {
|
|
'status': 'published',
|
|
'content_type': 'image',
|
|
'file': ObjectId('5673f260c379cf0007b31bed'),
|
|
'attachments': [{
|
|
'files': [
|
|
{'slug': '01', 'file': ObjectId('5679b25ec379cf25636688f6')},
|
|
{'slug': '02b', 'file': ObjectId('5679b308c379cf25636688f7')},
|
|
{'slug': '03', 'file': ObjectId('5679b33bc379cf25636688f8')},
|
|
],
|
|
'field': 'properties.content'
|
|
}],
|
|
},
|
|
'_updated': datetime.datetime(2016, 5, 2, 14, 19, 58, 0, tzinfo=tz_util.utc),
|
|
'name': 'Image test',
|
|
'project': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID,
|
|
'_created': datetime.datetime(2016, 5, 2, 14, 19, 37, 0, tzinfo=tz_util.utc),
|
|
'_etag': '6b8589b42c880e3626f43f3e82a5c5b946742687'
|
|
}
|
|
|
|
EXAMPLE_PAGE_NODE_OLD_ATTACHMENT_SCHEMA = {
|
|
'_id': ObjectId('572761099837730efe8e120a'),
|
|
'picture': ObjectId('5673f260c379cf0007b31bc4'),
|
|
'description': '',
|
|
'node_type': 'page',
|
|
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
|
|
'properties': {
|
|
'status': 'published',
|
|
'content': 'Überinteressant Verhaaltje™ voor het slapengaan.',
|
|
'url': 'jemoeder',
|
|
'attachments': [{
|
|
'files': [
|
|
{'slug': '03', 'file': ObjectId('5679b33bc379cf256366ddd8')},
|
|
{'slug': '04', 'file': ObjectId('5679b35bc379cf256366ddd9')},
|
|
],
|
|
'field': 'properties.content'
|
|
}],
|
|
},
|
|
'_updated': datetime.datetime(2016, 5, 2, 14, 19, 58, 0, tzinfo=tz_util.utc),
|
|
'name': 'Page test',
|
|
'project': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID,
|
|
'_created': datetime.datetime(2016, 5, 2, 14, 19, 37, 0, tzinfo=tz_util.utc),
|
|
'_etag': '6b8589b42c880e3626f43f3e82a5c5b946742687'
|
|
}
|
|
|
|
|
|
class AbstractNodeReplacementTest(AbstractPillarTest):
|
|
project_overrides = None
|
|
|
|
def setUp(self, **kwargs):
|
|
AbstractPillarTest.setUp(self, **kwargs)
|
|
|
|
self.project_id, self.proj = self.ensure_project_exists(
|
|
project_overrides=self.project_overrides)
|
|
|
|
self.ensure_file_exists({
|
|
'_id': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA['picture_header'],
|
|
'project': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID,
|
|
})
|
|
self.ensure_file_exists({
|
|
'_id': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA['picture_square'],
|
|
'project': EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA_ID,
|
|
})
|
|
|
|
def fetch_project_from_db(self):
|
|
return super(AbstractNodeReplacementTest, self).fetch_project_from_db(self.project_id)
|
|
|
|
def add_group_permission_to_asset_node_type(self):
|
|
group_perms = {'group': ctd.EXAMPLE_PROJECT_READONLY_GROUP_ID,
|
|
'methods': ['POST', 'PUT']}
|
|
# Assign some permissions to the node types, so we're sure they don't get overwritten.
|
|
with self.app.app_context():
|
|
proj_coll = self.app.db()['projects']
|
|
proj_coll.update_one(
|
|
{'_id': self.project_id,
|
|
'node_types.name': 'asset'},
|
|
{'$push': {'node_types.$.permissions.groups': group_perms}}
|
|
)
|
|
|
|
return group_perms
|
|
|
|
|
|
class ReplaceNodeTypesTest(AbstractNodeReplacementTest):
|
|
def test_replace_pillar_node_type_schemas(self):
|
|
from pillar.api.node_types.group import node_type_group
|
|
from pillar.cli import replace_pillar_node_type_schemas
|
|
|
|
group_perms = self.add_group_permission_to_asset_node_type()
|
|
|
|
# Run the CLI command
|
|
with self.app.test_request_context():
|
|
replace_pillar_node_type_schemas(proj_url=self.proj['url'])
|
|
|
|
# Fetch the project again from MongoDB
|
|
dbproj = self.fetch_project_from_db()
|
|
|
|
# Test that the node types were updated
|
|
nt_group = get_node_type(dbproj, 'group')
|
|
self.assertEqual(node_type_group['description'], nt_group['description'])
|
|
|
|
# Test that the permissions set previously are still there.
|
|
nt_asset = get_node_type(dbproj, 'asset')
|
|
self.assertEqual([group_perms], nt_asset['permissions']['groups'])
|
|
|
|
|
|
class UpgradeAttachmentSchemaTest(AbstractNodeReplacementTest):
|
|
project_overrides = EXAMPLE_PROJECT_OLD_ATTACHMENT_SCHEMA
|
|
|
|
def setUp(self, **kwargs):
|
|
super(UpgradeAttachmentSchemaTest, self).setUp(**kwargs)
|
|
|
|
self.ensure_file_exists(
|
|
{'_id': EXAMPLE_ASSET_NODE_OLD_ATTACHMENT_SCHEMA['properties']['file']})
|
|
|
|
for node in (EXAMPLE_ASSET_NODE_OLD_ATTACHMENT_SCHEMA,
|
|
EXAMPLE_PAGE_NODE_OLD_ATTACHMENT_SCHEMA):
|
|
for att in node['properties']['attachments']:
|
|
for filedict in att['files']:
|
|
self.ensure_file_exists({'_id': filedict['file']})
|
|
|
|
def test_schema_upgrade(self):
|
|
from pillar.cli import upgrade_attachment_schema
|
|
from pillar.api.node_types.asset import node_type_asset
|
|
|
|
group_perms = self.add_group_permission_to_asset_node_type()
|
|
|
|
with self.app.test_request_context():
|
|
upgrade_attachment_schema(self.proj['url'])
|
|
|
|
dbproj = self.fetch_project_from_db()
|
|
|
|
# Test that the schemas were upgraded to the current schema.
|
|
nt_asset = get_node_type(dbproj, 'asset')
|
|
self.assertEqual(node_type_asset['dyn_schema']['attachments'],
|
|
nt_asset['dyn_schema']['attachments'])
|
|
self.assertNotIn('attachments', nt_asset['form_schema'])
|
|
|
|
# Test that the permissions set previously are still there.
|
|
self.assertEqual([group_perms], nt_asset['permissions']['groups'])
|
|
|
|
|
|
class CreateBlogTest(AbstractPillarTest):
|
|
def setUp(self, **kwargs):
|
|
AbstractPillarTest.setUp(self, **kwargs)
|
|
|
|
self.project_id, self.proj = self.ensure_project_exists()
|
|
self.ensure_file_exists({'_id': self.proj['picture_header']})
|
|
self.ensure_file_exists({'_id': self.proj['picture_square']})
|
|
|
|
def test_create_blog(self):
|
|
"""Very simple test to check the create_blog CLI command."""
|
|
|
|
from pillar.cli import create_blog
|
|
|
|
with self.app.test_request_context():
|
|
create_blog(self.proj['url'])
|
|
|
|
dbproj = self.fetch_project_from_db()
|
|
nt_blog = get_node_type(dbproj, 'blog')
|
|
self.assertIsNotNone(nt_blog)
|
|
|
|
# I trust that the blog node has been created too.
|