You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.0 KiB

  1. # frozen_string_literal: true
  2. module JsonLdHelper
  3. def equals_or_includes?(haystack, needle)
  4. haystack.is_a?(Array) ? haystack.include?(needle) : haystack == needle
  5. end
  6. def equals_or_includes_any?(haystack, needles)
  7. needles.any? { |needle| equals_or_includes?(haystack, needle) }
  8. end
  9. def first_of_value(value)
  10. value.is_a?(Array) ? value.first : value
  11. end
  12. # The url attribute can be a string, an array of strings, or an array of objects.
  13. # The objects could include a mimeType. Not-included mimeType means it's text/html.
  14. def url_to_href(value, preferred_type = nil)
  15. single_value = if value.is_a?(Array) && !value.first.is_a?(String)
  16. value.find { |link| preferred_type.nil? || ((link['mimeType'].presence || 'text/html') == preferred_type) }
  17. elsif value.is_a?(Array)
  18. value.first
  19. else
  20. value
  21. end
  22. if single_value.nil? || single_value.is_a?(String)
  23. single_value
  24. else
  25. single_value['href']
  26. end
  27. end
  28. def as_array(value)
  29. value.is_a?(Array) ? value : [value]
  30. end
  31. def value_or_id(value)
  32. value.is_a?(String) || value.nil? ? value : value['id']
  33. end
  34. def supported_context?(json)
  35. !json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)
  36. end
  37. def unsupported_uri_scheme?(uri)
  38. !uri.start_with?('http://', 'https://')
  39. end
  40. def canonicalize(json)
  41. graph = RDF::Graph.new << JSON::LD::API.toRdf(json, documentLoader: method(:load_jsonld_context))
  42. graph.dump(:normalize)
  43. end
  44. def fetch_resource(uri, id)
  45. unless id
  46. json = fetch_resource_without_id_validation(uri)
  47. return unless json
  48. uri = json['id']
  49. end
  50. json = fetch_resource_without_id_validation(uri)
  51. json.present? && json['id'] == uri ? json : nil
  52. end
  53. def fetch_resource_without_id_validation(uri)
  54. build_request(uri).perform do |response|
  55. response.code == 200 ? body_to_json(response.body_with_limit) : nil
  56. end
  57. end
  58. def body_to_json(body)
  59. body.is_a?(String) ? Oj.load(body, mode: :strict) : body
  60. rescue Oj::ParseError
  61. nil
  62. end
  63. def merge_context(context, new_context)
  64. if context.is_a?(Array)
  65. context << new_context
  66. else
  67. [context, new_context]
  68. end
  69. end
  70. private
  71. def build_request(uri)
  72. request = Request.new(:get, uri)
  73. request.add_headers('Accept' => 'application/activity+json, application/ld+json')
  74. request
  75. end
  76. def load_jsonld_context(url, _options = {}, &_block)
  77. json = Rails.cache.fetch("jsonld:context:#{url}", expires_in: 30.days, raw: true) do
  78. request = Request.new(:get, url)
  79. request.add_headers('Accept' => 'application/ld+json')
  80. request.perform do |res|
  81. raise JSON::LD::JsonLdError::LoadingDocumentFailed unless res.code == 200 && res.mime_type == 'application/ld+json'
  82. res.body_with_limit
  83. end
  84. end
  85. doc = JSON::LD::API::RemoteDocument.new(url, json)
  86. block_given? ? yield(doc) : doc
  87. end
  88. end