formatters.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import json
  2. import logging
  3. import uuid
  4. from abc import ABCMeta, abstractmethod
  5. from lakesuperior.globals import RES_CREATED, RES_DELETED, RES_UPDATED
  6. class BaseASFormatter(metaclass=ABCMeta):
  7. '''
  8. Format message as ActivityStreams.
  9. This is not really a `logging.Formatter` subclass, but a plain string
  10. builder.
  11. '''
  12. ev_types = {
  13. RES_CREATED : 'Create',
  14. RES_DELETED : 'Delete',
  15. RES_UPDATED : 'Update',
  16. }
  17. ev_names = {
  18. RES_CREATED : 'Resource Modification',
  19. RES_DELETED : 'Resource Creation',
  20. RES_UPDATED : 'Resource Deletion',
  21. }
  22. def __init__(self, uri, ev_type, time, type, data=None,
  23. data_fmt='text/turtle', metadata=None):
  24. '''
  25. Format output according to granularity level.
  26. NOTE: Granularity level does not refer to the logging levels, i.e.
  27. *when* a message gets logged, in fact all the Messaging logger messages
  28. are logged under the same level. This it is rather about *what* gets
  29. logged in a message.
  30. @param record (dict) This holds a dict with the following keys:
  31. - `uri`: URI of the resource.
  32. - `ev_type`: one of `create`, `delete` or `update`
  33. - `time`: Timestamp of the ev_type.
  34. - `data`: if messaging is configured with `provenance` level, this is
  35. a `rdflib.Graph` containing the triples that have been removed or
  36. added.
  37. - `metadata`: provenance metadata as a rdflib.Graph object. This
  38. contains properties such as actor(s), action (add/remove), etc. This is
  39. only meaningful for `ASDeltaFormatter`.
  40. '''
  41. self.uri = uri
  42. self.ev_type = ev_type
  43. self.time = time
  44. self.type = type
  45. self.data = data or None
  46. self.metadata = metadata
  47. @abstractmethod
  48. def __str__(self):
  49. pass
  50. class ASResourceFormatter(BaseASFormatter):
  51. '''
  52. Sends information about a resource being created, updated or deleted, by
  53. who and when, with no further information about what changed.
  54. '''
  55. def __str__(self):
  56. '''
  57. Output structured data as string.
  58. '''
  59. ret = {
  60. '@context': 'https://www.w3.org/ns/activitystreams',
  61. 'id' : 'urn:uuid:{}'.format(uuid.uuid4()),
  62. 'type' : self.ev_types[self.ev_type],
  63. 'name' : self.ev_names[self.ev_type],
  64. 'object' : {
  65. 'id' : self.uri,
  66. 'updated' : self.time,
  67. 'type' : self.type,
  68. },
  69. 'actor' : self.metadata.get('actor', None),
  70. }
  71. return json.dumps(ret)
  72. class ASDeltaFormatter(BaseASFormatter):
  73. '''
  74. Sends the same information as `ASResourceFormatter` with the addition of
  75. the triples that were added and the ones that were removed in the request.
  76. This may be used to send rich provenance data to a preservation system.
  77. '''
  78. def __str__(self):
  79. '''
  80. Output structured data as string.
  81. '''
  82. ret = {
  83. '@context': 'https://www.w3.org/ns/activitystreams',
  84. 'id' : 'urn:uuid:{}'.format(uuid.uuid4()),
  85. 'type' : self.ev_types[self.ev_type],
  86. 'name' : self.ev_names[self.ev_type],
  87. 'object' : {
  88. 'id' : self.uri,
  89. 'updated' : self.time,
  90. 'type' : self.type,
  91. },
  92. 'actor' : self.metadata.get('actor', None),
  93. 'data' : self.data,
  94. }
  95. return json.dumps(ret)