New authentication logic
We are replacing the existing mixed BaseAuth TokenAuth authentication logic and permissions system with a more streamlined solution, based on user id and groups checking against node_type stored permissions. Such permissions can be overridden on the node level (and complement the public GET operations on the node entry point).
This commit is contained in:
parent
474ddfc7af
commit
018ddfa20b
@ -17,14 +17,15 @@ from bson import ObjectId
|
||||
from flask import g
|
||||
from flask import request
|
||||
from flask import url_for
|
||||
from flask import abort
|
||||
|
||||
from pre_hooks import pre_GET
|
||||
from pre_hooks import pre_PUT
|
||||
from pre_hooks import pre_PATCH
|
||||
from pre_hooks import pre_POST
|
||||
from pre_hooks import pre_DELETE
|
||||
from pre_hooks import check_permissions
|
||||
from pre_hooks import compute_permissions
|
||||
# from pre_hooks import check_permissions
|
||||
# from pre_hooks import compute_permissions
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
@ -47,9 +48,13 @@ class SystemUtility():
|
||||
|
||||
|
||||
def validate(token):
|
||||
"""Validate a Token against Blender ID server
|
||||
"""
|
||||
"""Validate a token against the Blender ID server. This simple lookup
|
||||
returns a dictionary with the following keys:
|
||||
|
||||
- message: a success message
|
||||
- valid: a boolean, stating if the token is valid
|
||||
- user: a dictionary with information regarding the user
|
||||
"""
|
||||
payload = dict(
|
||||
token=token)
|
||||
try:
|
||||
@ -59,41 +64,55 @@ def validate(token):
|
||||
raise e
|
||||
|
||||
if r.status_code == 200:
|
||||
message = r.json()['message']
|
||||
valid = r.json()['valid']
|
||||
user = r.json()['user']
|
||||
response = r.json()
|
||||
validation_result = dict(
|
||||
message=response['message'],
|
||||
valid=response['valid'],
|
||||
user=response['user'])
|
||||
else:
|
||||
message = ""
|
||||
valid = False
|
||||
user = None
|
||||
return dict(valid=valid, message=message, user=user)
|
||||
validation_result = dict(valid=False)
|
||||
return validation_result
|
||||
|
||||
|
||||
def validate_token():
|
||||
"""Validate the token provided in the request and populate the current_user
|
||||
flask.g object, so that permissions and access to a resource can be defined
|
||||
from it.
|
||||
"""
|
||||
if not request.authorization:
|
||||
# If no authorization headers are provided, we are getting a request
|
||||
# from a non logged in user. Proceed accordingly.
|
||||
return None
|
||||
|
||||
current_user = {}
|
||||
|
||||
token = request.authorization.username
|
||||
tokens = app.data.driver.db['tokens']
|
||||
users = app.data.driver.db['users']
|
||||
|
||||
lookup = {'token': token, 'expire_time': {"$gt": datetime.now()}}
|
||||
dbtoken = tokens.find_one(lookup)
|
||||
if not dbtoken:
|
||||
db_token = tokens.find_one(lookup)
|
||||
if not db_token:
|
||||
# If no valid token is found, we issue a new request to the Blender ID
|
||||
# to verify the validity of the token. We will get basic user info if
|
||||
# the user is authorized and we will make a new token.
|
||||
validation = validate(token)
|
||||
if validation['valid']:
|
||||
users = app.data.driver.db['users']
|
||||
email = validation['user']['email']
|
||||
dbuser = users.find_one({'email': email})
|
||||
db_user = users.find_one({'email': email})
|
||||
tmpname = email.split('@')[0]
|
||||
if not dbuser:
|
||||
if not db_user:
|
||||
user_data = {
|
||||
'first_name': tmpname,
|
||||
'last_name': tmpname,
|
||||
'email': email,
|
||||
'role': ['admin'],
|
||||
}
|
||||
r = post_internal('users', user_data)
|
||||
user_id = r[0]["_id"]
|
||||
user_id = r[0]['_id']
|
||||
groups = None
|
||||
else:
|
||||
user_id = dbuser['_id']
|
||||
user_id = db_user['_id']
|
||||
groups = db_user['groups']
|
||||
|
||||
token_data = {
|
||||
'user': user_id,
|
||||
@ -101,20 +120,27 @@ def validate_token():
|
||||
'expire_time': datetime.now() + timedelta(hours=1)
|
||||
}
|
||||
post_internal('tokens', token_data)
|
||||
return token_data
|
||||
current_user = dict(
|
||||
user_id=user_id,
|
||||
token=token,
|
||||
groups=groups,
|
||||
token_expire_time=datetime.now() + timedelta(hours=1))
|
||||
#return token_data
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
token_data = {
|
||||
'user': dbtoken['user'],
|
||||
'token': dbtoken['token'],
|
||||
'expire_time': dbtoken['expire_time']
|
||||
}
|
||||
return token_data
|
||||
users = app.data.driver.db['users']
|
||||
db_user = users.find_one(db_token['user'])
|
||||
current_user = dict(
|
||||
user_id=db_token['user'],
|
||||
token=db_token['token'],
|
||||
groups=db_user['groups'],
|
||||
token_expire_time=db_token['expire_time'])
|
||||
|
||||
setattr(g, 'current_user', current_user)
|
||||
|
||||
|
||||
class TokensAuth(TokenAuth):
|
||||
|
||||
def check_auth(self, token, allowed_roles, resource, method):
|
||||
if not token:
|
||||
return False
|
||||
@ -127,21 +153,13 @@ class TokensAuth(TokenAuth):
|
||||
|
||||
# return validation['valid']
|
||||
return True
|
||||
"""
|
||||
users = app.data.driver.db['users']
|
||||
lookup = {'first_name': token['username']}
|
||||
if allowed_roles:
|
||||
lookup['role'] = {'$in': allowed_roles}
|
||||
user = users.find_one(lookup)
|
||||
if not user:
|
||||
return False
|
||||
return token
|
||||
"""
|
||||
|
||||
|
||||
class BasicsAuth(BasicAuth):
|
||||
def check_auth(self, username, password, allowed_roles, resource, method):
|
||||
# return username == 'admin' and password == 'secret'
|
||||
print username
|
||||
print password
|
||||
return True
|
||||
|
||||
|
||||
@ -157,12 +175,29 @@ class CustomTokenAuth(BasicsAuth):
|
||||
return self.authorized_protected(
|
||||
self, allowed_roles, resource, method)
|
||||
else:
|
||||
print 'is auth'
|
||||
return self.token_auth.authorized(allowed_roles, resource, method)
|
||||
|
||||
def authorized_protected(self):
|
||||
pass
|
||||
|
||||
|
||||
class NewAuth(TokenAuth):
|
||||
def check_auth(self, token, allowed_roles, resource, method):
|
||||
if not token:
|
||||
return False
|
||||
else:
|
||||
print '---'
|
||||
print 'validating'
|
||||
print token
|
||||
print resource
|
||||
print method
|
||||
print '---'
|
||||
validate_token()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ValidateCustomFields(Validator):
|
||||
def convert_properties(self, properties, node_schema):
|
||||
for prop in node_schema:
|
||||
@ -229,11 +264,10 @@ def post_item(entry, data):
|
||||
# automatically. The default path (which work in Docker) can be overriden with
|
||||
# an env variable.
|
||||
settings_path = os.environ.get('EVE_SETTINGS', '/data/dev/pillar/pillar/settings.py')
|
||||
app = Eve(settings=settings_path, validator=ValidateCustomFields, auth=CustomTokenAuth)
|
||||
app = Eve(settings=settings_path, validator=ValidateCustomFields, auth=NewAuth)
|
||||
|
||||
import config
|
||||
app.config.from_object(config.Deployment)
|
||||
app.config['MONGO_HOST'] = os.environ.get('MONGO_HOST', 'localhost')
|
||||
|
||||
client = MongoClient(app.config['MONGO_HOST'], 27017)
|
||||
db = client.eve
|
||||
@ -243,8 +277,10 @@ def global_validation():
|
||||
token_data = validate_token()
|
||||
if token_data:
|
||||
setattr(g, 'token_data', token_data)
|
||||
setattr(g, 'validate', validate(token_data['token']))
|
||||
#setattr(g, 'validate', validate(token_data['token']))
|
||||
check_permissions(token_data['user'], app.data.driver)
|
||||
else:
|
||||
print 'NO TOKEN'
|
||||
|
||||
|
||||
def pre_GET_nodes(request, lookup):
|
||||
@ -270,11 +306,13 @@ def pre_PATCH_nodes(request):
|
||||
|
||||
|
||||
def pre_POST_nodes(request):
|
||||
global_validation()
|
||||
# global_validation()
|
||||
# print ("Post")
|
||||
# print ("World: {0}".format(g.get('world_permissions')))
|
||||
# print ("Group: {0}".format(g.get('groups_permissions')))
|
||||
return pre_POST(request, app.data.driver)
|
||||
# return pre_POST(request, app.data.driver)
|
||||
print 'pre posting'
|
||||
print request
|
||||
|
||||
|
||||
def pre_DELETE_nodes(request, lookup):
|
||||
@ -287,20 +325,80 @@ def pre_DELETE_nodes(request, lookup):
|
||||
return pre_DELETE(request, lookup, app.data.driver)
|
||||
|
||||
|
||||
app.on_pre_GET_nodes += pre_GET_nodes
|
||||
#app.on_pre_GET_nodes += pre_GET_nodes
|
||||
app.on_pre_POST_nodes += pre_POST_nodes
|
||||
app.on_pre_PATCH_nodes += pre_PATCH_nodes
|
||||
app.on_pre_PUT_nodes += pre_PUT_nodes
|
||||
# app.on_pre_PATCH_nodes += pre_PATCH_nodes
|
||||
#app.on_pre_PUT_nodes += pre_PUT_nodes
|
||||
app.on_pre_DELETE_nodes += pre_DELETE_nodes
|
||||
|
||||
|
||||
def check_permissions(resource, method):
|
||||
"""Check user permissions to access a node. We look up node permissions from
|
||||
world to groups to users and match them with the computed user permissions.
|
||||
If there is not match, we return 403.
|
||||
"""
|
||||
current_user = g.get('current_user', None)
|
||||
|
||||
if 'permissions' in resource:
|
||||
# If permissions are embedde in the node (this overrides any other
|
||||
# permission previously set)
|
||||
resource_permissions = resource['permissions']
|
||||
elif type(resource['node_type']) is dict:
|
||||
# If the node_type is embedded in the document, extract permissions
|
||||
# from there
|
||||
resource_permissions = resource['node_type']['permissions']
|
||||
else:
|
||||
# If the node_type is referenced with an ObjectID (was not embedded on
|
||||
# request) query for if from the database and get the permissions
|
||||
node_types_collection = app.data.driver.db['node_types']
|
||||
node_type = node_types_collection.find_one(resource['node_type'])
|
||||
resource_permissions = node_type['permissions']
|
||||
|
||||
if current_user:
|
||||
# If the user is authenticated, proceed to compare the group permissions
|
||||
for permission in resource_permissions['groups']:
|
||||
if permission['group'] in current_user['groups']:
|
||||
if method in permission['methods']:
|
||||
return
|
||||
|
||||
for permission in resource_permissions['users']:
|
||||
if current_user['user_id'] == permission['user']:
|
||||
if method in permission['methods']:
|
||||
return
|
||||
|
||||
# Check if the node is public or private. This must be set for non logged
|
||||
# in users to see the content. For most BI projects this is on by default,
|
||||
# while for private project this will not be set at all.
|
||||
if 'world' in permissions and method in permissions['world']:
|
||||
return
|
||||
|
||||
abort(403)
|
||||
|
||||
def before_returning_node(response):
|
||||
# Run validation process, since GET on nodes entry point is public
|
||||
validate_token()
|
||||
check_permissions(response, 'GET')
|
||||
|
||||
def before_replacing_node(item, original):
|
||||
check_permissions(original, 'PUT')
|
||||
|
||||
def before_inserting_nodes(items):
|
||||
for item in items:
|
||||
check_permissions(item, 'POST')
|
||||
|
||||
app.on_fetched_item_nodes += before_returning_node
|
||||
app.on_replace_nodes += before_replacing_node
|
||||
app.on_insert_nodes += before_inserting_nodes
|
||||
|
||||
|
||||
def post_GET_user(request, payload):
|
||||
print 'computing permissions'
|
||||
json_data = json.loads(payload.data)
|
||||
# Check if we are querying the users endpoint (instead of the single user)
|
||||
if json_data.get('_id') is None:
|
||||
return
|
||||
json_data['computed_permissions'] = \
|
||||
compute_permissions(json_data['_id'], app.data.driver)
|
||||
# json_data['computed_permissions'] = \
|
||||
# compute_permissions(json_data['_id'], app.data.driver)
|
||||
payload.data = json.dumps(json_data)
|
||||
|
||||
app.on_post_GET_users += post_GET_user
|
||||
|
149
pillar/manage.py
149
pillar/manage.py
@ -1,4 +1,5 @@
|
||||
import os
|
||||
from eve.methods.put import put_internal
|
||||
from application import app
|
||||
from application import db
|
||||
from application import post_item
|
||||
@ -48,25 +49,6 @@ def clear_db():
|
||||
db.drop_collection('users')
|
||||
|
||||
|
||||
@manager.command
|
||||
def remove_properties_order():
|
||||
"""Removes properties.order
|
||||
"""
|
||||
from pymongo import MongoClient
|
||||
client = MongoClient(MONGO_HOST, 27017)
|
||||
db = client.eve
|
||||
nodes = db.nodes.find()
|
||||
for node in nodes:
|
||||
new_prop = {}
|
||||
for prop in node['properties']:
|
||||
if prop == 'order':
|
||||
continue
|
||||
else:
|
||||
new_prop[prop] = node['properties'][prop]
|
||||
db.nodes.update({"_id": node['_id']},
|
||||
{"$set": {"properties": new_prop}})
|
||||
|
||||
|
||||
@manager.command
|
||||
def upgrade_node_types():
|
||||
"""Wipes node_types collection
|
||||
@ -410,14 +392,6 @@ def populate_node_types(old_ids={}):
|
||||
scene_node_type = {
|
||||
'name': 'scene',
|
||||
'description': 'Scene node type',
|
||||
'dyn_schema': {
|
||||
'order': {
|
||||
'type': 'integer',
|
||||
}
|
||||
},
|
||||
'form_schema': {
|
||||
'order': {},
|
||||
},
|
||||
'parent': {
|
||||
"node_types": ["act"]
|
||||
}
|
||||
@ -426,49 +400,11 @@ def populate_node_types(old_ids={}):
|
||||
act_node_type = {
|
||||
'name': 'act',
|
||||
'description': 'Act node type',
|
||||
'dyn_schema': {
|
||||
'order': {
|
||||
'type': 'integer',
|
||||
}
|
||||
},
|
||||
'form_schema': {
|
||||
'order': {},
|
||||
},
|
||||
'parent': {}
|
||||
}
|
||||
|
||||
comment_node_type = {
|
||||
'name': 'comment',
|
||||
'description': 'Comment node type',
|
||||
'dyn_schema': {
|
||||
'text': {
|
||||
'type': 'string',
|
||||
'maxlength': 256
|
||||
},
|
||||
'attachments': {
|
||||
'type': 'list',
|
||||
'schema': {
|
||||
'type': 'objectid',
|
||||
'data_relation': {
|
||||
'resource': 'files',
|
||||
'field': '_id',
|
||||
'embeddable': True
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'form_schema': {
|
||||
'text': {},
|
||||
'attachments': {
|
||||
'items': [("File", "name")]
|
||||
}
|
||||
},
|
||||
'parent': {
|
||||
"node_types": ["shot", "task"]
|
||||
}
|
||||
}
|
||||
|
||||
project_node_type = {
|
||||
node_type_project = {
|
||||
'name': 'project',
|
||||
'parent': {},
|
||||
'description': 'The official project type',
|
||||
@ -567,9 +503,17 @@ def populate_node_types(old_ids={}):
|
||||
}
|
||||
},
|
||||
},
|
||||
'permissions': {
|
||||
'groups': [{
|
||||
'group': '5596e975ea893b269af85c0e',
|
||||
'methods': ['GET', 'PUT', 'POST']
|
||||
}],
|
||||
'users': [],
|
||||
'world': ['GET']
|
||||
}
|
||||
}
|
||||
|
||||
group_node_type = {
|
||||
node_type_group = {
|
||||
'name': 'group',
|
||||
'description': 'Generic group node type',
|
||||
'parent': {},
|
||||
@ -594,9 +538,17 @@ def populate_node_types(old_ids={}):
|
||||
'status': {},
|
||||
'notes': {},
|
||||
},
|
||||
'permissions': {
|
||||
'groups': [{
|
||||
'group': '5596e975ea893b269af85c0e',
|
||||
'methods': ['GET', 'PUT', 'POST']
|
||||
}],
|
||||
'users': [],
|
||||
'world': ['GET']
|
||||
}
|
||||
}
|
||||
|
||||
asset_node_type = {
|
||||
node_type_asset = {
|
||||
'name': 'asset',
|
||||
'description': 'Assets for Elephants Dream',
|
||||
# This data type does not have parent limitations (can be child
|
||||
@ -633,6 +585,14 @@ def populate_node_types(old_ids={}):
|
||||
'status': {},
|
||||
'content_type': {},
|
||||
'file': {},
|
||||
},
|
||||
'permissions': {
|
||||
'groups': [{
|
||||
'group': '5596e975ea893b269af85c0e',
|
||||
'methods': ['GET', 'PUT', 'POST']
|
||||
}],
|
||||
'users': [],
|
||||
'world': ['GET']
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,6 +626,14 @@ def populate_node_types(old_ids={}):
|
||||
},
|
||||
'parent': {
|
||||
"node_types": ["group", "project"]
|
||||
},
|
||||
'permissions': {
|
||||
'groups': [{
|
||||
'group': '5596e975ea893b269af85c0e',
|
||||
'methods': ['GET', 'PUT', 'POST']
|
||||
}],
|
||||
'users': [],
|
||||
'world': ['GET']
|
||||
}
|
||||
}
|
||||
|
||||
@ -734,6 +702,14 @@ def populate_node_types(old_ids={}):
|
||||
},
|
||||
'parent': {
|
||||
'node_types': ['asset',]
|
||||
},
|
||||
'permissions': {
|
||||
'groups': [{
|
||||
'group': '5596e975ea893b269af85c0e',
|
||||
'methods': ['GET', 'PUT', 'POST']
|
||||
}],
|
||||
'users': [],
|
||||
'world': ['GET']
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,10 +733,16 @@ def populate_node_types(old_ids={}):
|
||||
node_name = node_type['name']
|
||||
if node_name in old_ids:
|
||||
node_type = mix_node_type(old_ids[node_name], node_type)
|
||||
# Remove old node_type
|
||||
db.node_types.remove({'_id': old_ids[node_name]})
|
||||
# Insert new node_type
|
||||
db.node_types.insert(node_type)
|
||||
node_id = node_type['_id']
|
||||
|
||||
# Removed internal fields that would cause validation error
|
||||
internal_fields = ['_id', '_etag', '_updated', '_created']
|
||||
for field in internal_fields:
|
||||
node_type.pop(field, None)
|
||||
|
||||
p = put_internal('node_types', node_type, **{'_id': node_id})
|
||||
print p
|
||||
|
||||
else:
|
||||
print("Making the node")
|
||||
print(node_type)
|
||||
@ -770,9 +752,9 @@ def populate_node_types(old_ids={}):
|
||||
# upgrade(task_node_type, old_ids)
|
||||
# upgrade(scene_node_type, old_ids)
|
||||
# upgrade(act_node_type, old_ids)
|
||||
# upgrade(comment_node_type, old_ids)
|
||||
upgrade(project_node_type, old_ids)
|
||||
upgrade(asset_node_type, old_ids)
|
||||
upgrade(node_type_project, old_ids)
|
||||
upgrade(node_type_group, old_ids)
|
||||
upgrade(node_type_asset, old_ids)
|
||||
upgrade(node_type_storage, old_ids)
|
||||
upgrade(node_type_comment, old_ids)
|
||||
|
||||
@ -1037,6 +1019,23 @@ def make_thumbnails():
|
||||
t = build_thumbnails(file_path=f['path'])
|
||||
print t
|
||||
|
||||
@manager.command
|
||||
def add_node_permissions():
|
||||
import codecs
|
||||
import sys
|
||||
UTF8Writer = codecs.getwriter('utf8')
|
||||
sys.stdout = UTF8Writer(sys.stdout)
|
||||
nodes_collection = app.data.driver.db['nodes']
|
||||
node_types_collection = app.data.driver.db['node_types']
|
||||
nodes = nodes_collection.find()
|
||||
for node in nodes:
|
||||
print u"{0}".format(node['name'])
|
||||
if 'permissions' not in node:
|
||||
node_type = node_types_collection.find_one(node['node_type'])
|
||||
# nodes_collection.update({'_id': node['_id']},
|
||||
# {"$set": {'permissions': node_type['permissions']}})
|
||||
print node['_id']
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
manager.run()
|
||||
|
@ -11,8 +11,6 @@ ITEM_METHODS = ['GET', 'PUT', 'DELETE', 'PATCH']
|
||||
|
||||
PAGINATION_LIMIT = 25
|
||||
|
||||
# To be implemented on Eve 0.6
|
||||
# RETURN_MEDIA_AS_URL = True
|
||||
|
||||
users_schema = {
|
||||
'first_name': {
|
||||
@ -147,6 +145,56 @@ organizations_schema = {
|
||||
}
|
||||
}
|
||||
|
||||
permissions_embedded_schema = {
|
||||
'groups': {
|
||||
'type': 'list',
|
||||
'schema': {
|
||||
'type': 'dict',
|
||||
'schema': {
|
||||
'group': {
|
||||
'type': 'objectid',
|
||||
'required': True,
|
||||
'data_relation': {
|
||||
'resource': 'groups',
|
||||
'field': '_id',
|
||||
'embeddable': True
|
||||
}
|
||||
},
|
||||
'methods': {
|
||||
'type': 'list',
|
||||
'required': True,
|
||||
'allowed': ['GET', 'PUT', 'POST', 'DELETE']
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
'users': {
|
||||
'type': 'list',
|
||||
'schema': {
|
||||
'type': 'dict',
|
||||
'schema': {
|
||||
'user' : {
|
||||
'type': 'objectid',
|
||||
'required': True,
|
||||
},
|
||||
'methods': {
|
||||
'type': 'list',
|
||||
'required': True,
|
||||
'allowed': ['GET', 'PUT', 'POST', 'DELETE']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'world': {
|
||||
'type': 'list',
|
||||
#'required': True,
|
||||
'allowed': ['GET',]
|
||||
},
|
||||
'is_free': {
|
||||
'type': 'boolean',
|
||||
}
|
||||
}
|
||||
|
||||
nodes_schema = {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
@ -200,11 +248,15 @@ nodes_schema = {
|
||||
'embeddable': True
|
||||
},
|
||||
},
|
||||
'properties': {
|
||||
'type' : 'dict',
|
||||
'valid_properties' : True,
|
||||
'required': True,
|
||||
'properties': {
|
||||
'type' : 'dict',
|
||||
'valid_properties' : True,
|
||||
'required': True,
|
||||
},
|
||||
'permissions': {
|
||||
'type': 'dict',
|
||||
'schema': permissions_embedded_schema
|
||||
}
|
||||
}
|
||||
|
||||
node_types_schema = {
|
||||
@ -229,6 +281,11 @@ node_types_schema = {
|
||||
'parent': {
|
||||
'type': 'dict',
|
||||
'required': True,
|
||||
},
|
||||
'permissions': {
|
||||
'type': 'dict',
|
||||
'required': True,
|
||||
'schema': permissions_embedded_schema
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +389,6 @@ files_schema = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
groups_schema = {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
@ -364,11 +420,15 @@ groups_schema = {
|
||||
}
|
||||
|
||||
nodes = {
|
||||
'schema': nodes_schema
|
||||
'schema': nodes_schema,
|
||||
'public_methods': ['GET'],
|
||||
'public_item_methods': ['GET']
|
||||
}
|
||||
|
||||
node_types = {
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
'public_methods': ['GET'],
|
||||
'public_item_methods': ['GET'],
|
||||
'schema': node_types_schema,
|
||||
}
|
||||
|
||||
@ -379,7 +439,6 @@ users = {
|
||||
'cache_control': 'max-age=10,must-revalidate',
|
||||
'cache_expires': 10,
|
||||
|
||||
# most global settings can be overridden at resource level
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
|
||||
'public_methods': ['GET', 'POST'],
|
||||
@ -399,7 +458,9 @@ tokens = {
|
||||
|
||||
files = {
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
'schema': files_schema,
|
||||
'public_methods': ['GET'],
|
||||
'public_item_methods': ['GET'],
|
||||
'schema': files_schema
|
||||
}
|
||||
|
||||
|
||||
@ -423,5 +484,5 @@ DOMAIN = {
|
||||
}
|
||||
|
||||
|
||||
if os.environ.get('MONGO_HOST'):
|
||||
MONGO_HOST = os.environ.get('MONGO_HOST')
|
||||
MONGO_HOST = os.environ.get('MONGO_HOST', 'localhost')
|
||||
MONGO_PORT = os.environ.get('MONGO_PORT', 27017)
|
||||
|
Loading…
x
Reference in New Issue
Block a user