ldp_nr.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from rdflib import Graph
  2. from rdflib.namespace import RDF, XSD
  3. from rdflib.resource import Resource
  4. from rdflib.term import URIRef, Literal, Variable
  5. from lakesuperior.dictionaries.namespaces import ns_collection as nsc
  6. from lakesuperior.model.ldpr import Ldpr, atomic
  7. from lakesuperior.model.ldp_rs import LdpRs
  8. class LdpNr(Ldpr):
  9. '''LDP-NR (Non-RDF Source).
  10. Definition: https://www.w3.org/TR/ldp/#ldpnr
  11. '''
  12. base_types = {
  13. nsc['fcrepo'].Binary,
  14. nsc['fcrepo'].Resource,
  15. nsc['ldp'].Resource,
  16. nsc['ldp'].NonRDFSource,
  17. }
  18. def __init__(self, uuid, stream=None, mimetype='application/octet-stream',
  19. disposition=None, **kwargs):
  20. '''
  21. Extends Ldpr.__init__ by adding LDP-NR specific parameters.
  22. '''
  23. super().__init__(uuid, **kwargs)
  24. if stream:
  25. self.workflow = self.WRKF_INBOUND
  26. self.stream = stream
  27. else:
  28. self.workflow = self.WRKF_OUTBOUND
  29. self.mimetype = mimetype
  30. self.disposition = disposition
  31. @property
  32. def filename(self):
  33. return self.imr.value(nsc['ebucore'].filename)
  34. @property
  35. def local_path(self):
  36. cksum_term = self.imr.value(nsc['premis'].hasMessageDigest)
  37. cksum = str(cksum_term.identifier.replace('urn:sha1:',''))
  38. return self.nonrdfly.local_path(cksum)
  39. ## LDP METHODS ##
  40. def get(self, **kwargs):
  41. return LdpRs(self.uuid).get(**kwargs)
  42. @atomic
  43. def post(self):
  44. '''
  45. Create a new binary resource with a corresponding RDF representation.
  46. @param file (Stream) A Stream resource representing the uploaded file.
  47. '''
  48. # Persist the stream.
  49. file_uuid = self.nonrdfly.persist(self.stream)
  50. # Gather RDF metadata.
  51. for t in self.base_types:
  52. self.provided_imr.add(RDF.type, t)
  53. # @TODO check that the existing resource is of the same LDP type.
  54. self._add_metadata(digest=file_uuid)
  55. # Try to persist metadata. If it fails, delete the file.
  56. self._logger.debug('Persisting LDP-NR triples in {}'.format(self.urn))
  57. try:
  58. rsrc = self._create_rsrc()
  59. except:
  60. self.nonrdfly.delete(file_uuid)
  61. raise
  62. else:
  63. return rsrc
  64. def put(self):
  65. return self.post()
  66. ## PROTECTED METHODS ##
  67. def _add_metadata(self, digest):
  68. '''
  69. Add all metadata for the RDF representation of the LDP-NR.
  70. @param stream (BufferedIO) The uploaded data stream.
  71. @param mimetype (string) MIME type of the uploaded file.
  72. @param disposition (defaultdict) The `Content-Disposition` header
  73. content, parsed through `parse_rfc7240`.
  74. '''
  75. # File size.
  76. self._logger.debug('Data stream size: {}'.format(self.stream.limit))
  77. self.provided_imr.set(nsc['premis'].hasSize, Literal(self.stream.limit))
  78. # Checksum.
  79. cksum_term = URIRef('urn:sha1:{}'.format(digest))
  80. self.provided_imr.set(nsc['premis'].hasMessageDigest, cksum_term)
  81. # MIME type.
  82. self.provided_imr.set(nsc['ebucore']['hasMimeType'],
  83. Literal(self.mimetype))
  84. # File name.
  85. self._logger.debug('Disposition: {}'.format(self.disposition))
  86. try:
  87. self.provided_imr.set(nsc['ebucore']['filename'], Literal(
  88. self.disposition['attachment']['parameters']['filename']))
  89. except (KeyError, TypeError) as e:
  90. pass