ldp_nr.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import logging
  2. import pdb
  3. from rdflib import Graph
  4. from rdflib.namespace import RDF, XSD
  5. from rdflib.resource import Resource
  6. from rdflib.term import URIRef, Literal, Variable
  7. from lakesuperior import env
  8. from lakesuperior.dictionaries.namespaces import ns_collection as nsc
  9. from lakesuperior.model.ldp.ldpr import Ldpr
  10. from lakesuperior.model.ldp.ldp_rs import LdpRs
  11. nonrdfly = env.app_globals.nonrdfly
  12. logger = logging.getLogger(__name__)
  13. default_hash_algo = env.app_globals.config['application']['uuid']['algo']
  14. class LdpNr(Ldpr):
  15. """LDP-NR (Non-RDF Source).
  16. Definition: https://www.w3.org/TR/ldp/#ldpnr
  17. """
  18. def __init__(self, *args, stream=None, mimetype=None, disposition=None,
  19. prov_cksum_algo=None, prov_cksum=None, **kwargs):
  20. """
  21. Extends :meth:`lakesuperior.model.Ldpr.__init__` by adding LDP-NR
  22. specific parameters.
  23. """
  24. super().__init__(*args, **kwargs)
  25. self.base_types = super().base_types | {
  26. nsc['fcrepo'].Binary,
  27. nsc['ldp'].NonRDFSource,
  28. }
  29. self.stream = stream
  30. if mimetype:
  31. self.mimetype = mimetype
  32. else:
  33. self.mimetype = (
  34. str(self.metadata.value(nsc['ebucore'].hasMimeType))
  35. if self.is_stored
  36. else 'application/octet-stream')
  37. self.disposition = disposition
  38. self.prov_cksum_algo = prov_cksum_algo
  39. self.prov_cksum = prov_cksum
  40. @property
  41. def filename(self):
  42. """
  43. File name of the original uploaded file.
  44. :rtype: str
  45. """
  46. return self.metadata.value(nsc['ebucore'].filename)
  47. @property
  48. def content(self):
  49. """
  50. Binary content.
  51. :return: File handle of the resource content.
  52. :rtype: io.BufferedReader
  53. """
  54. return open(self.local_path, 'rb')
  55. @property
  56. def content_size(self):
  57. """
  58. Byte size of the binary content.
  59. :rtype: int
  60. """
  61. return int(self.metadata.value(nsc['premis'].hasSize))
  62. @property
  63. def local_path(self):
  64. """
  65. Path on disk of the binary content.
  66. :rtype: str
  67. """
  68. cksum_term = self.metadata.value(nsc['premis'].hasMessageDigest)
  69. cksum = str(cksum_term).replace(f'urn:{default_hash_algo}:','')
  70. return nonrdfly.__class__.local_path(
  71. nonrdfly.root, cksum, nonrdfly.bl, nonrdfly.bc)
  72. def create_or_replace(self, create_only=False):
  73. """
  74. Create a new binary resource with a corresponding RDF representation.
  75. :param bool create_only: Whether the resource is being created or
  76. updated.
  77. """
  78. # Persist the stream.
  79. self.digest, self.size = nonrdfly.persist(
  80. self.uid, self.stream, prov_cksum_algo=self.prov_cksum_algo,
  81. prov_cksum=self.prov_cksum)
  82. # Try to persist metadata. If it fails, delete the file.
  83. logger.debug('Persisting LDP-NR triples in {}'.format(self.uri))
  84. try:
  85. ev_type = super().create_or_replace(create_only)
  86. except:
  87. # self.digest is also the file UID.
  88. nonrdfly.delete(self.digest)
  89. raise
  90. else:
  91. return ev_type
  92. ## PROTECTED METHODS ##
  93. def _add_srv_mgd_triples(self, *args, **kwargs):
  94. """
  95. Add all metadata for the RDF representation of the LDP-NR.
  96. :param BufferedIO stream: The uploaded data stream.
  97. :param str mimetype: MIME type of the uploaded file.
  98. :param defaultdict disposition: The ``Content-Disposition`` header
  99. content, parsed through ``parse_rfc7240``.
  100. """
  101. super()._add_srv_mgd_triples(*args, **kwargs)
  102. # File size.
  103. logger.debug('Data stream size: {}'.format(self.size))
  104. self.provided_imr.set((
  105. self.uri, nsc['premis'].hasSize, Literal(self.size)))
  106. # Checksum.
  107. cksum_term = URIRef(f'urn:{default_hash_algo}:{self.digest}')
  108. self.provided_imr.set((
  109. self.uri, nsc['premis'].hasMessageDigest, cksum_term))
  110. # MIME type.
  111. self.provided_imr.set((
  112. self.uri, nsc['ebucore']['hasMimeType'], Literal(self.mimetype)))
  113. # File name.
  114. logger.debug('Disposition: {}'.format(self.disposition))
  115. try:
  116. self.provided_imr.set((
  117. self.uri, nsc['ebucore']['filename'], Literal(
  118. self.disposition['attachment']['parameters']['filename'])))
  119. except (KeyError, TypeError) as e:
  120. pass