Bläddra i källkod

Direct and indirect containers.

Stefano Cossu 7 år sedan
förälder
incheckning
c162bfd830

+ 14 - 15
lakesuperior/model/ldp_rs.py

@@ -94,14 +94,15 @@ class LdpRs(Ldpr):
         '''
         g = Graph().parse(data=data, format=format, publicID=self.urn)
 
-        imr = Resource(self._check_mgd_terms(g, handling), self.urn)
-        imr = self._add_srv_mgd_triples(imr, create=True)
-        self._ensure_single_subject_rdf(imr.graph)
+        self.provided_imr = Resource(self._check_mgd_terms(g, handling),
+                self.urn)
+        self._add_srv_mgd_triples(create=True)
+        self._ensure_single_subject_rdf(self.provided_imr.graph)
 
         if create_only:
-            res = self.rdfly.create_rsrc(imr)
+            res = self.rdfly.create_rsrc(self.provided_imr)
         else:
-            res = self.rdfly.create_or_replace_rsrc(imr)
+            res = self.rdfly.create_or_replace_rsrc(self.provided_imr)
 
         self._set_containment_rel()
 
@@ -143,32 +144,30 @@ class LdpRs(Ldpr):
         return g
 
 
-    def _add_srv_mgd_triples(self, rsrc, create=False):
+    def _add_srv_mgd_triples(self, create=False):
         '''
         Add server-managed triples to a resource.
 
         @param create (boolean) Whether the resource is being created.
         '''
         # Message digest.
-        cksum = Digest.rdf_cksum(rsrc.graph)
-        rsrc.set(nsc['premis'].hasMessageDigest,
+        cksum = Digest.rdf_cksum(self.provided_imr.graph)
+        self.provided_imr.set(nsc['premis'].hasMessageDigest,
                 URIRef('urn:sha1:{}'.format(cksum)))
 
         # Create and modify timestamp.
         # @TODO Use gunicorn to get request timestamp.
         ts = Literal(arrow.utcnow(), datatype=XSD.dateTime)
         if create:
-            rsrc.set(nsc['fcrepo'].created, ts)
-            rsrc.set(nsc['fcrepo'].createdBy, self.DEFAULT_USER)
+            self.provided_imr.set(nsc['fcrepo'].created, ts)
+            self.provided_imr.set(nsc['fcrepo'].createdBy, self.DEFAULT_USER)
 
-        rsrc.set(nsc['fcrepo'].lastModified, ts)
-        rsrc.set(nsc['fcrepo'].lastModifiedBy, self.DEFAULT_USER)
+        self.provided_imr.set(nsc['fcrepo'].lastModified, ts)
+        self.provided_imr.set(nsc['fcrepo'].lastModifiedBy, self.DEFAULT_USER)
 
         # Base LDP types.
         for t in self.base_types:
-            rsrc.add(RDF.type, t)
-
-        return rsrc
+            self.provided_imr.add(RDF.type, t)
 
 
     def _sparql_delta(self, q, handling=None):

+ 49 - 11
lakesuperior/model/ldpr.py

@@ -93,8 +93,11 @@ class Ldpr(metaclass=ABCMeta):
     '''
 
     FCREPO_PTREE_TYPE = nsc['fcrepo'].Pairtree
+    INS_CNT_REL_URI = nsc['ldp'].insertedContentRelation
     LDP_NR_TYPE = nsc['ldp'].NonRDFSource
     LDP_RS_TYPE = nsc['ldp'].RDFSource
+    MBR_RSRC_URI = nsc['ldp'].membershipResource
+    MBR_REL_URI = nsc['ldp'].hasMemberRelation
     RETURN_CHILD_RES_URI = nsc['fcrepo'].EmbedResources
     RETURN_INBOUND_REF_URI = nsc['fcrepo'].InboundReferences
     RETURN_SRV_MGD_RES_URI = nsc['fcrepo'].ServerManaged
@@ -499,22 +502,17 @@ class Ldpr(metaclass=ABCMeta):
         '''
         if '/' in self.uuid:
             # Traverse up the hierarchy to find the parent.
-            cparent_uri = self._find_parent_or_create_pairtree(self.uuid)
+            parent_uri = self._find_parent_or_create_pairtree(self.uuid)
 
-            # Reroute possible containment relationships between parent and new
-            # resource.
-            #self._splice_in(cparent)
-
-            if cparent_uri:
-                self.rdfly.ds.add((cparent_uri, nsc['ldp'].contains,
+            if parent_uri:
+                self.rdfly.ds.add((parent_uri, nsc['ldp'].contains,
                         self.rsrc.identifier))
+
+                # Direct or indirect container relationship.
+                self._add_ldp_dc_ic_rel(parent_uri)
         else:
             self.rsrc.graph.add((nsc['fcsystem'].root, nsc['ldp'].contains,
                     self.rsrc.identifier))
-        # If a resource has no parent and should be parent of the new resource,
-        # add the relationship.
-        #for child_uri in self.find_lost_children():
-        #    self.rsrc.add(nsc['ldp'].contains, child_uri)
 
 
     def _find_parent_or_create_pairtree(self, uuid):
@@ -576,3 +574,43 @@ class Ldpr(metaclass=ABCMeta):
         self.rdfly.create_rsrc(imr)
 
 
+    def _add_ldp_dc_ic_rel(self, cont_uri):
+        '''
+        Add relationship triples from a direct or indirect container parent.
+
+        @param cont_uri (rdflib.term.URIRef)  The container URI.
+        '''
+        cont_imr = self.rdfly.extract_imr(cont_uri, incl_children=False)
+        cont_p = set(cont_imr.graph.predicates())
+        add_g = Graph()
+
+        self._logger.info('Checking direct or indirect containment.')
+        self._logger.debug('Parent predicates: {}'.format(cont_p))
+
+        if self.MBR_RSRC_URI in cont_p and self.MBR_REL_URI in cont_p:
+            s = Translator.localize_term(
+                    cont_imr.value(self.MBR_RSRC_URI).identifier)
+            p = cont_imr.value(self.MBR_REL_URI).identifier
+
+            if cont_imr[RDF.type : nsc['ldp'].DirectContainer]:
+                self._logger.info('Parent is a direct container.')
+
+                self._logger.debug('Creating DC triples.')
+                add_g.add((s, p, self.urn))
+
+            elif cont_imr[RDF.type : nsc['ldp'].IndirectContainer] \
+                   and self.INS_CNT_REL_URI in cont_p:
+                self._logger.info('Parent is an indirect container.')
+                cont_rel_uri = cont_imr.value(self.INS_CNT_REL_URI).identifier
+                target_uri = self.provided_imr.value(cont_rel_uri).identifier
+                self._logger.debug('Target URI: {}'.format(target_uri))
+                if target_uri:
+                    self._logger.debug('Creating IC triples.')
+                    add_g.add((s, p, target_uri))
+
+        if len(add_g):
+            self._logger.debug('Adding DC/IC triples: {}'.format(
+                add_g.serialize(format='turtle').decode('utf-8')))
+            self.rdfly.modify_dataset(Graph(), add_g)
+
+

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

@@ -112,15 +112,6 @@ class SimpleLayout(BaseRdfLayout):
         See base_rdf_layout.replace_rsrc.
         '''
         rsrc = self.rsrc(imr.identifier)
-        # Delete all triples but keep creation date and creator.
-        #created = rsrc.value(nsc['fcrepo'].created)
-        #created_by = rsrc.value(nsc['fcrepo'].createdBy)
-
-        #if not created or not created_by:
-        #    raise InvalidResourceError(urn)
-
-        #imr.set(nsc['fcrepo'].created, created)
-        #imr.set(nsc['fcrepo'].createdBy, created_by)
 
         # Delete the stored triples but spare the protected predicates.
         del_trp_qry = []
@@ -143,8 +134,15 @@ class SimpleLayout(BaseRdfLayout):
         '''
         See base_rdf_layout.update_rsrc.
         '''
-        self.ds -= remove_trp
-        self.ds += add_trp
+        #self._logger.debug('Remove triples: {}'.format(
+        #        remove_trp.serialize(format='turtle').decode('utf-8')))
+        #self._logger.debug('Add triples: {}'.format(
+        #        add_trp.serialize(format='turtle').decode('utf-8')))
+
+        for t in remove_trp:
+            self.ds.remove(t)
+        for t in add_trp:
+            self.ds.add(t)
 
 
     def delete_rsrc(self, urn, inbound=True, delete_children=True):

+ 28 - 4
lakesuperior/util/translator.py

@@ -1,3 +1,5 @@
+import logging
+
 from collections import defaultdict
 
 from flask import request
@@ -13,6 +15,13 @@ class Translator:
     All static methods.
     '''
 
+    _logger = logging.getLogger(__name__)
+
+    @staticmethod
+    def base_url():
+        return request.host_url + request.path.split('/')[1]
+
+
     @staticmethod
     def camelcase(word):
         '''
@@ -40,10 +49,25 @@ class Translator:
 
         @return string
         '''
-        return s.replace(
-            request.host_url + 'rest/',
-            str(nsc['fcres'])
-        )
+        #import pdb; pdb.set_trace()
+        return s.replace(Translator.base_url()+'/', str(nsc['fcres']))\
+                .replace(Translator.base_url(), str(nsc['fcres']))
+
+
+    @staticmethod
+    def localize_term(uri):
+        '''
+        Convert an URI into an URN.
+
+        @param rdflib.term.URIRef urn Input URI.
+
+        @return rdflib.term.URIRef
+        '''
+        #import pdb; pdb.set_trace()
+        Translator._logger.debug('Input URI: {}'.format(uri))
+        if uri.strip('/') == Translator.base_url():
+            return BaseRdfLayout.ROOT_NODE_URN
+        return URIRef(Translator.localize_string(str(uri)))
 
 
     @staticmethod