krikri 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/krikri/original_record.rb +1 -0
- data/lib/krikri/async_uri_getter.rb +127 -0
- data/lib/krikri/engine.rb +18 -0
- data/lib/krikri/ldp.rb +3 -2
- data/lib/krikri/ldp/invalidatable.rb +107 -0
- data/lib/krikri/ldp/rdf_source.rb +24 -6
- data/lib/krikri/ldp/resource.rb +22 -1
- data/lib/krikri/map_crosswalk.rb +5 -2
- data/lib/krikri/version.rb +1 -1
- data/spec/internal/Gemfile.lock +4 -4
- data/spec/internal/config/initializers/blacklight_initializer.rb +1 -1
- data/spec/internal/config/initializers/devise.rb +2 -2
- data/spec/internal/config/secrets.yml +2 -2
- data/spec/internal/db/development.sqlite3 +0 -0
- data/spec/internal/db/migrate/{20151222175607_devise_create_users.rb → 20160113172004_devise_create_users.rb} +0 -0
- data/spec/internal/db/migrate/{20151222175629_create_searches.blacklight.rb → 20160113172024_create_searches.blacklight.rb} +0 -0
- data/spec/internal/db/migrate/{20151222175630_create_bookmarks.blacklight.rb → 20160113172025_create_bookmarks.blacklight.rb} +0 -0
- data/spec/internal/db/migrate/{20151222175631_add_polymorphic_type_to_bookmarks.blacklight.rb → 20160113172026_add_polymorphic_type_to_bookmarks.blacklight.rb} +0 -0
- data/spec/internal/db/schema.rb +1 -1
- data/spec/internal/db/test.sqlite3 +0 -0
- data/spec/internal/log/development.log +84 -84
- data/spec/internal/log/test.log +5709 -3532
- data/spec/lib/krikri/async_uri_getter_spec.rb +106 -0
- data/spec/lib/krikri/map_crosswalk_spec.rb +18 -0
- data/spec/lib/krikri/search_index_spec.rb +22 -14
- data/spec/models/dpla/map/aggregation_spec.rb +21 -0
- data/spec/models/original_record_spec.rb +3 -0
- data/spec/support/shared_contexts/entities_query.rb +1 -0
- data/spec/support/shared_examples/ldp_invalidatable.rb +98 -0
- data/spec/support/shared_examples/rdf_source.rb +2 -1
- metadata +18 -184
- data/spec/internal/db/test.sqlite3-journal +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_alerts.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_background-variant.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_border-radius.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_buttons.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_center-block.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_clearfix.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_forms.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_gradients.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_grid-framework.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_grid.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_hide-text.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_image.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_labels.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_list-group.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_nav-divider.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_nav-vertical-align.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_opacity.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_pagination.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_panels.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_progress-bar.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_reset-filter.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_resize.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_responsive-visibility.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_size.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_tab-focus.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_table-row.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_text-emphasis.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_text-overflow.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/4a3ee647961c7e45976eb2c0a94406aad3427b3d/_vendor-prefixes.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/93e201cf4a11978a1f491a057a3bd569c3825210/blacklight.css.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_alerts.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_badges.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_breadcrumbs.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_button-groups.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_buttons.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_carousel.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_close.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_code.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_component-animations.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_dropdowns.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_forms.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_glyphicons.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_grid.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_input-groups.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_jumbotron.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_labels.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_list-group.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_media.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_mixins.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_modals.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_navbar.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_navs.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_normalize.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_pager.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_pagination.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_panels.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_popovers.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_print.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_progress-bars.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_responsive-embed.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_responsive-utilities.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_scaffolding.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_tables.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_thumbnails.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_tooltip.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_type.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_utilities.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_variables.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/a1ec1bb9c9cafeb054d542e861ebc8ffd5904439/_wells.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/b28605b1c659cf09fc72f3c1fff32918869d28b8/_bootstrap-sprockets.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/b28605b1c659cf09fc72f3c1fff32918869d28b8/_bootstrap.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/ca8c12d03785e0d6cd4554f4d3939e7836d38282/_blacklight_base.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sass/ca8c12d03785e0d6cd4554f4d3939e7836d38282/blacklight.scssc +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/4052820c15af72ba690230a0f92bd75e +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/496a0d7dce1ff6bf4a9c3a089ea3a635 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/50b9db0b908b421a9b941a445dbaeacc +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/528c628cf107f8be6dd122e1154344be +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/8edfca9082e02111be92e79000667f22 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/90b54a819800edfa41b67722d1561040 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/9c653367feff82588eb6041d783a5809 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/b35e12934e9f05662777579549e31cd7 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/bb108ef3fc4c96d1c20cc41f97d943a0 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/dbba4bbc32c17ade3d618c5d0baeb371 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/e9f7ccc553ce1a217709cc7a08cfb032 +0 -0
- data/spec/internal/tmp/cache/assets/test/sprockets/f274b5f22db177b6464b50691d531688 +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5aa4fcca719417b8f265da3ee528f69d5fcbc3ec
|
4
|
+
data.tar.gz: d505e82b5881a9fae1e3f65b85b19157a6083bae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 197ad8e9e763ce9abb331dc57b9bca7a12103484107f6b27002adc946a8a5244eb27b1756e5dbf8e37881977a59a0ba541639c5485ed9ff11f55f3453362902f
|
7
|
+
data.tar.gz: 0c328d43f14401964ec57725850d813cf50892b6c11f3e71fc74c2fa318b8b96c83a8eec8dde3542211b9d70787eb6322ae8c7d4ddac8bee916fee6adf8aaca3
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
require 'thread'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module Krikri
|
9
|
+
##
|
10
|
+
# Helper class for fetching multiple URLs concurrently.
|
11
|
+
#
|
12
|
+
# @example to fetch 5 URLs in 5 threads
|
13
|
+
# urls = ['http://example.com/one',
|
14
|
+
# 'http://example.com/two',
|
15
|
+
# 'http://example.com/three',
|
16
|
+
# 'http://example.com/four',
|
17
|
+
# 'http://example.com/five']
|
18
|
+
# .map { |url| URI.parse(url) }
|
19
|
+
#
|
20
|
+
# getter = Krikri::AsyncUriGetter.new
|
21
|
+
#
|
22
|
+
# requests = urls.map do |url|
|
23
|
+
# getter.add_request(uri: url, opts: { follow_redirects: true })
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# At this point, 5 threads are launched to fetch the list of URLs. We can
|
27
|
+
# wait for them all to finish if we want to make sure we don't continue until
|
28
|
+
# all threads have terminated: `requests.map(&:join)`
|
29
|
+
#
|
30
|
+
# Or simply access the responses and have our current thread block until
|
31
|
+
# they're available:
|
32
|
+
#
|
33
|
+
# requests.each do |request|
|
34
|
+
# request.with_response do |response|
|
35
|
+
# if response.status == 200
|
36
|
+
# puts "Response body: #{response.body}"
|
37
|
+
# else
|
38
|
+
# puts "Got return status: #{response.status}"
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
class AsyncUriGetter
|
44
|
+
MAX_REDIRECTS = 10
|
45
|
+
|
46
|
+
##
|
47
|
+
# Create a new asynchronous URL fetcher.
|
48
|
+
#
|
49
|
+
# @param opts [Hash] a hash of the supported options, which are:
|
50
|
+
# @option opts [Boolean] :follow_redirects Whether to follow HTTP 3xx
|
51
|
+
# redirects.
|
52
|
+
# @option opts [Integer] :max_redirects Number of redirects to follow before
|
53
|
+
# giving up. (default: 10)
|
54
|
+
def initialize(opts: {})
|
55
|
+
@default_opts = { max_redirects: MAX_REDIRECTS }.merge(opts)
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Run a request (in a new thread) and return a promise-like object for the
|
60
|
+
# response.
|
61
|
+
#
|
62
|
+
# @param uri [URI] the URI to be fetched
|
63
|
+
# @param headers [Hash<String, String>] HTTP headers to include with the
|
64
|
+
# request
|
65
|
+
# @param opts [Hash] options to override the ones provided when
|
66
|
+
# AsyncUriGetter was initialized. All supported options from `#initialize`
|
67
|
+
# are available here as well.
|
68
|
+
def add_request(uri: nil, headers: {}, opts: {})
|
69
|
+
fail ArgumentError, "uri must be a URI; got: #{uri}" unless uri.is_a?(URI)
|
70
|
+
Request.new(uri, headers, @default_opts.merge(opts))
|
71
|
+
end
|
72
|
+
|
73
|
+
Request = Struct.new(:uri, :headers, :opts) do
|
74
|
+
def initialize(*)
|
75
|
+
super
|
76
|
+
@request_thread = start_request
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Wait for the request thread to complete
|
81
|
+
def join
|
82
|
+
@request_thread.join
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# @yield [Faraday::Response] the response returned for the request
|
87
|
+
def with_response
|
88
|
+
yield @request_thread.value
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
##
|
94
|
+
# Run the Faraday request in a new thread
|
95
|
+
def start_request
|
96
|
+
Thread.new do
|
97
|
+
http.get(uri) do |request|
|
98
|
+
headers.each { |header, val| request.headers[header.to_s] = val }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# @return [Faraday::Connection] a connection with sensible defaults
|
105
|
+
def http
|
106
|
+
@http ||= Faraday.new do |conn|
|
107
|
+
conn.request :retry,
|
108
|
+
max: 4,
|
109
|
+
interval: 0.025,
|
110
|
+
interval_randomness: 0.5,
|
111
|
+
backoff_factor: 2,
|
112
|
+
exceptions: [Faraday::ConnectionFailed,
|
113
|
+
'Errno::ETIMEDOUT',
|
114
|
+
'Timeout::Error',
|
115
|
+
'Error::TimeoutError',
|
116
|
+
Faraday::TimeoutError]
|
117
|
+
if opts.fetch(:follow_redirects, false)
|
118
|
+
conn.use(FaradayMiddleware::FollowRedirects,
|
119
|
+
limit: opts.fetch(:max_redirects))
|
120
|
+
end
|
121
|
+
|
122
|
+
conn.adapter Faraday.default_adapter
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/krikri/engine.rb
CHANGED
@@ -83,6 +83,12 @@ module Krikri
|
|
83
83
|
end
|
84
84
|
|
85
85
|
initializer :aggregation do
|
86
|
+
class NamespaceError < RuntimeError
|
87
|
+
def initialize(uri)
|
88
|
+
super("Tried to get DPLA ID for non-DPLA URI #{uri}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
86
92
|
DPLA::MAP::Aggregation.class_eval do
|
87
93
|
include Krikri::MapCrosswalk
|
88
94
|
include Krikri::LDP::RdfSource
|
@@ -124,6 +130,18 @@ module Krikri
|
|
124
130
|
.to_s)
|
125
131
|
end
|
126
132
|
|
133
|
+
##
|
134
|
+
# @return [String, nil] returns only the final portion of the URI (the
|
135
|
+
# "local name"), with the `#base_uri` removed. `nil` if this is a node
|
136
|
+
#
|
137
|
+
# @raise NamespaceError
|
138
|
+
def dpla_id
|
139
|
+
return nil if node?
|
140
|
+
raise NamespaceError, rdf_subject unless id.start_with?(base_uri)
|
141
|
+
|
142
|
+
id.gsub("#{base_uri}/", '')
|
143
|
+
end
|
144
|
+
|
127
145
|
private
|
128
146
|
|
129
147
|
def local_name_from_original_record
|
data/lib/krikri/ldp.rb
CHANGED
@@ -4,7 +4,8 @@ module Krikri
|
|
4
4
|
# As LDP support develops, it might be possible to excract this or replace it
|
5
5
|
# with a tool like the `ldp` gem.
|
6
6
|
module LDP
|
7
|
-
autoload :Resource,
|
8
|
-
autoload :RdfSource,
|
7
|
+
autoload :Resource, 'krikri/ldp/resource'
|
8
|
+
autoload :RdfSource, 'krikri/ldp/rdf_source'
|
9
|
+
autoload :Invalidatable, 'krikri/ldp/invalidatable'
|
9
10
|
end
|
10
11
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Krikri::LDP
|
2
|
+
##
|
3
|
+
# Implements invalidation for `Krikri::LDP::Resource`s. This is different
|
4
|
+
# from deletion, in that the resource continues to respond `200 OK`, and
|
5
|
+
# return the representation, Nothing is removed from the LDP server.
|
6
|
+
#
|
7
|
+
# Works as a mixin to `Krikri::LDP::Resource`, assuming an implementation of
|
8
|
+
# `#rdf_source`, which may simply return `self`.
|
9
|
+
#
|
10
|
+
# @example invalidating a resource
|
11
|
+
# class MyResource
|
12
|
+
# include Krikri::LDP::Resource
|
13
|
+
# include Krikri::LDP::Invalidatable
|
14
|
+
#
|
15
|
+
# def rdf_subject
|
16
|
+
# @rdf_subject ||= RDF::URI('http://example.com/ldp/a/resource/path')
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# invalidatable_resource = MyResource.new
|
21
|
+
# # the resource must exist before it can be invalidated!
|
22
|
+
# invalidatable_resource.save
|
23
|
+
#
|
24
|
+
# invalidatable_resource.invalidate!
|
25
|
+
# invalidatable_resource.invalidated? # => true
|
26
|
+
# invalidatable_resource.invalidated_at_time
|
27
|
+
# # => Thu, 03 Dec 2015 10:27:45 -0800
|
28
|
+
#
|
29
|
+
# @see http://www.w3.org/TR/2013/REC-prov-dm-20130430/#term-Invalidation
|
30
|
+
# for documentation on PROV invalidation
|
31
|
+
module Invalidatable
|
32
|
+
# @see RDF::PROV
|
33
|
+
INVALIDATED_BY_URI = RDF::PROV.wasInvalidatedBy
|
34
|
+
INVALIDATED_TIME_URI = RDF::PROV.invalidatedAtTime
|
35
|
+
|
36
|
+
##
|
37
|
+
# Invalidates the resource by marking it with a `prov:invalidatedAtTime`. If
|
38
|
+
# an `RDF::Term` is passed as the first argument, that term is used as the
|
39
|
+
# value of `prov:wasInvalidatedBy`.
|
40
|
+
#
|
41
|
+
# @example invalidating with an activity
|
42
|
+
# invalidatable_resource.invalidate!(RDF::URI('http://example.org/moomin'))
|
43
|
+
# invalidatable_resource.was_invalidated_by
|
44
|
+
# # => #<RDF::URI:0x2acab846109c URI:http://example.org/moomin>
|
45
|
+
#
|
46
|
+
# @param activity_uri [RDF::Term] a URI for the invalidating activity. If
|
47
|
+
# none is given, this defaults to `nil` and no `prov:wasInvalidatedBy`
|
48
|
+
# statement is added.
|
49
|
+
# @param ignore_invalid [Boolean] if true, supresses errors on already,
|
50
|
+
# invalid records
|
51
|
+
#
|
52
|
+
# @raise [RuntimeError] when the resource does not exist or is already
|
53
|
+
# invalid; unless `ignore_invalid` is `true`
|
54
|
+
# @return [void]
|
55
|
+
def invalidate!(activity_uri = nil, ignore_invalid = false)
|
56
|
+
raise "Cannot invalidate #{rdf_subject}, does not exist." unless exists?
|
57
|
+
|
58
|
+
# force a reload unless we have cached an invalidatedAtTime
|
59
|
+
rdf_source.get({}, true) unless invalidated?
|
60
|
+
# we check invalidated again in case the reload came back invalid
|
61
|
+
if invalidated?
|
62
|
+
return if ignore_invalid
|
63
|
+
raise "Cannot invalidate #{rdf_subject}, already invalid."
|
64
|
+
end
|
65
|
+
|
66
|
+
uri = RDF::URI(rdf_subject)
|
67
|
+
|
68
|
+
rdf_source << [uri, INVALIDATED_BY_URI, activity_uri] unless
|
69
|
+
activity_uri.nil?
|
70
|
+
rdf_source << [uri, INVALIDATED_TIME_URI, DateTime.now]
|
71
|
+
|
72
|
+
rdf_source.save
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# @return [Boolean] `true` if the resource has been marked invalidated.
|
77
|
+
def invalidated?
|
78
|
+
!invalidated_at_time.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# @return [DateTime, nil] the time this resource was marked invalidated;
|
83
|
+
# gives `nil` if the resource has not been invalidated.
|
84
|
+
#
|
85
|
+
# @note if two invalidatedAtTimes exist, we may get either of them back!
|
86
|
+
def invalidated_at_time
|
87
|
+
time = first_property(INVALIDATED_TIME_URI)
|
88
|
+
time.nil? ? nil : time.object
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# @return [RDF::URI, nil] the activity responsible for invalidating the
|
93
|
+
# resource
|
94
|
+
#
|
95
|
+
# @note if two wasInvalidatedBys exist, we may get either of them back!
|
96
|
+
def was_invalidated_by
|
97
|
+
first_property(INVALIDATED_BY_URI)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def first_property(predicate)
|
103
|
+
res = rdf_source.query([RDF::URI(rdf_subject), predicate, nil])
|
104
|
+
res.empty? ? nil : res.first.object
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -7,13 +7,26 @@ module Krikri::LDP
|
|
7
7
|
module RdfSource
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
include Krikri::LDP::Resource
|
10
|
+
include Krikri::LDP::Invalidatable
|
11
|
+
|
12
|
+
GENERATED_URI = RDF::PROV.wasGeneratedBy
|
13
|
+
REVISED_URI = RDF::DPLA.wasRevisedBy
|
14
|
+
|
15
|
+
##
|
16
|
+
# @return [Boolean] false if this resource does not ex
|
17
|
+
# @see Krikri::LDP::Resource#exists?
|
18
|
+
def exists?
|
19
|
+
return false if node?
|
20
|
+
super
|
21
|
+
end
|
22
|
+
alias_method :exist?, :exists?
|
10
23
|
|
11
24
|
##
|
12
25
|
# PUTs the LDP resource named in #rdf_subject, populating it's content
|
13
26
|
# (graph) from the object's RDF::Graph.
|
14
27
|
#
|
15
28
|
# @see Krikri::LDP::Resource#save
|
16
|
-
# @note this may leave the resource's graph out of sync with the LDP
|
29
|
+
# @note this may leave the resource's graph out of sync with the LDP
|
17
30
|
# endpoint since the endpoint may add management triples when saving.
|
18
31
|
def save(*)
|
19
32
|
result = super(dump(:ttl))
|
@@ -21,14 +34,14 @@ module Krikri::LDP
|
|
21
34
|
end
|
22
35
|
|
23
36
|
##
|
24
|
-
# Saves and forces reload. This updates the graph with any management
|
37
|
+
# Saves and forces reload. This updates the graph with any management
|
25
38
|
# triples added by the LDP endpoint.
|
26
39
|
#
|
27
40
|
# @see #save
|
28
41
|
def save_and_reload(*args)
|
29
42
|
result = save(*args)
|
30
43
|
get({}, true)
|
31
|
-
result
|
44
|
+
result
|
32
45
|
end
|
33
46
|
|
34
47
|
##
|
@@ -42,6 +55,12 @@ module Krikri::LDP
|
|
42
55
|
result
|
43
56
|
end
|
44
57
|
|
58
|
+
##
|
59
|
+
# @return [self]
|
60
|
+
def rdf_source
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
45
64
|
##
|
46
65
|
# Adds an appropritate provenance statement with the given URI and saves
|
47
66
|
# the resource.
|
@@ -64,8 +83,7 @@ module Krikri::LDP
|
|
64
83
|
# @see http://www.w3.org/TR/prov-primer/
|
65
84
|
# @see http://www.w3.org/TR/2013/REC-prov-o-20130430/
|
66
85
|
def save_with_provenance(activity_uri)
|
67
|
-
predicate =
|
68
|
-
exists? ? RDF::DPLA.wasRevisedBy : RDF::PROV.wasGeneratedBy
|
86
|
+
predicate = exists? ? REVISED_URI : GENERATED_URI
|
69
87
|
self << RDF::Statement(self, predicate, activity_uri)
|
70
88
|
save
|
71
89
|
end
|
@@ -75,7 +93,7 @@ module Krikri::LDP
|
|
75
93
|
##
|
76
94
|
# Clears the RDF::Graph and repopulates it from the http body. Forces text
|
77
95
|
# encoding to UTF-8 before passing to the `RDF::Reader`.
|
78
|
-
#
|
96
|
+
#
|
79
97
|
# @return [void]
|
80
98
|
#
|
81
99
|
# @see http://www.w3.org/TR/turtle/#sec-mime for info about Turtle encoding
|
data/lib/krikri/ldp/resource.rb
CHANGED
@@ -3,7 +3,28 @@ require 'faraday_middleware'
|
|
3
3
|
|
4
4
|
module Krikri::LDP
|
5
5
|
##
|
6
|
-
# Implements basic LDP CRUD operations
|
6
|
+
# Implements basic LDP CRUD operations. Requires an implementation of
|
7
|
+
# `#rdf_subject` returning an `RDF::URI`. The resource idenitified by the URI
|
8
|
+
# must conform to LDP Resource's interaction patterns.
|
9
|
+
#
|
10
|
+
# @example implementing a resource
|
11
|
+
# class MyResource
|
12
|
+
# include Krikri::LDP::Resource
|
13
|
+
#
|
14
|
+
# def rdf_subject
|
15
|
+
# @rdf_subject ||= RDF::URI('http://example.com/ldp/a/resource/path')
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @note Ideally, this is a general purpose LDP resource. However some HTTP
|
20
|
+
# PUT creation behavior may be specific to Marmotta. This avoids the need to
|
21
|
+
# interact directly with the owning container, but is a less generalized
|
22
|
+
# implementation.
|
23
|
+
#
|
24
|
+
# @see http://www.w3.org/TR/ldp/#h-ldpr-resource LDP Resource interaction
|
25
|
+
# patterns.
|
26
|
+
# @see https://wiki.apache.org/marmotta/LDPImplementationReport for
|
27
|
+
# information about Marmotta's PUT.
|
7
28
|
module Resource
|
8
29
|
extend ActiveSupport::Concern
|
9
30
|
|
data/lib/krikri/map_crosswalk.rb
CHANGED
@@ -134,7 +134,6 @@ module Krikri
|
|
134
134
|
|
135
135
|
set_value(sr, :relation, parent_sr.relation)
|
136
136
|
set_value(sr, :rights, parent_sr.rights, true)
|
137
|
-
set_value(sr, :temporal, parent_sr.temporal)
|
138
137
|
set_value(sr, :title, parent_sr.title)
|
139
138
|
|
140
139
|
set_value(sr, :collection, parent_sr.collection) do |coll|
|
@@ -149,6 +148,10 @@ module Krikri
|
|
149
148
|
build_time_span(date)
|
150
149
|
end
|
151
150
|
|
151
|
+
set_value(sr, :temporal, parent_sr.temporal) do |temporal|
|
152
|
+
build_time_span(temporal)
|
153
|
+
end
|
154
|
+
|
152
155
|
set_value(sr, :spatial, parent_sr.spatial) do |place|
|
153
156
|
build_place(place)
|
154
157
|
end
|
@@ -173,7 +176,7 @@ module Krikri
|
|
173
176
|
def build_time_span(source)
|
174
177
|
return unless source.is_a? DPLA::MAP::TimeSpan
|
175
178
|
date = {}
|
176
|
-
date
|
179
|
+
set_value(date, :displayDate, source.prefLabel, true, &:as_json)
|
177
180
|
set_value(date, :begin, source.begin, true, &:as_json)
|
178
181
|
set_value(date, :end, source.end, true, &:as_json)
|
179
182
|
|
data/lib/krikri/version.rb
CHANGED
data/spec/internal/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: /home/tjohnson/src/dpla/krikri
|
3
3
|
specs:
|
4
|
-
krikri (0.10.
|
4
|
+
krikri (0.10.1)
|
5
5
|
analysand (= 4.0.0)
|
6
6
|
audumbla (~> 0.1)
|
7
7
|
blacklight (~> 5.8.0)
|
@@ -152,8 +152,8 @@ GEM
|
|
152
152
|
domain_name (~> 0.5)
|
153
153
|
http_parser.rb (0.6.0)
|
154
154
|
i18n (0.7.0)
|
155
|
-
jbuilder (2.
|
156
|
-
activesupport (>= 3.0.0, < 5)
|
155
|
+
jbuilder (2.4.0)
|
156
|
+
activesupport (>= 3.0.0, < 5.1)
|
157
157
|
multi_json (~> 1.2)
|
158
158
|
jettywrapper (2.0.3)
|
159
159
|
activesupport (>= 3.0.0)
|
@@ -242,7 +242,7 @@ GEM
|
|
242
242
|
activesupport (= 4.1.6)
|
243
243
|
rake (>= 0.8.7)
|
244
244
|
thor (>= 0.18.1, < 2.0)
|
245
|
-
rake (10.
|
245
|
+
rake (10.5.0)
|
246
246
|
rdf (1.1.17.1)
|
247
247
|
link_header (~> 0.0, >= 0.0.8)
|
248
248
|
rdf-aggregate-repo (1.1.0.1)
|