WIP on libraries upgrade

This commit is contained in:
Francesco Siddi 2018-07-12 15:23:57 +02:00
parent 49075cbc60
commit 549cf0a3e8
29 changed files with 177 additions and 148 deletions

View File

@ -280,7 +280,7 @@ class PillarServer(BlinkerCompatibleEve):
self.encoding_service_client = Zencoder(self.config['ZENCODER_API_KEY'])
def _config_caching(self):
from flask_cache import Cache
from flask_caching import Cache
self.cache = Cache(self)
def set_languages(self, translations_folder: pathlib.Path):

View File

@ -97,7 +97,7 @@ class ValidateCustomFields(Validator):
return False
try:
value = self.convert_properties(value, node_type['dyn_schema'])
value = self.convert_properties(value, node_type['dyn_schema']['shema'])
except Exception as e:
log.warning("Error converting form properties", exc_info=True)
@ -107,7 +107,10 @@ class ValidateCustomFields(Validator):
if val:
# This ensures the modifications made by v's coercion rules are
# visible to this validator's output.
self.current[field] = v.current
#self.current[field] = v.current
print('*********')
print(valid_properties)
#print(v.current)
return True
log.warning('Error validating properties for node %s: %s', self.document, v.errors)
@ -149,39 +152,25 @@ class ValidateCustomFields(Validator):
if ip.prefixlen() == 0:
self._error(field_name, 'Zero-length prefix is not allowed')
def _validate_type_binary(self, field_name: str, value: bytes):
"""Add support for binary type.
# def _validate_coerce(self, coerce, field: str, value):
# """Override Cerberus' _validate_coerce method for richer features.
#
# This now supports named coercion functions (available in Cerberus 1.0+)
# and passes the field name to coercion functions as well.
# """
# if isinstance(coerce, str):
# coerce = getattr(self, f'_normalize_coerce_{coerce}')
#
# try:
# return coerce(field, value)
# except (TypeError, ValueError):
# self._error(field, cerberus.errors.ERROR_COERCION_FAILED.format(field))
This type was actually introduced in Cerberus 1.0, so we can drop
support for this once Eve starts using that version (or newer).
def _validator_markdown(self, field, value):
"""This is a placeholder.
Markdown is actually processed in a hook
"""
if not isinstance(value, (bytes, bytearray)):
self._error(field_name, f'wrong value type {type(value)}, expected bytes or bytearray')
def _validate_coerce(self, coerce, field: str, value):
"""Override Cerberus' _validate_coerce method for richer features.
This now supports named coercion functions (available in Cerberus 1.0+)
and passes the field name to coercion functions as well.
"""
if isinstance(coerce, str):
coerce = getattr(self, f'_normalize_coerce_{coerce}')
try:
return coerce(field, value)
except (TypeError, ValueError):
self._error(field, cerberus.errors.ERROR_COERCION_FAILED.format(field))
def _normalize_coerce_markdown(self, field: str, value):
"""Render Markdown from this field into {field}_html.
The field name MUST NOT end in `_html`. The Markdown is read from this
field and the rendered HTML is written to the field `{field}_html`.
"""
html = pillar.markdown.markdown(value)
field_name = pillar.markdown.cache_field_name(field)
self.current[field_name] = html
return value
@ -190,12 +179,12 @@ if __name__ == '__main__':
v = ValidateCustomFields()
v.schema = {
'foo': {'type': 'string', 'coerce': 'markdown'},
'foo': {'type': 'string', 'validator': 'markdown'},
'foo_html': {'type': 'string'},
'nested': {
'type': 'dict',
'schema': {
'bar': {'type': 'string', 'coerce': 'markdown'},
'bar': {'type': 'string', 'validator': 'markdown'},
'bar_html': {'type': 'string'},
}
}

View File

@ -155,7 +155,7 @@ organizations_schema = {
'description': {
'type': 'string',
'maxlength': 256,
'coerce': 'markdown',
'validator': 'markdown',
},
'_description_html': {'type': 'string'},
'website': {
@ -292,7 +292,7 @@ nodes_schema = {
},
'description': {
'type': 'string',
'coerce': 'markdown',
'validator': 'markdown',
},
'_description_html': {'type': 'string'},
'picture': _file_embedded_schema,
@ -326,8 +326,8 @@ nodes_schema = {
},
'properties': {
'type': 'dict',
'valid_properties': True,
'required': True,
# 'valid_properties': True,
'required': True
},
'permissions': {
'type': 'dict',
@ -539,7 +539,7 @@ projects_schema = {
},
'description': {
'type': 'string',
'coerce': 'markdown',
'validator': 'markdown',
},
'_description_html': {'type': 'string'},
# Short summary for the project
@ -833,4 +833,4 @@ UPSET_ON_PUT = False # do not create new document on PUT of non-existant URL.
X_DOMAINS = '*'
X_ALLOW_CREDENTIALS = True
X_HEADERS = 'Authorization'
XML = False
RENDERERS = ['eve.render.JSONRenderer']

View File

@ -12,7 +12,7 @@ ATTACHMENT_SLUG_REGEX = r'[a-zA-Z0-9_\-]+'
attachments_embedded_schema = {
'type': 'dict',
# TODO: will be renamed to 'keyschema' in Cerberus 1.0
'propertyschema': {
'keyschema': {
'type': 'string',
'regex': '^%s$' % ATTACHMENT_SLUG_REGEX,
},

View File

@ -7,7 +7,7 @@ node_type_comment = {
'type': 'string',
'minlength': 5,
'required': True,
'coerce': 'markdown',
'validator': 'markdown',
},
'_content_html': {'type': 'string'},
'status': {

View File

@ -3,7 +3,7 @@ node_type_group = {
'description': 'Folder node type',
'parent': ['group', 'project'],
'dyn_schema': {
# Used for sorting within the context of a group
'order': {
'type': 'integer'
},
@ -20,7 +20,8 @@ node_type_group = {
'notes': {
'type': 'string',
'maxlength': 256,
},
}
},
'form_schema': {
'url': {'visible': False},

View File

@ -9,7 +9,7 @@ node_type_post = {
'minlength': 5,
'maxlength': 90000,
'required': True,
'coerce': 'markdown',
'validator': 'markdown',
},
'_content_html': {'type': 'string'},
'status': {

View File

@ -8,6 +8,7 @@ import werkzeug.exceptions as wz_exceptions
from bson import ObjectId
from flask import current_app, Blueprint, request
import pillar.markdown
from pillar.api.activities import activity_subscribe, activity_object_add
from pillar.api.node_types import PILLAR_NAMED_NODE_TYPES
from pillar.api.file_storage_backends.gcs import update_file_name
@ -400,6 +401,40 @@ def textures_sort_files(nodes):
texture_sort_files(node)
def parse_markdown(node, original=None):
projects_collection = current_app.data.driver.db['projects']
project = projects_collection.find_one({'_id': node['project']}, {'node_types': 1})
# Query node type directly using the key
node_type = next(nt for nt in project['node_types']
if nt['name'] == node['node_type'])
schema = current_app.config['DOMAIN']['nodes']['schema']
schema['properties'] = node_type['dyn_schema']
def find_markdown_fields(schema, node):
"""Find and process all makrdown validated fields."""
for k, v in schema.items():
if isinstance(v, dict):
if 'validator' in v and 'markdown' == v['validator']:
# If there is a match with the validator: markdown pair, assign the sibling
# property (following the naming convention _<property>_html)
# the processed value.
if k in node:
html = pillar.markdown.markdown(node[k])
field_name = pillar.markdown.cache_field_name(k)
node[field_name] = html
if isinstance(node, dict) and k in node:
find_markdown_fields(v, node[k])
find_markdown_fields(schema, node)
return 'ok'
def parse_markdowns(items):
for item in items:
parse_markdown(item)
def setup_app(app, url_prefix):
from . import patch
patch.setup_app(app, url_prefix=url_prefix)
@ -408,12 +443,14 @@ def setup_app(app, url_prefix):
app.on_fetched_resource_nodes += before_returning_nodes
app.on_replace_nodes += before_replacing_node
app.on_replace_nodes += parse_markdown
app.on_replace_nodes += texture_sort_files
app.on_replace_nodes += deduct_content_type
app.on_replace_nodes += node_set_default_picture
app.on_replaced_nodes += after_replacing_node
app.on_insert_nodes += before_inserting_nodes
app.on_insert_nodes += parse_markdowns
app.on_insert_nodes += nodes_deduct_content_type
app.on_insert_nodes += nodes_set_default_picture
app.on_insert_nodes += textures_sort_files

View File

@ -225,4 +225,4 @@ class OrganizationPatchHandler(patch_handler.AbstractPatchHandler):
def setup_app(app):
OrganizationPatchHandler(patch_api_blueprint)
app.register_api_blueprint(patch_api_blueprint, url_prefix='/organizations')
# app.register_api_blueprint(patch_api_blueprint, url_prefix='/organizations')

View File

@ -522,13 +522,12 @@ class AbstractPillarTest(TestMinimal):
expected_status, resp.status_code, resp.data
))
def get_json():
if resp.mimetype != 'application/json':
raise TypeError('Unable to load JSON from mimetype %r' % resp.mimetype)
return mod_json.loads(resp.data)
resp.json = get_json
resp.get_json = get_json
# def get_json():
# if resp.mimetype != 'application/json':
# raise TypeError('Unable to load JSON from mimetype %r' % resp.mimetype)
# return mod_json.loads(resp.data)
#
# resp.get_json = get_json
return resp
@ -561,7 +560,7 @@ class AbstractPillarTest(TestMinimal):
raise TypeError('expected_user_id should be a string or ObjectId, '
f'but is {expected_user_id!r}')
resp = self.get('/api/users/me', expected_status=200, auth_token=token).json()
resp = self.get('/api/users/me', expected_status=200, auth_token=token).get_json()
if expected_user_id:
self.assertEqual(resp['_id'], str(expected_user_id))

View File

@ -2,8 +2,8 @@
BLENDER_ID_ENDPOINT = 'http://id.local:8001' # Non existant server
SERVER_NAME = 'localhost'
PILLAR_SERVER_ENDPOINT = 'http://localhost/api/'
SERVER_NAME = 'localhost.local'
PILLAR_SERVER_ENDPOINT = 'http://localhost.local/api/'
MAIN_PROJECT_ID = '5672beecc0261b2005ed1a33'

View File

@ -1,6 +1,7 @@
from pillar.api.eve_settings import *
MONGO_DBNAME = 'pillar_test'
MONGO_USERNAME = None
def override_eve():
@ -10,5 +11,7 @@ def override_eve():
test_settings.MONGO_HOST = MONGO_HOST
test_settings.MONGO_PORT = MONGO_PORT
test_settings.MONGO_DBNAME = MONGO_DBNAME
test_settings.MONGO1_USERNAME = MONGO_USERNAME
tests.MONGO_HOST = MONGO_HOST
tests.MONGO_DBNAME = MONGO_DBNAME
tests.MONGO_USERNAME = MONGO_USERNAME

View File

@ -21,7 +21,7 @@ def attachment_form_group_create(schema_prop):
def _attachment_build_single_field(schema_prop):
# Ugly hard-coded schema.
fake_schema = {
'slug': schema_prop['propertyschema'],
'slug': schema_prop['keyschema'],
'oid': schema_prop['valueschema']['schema']['oid'],
}
file_select_form_group = build_file_select_form(fake_schema)

View File

@ -10,10 +10,10 @@ celery[redis]==4.0.2
CommonMark==0.7.2
elasticsearch==6.1.1
elasticsearch-dsl==6.1.0
Eve==0.7.3
Flask==0.12
Eve==0.8
Flask==1.0.2
Flask-Babel==0.11.2
Flask-Cache==0.13.1
Flask-Caching==1.4.0
Flask-Script==2.0.6
Flask-Login==0.3.2
Flask-WTF==0.14.2
@ -37,7 +37,7 @@ zencoder==0.6.5
amqp==2.1.4
billiard==3.5.0.2
Flask-PyMongo==0.4.1
-e git+https://github.com/armadillica/cerberus.git@sybren-0.9#egg=Cerberus
Cerberus==1.2.0
Events==0.2.2
future==0.15.2
html5lib==0.99999999

View File

@ -294,7 +294,7 @@ class UserListTests(AbstractPillarTest):
def test_list_all_users_subscriber(self):
# Regular access should result in only your own info.
users = self.get('/api/users', auth_token='token').json()
users = self.get('/api/users', auth_token='token').get_json()
self.assertEqual(1, users['_meta']['total'])
# The 'auth' section should be removed.
@ -303,7 +303,7 @@ class UserListTests(AbstractPillarTest):
def test_list_all_users_admin(self):
# Admin access should result in all users
users = self.get('/api/users', auth_token='admin-token').json()
users = self.get('/api/users', auth_token='admin-token').get_json()
self.assertEqual(3, users['_meta']['total'])
# The 'auth' section should be removed.
@ -314,7 +314,7 @@ class UserListTests(AbstractPillarTest):
"""Even admins shouldn't be able to GET auth info."""
projection = json.dumps({'auth': 1})
users = self.get(f'/api/users?projection={projection}', auth_token='admin-token').json()
users = self.get(f'/api/users?projection={projection}', auth_token='admin-token').get_json()
self.assertEqual(3, users['_meta']['total'])
# The 'auth' section should be removed.
@ -333,21 +333,21 @@ class UserListTests(AbstractPillarTest):
def test_own_user_subscriber(self):
# Regular access should result in only your own info.
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').json()
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').get_json()
self.assertNotIn('auth', user_info)
def test_own_user_subscriber_explicit_projection(self):
# With a custom projection requesting the auth list
projection = json.dumps({'auth': 1})
user_info = self.get(f'/api/users/123456789abc123456789abc?projection={projection}',
auth_token='token').json()
auth_token='token').get_json()
self.assertNotIn('auth', user_info)
def test_other_user_subscriber(self):
from pillar.api.utils import remove_private_keys
# Requesting another user should be limited to full name and email.
user_info = self.get('/api/users/223456789abc123456789abc', auth_token='token').json()
user_info = self.get('/api/users/223456789abc123456789abc', auth_token='token').get_json()
self.assertNotIn('auth', user_info)
regular_info = remove_private_keys(user_info)
@ -357,7 +357,7 @@ class UserListTests(AbstractPillarTest):
from pillar.api.utils import remove_private_keys
# PUTting a user should work, and not mess up the auth field.
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').json()
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').get_json()
self.assertNotIn('auth', user_info)
put_user = remove_private_keys(user_info)
@ -378,7 +378,7 @@ class UserListTests(AbstractPillarTest):
group_ids = self.create_standard_groups()
# A user should be able to change only some fields, but not all.
user_info = self.get('/api/users/me', auth_token='token').json()
user_info = self.get('/api/users/me', auth_token='token').get_json()
# Alter all fields (except auth, another test already checks that that's uneditable).
put_user = remove_private_keys(user_info)
@ -395,7 +395,7 @@ class UserListTests(AbstractPillarTest):
auth_token='token',
etag=user_info['_etag'])
new_user_info = self.get('/api/users/me', auth_token='token').json()
new_user_info = self.get('/api/users/me', auth_token='token').get_json()
self.assertEqual(new_user_info['full_name'], put_user['full_name'])
self.assertEqual(new_user_info['username'], put_user['username'])
self.assertEqual(new_user_info['email'], put_user['email'])
@ -409,7 +409,7 @@ class UserListTests(AbstractPillarTest):
from pillar.api.utils import remove_private_keys
# PUTting the user as another user should fail.
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').json()
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').get_json()
put_user = remove_private_keys(user_info)
self.put('/api/users/123456789abc123456789abc', auth_token='other-token',
@ -420,7 +420,7 @@ class UserListTests(AbstractPillarTest):
from pillar.api.utils import remove_private_keys
# PUTting a user should work, and not mess up the auth field.
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').json()
user_info = self.get('/api/users/123456789abc123456789abc', auth_token='token').get_json()
put_user = remove_private_keys(user_info)
self.put('/api/users/123456789abc123456789abc', auth_token='admin-token',
@ -841,7 +841,7 @@ class UserCreationTest(AbstractPillarTest):
etag = db_user['_etag']
resp = self.put(f'/api/users/{user_id}', json=puttable, etag=etag,
auth_token='user-token', expected_status=200).json()
auth_token='user-token', expected_status=200).get_json()
etag = resp['_etag']
self.put(f'/api/users/{user_id}', json=empty_email, etag=etag,
auth_token='user-token', expected_status=422)
@ -851,7 +851,7 @@ class UserCreationTest(AbstractPillarTest):
# An admin should be able to edit this user, but also not clear the email address.
self.create_user(24 * 'a', roles={'admin'}, token='admin-token')
resp = self.put(f'/api/users/{user_id}', json=puttable, etag=etag,
auth_token='admin-token', expected_status=200).json()
auth_token='admin-token', expected_status=200).get_json()
etag = resp['_etag']
self.put(f'/api/users/{user_id}', json=empty_email, etag=etag,
auth_token='admin-token', expected_status=422)

View File

@ -296,7 +296,7 @@ class HomeProjectTest(AbstractHomeProjectTest):
# Create home project by getting it.
resp = self.get('/api/bcloud/home-project', auth_token='token')
before_delete_json_proj = resp.json()
before_delete_json_proj = resp.get_json()
# Delete the project.
self.delete(f'/api/projects/{before_delete_json_proj["_id"]}',
@ -305,7 +305,7 @@ class HomeProjectTest(AbstractHomeProjectTest):
# Recreate home project by getting it.
resp = self.get('/api/bcloud/home-project', auth_token='token')
after_delete_json_proj = resp.json()
after_delete_json_proj = resp.get_json()
self.assertEqual(before_delete_json_proj['_id'],
after_delete_json_proj['_id'])
@ -452,7 +452,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
def test_hdri_library__no_bcloud_version(self):
resp = self.get('/api/bcloud/texture-libraries', auth_token='token')
libs = resp.json()['_items']
libs = resp.get_json()['_items']
library_project_ids = {proj['_id'] for proj in libs}
self.assertNotIn(str(self.hdri_proj_id), library_project_ids)
@ -462,7 +462,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
resp = self.get('/api/bcloud/texture-libraries',
auth_token='token',
headers={'Blender-Cloud-Addon': '1.3.3'})
libs = resp.json()['_items']
libs = resp.get_json()['_items']
library_project_ids = {proj['_id'] for proj in libs}
self.assertNotIn(str(self.hdri_proj_id), library_project_ids)
self.assertIn(str(self.tex_proj_id), library_project_ids)
@ -471,7 +471,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
resp = self.get('/api/bcloud/texture-libraries',
auth_token='token',
headers={'Blender-Cloud-Addon': '1.4.0'})
libs = resp.json()['_items']
libs = resp.get_json()['_items']
library_project_ids = {proj['_id'] for proj in libs}
self.assertIn(str(self.hdri_proj_id), library_project_ids)
self.assertIn(str(self.tex_proj_id), library_project_ids)
@ -539,11 +539,11 @@ class HdriSortingTest(AbstractHomeProjectTest):
'name': 'Symmetrical Garden'
}
resp = self.post('/api/nodes', json=node, expected_status=201, auth_token='token')
node_info = resp.json()
node_info = resp.json
# Check that the node's files are in the right order
resp = self.get('/api/nodes/%s' % node_info['_id'], auth_token='token')
get_node = resp.json()
get_node = resp.json
self.assertEqual(['256p', '1k', '2k'],
[file_info['resolution']
@ -565,7 +565,7 @@ class HdriSortingTest(AbstractHomeProjectTest):
'name': 'Symmetrical Garden'
}
resp = self.post('/api/nodes', json=node, expected_status=201, auth_token='token')
node_info = resp.json()
node_info = resp.json
# Mess up the node's order
node['properties']['files'] = [
@ -578,7 +578,7 @@ class HdriSortingTest(AbstractHomeProjectTest):
# Check that the node's files are in the right order
resp = self.get('/api/nodes/%s' % node_info['_id'], auth_token='token')
get_node = resp.json()
get_node = resp.json
self.assertEqual(['256p', '1k', '2k'],
[file_info['resolution']

View File

@ -192,7 +192,7 @@ class FileMaxSizeTest(AbstractPillarTest):
expected_status=201,
auth_token='token',
files={'file': (test_file, 'test_file.bin')})
stream_info = resp.json()
stream_info = resp.get_json()
file_id = stream_info['file_id']
self.assert_file_doc_ok(file_id, file_size)
@ -216,7 +216,7 @@ class FileMaxSizeTest(AbstractPillarTest):
expected_status=201,
auth_token='token',
files={'file': (test_file, 'test_file.bin')})
stream_info = resp.json()
stream_info = resp.get_json()
file_id = stream_info['file_id']
self.assert_file_doc_ok(file_id, file_size)

View File

@ -16,10 +16,10 @@ class CoerceMarkdownTest(AbstractPillarTest):
}
created_data = self.post('/api/nodes', json=node, expected_status=201,
auth_token='token-a').json()
auth_token='token-a').get_json()
node_id = created_data['_id']
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').json()
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').get_json()
self.assertEqual('<h1>Title</h1>\n<p>This is content.</p>\n',
json_node['_description_html'])
@ -43,7 +43,7 @@ class CoerceMarkdownTest(AbstractPillarTest):
pid = r['_id']
json_proj = self.get(f'/api/projects/{pid}', auth_token='token-a').json()
json_proj = self.get(f'/api/projects/{pid}', auth_token='token-a').get_json()
json_proj.pop('node_types', None) # just to make it easier to print
import pprint
pprint.pprint(json_proj)
@ -63,9 +63,9 @@ class CoerceMarkdownTest(AbstractPillarTest):
}
created_data = self.post('/api/nodes', json=node, expected_status=201,
auth_token='token-a').json()
auth_token='token-a').get_json()
node_id = created_data['_id']
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').json()
json_node = self.get(f'/api/nodes/{node_id}', auth_token='token-a').get_json()
expect = '<h1>Title</h1>\n<!-- {test a="b"} -->\n'
self.assertEqual(expect, json_node['_description_html'])

View File

@ -253,7 +253,7 @@ class NodeSharingTest(AbstractPillarTest):
'name': str(self),
'properties': {},
})
self.node_id = resp.json()['_id']
self.node_id = resp.get_json()['_id']
def _check_share_data(self, share_data):
base_url = self.app.config['SHORT_LINK_BASE_URL']
@ -265,7 +265,7 @@ class NodeSharingTest(AbstractPillarTest):
# Share the node
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
expected_status=201)
share_data = resp.json()
share_data = resp.get_json()
self._check_share_data(share_data)
@ -279,7 +279,7 @@ class NodeSharingTest(AbstractPillarTest):
# Check that an anonymous user has acces.
resp = self.get('/api/nodes/%s' % self.node_id)
self.assertEqual(str(self.node_id), resp.json()['_id'])
self.assertEqual(str(self.node_id), resp.get_json()['_id'])
def test_other_user_access_shared_node(self):
# Share the node
@ -290,7 +290,7 @@ class NodeSharingTest(AbstractPillarTest):
other_user_id = self.create_user(user_id=24 * 'a')
self.create_valid_auth_token(other_user_id, 'other-token')
resp = self.get('/api/nodes/%s' % self.node_id, auth_token='other-token')
self.assertEqual(str(self.node_id), resp.json()['_id'])
self.assertEqual(str(self.node_id), resp.get_json()['_id'])
def test_get_share_data__unshared_node(self):
self.get('/api/nodes/%s/share' % self.node_id,
@ -304,7 +304,7 @@ class NodeSharingTest(AbstractPillarTest):
# Then get its share info.
resp = self.get('/api/nodes/%s/share' % self.node_id, auth_token='token')
share_data = resp.json()
share_data = resp.get_json()
self._check_share_data(share_data)
@ -349,7 +349,7 @@ class NodeSharingTest(AbstractPillarTest):
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
expected_status=201)
share_data = resp.json()
share_data = resp.get_json()
self._check_share_data(share_data)
self.assertEqual(3, create_short_link.call_count)
@ -360,19 +360,19 @@ class NodeSharingTest(AbstractPillarTest):
# Share the node
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
expected_status=201)
share_data = resp.json()
share_data = resp.get_json()
# Get the node with short_code
resp = self.get('/api/nodes/%s' % self.node_id,
json={'projection': {'short_code': 1}})
node = resp.json()
node = resp.get_json()
self.assertEqual(node['short_code'], share_data['short_code'])
self.assertTrue(node['short_link'].endswith(share_data['short_code']))
# Get the node without short_code
resp = self.get('/api/nodes/%s' % self.node_id,
qs={'projection': {'short_code': 0}})
node = resp.json()
node = resp.get_json()
self.assertNotIn('short_code', node)
self.assertNotIn('short_link', node)
@ -409,10 +409,10 @@ class TextureSortFilesTest(AbstractPillarTest):
},
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
})
node_id = resp.json()['_id']
node_id = resp.get_json()['_id']
resp = self.get(f'/api/nodes/{node_id}', auth_token='token')
node = resp.json()
node = resp.get_json()
map_types = [f['map_type'] for f in node['properties']['files']]
self.assertEqual(['color', 'alpha', 'specular'], map_types)
@ -435,10 +435,10 @@ class TextureSortFilesTest(AbstractPillarTest):
},
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
})
node_id = resp.json()['_id']
node_id = resp.get_json()['_id']
resp = self.get(f'/api/nodes/{node_id}', auth_token='token')
node = resp.json()
node = resp.get_json()
map_types = [f['map_type'] for f in node['properties']['files']]
self.assertEqual(['alpha', 'bump', 'specular'], map_types)
@ -453,10 +453,10 @@ class TextureSortFilesTest(AbstractPillarTest):
},
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
})
node_id = resp.json()['_id']
node_id = resp.get_json()['_id']
resp = self.get(f'/api/nodes/{node_id}', auth_token='token')
node = resp.json()
node = resp.get_json()
self.assertEqual([], node['properties']['files'])
def test_no_files_list(self):
@ -468,9 +468,9 @@ class TextureSortFilesTest(AbstractPillarTest):
'properties': {},
'user': ctd.EXAMPLE_PROJECT_OWNER_ID,
})
node_id = resp.json()['_id']
node_id = resp.get_json()['_id']
resp = self.get(f'/api/nodes/{node_id}', auth_token='token')
node = resp.json()
node = resp.get_json()
self.assertNotIn('files', node['properties'])

View File

@ -843,7 +843,7 @@ class IPRangeTest(AbstractIPRangeSingleOrgTest):
def test_ipranges_get_via_eve(self):
self.test_patch_set_ip_ranges_happy()
r = self.get(f'/api/organizations/{self.org_id}', auth_token='token')
from_eve = r.json()
from_eve = r.get_json()
# Eve cannot return binary data, at least not until we upgrade to a version
# that depends on Cerberus >= 1.0.
@ -853,7 +853,7 @@ class IPRangeTest(AbstractIPRangeSingleOrgTest):
self.assertEqual(expect_ranges, from_eve['ip_ranges'])
r = self.get(f'/api/organizations', auth_token='token')
from_eve = r.json()
from_eve = r.get_json()
self.assertEqual(expect_ranges, from_eve['_items'][0]['ip_ranges'])
def test_patch_unset_ip_ranges_happy(self):
@ -996,7 +996,7 @@ class IPRangeLoginRolesTest(AbstractIPRangeSingleOrgTest):
# user in the database.
resp = self.get('/api/users/me', auth_token='usertoken',
headers=headers, environ_overrides=env)
me = resp.json()
me = resp.get_json()
# The IP-based roles should be stored in the token document.
self.enter_app_context()

View File

@ -24,7 +24,7 @@ class AbstractPatchCommentTest(AbstractPillarTest):
resp = self.post('/api/nodes', json=asset,
auth_token='owner-token',
expected_status=201)
self.asset_id = resp.json()['_id']
self.asset_id = resp.get_json()['_id']
# Create the comment
comment = {'description': '',
@ -43,7 +43,7 @@ class AbstractPatchCommentTest(AbstractPillarTest):
resp = self.post('/api/nodes', json=comment,
auth_token='owner-token',
expected_status=201)
comment_info = resp.json()
comment_info = resp.get_json()
self.node_url = '/api/nodes/%s' % comment_info['_id']
@ -66,12 +66,12 @@ class VoteCommentTest(AbstractPatchCommentTest):
# Patch the node
res = self.patch(self.node_url,
json={'op': 'upvote'},
auth_token='token').json()
auth_token='token').get_json()
self.assertEqual(1, res['properties']['rating_positive'])
self.assertEqual(0, res['properties']['rating_negative'])
# Get the node again, to inspect its changed state.
patched_node = self.get(self.node_url, auth_token='token').json()
patched_node = self.get(self.node_url, auth_token='token').get_json()
self.assertEqual(1, patched_node['properties']['rating_positive'])
self.assertEqual(0, patched_node['properties']['rating_negative'])
self.assertEqual({'user': str(self.user_id), 'is_positive': True},
@ -87,12 +87,12 @@ class VoteCommentTest(AbstractPatchCommentTest):
# Patch the node
res = self.patch(self.node_url,
json={'op': 'downvote'},
auth_token='token').json()
auth_token='token').get_json()
self.assertEqual(0, res['properties']['rating_positive'])
self.assertEqual(1, res['properties']['rating_negative'])
# Get the node again, to inspect its changed state.
patched_node = self.get(self.node_url, auth_token='token').json()
patched_node = self.get(self.node_url, auth_token='token').get_json()
self.assertEqual(0, patched_node['properties']['rating_positive'])
self.assertEqual(1, patched_node['properties']['rating_negative'])
self.assertEqual({'user': str(self.user_id), 'is_positive': False},
@ -124,7 +124,7 @@ class VoteCommentTest(AbstractPatchCommentTest):
auth_token='token')
# Get the node again, to inspect its changed state.
patched_node = self.get(self.node_url, auth_token='token').json()
patched_node = self.get(self.node_url, auth_token='token').get_json()
self.assertEqual(0, patched_node['properties']['rating_positive'])
self.assertEqual(0, patched_node['properties']['rating_negative'])
self.assertEqual([], patched_node['properties'].get('ratings', []))
@ -167,7 +167,7 @@ class VoteCommentTest(AbstractPatchCommentTest):
auth_token='other-token-4')
# Inspect the result
patched_node = self.get(self.node_url, auth_token='token').json()
patched_node = self.get(self.node_url, auth_token='token').get_json()
self.assertEqual(3, patched_node['properties']['rating_positive'])
self.assertEqual(2, patched_node['properties']['rating_negative'])
self.assertEqual([
@ -181,16 +181,16 @@ class VoteCommentTest(AbstractPatchCommentTest):
class EditCommentTest(AbstractPatchCommentTest):
def test_comment_edit_happy(self, token='owner-token'):
pre_node = self.get(self.node_url, auth_token=token).json()
pre_node = self.get(self.node_url, auth_token=token).get_json()
res = self.patch(self.node_url,
json={'op': 'edit', 'content': 'Je moeder is niet je vader.'},
auth_token=token).json()
auth_token=token).get_json()
self.assertEqual('<p>Je moeder is niet je vader.</p>\n',
res['properties']['_content_html'])
# Get the node again, to inspect its changed state.
patched_node = self.get(self.node_url, auth_token=token).json()
patched_node = self.get(self.node_url, auth_token=token).get_json()
self.assertEqual('Je moeder is niet je vader.',
patched_node['properties']['content'])
self.assertEqual('<p>Je moeder is niet je vader.</p>\n',
@ -210,7 +210,7 @@ class EditCommentTest(AbstractPatchCommentTest):
expected_status=403)
# Get the node again, to inspect its old state.
patched_node = self.get(self.node_url, auth_token='token').json()
patched_node = self.get(self.node_url, auth_token='token').get_json()
self.assertEqual('Purrrr kittycat',
patched_node['properties']['content'])
self.assertEqual('<p>Purrrr kittycat</p>\n',

View File

@ -60,7 +60,7 @@ class PatchHandlerTest(AbstractPillarTest):
resp = self.patch('/api/test/%s' % oid, auth_token='user-token',
json={'op': 'test-echo',
'echo': '¡Thith ith Špahtah!'})
self.assertEqual({'echo': '¡Thith ith Špahtah!'}, resp.json())
self.assertEqual({'echo': '¡Thith ith Špahtah!'}, resp.get_json())
def test_patch_empty_response(self):
import bson

View File

@ -166,7 +166,7 @@ class ProjectEditTest(AbstractProjectTest):
project_info = self._create_user_and_project(['subscriber'])
project_url = '/api/projects/%(_id)s' % project_info
project = self.get(project_url, auth_token='token').json()
project = self.get(project_url, auth_token='token').get_json()
# Create another user we can try and assign the project to.
other_user_id = 'f00dd00df00dd00df00dd00d'
@ -199,7 +199,7 @@ class ProjectEditTest(AbstractProjectTest):
# Re-fetch from database to see which fields actually made it there.
# equal to put_project -> changed in DB
# equal to project -> not changed in DB
db_proj = self.get(project_url, auth_token='token').json()
db_proj = self.get(project_url, auth_token='token').get_json()
self.assertEqual(project['url'], db_proj['url'])
self.assertEqual(put_project['description'], db_proj['description'])
self.assertEqual(put_project['name'], db_proj['name'])
@ -391,7 +391,7 @@ class ProjectEditTest(AbstractProjectTest):
expected_status=204)
resp = self.get(f'/api/files/{fid}', expected_status=404)
self.assertEqual(str(fid), resp.json()['_id'])
self.assertEqual(str(fid), resp.get_json()['_id'])
with self.app.app_context():
db_file_after = files_coll.find_one(fid)
@ -413,7 +413,7 @@ class ProjectEditTest(AbstractProjectTest):
project_info['picture_header'] = str(fid)
resp = self.put(proj_url, auth_token='token', etag=etag,
json=remove_private_keys(project_info))
etag = resp.json()['_etag']
etag = resp.get_json()['_etag']
# DELETE the project.
self.delete(proj_url, auth_token='token', etag=etag, expected_status=204)
@ -433,7 +433,7 @@ class ProjectEditTest(AbstractProjectTest):
self.patch(proj_url, auth_token='token', json={'op': 'undelete'}, expected_status=204)
resp = self.get(f'/api/files/{fid}')
self.assertEqual(str(fid), resp.json()['_id'])
self.assertEqual(str(fid), resp.get_json()['_id'])
with self.app.app_context():
files_coll = self.app.db('files')
@ -456,7 +456,7 @@ class ProjectEditTest(AbstractProjectTest):
db_file_after = files_coll.find_one(fid)
self.assertTrue(db_file_after['_deleted'])
resp = self.get(proj_url, auth_token='token', expected_status=404).json()
resp = self.get(proj_url, auth_token='token', expected_status=404).get_json()
self.assertTrue(resp['_deleted'])

View File

@ -31,8 +31,8 @@ class ProjectMergerTest(AbstractPillarTest):
with self.app.app_context():
merging.merge_project(self.pid_from, self.pid_to)
db_file = self.get(f'/api/files/{fid}').json()
db_node = self.get(f'/api/nodes/{nid}').json()
db_file = self.get(f'/api/files/{fid}').get_json()
db_node = self.get(f'/api/nodes/{nid}').get_json()
self.assertEqual(db_file['project'], str(self.pid_to))
self.assertEqual(db_node['project'], str(self.pid_to))

View File

@ -63,7 +63,7 @@ class ServiceAccountCreationTest(AbstractPillarTest):
resp = self.put(f'/api/users/{user_id}',
json=puttable,
auth_token=token['token'],
etag=etag).json()
etag=etag).get_json()
etag = resp['_etag']
with self.app.test_request_context():

View File

@ -58,7 +58,7 @@ class RoleUpdatingTest(AbstractPillarTest):
self.get('/api/bcloud/update-subscription', auth_token='my-happy-token',
expected_status=204)
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual({'subscriber', 'has_subscription'}, set(user_info['roles']))
# Check the signals
@ -75,13 +75,13 @@ class RoleUpdatingTest(AbstractPillarTest):
# Make sure this user is currently known as a subcriber.
self.create_user(roles={'subscriber', 'has_subscription'}, token='my-happy-token')
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual({'subscriber', 'has_subscription'}, set(user_info['roles']))
# And after updating, it shouldn't be.
self.get('/api/bcloud/update-subscription', auth_token='my-happy-token',
expected_status=204)
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual([], user_info['roles'])
self.assertEqual(1, len(self.user_subs_signal_calls))
@ -98,7 +98,7 @@ class RoleUpdatingTest(AbstractPillarTest):
self.get('/api/bcloud/update-subscription', auth_token='my-happy-token',
expected_status=204)
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual(['demo'], user_info['roles'])
self.assertEqual(1, len(self.user_subs_signal_calls))
@ -113,13 +113,13 @@ class RoleUpdatingTest(AbstractPillarTest):
# Make sure this user is currently known as demo user.
self.create_user(roles={'demo'}, token='my-happy-token')
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual(['demo'], user_info['roles'])
# And after updating, it shouldn't be.
self.get('/api/bcloud/update-subscription', auth_token='my-happy-token',
expected_status=204)
user_info = self.get('/api/users/me', auth_token='my-happy-token').json()
user_info = self.get('/api/users/me', auth_token='my-happy-token').get_json()
self.assertEqual([], user_info['roles'])
self.assertEqual(1, len(self.user_subs_signal_calls))

View File

@ -14,8 +14,8 @@ class PurgeHomeProjectsTest(AbstractPillarTest):
user_b = self.create_user(user_id=24 * 'b', roles={'subscriber'}, token='token-b')
# GET the home project to create it.
home_a = self.get('/api/bcloud/home-project', auth_token='token-a').json()
home_b = self.get('/api/bcloud/home-project', auth_token='token-b').json()
home_a = self.get('/api/bcloud/home-project', auth_token='token-a').get_json()
home_b = self.get('/api/bcloud/home-project', auth_token='token-b').get_json()
with self.app.app_context():
users_coll = self.app.db('users')
@ -60,7 +60,7 @@ class UpgradeAttachmentSchemaTest(AbstractPillarTest):
"url": {"type": "string"},
"attachments": {
"type": "dict",
"propertyschema": {"type": "string", "regex": "^[a-zA-Z0-9_ ]+$"},
"keyschema": {"type": "string", "regex": "^[a-zA-Z0-9_ ]+$"},
"valueschema": {
"type": "dict",
"schema": {

View File

@ -42,7 +42,7 @@ class FlaskInternalApiTest(AbstractPillarTest):
with self.app.test_request_context():
# Check the asset in MongoDB
resp = self.get(url_for('nodes|item_lookup', _id=asset._id), auth_token='token')
db_asset = resp.json()
db_asset = resp.get_json()
self.assertEqual('Test asset', db_asset['name'])
return asset
@ -66,7 +66,7 @@ class FlaskInternalApiTest(AbstractPillarTest):
# Check the file in MongoDB
with self.app.test_request_context():
resp = self.get(url_for('files|item_lookup', _id=file_id), auth_token='token')
file_doc = resp.json()
file_doc = resp.get_json()
self.assertEqual('BlenderDesktopLogo.png', file_doc['filename'])
def test_create_asset_from_file(self):
@ -80,7 +80,7 @@ class FlaskInternalApiTest(AbstractPillarTest):
'properties': {}
},
expected_status=201)
parent_id = resp.json()['_id']
parent_id = resp.get_json()['_id']
with self.app.test_request_context(), open(blender_desktop_logo_path, 'rb') as fileobj:
resp = pillarsdk.Node.create_asset_from_file(
@ -99,5 +99,5 @@ class FlaskInternalApiTest(AbstractPillarTest):
# Check the node in MongoDB
with self.app.test_request_context():
resp = self.get(url_for('nodes|item_lookup', _id=node_id), auth_token='token')
node_doc = resp.json()
node_doc = resp.get_json()
self.assertEqual('BlenderDesktopLogo.png', node_doc['name'])

View File

@ -183,7 +183,7 @@ class AttachmentTest(AbstractPillarTest):
# We have to get the file document again, because retrieving it via the
# API (which is what the shortcode rendering is doing) will change its
# link URL.
db_file = self.get(f'/api/files/{oid}').json()
db_file = self.get(f'/api/files/{oid}').get_json()
link = db_file['variations'][0]['link']
with self.app.test_request_context():