Example #1
0
        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)
Example #2
0
            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)
Example #3
0
        def common_patch(creds, prefix):
            """
            PATCH handler for both collection and entity endpoints.
            """

            # Read patch from the client.
            patch = loads(flask.request.data)

            # And make sure it really is a patch and not something
            # totally weird that would blow up later.
            validate_json_patch(patch)

            # Alas, we need to poke into the patch a bit before we allow
            # it to execute.  Namely, we need to rebase paths and consult
            # access control rules.
            for op in patch:
                if 'path' in op:
                    # Determine whether this operation is a mutation.
                    # We have different access rules for reading and writing.
                    write = ('test' != op['op'])

                    # We default to empty dictionary when no value is given.
                    # This is however just for access control checks.
                    value = op.get('value', {})

                    # Adjust the path to include endpoint prefix.
                    op['path'] = prefix + normalize_path(op['path'])

                    # Validate the value at the path.
                    validate_dbdict_fragment(creds, value, op['path'], write)

                if 'from' in op:
                    # Adjust source path the same way as above.
                    op['from'] = prefix + normalize_path(op['from'])

                    # And verify that we can access the source data.
                    # XXX: This could be very broken as we should validate
                    #      access to all child entities and not just the root.
                    validate_dbdict_fragment(creds, {}, op['from'], False)

                # Remove None keys from values of non-merge operations.
                if 'value' in op and 'x-merge' != op['op']:
                    op['value'] = remove_nulls(op['value'])

            # Run the patch and hope for the best?
            return {'uuids': apply_patch(patch)}
Example #4
0
        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)