linked_rails 0.0.4.pre.g2c53724b3 → 0.0.4.pre.g3aeec2263
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/linked_rails/bulk_controller.rb +42 -2
- data/app/models/linked_rails/actions/item.rb +12 -4
- data/app/models/linked_rails/actions/object.rb +6 -3
- data/app/models/linked_rails/collection/view.rb +9 -8
- data/app/models/linked_rails/form/field/file_input.rb +5 -1
- data/app/models/linked_rails/form/field_factory.rb +1 -7
- data/app/models/linked_rails/form.rb +2 -1
- data/app/models/linked_rails/manifest.rb +26 -10
- data/app/models/linked_rails/menus/item.rb +1 -1
- data/app/models/linked_rails/menus/list.rb +15 -4
- data/app/models/linked_rails/ontology.rb +1 -0
- data/app/policies/linked_rails/collection_policy.rb +1 -0
- data/app/policies/linked_rails/form_policy.rb +13 -0
- data/app/policies/linked_rails/ontology_policy.rb +13 -0
- data/app/serializers/linked_rails/collection/view_serializer.rb +1 -0
- data/app/serializers/linked_rails/collection_serializer.rb +1 -0
- data/app/workers/linked_rails/invalidation_stream_worker.rb +16 -0
- data/lib/generators/linked_rails/install/templates/locales.yml +2 -0
- data/lib/linked_rails/controller/error_handling.rb +5 -0
- data/lib/linked_rails/errors/forbidden.rb +38 -0
- data/lib/linked_rails/errors.rb +3 -0
- data/lib/linked_rails/helpers/delta_helper.rb +3 -1
- data/lib/linked_rails/helpers/resource_helper.rb +11 -1
- data/lib/linked_rails/iri_mapper.rb +1 -1
- data/lib/linked_rails/model/cacheable.rb +45 -0
- data/lib/linked_rails/model/collections.rb +5 -1
- data/lib/linked_rails/model/iri.rb +8 -2
- data/lib/linked_rails/model/menuable.rb +3 -3
- data/lib/linked_rails/model.rb +1 -0
- data/lib/linked_rails/params_parser.rb +14 -4
- data/lib/linked_rails/policy.rb +4 -0
- data/lib/linked_rails/serializer/actionable.rb +3 -3
- data/lib/linked_rails/serializer.rb +7 -1
- data/lib/linked_rails/storage.rb +32 -0
- data/lib/linked_rails/url.rb +11 -0
- data/lib/linked_rails.rb +11 -2
- metadata +10 -3
- data/app/serializers/linked_rails/actions/object_serializer.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ce41ff4f34f22c35a736959cad35b9a42f3f03938449f918bf492907cdc6337
|
4
|
+
data.tar.gz: 86ab4fec516df9fc474a637e6ada4b6466abdbc03b565bbc46d0942026a89cac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4ab1bb7933a05fc0377f588ff8fa6340470341f0a45c977008a0fa2b3c226db5da304449b4da5a8fe20da66bc544e3928ce8aaa02d228b0ff9b6f50ed25075c
|
7
|
+
data.tar.gz: 0b9c3322d6fb05f2f18e8e777661b276cf9c68c4c540a5b7a66837412888c0876e19d923744d93bc10830d565af5ac0ca458da63ab5aa344ca0f645a221c8949
|
@@ -21,8 +21,11 @@ module LinkedRails
|
|
21
21
|
return response_for_wrong_host(opts) if wrong_host?(opts[:iri])
|
22
22
|
|
23
23
|
include = opts[:include].to_s == 'true'
|
24
|
+
resource = LinkedRails.iri_mapper.resource_from_iri(request_path_to_url(opts[:iri]), user_context)
|
24
25
|
|
25
|
-
response_from_request(include, RDF::URI(opts[:iri]))
|
26
|
+
return response_from_request(include, RDF::URI(opts[:iri])) if resource.blank?
|
27
|
+
|
28
|
+
response_from_resource(include, opts[:iri], resource)
|
26
29
|
rescue StandardError => e
|
27
30
|
handle_resource_error(opts, e)
|
28
31
|
end
|
@@ -84,10 +87,19 @@ module LinkedRails
|
|
84
87
|
false
|
85
88
|
end
|
86
89
|
|
90
|
+
def resource_cache_control(cacheable, status, resource_policy)
|
91
|
+
return :private unless status == 200 && cacheable
|
92
|
+
return 'no-cache' unless resource_policy.try(:public_resource?)
|
93
|
+
|
94
|
+
:public
|
95
|
+
end
|
96
|
+
|
87
97
|
def resource_params(param)
|
88
98
|
params = param.permit(:include, :iri)
|
89
99
|
params[:iri] = URI(params[:iri])
|
90
100
|
params
|
101
|
+
rescue URI::InvalidURIError
|
102
|
+
params.except(:iri)
|
91
103
|
end
|
92
104
|
|
93
105
|
def resource_response_body(iri, rack_body, status)
|
@@ -131,6 +143,17 @@ module LinkedRails
|
|
131
143
|
}.merge(opts)
|
132
144
|
end
|
133
145
|
|
146
|
+
def resource_status(resource_policy)
|
147
|
+
return 200 if resource_policy.show?
|
148
|
+
|
149
|
+
raise(
|
150
|
+
LinkedRails::Errors::Forbidden.new(
|
151
|
+
action_status: resource_policy.try(:action_status),
|
152
|
+
query: :show?
|
153
|
+
)
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
134
157
|
def response_for_wrong_host(opts)
|
135
158
|
iri = opts[:iri]
|
136
159
|
term = term_from_vocab(iri)
|
@@ -139,6 +162,23 @@ module LinkedRails
|
|
139
162
|
ontology_term_response(iri, term, opts[:include])
|
140
163
|
end
|
141
164
|
|
165
|
+
def response_from_resource(include, iri, resource)
|
166
|
+
resource_policy = policy(resource)
|
167
|
+
status = resource_status(resource_policy)
|
168
|
+
|
169
|
+
resource_response(
|
170
|
+
iri,
|
171
|
+
body: response_from_resource_body(include, iri, resource, status),
|
172
|
+
cache: resource_cache_control(resource.try(:cacheable?), status, resource_policy),
|
173
|
+
language: I18n.locale,
|
174
|
+
status: status
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
def response_from_resource_body(include, _iri, resource, status)
|
179
|
+
include && status == 200 ? resource_body(resource) : nil
|
180
|
+
end
|
181
|
+
|
142
182
|
def term_from_vocab(iri)
|
143
183
|
vocab = Vocab.for(iri)
|
144
184
|
tag = iri.to_s.split(vocab.to_s).last
|
@@ -216,7 +256,7 @@ module LinkedRails
|
|
216
256
|
|
217
257
|
def sanitized_relative_path(iri) # rubocop:disable Metrics/AbcSize
|
218
258
|
iri.path = "#{iri.path}/" unless iri.path&.ends_with?('/')
|
219
|
-
uri = URI(LinkedRails.iri.path.present? ? iri.to_s.split("#{LinkedRails.iri.path}/").last : iri)
|
259
|
+
uri = URI(LinkedRails.iri.path.chomp('/').present? ? iri.to_s.split("#{LinkedRails.iri.path}/").last : iri)
|
220
260
|
|
221
261
|
[uri.path, uri.query].compact.join('?')
|
222
262
|
end
|
@@ -61,15 +61,17 @@ module LinkedRails
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def object
|
64
|
-
|
65
|
-
|
66
|
-
@object || resource
|
64
|
+
object_from_var || resource
|
67
65
|
end
|
68
66
|
|
69
67
|
def object_iri
|
70
68
|
object&.iri&.anonymous? ? anonymous_object_iri : object&.iri
|
71
69
|
end
|
72
70
|
|
71
|
+
def object_root_relative_iri
|
72
|
+
RDF::URI(object_iri.to_s.split(LinkedRails.iri.to_s).second)
|
73
|
+
end
|
74
|
+
|
73
75
|
def parent
|
74
76
|
return @parent if instance_variable_defined?(:@parent)
|
75
77
|
|
@@ -152,6 +154,12 @@ module LinkedRails
|
|
152
154
|
LinkedRails.translate(:action, :label, self)
|
153
155
|
end
|
154
156
|
|
157
|
+
def object_from_var
|
158
|
+
return @object unless @object.respond_to?(:call)
|
159
|
+
|
160
|
+
@object = list.instance_exec(&@object)
|
161
|
+
end
|
162
|
+
|
155
163
|
def policy_expired?
|
156
164
|
@policy_expired ||= policy && resource_policy.try(:expired?)
|
157
165
|
end
|
@@ -187,7 +195,7 @@ module LinkedRails
|
|
187
195
|
|
188
196
|
def target_url_fallback # rubocop:disable Metrics/AbcSize
|
189
197
|
base = (resource.try(:singular_resource?) ? resource.singular_iri : resource.iri).dup
|
190
|
-
base.path = "#{base.path}/#{target_path}" if target_path.present?
|
198
|
+
base.path = "#{base.path.chomp('/')}/#{target_path}" if target_path.present?
|
191
199
|
base.query = Rack::Utils.parse_nested_query(base.query).merge(target_query).to_param if target_query.present?
|
192
200
|
base
|
193
201
|
end
|
@@ -12,8 +12,8 @@ module LinkedRails
|
|
12
12
|
alias parent action
|
13
13
|
delegate :object, to: :action
|
14
14
|
|
15
|
-
def
|
16
|
-
action.
|
15
|
+
def root_relative_iri
|
16
|
+
action.object_root_relative_iri
|
17
17
|
end
|
18
18
|
|
19
19
|
class << self
|
@@ -30,7 +30,10 @@ module LinkedRails
|
|
30
30
|
|
31
31
|
parent = parent_from_params!(params, user_context)
|
32
32
|
|
33
|
-
|
33
|
+
object = parent&.object
|
34
|
+
object.instance_variable_set(:@iri, parent.object_iri)
|
35
|
+
object.instance_variable_set(:@root_relative_iri, parent.object_root_relative_iri)
|
36
|
+
object
|
34
37
|
end
|
35
38
|
end
|
36
39
|
end
|
@@ -8,8 +8,9 @@ module LinkedRails
|
|
8
8
|
include LinkedRails::Model
|
9
9
|
|
10
10
|
attr_accessor :collection, :filter
|
11
|
-
delegate :apply_scope, :association_base, :association_class, :
|
12
|
-
:parent, :policy, :total_page_count, :unfiltered_collection, :user_context,
|
11
|
+
delegate :apply_scope, :association_base, :association_class, :child_resource, :default_page_size, :display,
|
12
|
+
:include_members,:parent, :policy, :total_page_count, :unfiltered_collection, :user_context,
|
13
|
+
to: :collection
|
13
14
|
delegate :count, to: :members
|
14
15
|
|
15
16
|
alias id iri
|
@@ -42,7 +43,7 @@ module LinkedRails
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def preview_includes
|
45
|
-
include_members ? {member_sequence: :members} : %i[member_sequence]
|
46
|
+
include_members ? {members: {}, member_sequence: :members} : %i[member_sequence]
|
46
47
|
end
|
47
48
|
|
48
49
|
def title
|
@@ -75,19 +76,19 @@ module LinkedRails
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def iris_from_scope?
|
78
|
-
members_query.is_a?(ActiveRecord::Relation) && !polymorphic_collection?
|
79
|
+
members_query.is_a?(ActiveRecord::Relation) && !polymorphic_collection?(members_query.klass)
|
79
80
|
end
|
80
81
|
|
81
82
|
def members_array
|
82
83
|
members_query.to_a
|
83
84
|
end
|
84
85
|
|
85
|
-
def polymorphic_collection?
|
86
|
-
column =
|
87
|
-
polymorphic =
|
86
|
+
def polymorphic_collection?(klass)
|
87
|
+
column = klass.inheritance_column
|
88
|
+
polymorphic = klass.columns_hash.include?(column)
|
88
89
|
return false unless polymorphic
|
89
90
|
|
90
|
-
return true if
|
91
|
+
return true if klass.descends_from_active_record?
|
91
92
|
|
92
93
|
members_query.where_values_hash.include?(column) &&
|
93
94
|
members_query.where_values_hash[column] != association_class.to_s
|
@@ -52,13 +52,7 @@ module LinkedRails
|
|
52
52
|
private
|
53
53
|
|
54
54
|
def attr_column(name)
|
55
|
-
|
56
|
-
if model_class.is_delegated_attribute?(name)
|
57
|
-
model_class.class_for_delegated_attribute(name)
|
58
|
-
else
|
59
|
-
model_class
|
60
|
-
end
|
61
|
-
column_model.column_for_attribute(name)
|
55
|
+
model_class.column_for_attribute(name)
|
62
56
|
end
|
63
57
|
|
64
58
|
def attr_to_datatype # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
@@ -5,6 +5,7 @@ require 'pundit'
|
|
5
5
|
module LinkedRails
|
6
6
|
class Form # rubocop:disable Metrics/ClassLength
|
7
7
|
include LinkedRails::Model
|
8
|
+
include LinkedRails::Model::Cacheable
|
8
9
|
|
9
10
|
class_attribute :abstract_form, :pages, :model_class
|
10
11
|
|
@@ -119,7 +120,7 @@ module LinkedRails
|
|
119
120
|
|
120
121
|
def has_many(key, **opts)
|
121
122
|
opts[:input_field] = Form::Field::AssociationInput
|
122
|
-
opts[:max_count]
|
123
|
+
opts[:max_count] ||= 99
|
123
124
|
field(key, **opts)
|
124
125
|
end
|
125
126
|
|
@@ -5,15 +5,11 @@ module LinkedRails
|
|
5
5
|
include ActiveModel::Model
|
6
6
|
include LinkedRails::Model
|
7
7
|
|
8
|
-
MANIFEST_KEY = 'cache:Manifest'
|
9
|
-
CACHE_DB = ENV.fetch('PERSISTENT_REDIS_DATABASE', '6')
|
10
|
-
|
11
8
|
def save
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}
|
9
|
+
Storage.hset(
|
10
|
+
:persistent,
|
11
|
+
:manifest,
|
12
|
+
URL.as_href(LinkedRails.iri) => web_manifest.to_json
|
17
13
|
)
|
18
14
|
end
|
19
15
|
|
@@ -45,7 +41,7 @@ module LinkedRails
|
|
45
41
|
def blob_preview_iri
|
46
42
|
return unless ActiveStorage::Blob.service.present?
|
47
43
|
|
48
|
-
LinkedRails.iri(path: 'rails/active_storage/blobs/redirect/{signed_id}/preview
|
44
|
+
"#{LinkedRails.iri(path: 'rails/active_storage/blobs/redirect')}/{signed_id}/preview"
|
49
45
|
end
|
50
46
|
|
51
47
|
def blob_upload_iri
|
@@ -142,7 +138,7 @@ module LinkedRails
|
|
142
138
|
|
143
139
|
def web_manifest_sw_section
|
144
140
|
{
|
145
|
-
src: "#{scope}/sw.js",
|
141
|
+
src: "#{scope.chomp('/')}/sw.js",
|
146
142
|
scope: scope
|
147
143
|
}
|
148
144
|
end
|
@@ -162,5 +158,25 @@ module LinkedRails
|
|
162
158
|
def tracking
|
163
159
|
[]
|
164
160
|
end
|
161
|
+
|
162
|
+
class << self
|
163
|
+
def destroy(iri)
|
164
|
+
Storage.hdel(:persistent, :manifest, URL.as_href(iri))
|
165
|
+
end
|
166
|
+
|
167
|
+
def move(from, to)
|
168
|
+
Storage.hset(
|
169
|
+
:persistent,
|
170
|
+
:redirect_prefix,
|
171
|
+
URL.as_href(from) => URL.as_href(to)
|
172
|
+
)
|
173
|
+
|
174
|
+
data = Storage.hget(:persistent, :manifest, URL.as_href(from))
|
175
|
+
|
176
|
+
Storage.hset(:persistent, :manifest, URL.as_href(to), data) if data
|
177
|
+
|
178
|
+
destroy(from)
|
179
|
+
end
|
180
|
+
end
|
165
181
|
end
|
166
182
|
end
|
@@ -26,7 +26,7 @@ module LinkedRails
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def menus
|
29
|
-
@menus ||= available_menus.map(&method(:
|
29
|
+
@menus ||= available_menus.map(&method(:memoized_menu_item))
|
30
30
|
end
|
31
31
|
|
32
32
|
def menu(tag)
|
@@ -49,9 +49,8 @@ module LinkedRails
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def menu_item(tag, options) # rubocop:disable Metrics/AbcSize
|
52
|
-
|
53
|
-
|
54
|
-
end
|
52
|
+
return unless show_menu_item?(tag, options)
|
53
|
+
|
55
54
|
options[:label_params] ||= {}
|
56
55
|
options[:label_params][:default] ||= ["menus.default.#{tag}".to_sym, tag.to_s.capitalize]
|
57
56
|
options[:label] ||= default_label(tag, options)
|
@@ -60,6 +59,10 @@ module LinkedRails
|
|
60
59
|
LinkedRails.menus_item_class.new(resource: resource, tag: tag, parent: self, **options)
|
61
60
|
end
|
62
61
|
|
62
|
+
def policy_verdict(policy, options)
|
63
|
+
policy.send(options[:policy], *options[:policy_arguments])
|
64
|
+
end
|
65
|
+
|
63
66
|
def resource_policy(policy_resource)
|
64
67
|
policy_resource ||= resource
|
65
68
|
policy_resource = instance_exec(&policy_resource) if policy_resource.respond_to?(:call)
|
@@ -69,6 +72,14 @@ module LinkedRails
|
|
69
72
|
@resource_policy[policy_resource] ||= Pundit.policy(user_context, policy_resource)
|
70
73
|
end
|
71
74
|
|
75
|
+
def show_menu_item?(_tag, options)
|
76
|
+
return true if options[:policy].blank?
|
77
|
+
|
78
|
+
policy = resource_policy(options[:policy_resource])
|
79
|
+
|
80
|
+
policy_verdict(policy, options)
|
81
|
+
end
|
82
|
+
|
72
83
|
def iri_template
|
73
84
|
base_template = resource.send(resource.try(:singular_resource?) ? :singular_iri_template : :iri_template)
|
74
85
|
|
@@ -13,6 +13,7 @@ module LinkedRails
|
|
13
13
|
end
|
14
14
|
attribute :serialized_iri_template, predicate: Vocab.ontola[:iriTemplate]
|
15
15
|
attribute :iri_template_opts, predicate: Vocab.ontola[:iriTemplateOpts]
|
16
|
+
attribute :download_urls, predicate: Vocab.schema.downloadUrl
|
16
17
|
attribute :default_type, predicate: Vocab.ontola[:defaultType], &:type
|
17
18
|
attribute :display, predicate: Vocab.ontola[:collectionDisplay] do |object|
|
18
19
|
Vocab.ontola["collectionDisplay/#{object.display || :default}"]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
class InvalidationStreamWorker < ActiveJob::Base
|
5
|
+
def perform(type, iri, resource_type)
|
6
|
+
entry = {
|
7
|
+
type: type,
|
8
|
+
resource: iri,
|
9
|
+
resourceType: resource_type
|
10
|
+
}
|
11
|
+
id = Storage.xadd(:stream, LinkedRails.cache_stream, entry)
|
12
|
+
|
13
|
+
raise('No message id returned, implies failure') if id.blank?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -6,6 +6,10 @@ module LinkedRails
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
include ActiveSupport::Rescuable
|
8
8
|
|
9
|
+
included do
|
10
|
+
rescue_from LinkedRails::Errors::Forbidden, with: :handle_error
|
11
|
+
end
|
12
|
+
|
9
13
|
private
|
10
14
|
|
11
15
|
def add_error_snackbar(error)
|
@@ -69,6 +73,7 @@ module LinkedRails
|
|
69
73
|
'Doorkeeper::Errors::InvalidGrantReuse' => 422,
|
70
74
|
'LinkedRails::Auth::Errors::Expired' => 410,
|
71
75
|
'LinkedRails::Auth::Errors::Unauthorized' => 401,
|
76
|
+
'LinkedRails::Errors::Forbidden' => 403,
|
72
77
|
'Pundit::NotAuthorizedError' => 403
|
73
78
|
}
|
74
79
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Errors
|
5
|
+
class Forbidden < StandardError
|
6
|
+
attr_reader :query, :record, :policy, :action, :action_status
|
7
|
+
|
8
|
+
# @param [Hash] options
|
9
|
+
# @option options [String] query The action of the request
|
10
|
+
# @option options [ActiveRecord::Base] record The record that was requested
|
11
|
+
# @option options [Policy] policy The policy that raised the exception
|
12
|
+
# @option options [String] message Override the default error message
|
13
|
+
# @return [String] the message
|
14
|
+
def initialize(**options)
|
15
|
+
@query = options.fetch(:query).to_s
|
16
|
+
@record = options[:record]
|
17
|
+
@policy = options[:policy]
|
18
|
+
@action = @query[-1] == '?' ? @query[0..-2] : @query
|
19
|
+
@action_status = options[:action_status]
|
20
|
+
@message = options[:message]
|
21
|
+
|
22
|
+
raise StandardError if @query.blank? && @message.blank?
|
23
|
+
|
24
|
+
super(@message || default_message)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def default_message
|
30
|
+
I18n.t(
|
31
|
+
"pundit.#{@policy.class.to_s.underscore}.#{@query}",
|
32
|
+
action: @action,
|
33
|
+
default: I18n.t('errors.access_denied')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -8,7 +8,9 @@ module LinkedRails
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def invalidate_collection_delta(collection)
|
11
|
-
|
11
|
+
iri = collection.is_a?(RDF::Resource) ? collection : collection.iri
|
12
|
+
|
13
|
+
[Vocab.sp[:Variable], Vocab.ontola[:baseCollection], iri, delta_iri(:invalidate)]
|
12
14
|
end
|
13
15
|
|
14
16
|
def invalidate_parent_collections_delta(resource)
|
@@ -46,12 +46,22 @@ module LinkedRails
|
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
+
def request_path_to_url(path)
|
50
|
+
return path unless path.present? && URI(path).relative?
|
51
|
+
|
52
|
+
port = [80, 443].include?(request.port) ? nil : request.port
|
53
|
+
URI::Generic.new(request.scheme, nil, request.host, port, nil, path, nil, nil, nil).to_s
|
54
|
+
end
|
55
|
+
|
49
56
|
def build_new_resource
|
50
57
|
controller_class.build_new(user_context: user_context)
|
51
58
|
end
|
52
59
|
|
53
60
|
def new_resource_from_parent
|
54
|
-
|
61
|
+
if requested_resource.is_a?(LinkedRails.collection_class) ||
|
62
|
+
requested_resource.is_a?(LinkedRails.collection_view_class)
|
63
|
+
return requested_resource.child_resource
|
64
|
+
end
|
55
65
|
|
56
66
|
parent_resource.build_child(
|
57
67
|
controller_class,
|
@@ -38,7 +38,7 @@ module LinkedRails
|
|
38
38
|
params = Rails.application.routes.recognize_path(iri.to_s, method: method)
|
39
39
|
|
40
40
|
route_params_to_opts(params.merge(query), iri.to_s)
|
41
|
-
rescue ActionController::RoutingError
|
41
|
+
rescue ActionController::RoutingError, SystemStackError
|
42
42
|
EMPTY_IRI_OPTS.dup
|
43
43
|
end
|
44
44
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Model
|
5
|
+
module Cacheable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
if respond_to?(:after_commit)
|
10
|
+
after_commit :publish_create, on: :create, if: :should_publish_changes
|
11
|
+
after_commit :publish_update, on: :update, if: :should_publish_changes
|
12
|
+
after_commit :publish_delete, on: :destroy, if: :should_publish_changes
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def cacheable?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def publish_create
|
21
|
+
publish_message('io.ontola.transactions.Created')
|
22
|
+
end
|
23
|
+
|
24
|
+
def publish_update
|
25
|
+
publish_message('io.ontola.transactions.Updated')
|
26
|
+
end
|
27
|
+
|
28
|
+
def publish_delete
|
29
|
+
publish_message('io.ontola.transactions.Deleted')
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def publish_message(type)
|
35
|
+
LinkedRails::InvalidationStreamWorker.perform_now(type, iri.to_s, self.class.iri.to_s)
|
36
|
+
rescue StandardError
|
37
|
+
LinkedRails::InvalidationStreamWorker.perform_later(type, iri.to_s, self.class.iri.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def should_publish_changes
|
41
|
+
cacheable? && !Rails.env.test?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -46,6 +46,8 @@ module LinkedRails
|
|
46
46
|
default_filters: {},
|
47
47
|
# collection_class [Array<Hash>] The default sortings applied to the collection.
|
48
48
|
default_sortings: [{key: Vocab.schema.dateCreated, direction: :desc}],
|
49
|
+
# download_urls [Array<URI>] URLs for downloading the content of this collection
|
50
|
+
download_urls: [],
|
49
51
|
# include_members [Boolean] Whether to include the members of this collection.
|
50
52
|
include_members: false,
|
51
53
|
# iri_template_keys [Array<Sym>] Custom query keys for the iri template
|
@@ -70,7 +72,9 @@ module LinkedRails
|
|
70
72
|
|
71
73
|
module ClassMethods
|
72
74
|
def collection_iri(**opts)
|
73
|
-
|
75
|
+
fragment = opts.delete(:fragment)
|
76
|
+
|
77
|
+
LinkedRails.iri(path: collection_root_relative_iri(**opts), fragment: fragment)
|
74
78
|
end
|
75
79
|
|
76
80
|
# Sets the defaults for all collections for this class.
|
@@ -10,7 +10,7 @@ module LinkedRails
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def anonymous_iri?
|
13
|
-
self.class < ActiveRecord::Base && new_record?
|
13
|
+
self.class < ActiveRecord::Base && new_record? && @iri.blank?
|
14
14
|
end
|
15
15
|
|
16
16
|
# @return [RDF::URI].
|
@@ -44,7 +44,12 @@ module LinkedRails
|
|
44
44
|
|
45
45
|
# @return [RDF::URI]
|
46
46
|
def root_relative_iri(**opts)
|
47
|
-
|
47
|
+
return @root_relative_iri if opts.blank? && @root_relative_iri.present?
|
48
|
+
|
49
|
+
root_relative_iri = RDF::URI(expand_iri_template(**iri_opts.merge(opts)))
|
50
|
+
@root_relative_iri = root_relative_iri if opts.blank?
|
51
|
+
|
52
|
+
root_relative_iri
|
48
53
|
end
|
49
54
|
|
50
55
|
# @return [String, Symbol]
|
@@ -62,6 +67,7 @@ module LinkedRails
|
|
62
67
|
iri = root_relative_iri.dup
|
63
68
|
iri.scheme = LinkedRails.scheme
|
64
69
|
iri.host = LinkedRails.host
|
70
|
+
iri.path = iri.path.presence || '/'
|
65
71
|
iri
|
66
72
|
end
|
67
73
|
|
@@ -6,16 +6,16 @@ module LinkedRails
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
def menus(user_context = nil)
|
9
|
-
menu_list(user_context)
|
9
|
+
menu_list(user_context)&.menus
|
10
10
|
end
|
11
11
|
|
12
12
|
def menu(tag, user_context = nil)
|
13
|
-
menu_list(user_context)
|
13
|
+
menu_list(user_context)&.menu(tag)
|
14
14
|
end
|
15
15
|
|
16
16
|
def menu_list(user_context = nil)
|
17
17
|
@menu_list ||= {}
|
18
|
-
@menu_list[user_context] ||= self.class.menu_class
|
18
|
+
@menu_list[user_context] ||= self.class.menu_class&.new(resource: self, user_context: user_context)
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
data/lib/linked_rails/model.rb
CHANGED
@@ -118,9 +118,13 @@ module LinkedRails
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def parse_attribute(klass, field_options, value)
|
121
|
-
|
121
|
+
[field_options.key, parse_attribute_value(klass, field_options, value)]
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse_attribute_value(klass, field_options, value)
|
125
|
+
return nil if value == Vocab.libro[:null]
|
122
126
|
|
123
|
-
|
127
|
+
(parse_enum_attribute(klass, field_options.key, value) || value).to_s
|
124
128
|
end
|
125
129
|
|
126
130
|
def parse_enum_attribute(klass, key, value)
|
@@ -133,9 +137,15 @@ module LinkedRails
|
|
133
137
|
|
134
138
|
def parse_iri_param(iri, reflection)
|
135
139
|
key = foreign_key_for_reflection(reflection)
|
136
|
-
|
140
|
+
return unless key
|
137
141
|
|
138
|
-
|
142
|
+
if iri == Vocab.libro[:null]
|
143
|
+
[key, nil]
|
144
|
+
else
|
145
|
+
value = parse_iri_param_value(iri, reflection)
|
146
|
+
|
147
|
+
[key, value.to_s] if value
|
148
|
+
end
|
139
149
|
end
|
140
150
|
|
141
151
|
def parse_iri_param_value(iri, reflection)
|
data/lib/linked_rails/policy.rb
CHANGED
@@ -15,10 +15,10 @@ module LinkedRails
|
|
15
15
|
|
16
16
|
module ClassMethods
|
17
17
|
def action_triples(object, _params)
|
18
|
-
if object
|
19
|
-
[]
|
20
|
-
else
|
18
|
+
if named_object?(object) || object.try(:singular_resource?)
|
21
19
|
object.try(:action_triples) || []
|
20
|
+
else
|
21
|
+
[]
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -115,7 +115,13 @@ module LinkedRails
|
|
115
115
|
collection_name = "#{name.to_s.singularize}_collection"
|
116
116
|
opts[:association] ||= name
|
117
117
|
opts[:polymorphic] ||= true
|
118
|
-
|
118
|
+
|
119
|
+
action_object = opts.delete(:action_object)
|
120
|
+
opts[:if] ||= -> (object) {
|
121
|
+
return action_object if object.iri.try(:path)&.end_with?('/action_object')
|
122
|
+
|
123
|
+
named_object?(object)
|
124
|
+
}
|
119
125
|
|
120
126
|
collection_opts = {}
|
121
127
|
collection_opts[:page_size] = opts.delete(:page_size) if opts.key?(:page_size)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
module LinkedRails
|
6
|
+
class Storage
|
7
|
+
REDIS_DB = {
|
8
|
+
cache: LinkedRails.cache_redis_database,
|
9
|
+
persistent: LinkedRails.persistent_redis_database,
|
10
|
+
stream: LinkedRails.stream_redis_database
|
11
|
+
}.freeze
|
12
|
+
KEYS = {
|
13
|
+
manifest: 'cache:Manifest',
|
14
|
+
redirect_exact: 'cache:Redirect:Exact',
|
15
|
+
redirect_prefix: 'cache:Redirect:Prefix'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
%i[xadd].each do |method|
|
20
|
+
define_method(method) do |db, *args|
|
21
|
+
Redis.new(db: REDIS_DB.fetch(db)).send(method, *args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
%i[hset hdel hget].each do |method|
|
26
|
+
define_method(method) do |db, key, *args|
|
27
|
+
Redis.new(db: REDIS_DB.fetch(db)).send(method, KEYS.fetch(key), *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/linked_rails.rb
CHANGED
@@ -22,6 +22,10 @@ module LinkedRails
|
|
22
22
|
|
23
23
|
mattr_accessor :whitelisted_spi_ips
|
24
24
|
mattr_writer :host, :scheme
|
25
|
+
mattr_accessor :persistent_redis_database, default: ENV['PERSISTENT_REDIS_DATABASE'].presence || 6
|
26
|
+
mattr_accessor :stream_redis_database, default: ENV['STREAM_REDIS_DATABASE'].presence || 7
|
27
|
+
mattr_accessor :cache_redis_database, default: ENV['CACHE_REDIS_DATABASE'].presence || 8
|
28
|
+
mattr_accessor :cache_stream, default: ENV['CACHE_STREAM'].presence || 'transactions'
|
25
29
|
|
26
30
|
def self.configurable_class(parent, klass, default: nil, reader: nil) # rubocop:disable Metrics/AbcSize
|
27
31
|
method = :"#{[parent, klass.to_s.downcase].compact.join('_')}_class"
|
@@ -50,8 +54,10 @@ module LinkedRails
|
|
50
54
|
@@scheme ||= Rails.application.routes.default_url_options[:protocol] || :http # rubocop:disable Style/ClassVars
|
51
55
|
end
|
52
56
|
|
53
|
-
def iri(**
|
54
|
-
|
57
|
+
def iri(**args)
|
58
|
+
opts = {scheme: LinkedRails.scheme, host: LinkedRails.host}.merge(args)
|
59
|
+
opts[:path] = opts[:path].presence || '/'
|
60
|
+
RDF::URI.new(**opts)
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
@@ -84,6 +90,7 @@ ActiveSupport::Inflector.inflections do |inflect|
|
|
84
90
|
inflect.acronym 'SHACL'
|
85
91
|
end
|
86
92
|
|
93
|
+
require 'linked_rails/errors'
|
87
94
|
require 'linked_rails/uri_template'
|
88
95
|
require 'linked_rails/vocab'
|
89
96
|
require 'linked_rails/cache'
|
@@ -101,3 +108,5 @@ require 'linked_rails/routes'
|
|
101
108
|
require 'linked_rails/serializer'
|
102
109
|
require 'linked_rails/translate'
|
103
110
|
require 'linked_rails/railtie'
|
111
|
+
require 'linked_rails/url'
|
112
|
+
require 'linked_rails/storage'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linked_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.4.pre.
|
4
|
+
version: 0.0.4.pre.g3aeec2263
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arthur Dingemans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_response
|
@@ -299,11 +299,12 @@ files:
|
|
299
299
|
- app/policies/linked_rails/collection/view_policy.rb
|
300
300
|
- app/policies/linked_rails/collection_policy.rb
|
301
301
|
- app/policies/linked_rails/enum_value_policy.rb
|
302
|
+
- app/policies/linked_rails/form_policy.rb
|
302
303
|
- app/policies/linked_rails/menus/item_policy.rb
|
303
304
|
- app/policies/linked_rails/menus/list_policy.rb
|
305
|
+
- app/policies/linked_rails/ontology_policy.rb
|
304
306
|
- app/policies/linked_rails/sequence_policy.rb
|
305
307
|
- app/serializers/linked_rails/actions/item_serializer.rb
|
306
|
-
- app/serializers/linked_rails/actions/object_serializer.rb
|
307
308
|
- app/serializers/linked_rails/collection/filter_field_serializer.rb
|
308
309
|
- app/serializers/linked_rails/collection/filter_option_serializer.rb
|
309
310
|
- app/serializers/linked_rails/collection/filter_serializer.rb
|
@@ -338,6 +339,7 @@ files:
|
|
338
339
|
- app/serializers/linked_rails/web_page_serializer.rb
|
339
340
|
- app/serializers/linked_rails/web_site_serializer.rb
|
340
341
|
- app/serializers/linked_rails/widget_serializer.rb
|
342
|
+
- app/workers/linked_rails/invalidation_stream_worker.rb
|
341
343
|
- config/initializers/inflections.rb
|
342
344
|
- lib/generators/linked_rails/install/install_generator.rb
|
343
345
|
- lib/generators/linked_rails/install/templates/README
|
@@ -387,6 +389,8 @@ files:
|
|
387
389
|
- lib/linked_rails/enhancements/destroyable/controller.rb
|
388
390
|
- lib/linked_rails/enhancements/updatable/controller.rb
|
389
391
|
- lib/linked_rails/enhancements/updatable/serializer.rb
|
392
|
+
- lib/linked_rails/errors.rb
|
393
|
+
- lib/linked_rails/errors/forbidden.rb
|
390
394
|
- lib/linked_rails/helpers/delta_helper.rb
|
391
395
|
- lib/linked_rails/helpers/ontola_actions_helper.rb
|
392
396
|
- lib/linked_rails/helpers/resource_helper.rb
|
@@ -395,6 +399,7 @@ files:
|
|
395
399
|
- lib/linked_rails/middleware/linked_data_params.rb
|
396
400
|
- lib/linked_rails/model.rb
|
397
401
|
- lib/linked_rails/model/actionable.rb
|
402
|
+
- lib/linked_rails/model/cacheable.rb
|
398
403
|
- lib/linked_rails/model/collections.rb
|
399
404
|
- lib/linked_rails/model/dirty.rb
|
400
405
|
- lib/linked_rails/model/enhancements.rb
|
@@ -418,10 +423,12 @@ files:
|
|
418
423
|
- lib/linked_rails/serializer/actionable.rb
|
419
424
|
- lib/linked_rails/serializer/menuable.rb
|
420
425
|
- lib/linked_rails/serializer/singularable.rb
|
426
|
+
- lib/linked_rails/storage.rb
|
421
427
|
- lib/linked_rails/test_methods.rb
|
422
428
|
- lib/linked_rails/translate.rb
|
423
429
|
- lib/linked_rails/types/iri_type.rb
|
424
430
|
- lib/linked_rails/uri_template.rb
|
431
|
+
- lib/linked_rails/url.rb
|
425
432
|
- lib/linked_rails/version.rb
|
426
433
|
- lib/linked_rails/vocab.rb
|
427
434
|
- lib/nill_class_renderer.rb
|