Example #1
0
    def _containment_rel(self, create, ignore_type=True):
        """Find the closest parent in the path indicated by the uid and
        establish a containment triple.

        Check the path-wise parent of the new resource. If it exists, add the
        containment relationship with this UID. Otherwise, create a container
        resource as the parent.
        This function may recurse up the path tree until an existing container
        is found.

        E.g. if only fcres:/a exists:
        - If ``fcres:/a/b/c/d`` is being created, a becomes container of
          ``fcres:/a/b/c/d``. Also, containers are created for fcres:a/b and
          ``fcres:/a/b/c``.
        - If ``fcres:/e`` is being created, the root node becomes container of
          ``fcres:/e``.

        :param bool create: Whether the resource is being created. If false,
        the parent container is not updated.
        "param bool ignore_type: If False (the default), an exception is raised
        if trying to create a resource under a non-container. This can be
        overridden in special cases (e.g. when migrating a repository in which
        a LDP-NR has "children" under ``fcr:versions``) by setting this to
        True.
        """
        from lakesuperior.model.ldp.ldp_factory import LdpFactory

        if '/' in self.uid.lstrip('/'):
            # Traverse up the hierarchy to find the parent.
            path_components = self.uid.lstrip('/').split('/')
            cnd_parent_uid = '/' + '/'.join(path_components[:-1])
            if rdfly.ask_rsrc_exists(cnd_parent_uid):
                parent_rsrc = LdpFactory.from_stored(cnd_parent_uid)
                if (not ignore_type
                        and nsc['ldp'].Container not in parent_rsrc.types):
                    raise InvalidResourceError(
                        cnd_parent_uid, 'Parent {} is not a container.')

                parent_uid = cnd_parent_uid
            else:
                parent_rsrc = LdpFactory.new_container(cnd_parent_uid)
                # This will trigger this method again and recurse until an
                # existing container or the root node is reached.
                parent_rsrc.create_or_replace()
                parent_uid = parent_rsrc.uid
        else:
            parent_uid = ROOT_UID

        parent_rsrc = LdpFactory.from_stored(
            parent_uid, repr_opts={'incl_children': False}, handling='none')

        # Only update parent if the resource is new.
        if create:
            add_gr = Graph()
            add_gr.add({(nsc['fcres'][parent_uid], nsc['ldp'].contains,
                         self.uri)})
            parent_rsrc.modify(RES_UPDATED, add_trp=add_gr)

        # Direct or indirect container relationship.
        return self._add_ldp_dc_ic_rel(parent_rsrc)
Example #2
0
def create_or_replace(uid, stream=None, **kwargs):
    '''
    Create or replace a resource with a specified UID.

    If the resource already exists, all user-provided properties of the
    existing resource are deleted. If the resource exists and the provided
    content is empty, an exception is raised (not sure why, but that's how
    FCREPO4 handles it).

    @param uid (string) UID of the resource to be created or updated.
    @param stream (BytesIO) Content stream. If empty, an empty container is
    created.
    @param **kwargs Other parameters are passed to the
    LdpFactory.from_provided method. Please see the documentation for that
    method for explanation of individual parameters.

    @return string Event type: whether the resource was created or updated.
    '''
    rsrc = LdpFactory.from_provided(uid, stream=stream, **kwargs)

    if not stream and rsrc.is_stored:
        raise InvalidResourceError(
            rsrc.uid,
            'Resource {} already exists and no data set was provided.')

    return rsrc.create_or_replace_rsrc()
Example #3
0
    def new_container(uid):
        if not uid.startswith('/') or uid == '/':
            raise InvalidResourceError(uid)
        if rdfly.ask_rsrc_exists(uid):
            raise ResourceExistsError(uid)
        rsrc = Ldpc(uid, provided_imr=Resource(Graph(), nsc['fcres'][uid]))

        return rsrc
    def snapshot_uid(self, uid, ver_uid):
        """
        Create a versioned UID string from a main UID and a version UID.
        """
        if VERS_CONT_LABEL in uid:
            raise InvalidResourceError(
                uid, 'Resource \'{}\' is already a version.')

        return '{}/{}/{}'.format(uid, VERS_CONT_LABEL, ver_uid)
Example #5
0
    def _containment_rel(self, create):
        '''Find the closest parent in the path indicated by the uid and
        establish a containment triple.

        Check the path-wise parent of the new resource. If it exists, add the
        containment relationship with this UID. Otherwise, create a container
        resource as the parent.
        This function may recurse up the path tree until an existing container
        is found.

        E.g. if only fcres:/a exists:
        - If fcres:/a/b/c/d is being created, a becomes container of
          fcres:/a/b/c/d. Also, containers are created for fcres:a/b and
          fcres:/a/b/c.
        - If fcres:/e is being created, the root node becomes container of
          fcres:/e.

        @param create (bool) Whether the resource is being created. If false,
        the parent container is not updated.
        '''
        from lakesuperior.model.ldp_factory import LdpFactory

        if '/' in self.uid.lstrip('/'):
            # Traverse up the hierarchy to find the parent.
            path_components = self.uid.lstrip('/').split('/')
            cnd_parent_uid = '/' + '/'.join(path_components[:-1])
            if rdfly.ask_rsrc_exists(cnd_parent_uid):
                parent_rsrc = LdpFactory.from_stored(cnd_parent_uid)
                if nsc['ldp'].Container not in parent_rsrc.types:
                    raise InvalidResourceError(
                        cnd_parent_uid, 'Parent {} is not a container.')

                parent_uid = cnd_parent_uid
            else:
                parent_rsrc = LdpFactory.new_container(cnd_parent_uid)
                # This will trigger this method again and recurse until an
                # existing container or the root node is reached.
                parent_rsrc.create_or_replace()
                parent_uid = parent_rsrc.uid
        else:
            parent_uid = ROOT_UID

        parent_rsrc = LdpFactory.from_stored(
            parent_uid, repr_opts={'incl_children': False}, handling='none')

        # Only update parent if the resource is new.
        if create:
            add_gr = Graph()
            add_gr.add(
                (nsc['fcres'][parent_uid], nsc['ldp'].contains, self.uri))
            parent_rsrc._modify_rsrc(RES_UPDATED, add_trp=add_gr)

        # Direct or indirect container relationship.
        return self._add_ldp_dc_ic_rel(parent_rsrc)
Example #6
0
def resurrect(uid):
    """
    Reinstate a buried (soft-deleted) resource.

    :param str uid: Resource UID.
    """
    try:
        rsrc = LdpFactory.from_stored(uid)
    except TombstoneError as e:
        if e.uid != uid:
            raise
        else:
            return LdpFactory.from_stored(uid, strict=False).resurrect()
    else:
        raise InvalidResourceError(uid,
                                   msg='Resource {} is not dead.'.format(uid))
Example #7
0
    def mint_uid(parent_uid, path=None):
        """
        Mint a new resource UID based on client directives.

        This method takes a parent ID and a tentative path and returns an LDP
        resource UID.

        This may raise an exception resulting in a 404 if the parent is not
        found or a 409 if the parent is not a valid container.

        :param str parent_uid: UID of the parent resource. It must be an
            existing LDPC.
        :param str path: path to the resource, relative to the parent.

        :rtype: str
        :return: The confirmed resource UID. This may be different from
            what has been indicated.
        """
        def split_if_legacy(uid):
            if config['application']['store']['ldp_rs']['legacy_ptree_split']:
                uid = tbox.split_uuid(uid)
            return uid

        if path and path.startswith('/'):
            raise ValueError('Slug cannot start with a slash.')
        # Shortcut!
        if not path and parent_uid == '/':
            return '/' + split_if_legacy(str(uuid4()))

        if not parent_uid.startswith('/'):
            raise ValueError('Invalid parent UID: {}'.format(parent_uid))

        parent = LdpFactory.from_stored(parent_uid)
        if nsc['ldp'].Container not in parent.types:
            raise InvalidResourceError(parent_uid,
                                       'Parent {} is not a container.')

        pfx = parent_uid.rstrip('/') + '/'
        if path:
            cnd_uid = pfx + path
            if not rdfly.ask_rsrc_exists(cnd_uid):
                return cnd_uid

        return pfx + split_if_legacy(str(uuid4()))
Example #8
0
def update(uid, update_str, is_metadata=False):
    '''
    Update a resource with a SPARQL-Update string.

    @param uid (string) Resource UID.
    @param update_str (string) SPARQL-Update statements.
    @param is_metadata (bool) Whether the resource metadata is being updated.
    If False, and the resource being updated is a LDP-NR, an error is raised.
    '''
    rsrc = LdpFactory.from_stored(uid)
    if LDP_NR_TYPE in rsrc.ldp_types:
        if is_metadata:
            rsrc.patch_metadata(update_str)
        else:
            raise InvalidResourceError(uid)
    else:
        rsrc.patch(update_str)

    return rsrc
Example #9
0
def update(uid, update_str, is_metadata=False):
    """
    Update a resource with a SPARQL-Update string.

    :param string uid: Resource UID.
    :param string update_str: SPARQL-Update statements.
    :param bool is_metadata: Whether the resource metadata are being updated.

    :raise InvalidResourceError: If ``is_metadata`` is False and the resource
        being updated is a LDP-NR.
    """
    # FCREPO is lenient here and Hyrax requires it.
    rsrc = LdpFactory.from_stored(uid, handling='lenient')
    if LDP_NR_TYPE in rsrc.ldp_types and not is_metadata:
        raise InvalidResourceError(
            'Cannot use this method to update an LDP-NR content.')

    delta = rsrc.sparql_delta(update_str)
    rsrc.modify(RES_UPDATED, *delta)

    return rsrc
Example #10
0
def update(uid, update_str, is_metadata=False, handling='strict'):
    """
    Update a resource with a SPARQL-Update string.

    :param string uid: Resource UID.
    :param string update_str: SPARQL-Update statements.
    :param bool is_metadata: Whether the resource metadata are being updated.
    :param str handling: How to handle server-managed triples. ``strict``
        (the default) rejects the update with an exception if server-managed
        triples are being changed. ``lenient`` modifies the update graph so
        offending triples are removed and the update can be applied.

    :raise InvalidResourceError: If ``is_metadata`` is False and the resource
        being updated is a LDP-NR.
    """
    rsrc = LdpFactory.from_stored(uid, handling=handling)
    if LDP_NR_TYPE in rsrc.ldp_types and not is_metadata:
        raise InvalidResourceError(
            'Cannot use this method to update an LDP-NR content.')

    delta = rsrc.sparql_delta(update_str)
    rsrc.modify(RES_UPDATED, *delta)

    return rsrc