Esempio n. 1
0
def create(parent, slug=None, **kwargs):
    r"""
    Mint a new UID and create a resource.

    The UID is computed from a given parent UID and a "slug", a proposed path
    relative to the parent. The application will attempt to use the suggested
    path but it may use a different one if a conflict with an existing resource
    arises.

    :param str parent: UID of the parent resource.
    :param str slug: Tentative path relative to the parent UID.
    :param \*\*kwargs: Other parameters are passed to the
      :py:meth:`~lakesuperior.model.ldp.ldp_factory.LdpFactory.from_provided`
      method.

    :rtype: tuple(str, lakesuperior.model.ldp.ldpr.Ldpr)
    :return: A tuple of:
        1. Event type (str): whether the resource was created or updated.
        2. Resource (lakesuperior.model.ldp.ldpr.Ldpr): The new or updated resource.
    """
    uid = LdpFactory.mint_uid(parent, slug)
    logger.debug('Minted UID for new resource: {}'.format(uid))
    rsrc = LdpFactory.from_provided(uid, **kwargs)

    rsrc.create_or_replace(create_only=True)

    return rsrc
Esempio n. 2
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)
Esempio n. 3
0
def get_metadata(uid):
    """
    Get metadata (admin triples) of an LDPR resource.

    :param string uid: Resource UID.
    """
    return LdpFactory.from_stored(uid).metadata
Esempio n. 4
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))
Esempio n. 5
0
def revert_to_version(uid, ver_uid):
    """
    Restore a resource to a previous version state.

    :param str uid: Resource UID.
    :param str ver_uid: Version UID.
    """
    return LdpFactory.from_stored(uid).revert_to_version(ver_uid)
Esempio n. 6
0
def exists(uid):
    """
    Return whether a resource exists (is stored) in the repository.

    :param string uid: Resource UID.
    """
    try:
        exists = LdpFactory.from_stored(uid).is_stored
    except ResourceNotExistsError:
        exists = False
    return exists
Esempio n. 7
0
def create_version(uid, ver_uid):
    """
    Create a resource version.

    :param string uid: Resource UID.
    :param string ver_uid: Version UID to be appended to the resource URI.
      NOTE: this is a "slug", i.e. the version URI is not guaranteed to be the
      one indicated.

    :rtype: str
    :return: Version UID.
    """
    return LdpFactory.from_stored(uid).create_version(ver_uid)
Esempio n. 8
0
    def bury(self, inbound, tstone_pointer=None):
        """
        Delete a single resource and create a tombstone.

        :param bool inbound: Whether inbound relationships are
            removed. If ``False``, resources will keep referring
            to the deleted resource; their link will point to a tombstone
            (which will raise a ``TombstoneError`` in the Python API or a
            ``410 Gone`` in the LDP API).
        :param rdflib.URIRef tstone_pointer: If set to a URI, this creates a
            pointer to the tombstone of the resource that used to contain the
            deleted resource. Otherwise the deleted resource becomes a
            tombstone.
        """
        logger.info('Burying resource {}'.format(self.uid))
        # ldp:Resource is also used in rdfly.ask_rsrc_exists.
        remove_trp = {(nsc['fcrepo'].uid, nsc['rdf'].type, nsc['ldp'].Resource)
                      }

        if tstone_pointer:
            add_trp = {(self.uri, nsc['fcsystem'].tombstone, tstone_pointer)}
        else:
            add_trp = {
                (self.uri, RDF.type, nsc['fcsystem'].Tombstone),
                (self.uri, nsc['fcsystem'].buried, thread_env.timestamp_term),
            }

        # Bury descendants.
        from lakesuperior.model.ldp.ldp_factory import LdpFactory
        for desc_uri in rdfly.get_descendants(self.uid):
            try:
                desc_rsrc = LdpFactory.from_stored(
                    env.app_globals.rdfly.uri_to_uid(desc_uri),
                    repr_opts={'incl_children': False})
            except (TombstoneError, ResourceNotExistsError):
                continue
            desc_rsrc.bury(inbound, tstone_pointer=self.uri)

        # Cut inbound relationships
        if inbound:
            for ib_rsrc_uri in self.imr[::self.uri]:
                remove_trp = {(ib_rsrc_uri, None, self.uri)}
                ib_rsrc = Ldpr(ib_rsrc_uri)
                # To preserve inbound links in history, create a snapshot
                ib_rsrc.create_version()
                ib_rsrc.modify(RES_UPDATED, remove_trp)

        self.modify(RES_DELETED, remove_trp, add_trp)

        return RES_DELETED
Esempio n. 9
0
    def resurrect(self):
        """
        Resurrect a resource from a tombstone.
        """
        remove_trp = {
            (self.uri, nsc['rdf'].type, nsc['fcsystem'].Tombstone),
            (self.uri, nsc['fcsystem'].tombstone, None),
            (self.uri, nsc['fcsystem'].buried, None),
        }
        add_trp = {
            (self.uri, nsc['rdf'].type, nsc['ldp'].Resource),
        }

        self.modify(RES_CREATED, remove_trp, add_trp)

        # Resurrect descendants.
        from lakesuperior.model.ldp.ldp_factory import LdpFactory
        descendants = env.app_globals.rdfly.get_descendants(self.uid)
        for desc_uri in descendants:
            LdpFactory.from_stored(rdfly.uri_to_uid(desc_uri),
                                   strict=False).resurrect()

        return self.uri
Esempio n. 10
0
def create_or_replace(uid, **kwargs):
    r"""
    Create or replace a resource with a specified UID.

    :param string uid: UID of the resource to be created or updated.
    :param \*\*kwargs: Other parameters are passed to the
        :py:meth:`~lakesuperior.model.ldp.ldp_factory.LdpFactory.from_provided`
        method.

    :rtype: tuple(str, lakesuperior.model.ldp.ldpr.Ldpr)
    :return: A tuple of:
        1. Event type (str): whether the resource was created or updated.
        2. Resource (lakesuperior.model.ldp.ldpr.Ldpr): The new or updated
            resource.
    """
    rsrc = LdpFactory.from_provided(uid, **kwargs)
    return rsrc.create_or_replace(), rsrc
Esempio n. 11
0
def delete(uid, soft=True, inbound=True):
    """
    Delete a resource.

    :param string uid: Resource UID.
    :param bool soft: Whether to perform a soft-delete and leave a
        tombstone resource, or wipe any memory of the resource.
    """
    # If referential integrity is enforced, grab all inbound relationships
    # to break them.
    refint = env.app_globals.rdfly.config['referential_integrity']
    inbound = True if refint else inbound

    if soft:
        repr_opts = {'incl_inbound': True} if inbound else {}
        rsrc = LdpFactory.from_stored(uid, repr_opts)
        return rsrc.bury(inbound)
    else:
        Ldpr.forget(uid, inbound)
Esempio n. 12
0
def get(uid, repr_options={}):
    """
    Get an LDPR resource.

    The resource comes preloaded with user data and metadata as indicated by
    the `repr_options` argument. Any further handling of this resource is done
    outside of a transaction.

    :param string uid: Resource UID.
    :param  repr_options: (dict(bool)) Representation options. This is a dict
        that is unpacked downstream in the process. The default empty dict
        results in default values. The accepted dict keys are:

    - incl_inbound: include inbound references. Default: False.
    - incl_children: include children URIs. Default: True.
    - embed_children: Embed full graph of all child resources. Default: False
    """
    rsrc = LdpFactory.from_stored(uid, repr_opts=repr_options)
    # Load graph before leaving the transaction.
    rsrc.imr

    return rsrc
Esempio n. 13
0
def update_delta(uid, remove_trp, add_trp):
    """
    Update a resource graph (LDP-RS or LDP-NR) with sets of add/remove triples.

    A set of triples to add and/or a set of triples to remove may be provided.

    :param string uid: Resource UID.
    :param set(tuple(rdflib.term.Identifier)) remove_trp: Triples to
        remove, as 3-tuples of RDFLib terms.
    :param set(tuple(rdflib.term.Identifier)) add_trp: Triples to
        add, as 3-tuples of RDFLib terms.
    """
    rsrc = LdpFactory.from_stored(uid)

    # FIXME Wrong place to put this, should be at the LDP level.
    remove_trp = {(rel_uri_to_urn(s, uid), p, rel_uri_to_urn(o, uid))
                  for s, p, o in remove_trp}
    add_trp = {(rel_uri_to_urn(s, uid), p, rel_uri_to_urn(o, uid))
               for s, p, o in add_trp}
    remove_trp = rsrc.check_mgd_terms(remove_trp)
    add_trp = rsrc.check_mgd_terms(add_trp)

    return rsrc.modify(RES_UPDATED, remove_trp, add_trp)
Esempio n. 14
0
    def _add_ldp_dc_ic_rel(self, cont_rsrc):
        """
        Add relationship triples from a parent direct or indirect container.

        :param rdflib.resource.Resouce cont_rsrc:  The container resource.
        """
        logger.info('Checking direct or indirect containment.')

        add_trp = {(self.uri, nsc['fcrepo'].hasParent, cont_rsrc.uri)}

        if (nsc['ldp'].DirectContainer in cont_rsrc.ldp_types
                or nsc['ldp'].IndirectContainer in cont_rsrc.ldp_types):
            from lakesuperior.model.ldp.ldp_factory import LdpFactory

            cont_p = cont_rsrc.metadata.terms_by_type('p')
            logger.debug('Parent predicates: {}'.format(cont_p))

            s = cont_rsrc.metadata.value(self.MBR_RSRC_URI) or cont_rsrc.uri
            p = cont_rsrc.metadata.value(self.MBR_REL_URI) or DEF_MBR_REL_URI
            #import pdb; pdb.set_trace()

            if nsc['ldp'].IndirectContainer in cont_rsrc.ldp_types:
                logger.info('Parent is an indirect container.')
                cont_rel_uri = cont_rsrc.metadata.value(self.INS_CNT_REL_URI)
                o = (self.provided_imr.value(cont_rel_uri)
                     or DEF_INS_CNT_REL_URI)
                logger.debug(f'Target URI: {o}')

            else:
                logger.info('Parent is a direct container.')
                o = self.uri

            target_rsrc = LdpFactory.from_stored(rdfly.uri_to_uid(s))
            target_rsrc.modify(RES_UPDATED, add_trp={(s, p, o)})

        return add_trp
Esempio n. 15
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
Esempio n. 16
0
def get_version_info(uid):
    """
    Get version metadata (fcr:versions).
    """
    return LdpFactory.from_stored(uid).version_info
Esempio n. 17
0
def get_version(uid, ver_uid):
    """
    Get version metadata (fcr:versions).
    """
    return LdpFactory.from_stored(uid).get_version(ver_uid)