Browse Source

Bury + resurrect.

Stefano Cossu 6 years ago
parent
commit
d3efab525e

+ 11 - 3
lakesuperior/api/resource.py

@@ -310,7 +310,7 @@ def delete(uid, soft=True):
 
     if soft:
         rsrc = LdpFactory.from_stored(uid, repr_opts)
-        ret = rsrc.bury_rsrc(inbound)
+        ret = rsrc.bury(inbound)
 
         for child_uri in children:
             try:
@@ -319,7 +319,7 @@ def delete(uid, soft=True):
                     repr_opts={'incl_children' : False})
             except (TombstoneError, ResourceNotExistsError):
                 continue
-            child_rsrc.bury_rsrc(inbound, tstone_pointer=rsrc.uri)
+            child_rsrc.bury(inbound, tstone_pointer=rsrc.uri)
     else:
         ret = env.app_globals.rdfly.forget_rsrc(uid, inbound)
         for child_uri in children:
@@ -347,4 +347,12 @@ def resurrect(uid):
 
     :param str uid: Resource UID.
     """
-    return LdpFactory.from_stored(uid, strict=False).resurrect_rsrc()
+    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('Resource {} is not dead.'.format(uid))

+ 2 - 4
lakesuperior/model/ldp_factory.py

@@ -52,12 +52,10 @@ class LdpFactory:
 
         N.B. The resource must exist.
 
-        :param  uid: UID of the instance.
+        :param str uid: UID of the instance.
         """
-        #logger.info('Retrieving stored resource: {}'.format(uid))
+        # This will blow up if strict is True and the resource is a tombstone.
         rsrc_meta = rdfly.get_metadata(uid, strict=strict)
-        #logger.debug('Extracted metadata: {}'.format(
-        #        pformat(set(rsrc_meta))))
         rdf_types = set(rsrc_meta[nsc['fcres'][uid] : RDF.type])
 
         if LDP_NR_TYPE in rdf_types:

+ 18 - 40
lakesuperior/model/ldpr.py

@@ -412,23 +412,21 @@ class Ldpr(metaclass=ABCMeta):
         return ev_type
 
 
-    def bury_rsrc(self, inbound, tstone_pointer=None):
+    def bury(self, inbound, tstone_pointer=None):
         """
         Delete a single resource and create a tombstone.
 
         :param boolean inbound: Whether to delete the inbound relationships.
-        :param rdflib.URIRef tstone_pointer: If set to a URN, this creates a
+        :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))
-        # Create a backup snapshot for resurrection purposes.
-        self.create_version()
-
+        # ldp:Resource is also used in rdfly.ask_rsrc_exists.
         remove_trp = {
-            trp for trp in self.imr
-            if trp[1] != nsc['fcrepo'].hasVersion}
+            (nsc['fcrepo'].uid, nsc['rdf'].type, nsc['ldp'].Resource)
+        }
 
         if tstone_pointer:
             add_trp = {
@@ -436,7 +434,7 @@ class Ldpr(metaclass=ABCMeta):
         else:
             add_trp = {
                 (self.uri, RDF.type, nsc['fcsystem'].Tombstone),
-                (self.uri, nsc['fcrepo'].created, thread_env.timestamp_term),
+                (self.uri, nsc['fcsystem'].buried, thread_env.timestamp_term),
             }
 
         ib_rsrc_uris = self.imr.subjects(None, self.uri)
@@ -453,7 +451,7 @@ class Ldpr(metaclass=ABCMeta):
         return RES_DELETED
 
 
-    def forget_rsrc(self, inbound=True):
+    def forget(self, inbound=True):
         """
         Remove all traces of a resource and versions.
         """
@@ -466,42 +464,22 @@ class Ldpr(metaclass=ABCMeta):
         return RES_DELETED
 
 
-    def resurrect_rsrc(self):
+    def resurrect(self):
         """
         Resurrect a resource from a tombstone.
-
-        @EXPERIMENTAL
         """
-        tstone_trp = set(rdfly.get_imr(self.uid, strict=False))
-
-        ver_rsp = self.version_info.query('''
-        SELECT ?uid {
-          ?latest fcrepo:hasVersionLabel ?uid ;
-            fcrepo:created ?ts .
+        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),
         }
-        ORDER BY DESC(?ts)
-        LIMIT 1
-        ''')
-        ver_uid = str(ver_rsp.bindings[0]['uid'])
-        ver_trp = set(rdfly.get_metadata(self.uid, ver_uid))
-
-        laz_gr = Graph()
-        for t in ver_trp:
-            if t[1] != RDF.type or t[2] not in {
-                nsc['fcrepo'].Version,
-            }:
-                laz_gr.add((self.uri, t[1], t[2]))
-        laz_gr.add((self.uri, RDF.type, nsc['fcrepo'].Resource))
-        if nsc['ldp'].NonRdfSource in laz_gr[:RDF.type:]:
-            laz_gr.add((self.uri, RDF.type, nsc['fcrepo'].Binary))
-        elif nsc['ldp'].Container in laz_gr[:RDF.type:]:
-            laz_gr.add((self.uri, RDF.type, nsc['fcrepo'].Container))
-
-        laz_set = set(laz_gr) | self._containment_rel()
-        self.modify(RES_CREATED, tstone_trp, laz_set)
 
-        return self.uri
+        self.modify(RES_CREATED, remove_trp, add_trp)
 
+        return self.uri
 
 
     def create_version(self, ver_uid=None):
@@ -707,7 +685,7 @@ class Ldpr(metaclass=ABCMeta):
         """
         rdfly.modify_rsrc(self.uid, remove_trp, add_trp)
         # Clear IMR buffer.
-        if hasattr(self, 'imr'):
+        if hasattr(self, '_imr'):
             delattr(self, '_imr')
             try:
                 self.imr

+ 1 - 1
lakesuperior/store/ldp_rs/rsrc_centric_layout.py

@@ -328,7 +328,7 @@ class RsrcCentricLayout:
         return userdata_gr
 
 
-    def get_version_info(self, uid, strict=True):
+    def get_version_info(self, uid):
         """
         Get all metadata about a resource's versions.
 

+ 23 - 0
tests/api/test_resource_api.py

@@ -362,6 +362,29 @@ class TestResourceCRUD:
             nsc['fcres'][target_uid]]
 
 
+    def test_soft_delete(self):
+        """
+        Soft-delete a resource.
+        """
+        uid = '/test_soft_delete01'
+        rsrc_api.create_or_replace(uid)
+        rsrc_api.delete(uid)
+        with pytest.raises(TombstoneError):
+            rsrc_api.get(uid)
+
+
+    def test_resurrect(self):
+        """
+        Resurrect a soft-deleted resource.
+        """
+        uid = '/test_soft_delete02'
+        rsrc_api.create_or_replace(uid)
+        rsrc_api.delete(uid)
+        rsrc_api.resurrect(uid)
+
+        rsrc = rsrc_api.get(uid)
+        assert nsc['ldp'].Resource in rsrc.ldp_types
+
 
 @pytest.mark.usefixtures('db')
 class TestResourceVersioning: