def tenant_token(credentials={}, tenant=None): tenant_row = call_sync(manager.model['tenant'].get, tenant) if tenant_row is None: raise NotFound('invalid tenant') if 'tenant' in credentials: return make_token_result(credentials) user = call_sync(manager.model['user'].get, credentials['user']) if user is None or not user.desired.get('alicorn'): try: member = call_sync(manager.model['member'].one, tenant=tenant, user=credentials['user']) except KeyError: raise Forbidden('you are not a member of the tenant') # Bestow project owner role for alicorns if user.desired.get('alicorn'): role = 'owner' else: role = member.desired['role'] return make_token_result({ 'tenant': tenant, 'role': role })
def entity_handler(credentials={}, **keys): jpath = endpoint.to_jpath(keys)[:-1] if 'GET' == flask.request.method: # Make sure that we can access the entity. validate_dbdict_fragment(credentials, {}, jpath, False) try: # Get data from manager who can access the model. data = call_sync(manager.get_entity, path, keys) except KeyError: raise PathError('not found', jpath) # Strip keys with None values. return remove_nulls(data) if 'DELETE' == flask.request.method: # Make sure that we can write to that entity. validate_dbdict_fragment(credentials, {}, jpath, True) # Construct patch that would remove it. patch = [{'op': 'remove', 'path': jpath}] # Execute as usual. return {'uuids': apply_patch(patch)} if 'PATCH' == flask.request.method: return common_patch(credentials, jpath)
def apply_patch(patch): """ Preprocess and apply validated JSON Patch to database. Returns dictionary with placeholder to uuid mappings. """ try: # Get root of the database dictionary mapping. root = Children(manager.db, schema.root) # Convert placeholders in the input patch to actual uuids. # Returns mapped placeholders for client to orient himself. uuids = preprocess_patch(root, patch) # Apply the patch. Pointer(root).patch(patch) # Determine our transaction id. txid = int(manager.db.execute('SELECT cork();').fetchone()[0]) # Register our completion watch. call_sync(manager.listener.register, txid) try: try: # Attempt to commit the transaction. manager.db.commit() except DatabaseError, e: # We have nothing better for now. raise DataError(e.orig.diag.message_primary, []) except: # Transaction failed, remove the completion watch. call_sync(manager.listener.abort, txid) # Re-raise the exception. raise # Wait for the transaction to propagate. call_sync(manager.listener.wait, txid) # Stop waiting for the transaction. call_sync(manager.listener.abort, txid) # Return mapped uuids to the client now, when all data safely # hit the model and he will be able to retrieve them. return uuids except: # Roll back the transaction on any error. manager.db.rollback() # Re-raise the exception. raise
def join_handler(credentials={}, **keys): jpath = endpoint.to_jpath(keys)[:-2] if 'GET' == flask.request.method: # Make sure all access control restrictions are applied. validate_dbdict_fragment(credentials, {}, jpath, False) try: # Let the manager deal with model access and data # retrieval. XXX: Access control is broken there, BTW. data = call_sync(manager.list_collection_join, path, keys) except KeyError: raise PathError('not found', jpath) # We promised not to return any nulls in the output. return remove_nulls(data)
def collection_handler(credentials={}, **keys): jpath = endpoint.to_jpath(keys)[:-2] if 'GET' == flask.request.method: # Make sure all access control restrictions are applied. validate_dbdict_fragment(credentials, {}, jpath, False) try: # Let the manager deal with model access and data # retrieval. XXX: Access control is broken there, BTW. data = call_sync(manager.list_collection, path, keys) except KeyError: raise PathError('not found', jpath) # We promised not to return any nulls in the output. return remove_nulls(data) if 'POST' == flask.request.method: # Read data from client. data = loads(flask.request.data) # Make sure it's at least a litle sane. if not isinstance(data, Mapping): raise DataError('invalid entity', jpath) # Desired state must be present when POSTing. if 'desired' not in data: raise DataError('desired state missing', jpath + ['desired']) # When primary keys must be specified by the user, make sure # that they are present and do not invent them on our own. if endpoint.table.user_pkey: djpath = jpath + ['desired'] if isinstance(endpoint.table.pkey, basestring): if endpoint.table.pkey not in data['desired']: raise DataError('primary key missing', djpath + [endpoint.table.pkey]) else: for key in endpoint.table.pkey: if key not in data['desired']: raise DataError('primary key missing', djpath + [key]) if 'desired' in data: # Extract the primary key placeholder. pkey = data['desired'].get(endpoint.table.pkey, 'POST') else: # Or default to one named 'POST'. pkey = 'POST' # Get rid of keys with None values. data = remove_nulls(data) # Calculate hypothetical destination path. post_path = jpath + [pkey] # Make sure all access control restrictions are applied. validate_dbdict_fragment(credentials, data, post_path, True) # This is what the patch should look like: patch = [{'op': 'add', 'path': post_path, 'value': data}] # Apply the patch and return resulting set of UUIDs. return {'uuids': apply_patch(patch)} if 'PATCH' == flask.request.method: return common_patch(credentials, jpath)