Преглед изворни кода

Delete tombstone; make leave_tombstone method public.

Stefano Cossu пре 7 година
родитељ
комит
f7aa1ac9c6

+ 9 - 0
doc/notes/fcrepo4_deltas.md

@@ -74,6 +74,15 @@ use of content negotiation to do that. Any request to an LDP-NR with an
 `Accept` header set to one of the supported RDF serialization formats will
 yield the RDF metadata of the resource instead of the binary contents.
 
+## Tombstone methods
+
+If a client requests a tombstone resource in
+FCREPO4 with a method other than DELETE, the server will return `405 Method Not
+Allowed` regardless of whether the tombstone exists or not.
+
+LAKEsuperior will return `405` only if the tombstone actually exists, `404`
+otherwise.
+
 ## Asynchronous processing
 
 *TODO*

+ 31 - 4
lakesuperior/endpoints/ldp.py

@@ -214,8 +214,8 @@ def patch_resource(uuid):
 
     try:
         rsrc.patch(request.get_data().decode('utf-8'))
-    except ResourceNotExistsError:
-        return 'Resource #{} not found.'.format(rsrc.uuid), 404
+    except ResourceNotExistsError as e:
+        return str(e), 404
     except TombstoneError as e:
         return _tombstone_response(e, uuid)
     except ServerManagedTermError as e:
@@ -234,14 +234,41 @@ def delete_resource(uuid):
 
     try:
         rsrc.delete()
-    except ResourceNotExistsError:
-        return 'Resource #{} not found.'.format(rsrc.uuid), 404
+    except ResourceNotExistsError as e:
+        return str(e), 404
     except TombstoneError as e:
         return _tombstone_response(e, uuid)
 
     return '', 204, headers
 
 
+@ldp.route('/<path:uuid>/fcr:tombstone', methods=['GET', 'POST', 'PUT',
+        'PATCH', 'DELETE'])
+def tombstone(uuid):
+    '''
+    Handle all tombstone operations.
+
+    The only allowed method is DELETE; any other verb will return a 405.
+    '''
+    logger.debug('Deleting tombstone for {}.'.format(uuid))
+    rsrc = Ldpr(uuid, {'value' : 'minimal'})
+    try:
+        imr = rsrc.imr
+    except TombstoneError as e:
+        if request.method == 'DELETE':
+            if e.uuid == uuid:
+                rsrc.delete_tombstone()
+                return '', 204
+            else:
+                return _tombstone_response(e, uuid)
+        else:
+            return 'Method Not Allowed.', 405
+    except ResourceNotExistsError as e:
+        return str(e), 404
+    else:
+        return '', 404
+
+
 def class_from_req_body():
     '''
     Determine LDP type (and instance class) from the provided RDF body.

+ 9 - 1
lakesuperior/model/ldpr.py

@@ -484,7 +484,15 @@ class Ldpr(metaclass=ABCMeta):
         '''
         https://www.w3.org/TR/ldp/#ldpr-HTTP_DELETE
         '''
-        self.rdfly.delete_rsrc(self.urn)
+        return self.rdfly.delete_rsrc(self.urn)
+
+
+    @transactional
+    def delete_tombstone(self):
+        '''
+        Delete a tombstone.
+        '''
+        return self.rdfly.delete_tombstone(self.urn)
 
 
     ## PROTECTED METHODS ##

+ 27 - 12
lakesuperior/store_layouts/rdf/base_rdf_layout.py

@@ -203,9 +203,9 @@ class BaseRdfLayout(metaclass=ABCMeta):
 
         for child_rsrc in children:
             self._do_delete_rsrc(child_rsrc, inbound)
-            self._leave_tombstone(child_rsrc.identifier, urn)
+            self.leave_tombstone(child_rsrc.identifier, urn)
 
-        return self._leave_tombstone(urn)
+        return self.leave_tombstone(urn)
 
 
     ## INTERFACE METHODS ##
@@ -277,26 +277,41 @@ class BaseRdfLayout(metaclass=ABCMeta):
 
 
     @abstractmethod
-    def _do_delete_rsrc(self, rsrc, inbound):
+    def leave_tombstone(self, urn, parent_urn=None):
         '''
-        Delete a single resource.
+        Leave a tombstone when deleting a resource.
 
-        @param rsrc (rdflib.resource.Resource) Resource to be deleted.
-        @param inbound (boolean) Whether to delete the inbound relationships.
+        If a parent resource is specified, a pointer to the parent's tombstone
+        is added instead.
+
+        @param urn (rdflib.term.URIRef) URN of the deleted resource.
+        @param parent_urn (rdflib.term.URIRef) URI of deleted parent.
         '''
         pass
 
 
     @abstractmethod
-    def _leave_tombstone(self, urn, parent_urn=None):
+    def delete_tombstone(self, rsrc):
         '''
-        Leave a tombstone when deleting a resource.
+        Delete a tombstone.
 
-        If a parent resource is specified, a pointer to the parent's tombstone
-        is added instead.
+        This means removing the `fcsystem:Tombstone` RDF type and the tombstone
+        creation date, as well as all inbound `fcsystem:tombstone`
+        relationships.
 
-        @param urn (rdflib.term.URIRef) URN of the deleted resource.
-        @param parent_urn (rdflib.term.URIRef) URI of deleted parent.
+        NOTE: This method should NOT indiscriminately wipe all triples about
+        the subject. Some other metadata may be left for some good reason.
+        '''
+        pass
+
+
+    @abstractmethod
+    def _do_delete_rsrc(self, rsrc, inbound):
+        '''
+        Delete a single resource.
+
+        @param rsrc (rdflib.resource.Resource) Resource to be deleted.
+        @param inbound (boolean) Whether to delete the inbound relationships.
         '''
         pass
 

+ 9 - 2
lakesuperior/store_layouts/rdf/simple_layout.py

@@ -176,9 +176,9 @@ class SimpleLayout(BaseRdfLayout):
         return urn
 
 
-    def _leave_tombstone(self, urn, parent_urn=None):
+    def leave_tombstone(self, urn, parent_urn=None):
         '''
-        See BaseRdfLayout._leave_tombstone
+        See BaseRdfLayout.leave_tombstone
         '''
         if parent_urn:
             self.ds.add((urn, nsc['fcsystem'].tombstone, parent_urn))
@@ -189,3 +189,10 @@ class SimpleLayout(BaseRdfLayout):
             self.ds.add((urn, nsc['fcrepo'].created, ts))
 
 
+    def delete_tombstone(self, urn):
+        '''
+        See BaseRdfLayout.leave_tombstone
+        '''
+        self.ds.remove((urn, RDF.type, nsc['fcsystem'].Tombstone))
+        self.ds.remove((urn, nsc['fcrepo'].created, None))
+        self.ds.remove((None, nsc['fcsystem'].tombstone, urn))