linked_rails 0.0.3 → 0.0.4.pre.g0ec6e30ca
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/LICENSE +21 -674
- data/app/controllers/linked_rails/actions/objects_controller.rb +9 -0
- data/app/controllers/linked_rails/bulk_controller.rb +107 -22
- data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
- data/app/models/linked_rails/actions/item.rb +72 -55
- data/app/models/linked_rails/actions/list.rb +6 -31
- data/app/models/linked_rails/actions/object.rb +40 -0
- data/app/models/linked_rails/collection/configuration.rb +55 -0
- data/app/models/linked_rails/collection/filter.rb +1 -1
- data/app/models/linked_rails/collection/filter_field.rb +19 -2
- data/app/models/linked_rails/collection/filter_option.rb +1 -1
- data/app/models/linked_rails/collection/filterable.rb +6 -9
- data/app/models/linked_rails/collection/infinite.rb +113 -0
- data/app/models/linked_rails/collection/infinite_view.rb +1 -90
- data/app/models/linked_rails/collection/iri.rb +47 -43
- data/app/models/linked_rails/collection/iri_mapping.rb +15 -7
- data/app/models/linked_rails/collection/paginated.rb +46 -0
- data/app/models/linked_rails/collection/paginated_view.rb +1 -33
- data/app/models/linked_rails/collection/sortable.rb +1 -9
- data/app/models/linked_rails/collection/sorting.rb +1 -1
- data/app/models/linked_rails/collection/view.rb +53 -15
- data/app/models/linked_rails/collection.rb +53 -85
- data/app/models/linked_rails/creative_work.rb +1 -1
- data/app/models/linked_rails/entry_point.rb +8 -5
- data/app/models/linked_rails/enum_value.rb +40 -2
- data/app/models/linked_rails/form/field/association_input.rb +7 -1
- data/app/models/linked_rails/form/field/file_input.rb +5 -0
- data/app/models/linked_rails/form/field/resource_field.rb +2 -0
- data/{lib/linked_rails/enhancements/indexable/model.rb → app/models/linked_rails/form/field/url_input.rb} +3 -3
- data/app/models/linked_rails/form/field.rb +37 -13
- data/app/models/linked_rails/form/field_factory.rb +49 -25
- data/app/models/linked_rails/form/group.rb +4 -6
- data/app/models/linked_rails/form/page.rb +8 -4
- data/app/models/linked_rails/form.rb +17 -21
- data/app/models/linked_rails/manifest.rb +102 -22
- data/app/models/linked_rails/menus/item.rb +11 -14
- data/app/models/linked_rails/menus/list.rb +30 -10
- data/app/models/linked_rails/ontology/base.rb +3 -1
- data/app/models/linked_rails/ontology/class.rb +3 -3
- data/app/models/linked_rails/ontology.rb +6 -5
- data/app/models/linked_rails/property_query.rb +2 -0
- data/app/models/linked_rails/sequence.rb +4 -13
- data/app/models/linked_rails/shacl/property_shape.rb +1 -1
- data/app/models/linked_rails/web_page.rb +0 -4
- data/app/models/linked_rails/web_site.rb +0 -4
- data/app/models/linked_rails/widget.rb +4 -11
- data/app/policies/linked_rails/actions/object_policy.rb +11 -0
- data/app/policies/linked_rails/collection_policy.rb +3 -2
- 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/actions/item_serializer.rb +5 -5
- data/app/serializers/linked_rails/collection/filter_field_serializer.rb +3 -2
- data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/view_serializer.rb +4 -3
- data/app/serializers/linked_rails/collection_serializer.rb +8 -7
- data/app/serializers/linked_rails/condition_serializer.rb +3 -3
- data/app/serializers/linked_rails/entry_point_serializer.rb +3 -3
- data/app/serializers/linked_rails/enum_value_serializer.rb +1 -0
- data/app/serializers/linked_rails/form/field/association_input_serializer.rb +1 -0
- data/app/serializers/linked_rails/form/field/file_input_serializer.rb +11 -0
- data/app/serializers/linked_rails/form/field_serializer.rb +3 -1
- data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
- data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
- data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
- data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
- data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
- data/app/serializers/linked_rails/property_query_serializer.rb +7 -0
- data/app/serializers/linked_rails/sequence_serializer.rb +2 -5
- data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
- data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
- data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
- data/app/serializers/linked_rails/widget_serializer.rb +3 -3
- data/app/workers/linked_rails/invalidation_stream_worker.rb +16 -0
- data/lib/generators/linked_rails/install/install_generator.rb +5 -8
- data/lib/generators/linked_rails/install/templates/README +2 -0
- data/lib/generators/linked_rails/install/templates/app_menu_list.rb +36 -7
- data/lib/generators/linked_rails/install/templates/application_menu_list.rb +40 -1
- data/lib/generators/linked_rails/install/templates/initializer.rb +1 -2
- data/lib/generators/linked_rails/install/templates/locales.yml +16 -0
- data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
- data/lib/generators/linked_rails/install/templates/vocab.rb +1 -0
- data/lib/generators/linked_rails/install/templates/vocab.yml +2 -2
- data/lib/generators/linked_rails/model/model_generator.rb +0 -1
- data/lib/generators/linked_rails/model/templates/controller.rb.tt +5 -1
- data/lib/generators/linked_rails/model/templates/form.rb.tt +3 -0
- data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +15 -0
- data/lib/generators/linked_rails/model/templates/policy.rb.tt +13 -0
- data/lib/generators/linked_rails/model/templates/serializer.rb.tt +5 -1
- data/lib/linked_rails/active_response/controller/collections.rb +1 -1
- data/lib/linked_rails/active_response/controller/crud_defaults.rb +4 -4
- data/lib/linked_rails/active_response/controller/params.rb +10 -10
- data/lib/linked_rails/active_response/controller.rb +8 -18
- data/lib/linked_rails/active_response/responders/rdf.rb +19 -10
- data/lib/linked_rails/callable_variable.rb +1 -1
- data/lib/linked_rails/collection_params_parser.rb +93 -0
- data/lib/linked_rails/controller/actionable.rb +121 -0
- data/lib/linked_rails/controller/authorization.rb +6 -0
- data/lib/linked_rails/controller/default_actions/create.rb +52 -0
- data/lib/linked_rails/controller/default_actions/destroy.rb +42 -0
- data/lib/linked_rails/controller/default_actions/update.rb +43 -0
- data/lib/linked_rails/controller/delta.rb +58 -0
- data/lib/linked_rails/controller/error_handling.rb +12 -7
- data/lib/linked_rails/controller/rendering.rb +48 -0
- data/lib/linked_rails/controller.rb +24 -4
- data/lib/linked_rails/enhancements/creatable/controller.rb +1 -1
- data/lib/linked_rails/enhancements/destroyable/controller.rb +1 -1
- data/lib/linked_rails/enhancements/updatable/controller.rb +1 -1
- data/lib/linked_rails/enhancements.rb +0 -16
- data/lib/linked_rails/errors/forbidden.rb +37 -0
- data/lib/linked_rails/errors.rb +3 -0
- data/lib/linked_rails/helpers/delta_helper.rb +28 -57
- data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
- data/lib/linked_rails/helpers/resource_helper.rb +14 -2
- data/lib/linked_rails/iri_mapper.rb +18 -40
- data/lib/linked_rails/middleware/error_handling.rb +51 -0
- data/lib/linked_rails/middleware/linked_data_params.rb +30 -151
- data/lib/linked_rails/model/actionable.rb +68 -0
- data/lib/linked_rails/model/cacheable.rb +45 -0
- data/lib/linked_rails/model/collections.rb +203 -39
- data/lib/linked_rails/model/dirty.rb +6 -18
- data/lib/linked_rails/model/enhancements.rb +1 -6
- data/lib/linked_rails/model/filtering.rb +4 -6
- data/lib/linked_rails/model/indexable.rb +6 -16
- data/lib/linked_rails/model/iri.rb +29 -19
- data/lib/linked_rails/model/iri_mapping.rb +37 -8
- data/lib/linked_rails/model/menuable.rb +28 -0
- data/lib/linked_rails/model/serialization.rb +2 -15
- data/lib/linked_rails/model/singularable.rb +57 -0
- data/lib/linked_rails/model/sorting.rb +0 -5
- data/lib/linked_rails/model/tables.rb +26 -0
- data/lib/linked_rails/model.rb +18 -7
- data/lib/linked_rails/params_parser.rb +140 -53
- data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
- data/lib/linked_rails/policy.rb +44 -46
- data/lib/linked_rails/railtie.rb +11 -0
- data/lib/linked_rails/rdf_error.rb +2 -2
- data/lib/linked_rails/renderers.rb +1 -0
- data/lib/linked_rails/routes.rb +38 -22
- data/lib/linked_rails/serializer/actionable.rb +27 -0
- data/lib/linked_rails/serializer/menuable.rb +31 -0
- data/lib/linked_rails/serializer/singularable.rb +26 -0
- data/lib/linked_rails/serializer.rb +35 -12
- data/lib/linked_rails/storage.rb +32 -0
- data/lib/linked_rails/test_methods.rb +114 -0
- data/lib/linked_rails/translate.rb +31 -9
- data/lib/linked_rails/types/iri_type.rb +37 -0
- data/lib/linked_rails/uri_template.rb +30 -0
- data/lib/linked_rails/url.rb +11 -0
- data/lib/linked_rails/version.rb +1 -1
- data/lib/linked_rails/vocab.rb +9 -0
- data/lib/linked_rails.rb +40 -14
- data/lib/rails/welcome_controller.rb +3 -3
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +78 -33
- data/app/models/linked_rails/actions/default_actions/create.rb +0 -60
- data/app/models/linked_rails/actions/default_actions/destroy.rb +0 -45
- data/app/models/linked_rails/actions/default_actions/update.rb +0 -50
- data/app/models/linked_rails/actions/default_actions.rb +0 -17
- data/lib/generators/linked_rails/install/templates/application_action_list.rb +0 -3
- data/lib/generators/linked_rails/model/templates/action_list.rb.tt +0 -6
- data/lib/linked_rails/enhancements/actionable/model.rb +0 -71
- data/lib/linked_rails/enhancements/actionable/serializer.rb +0 -25
- data/lib/linked_rails/enhancements/creatable/action.rb +0 -15
- data/lib/linked_rails/enhancements/destroyable/action.rb +0 -15
- data/lib/linked_rails/enhancements/destroyable/routing.rb +0 -19
- data/lib/linked_rails/enhancements/menuable/model.rb +0 -36
- data/lib/linked_rails/enhancements/menuable/serializer.rb +0 -33
- data/lib/linked_rails/enhancements/route_concerns.rb +0 -56
- data/lib/linked_rails/enhancements/singularable/controller.rb +0 -43
- data/lib/linked_rails/enhancements/singularable/model.rb +0 -47
- data/lib/linked_rails/enhancements/singularable/serializer.rb +0 -28
- data/lib/linked_rails/enhancements/tableable/model.rb +0 -28
- data/lib/linked_rails/enhancements/updatable/action.rb +0 -15
- data/lib/linked_rails/enhancements/updatable/routing.rb +0 -20
@@ -11,7 +11,8 @@ module LinkedRails
|
|
11
11
|
def show
|
12
12
|
render json: authorized_resources
|
13
13
|
|
14
|
-
print_timings
|
14
|
+
print_timings unless Rails.env.production?
|
15
|
+
send_timings if client
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
@@ -20,8 +21,11 @@ module LinkedRails
|
|
20
21
|
return response_for_wrong_host(opts) if wrong_host?(opts[:iri])
|
21
22
|
|
22
23
|
include = opts[:include].to_s == 'true'
|
24
|
+
resource = LinkedRails.iri_mapper.resource_from_iri(request_path_to_url(opts[:iri]), user_context)
|
23
25
|
|
24
|
-
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)
|
25
29
|
rescue StandardError => e
|
26
30
|
handle_resource_error(opts, e)
|
27
31
|
end
|
@@ -30,12 +34,16 @@ module LinkedRails
|
|
30
34
|
@authorized_resources ||=
|
31
35
|
params
|
32
36
|
.require(:resources)
|
33
|
-
.map { |param| param
|
37
|
+
.map { |param| resource_params(param) }
|
34
38
|
.map(&method(:timed_authorized_resource))
|
35
39
|
end
|
36
40
|
|
41
|
+
def client
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
37
45
|
def handle_resource_error(opts, error)
|
38
|
-
log_resource_error(error)
|
46
|
+
log_resource_error(error, opts[:iri])
|
39
47
|
status = error_status(error)
|
40
48
|
body = error_body(status, error, opts[:iri]) if opts[:include].to_s == 'true'
|
41
49
|
|
@@ -50,7 +58,7 @@ module LinkedRails
|
|
50
58
|
resource_body(error_resource(status, error, iri))
|
51
59
|
end
|
52
60
|
|
53
|
-
def log_resource_error(error)
|
61
|
+
def log_resource_error(error, _iri)
|
54
62
|
return unless log_resource_error?(error)
|
55
63
|
|
56
64
|
Rails.logger.error(error)
|
@@ -64,23 +72,34 @@ module LinkedRails
|
|
64
72
|
def print_timings
|
65
73
|
Rails.logger.debug(
|
66
74
|
"\n CPU system user+system real inc status cache iri\n" \
|
67
|
-
"#{
|
75
|
+
"#{timing_lines.join("\n")}\n" \
|
68
76
|
" User: #{current_user.class}(#{current_user.id})"
|
69
77
|
)
|
70
78
|
end
|
71
79
|
|
80
|
+
def send_timings
|
81
|
+
timings.each do |timing|
|
82
|
+
client.send_json(timing_json(timing))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
72
86
|
def require_doorkeeper_token?
|
73
87
|
false
|
74
88
|
end
|
75
89
|
|
76
|
-
def
|
77
|
-
return
|
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?)
|
78
93
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
:public
|
95
|
+
end
|
96
|
+
|
97
|
+
def resource_params(param)
|
98
|
+
params = param.permit(:include, :iri)
|
99
|
+
params[:iri] = URI(params[:iri])
|
100
|
+
params
|
101
|
+
rescue URI::InvalidURIError
|
102
|
+
params.except(:iri)
|
84
103
|
end
|
85
104
|
|
86
105
|
def resource_response_body(iri, rack_body, status)
|
@@ -109,7 +128,7 @@ module LinkedRails
|
|
109
128
|
fullpath = iri.query.blank? ? iri.path : "#{iri.path}?#{iri.query}"
|
110
129
|
|
111
130
|
request.env.slice(*REQUEST_HEADERS).merge(
|
112
|
-
'HTTP_ACCEPT' => 'application/
|
131
|
+
'HTTP_ACCEPT' => 'application/empathy+json',
|
113
132
|
'HTTP_OPERATOR_ARG_GRAPH' => 'true',
|
114
133
|
'ORIGINAL_FULLPATH' => fullpath
|
115
134
|
)
|
@@ -124,6 +143,12 @@ module LinkedRails
|
|
124
143
|
}.merge(opts)
|
125
144
|
end
|
126
145
|
|
146
|
+
def resource_status(resource_policy)
|
147
|
+
raise(LinkedRails::Errors::Forbidden.new(query: :show?)) unless resource_policy.show?
|
148
|
+
|
149
|
+
200
|
150
|
+
end
|
151
|
+
|
127
152
|
def response_for_wrong_host(opts)
|
128
153
|
iri = opts[:iri]
|
129
154
|
term = term_from_vocab(iri)
|
@@ -132,18 +157,73 @@ module LinkedRails
|
|
132
157
|
ontology_term_response(iri, term, opts[:include])
|
133
158
|
end
|
134
159
|
|
160
|
+
def response_from_resource(include, iri, resource)
|
161
|
+
resource_policy = policy(resource)
|
162
|
+
status = resource_status(resource_policy)
|
163
|
+
|
164
|
+
resource_response(
|
165
|
+
iri,
|
166
|
+
body: response_from_resource_body(include, iri, resource, status),
|
167
|
+
cache: resource_cache_control(resource.try(:cacheable?), status, resource_policy),
|
168
|
+
language: I18n.locale,
|
169
|
+
status: status
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
173
|
+
def response_from_resource_body(include, _iri, resource, status)
|
174
|
+
include && status == 200 ? resource_body(resource) : nil
|
175
|
+
end
|
176
|
+
|
135
177
|
def term_from_vocab(iri)
|
136
178
|
vocab = Vocab.for(iri)
|
137
|
-
tag = iri.split(vocab.to_s).last
|
179
|
+
tag = iri.to_s.split(vocab.to_s).last
|
138
180
|
vocab[tag]
|
139
181
|
rescue NoMethodError
|
140
182
|
nil
|
141
183
|
end
|
142
184
|
|
185
|
+
def timing_json(timing) # rubocop:disable Metrics/MethodLength
|
186
|
+
route = Rails.application.routes.recognize_path(timing[:resource].to_s)
|
187
|
+
|
188
|
+
{
|
189
|
+
type: 'web',
|
190
|
+
timings: {
|
191
|
+
total_duration: timing[:time].total
|
192
|
+
},
|
193
|
+
default_labels: {
|
194
|
+
action: route[:action] || 'show',
|
195
|
+
controller: route[:controller] || 'subresource',
|
196
|
+
status: timing[:status],
|
197
|
+
include: timing[:include]
|
198
|
+
}
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def timing_lines
|
203
|
+
timings.map do |timing|
|
204
|
+
include = timing[:include].to_s.ljust(5)
|
205
|
+
"#{timing[:time].to_s[0..-2]} - #{include} #{timing[:status]} #{timing[:cache]} #{timing[:resource]}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def ontology_class(iri)
|
210
|
+
klass = LinkedRails.linked_models.detect do |model|
|
211
|
+
(model.iri.is_a?(Array) ? model.iri : [model.iri]).include?(iri)
|
212
|
+
end
|
213
|
+
LinkedRails.ontology_class_class.new(iri: iri, klass: klass)
|
214
|
+
end
|
215
|
+
|
216
|
+
def ontology_property(iri)
|
217
|
+
LinkedRails.ontology_property_class.new(iri: iri)
|
218
|
+
end
|
219
|
+
|
143
220
|
def ontology_term_response(iri, term, include)
|
221
|
+
capital = term.relativize(term.vocab).to_s[0] =~ /[A-Z]/
|
222
|
+
resource = capital ? ontology_class(term) : ontology_property(term)
|
223
|
+
|
144
224
|
resource_response(
|
145
225
|
iri,
|
146
|
-
body: include ? resource_body(
|
226
|
+
body: include ? resource_body(resource) : nil,
|
147
227
|
cache: :public,
|
148
228
|
language: I18n.locale,
|
149
229
|
status: 200
|
@@ -161,6 +241,8 @@ module LinkedRails
|
|
161
241
|
language: response_language(headers),
|
162
242
|
status: status
|
163
243
|
)
|
244
|
+
rescue URI::InvalidURIError, ActionController::BadRequest
|
245
|
+
resource_response(iri)
|
164
246
|
end
|
165
247
|
|
166
248
|
def response_language(headers)
|
@@ -169,7 +251,7 @@ module LinkedRails
|
|
169
251
|
|
170
252
|
def sanitized_relative_path(iri) # rubocop:disable Metrics/AbcSize
|
171
253
|
iri.path = "#{iri.path}/" unless iri.path&.ends_with?('/')
|
172
|
-
uri = URI(LinkedRails.iri.path.present? ? iri.to_s.split("#{LinkedRails.iri.path}/").last : iri)
|
254
|
+
uri = URI(LinkedRails.iri.path.chomp('/').present? ? iri.to_s.split("#{LinkedRails.iri.path}/").last : iri)
|
173
255
|
|
174
256
|
[uri.path, uri.query].compact.join('?')
|
175
257
|
end
|
@@ -181,15 +263,18 @@ module LinkedRails
|
|
181
263
|
def timed_authorized_resource(resource)
|
182
264
|
res = nil
|
183
265
|
time = Benchmark.measure { res = authorized_resource(resource) }
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
266
|
+
timings << {
|
267
|
+
time: time,
|
268
|
+
include: resource[:include],
|
269
|
+
status: res[:status],
|
270
|
+
cache: res[:cache],
|
271
|
+
resource: resource[:iri]
|
272
|
+
}
|
188
273
|
res
|
189
274
|
end
|
190
275
|
|
191
276
|
def wrong_host?(iri)
|
192
|
-
!iri.starts_with?(LinkedRails.iri)
|
277
|
+
!iri.to_s.starts_with?(LinkedRails.iri)
|
193
278
|
end
|
194
279
|
end
|
195
280
|
end
|
@@ -3,47 +3,5 @@
|
|
3
3
|
module LinkedRails
|
4
4
|
class EnumValuesController < LinkedRails.controller_parent_class
|
5
5
|
active_response :index
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
def enum_options!
|
10
|
-
serializer_class!.enum_options(params[:attribute]) || raise(ActiveRecord::RecordNotFound)
|
11
|
-
end
|
12
|
-
|
13
|
-
def requested_resource
|
14
|
-
return super unless action_name == 'index'
|
15
|
-
|
16
|
-
@requested_resource ||= LinkedRails::Sequence.new(
|
17
|
-
enum_options!.values,
|
18
|
-
id: index_iri,
|
19
|
-
scope: LinkedRails::EnumValuePolicy::Scope
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
|
-
def model_class
|
24
|
-
@model_class ||= self.class.linked_models.detect do |klass|
|
25
|
-
klass.to_s == ([params[:module]].compact + [params[:klass]&.singularize]).join('/').classify
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def model_class!
|
30
|
-
model_class || raise(ActiveRecord::RecordNotFound)
|
31
|
-
end
|
32
|
-
|
33
|
-
def serializer_class
|
34
|
-
@serializer_class ||= RDF::Serializers.serializer_for(model_class!)
|
35
|
-
end
|
36
|
-
|
37
|
-
def serializer_class!
|
38
|
-
serializer_class || raise(ActiveRecord::RecordNotFound)
|
39
|
-
end
|
40
|
-
|
41
|
-
class << self
|
42
|
-
def linked_models
|
43
|
-
@linked_models ||= ObjectSpace.each_object(Class).select do |c|
|
44
|
-
c.included_modules.include?(LinkedRails::Model)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
6
|
end
|
49
7
|
end
|
@@ -7,15 +7,23 @@ module LinkedRails
|
|
7
7
|
class Item # rubocop:disable Metrics/ClassLength
|
8
8
|
include ActiveModel::Model
|
9
9
|
include LinkedRails::Model
|
10
|
-
enhance LinkedRails::Enhancements::Singularable
|
11
10
|
|
12
|
-
attr_accessor :list, :policy_arguments, :submit_label
|
11
|
+
attr_accessor :inherit, :list, :one_click, :policy_arguments, :submit_label, :target_path, :target_query
|
13
12
|
attr_writer :parent, :resource, :root_relative_iri, :user_context, :object,
|
14
13
|
:target
|
15
14
|
delegate :user_context, to: :list, allow_nil: true
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
collection_options(
|
16
|
+
association_base: lambda {
|
17
|
+
action_list = association_class.get_action_list(parent, user_context)
|
18
|
+
|
19
|
+
action_list.actions
|
20
|
+
},
|
21
|
+
display: :grid,
|
22
|
+
title: -> { I18n.t('actions.plural') }
|
23
|
+
)
|
24
|
+
|
25
|
+
%i[condition description result type policy label image target_url collection form
|
26
|
+
tag http_method favorite action_path policy_resource predicate resource].each do |method|
|
19
27
|
attr_writer method
|
20
28
|
define_method method do
|
21
29
|
var = instance_variable_get(:"@#{method}")
|
@@ -28,10 +36,10 @@ module LinkedRails
|
|
28
36
|
|
29
37
|
def action_status
|
30
38
|
@action_status ||=
|
31
|
-
if
|
32
|
-
Vocab.schema.CompletedActionStatus
|
33
|
-
elsif policy_valid?
|
39
|
+
if policy_valid?
|
34
40
|
Vocab.schema.PotentialActionStatus
|
41
|
+
elsif policy_status
|
42
|
+
policy_status
|
35
43
|
elsif policy_expired?
|
36
44
|
Vocab.ontola[:ExpiredActionStatus]
|
37
45
|
else
|
@@ -39,46 +47,29 @@ module LinkedRails
|
|
39
47
|
end
|
40
48
|
end
|
41
49
|
|
42
|
-
def as_json(_opts
|
50
|
+
def as_json(**_opts)
|
43
51
|
{}
|
44
52
|
end
|
45
53
|
|
46
54
|
def available?
|
47
|
-
return false unless action_status == Vocab.schema.PotentialActionStatus
|
48
|
-
|
49
55
|
@condition.nil? || condition
|
50
56
|
end
|
51
57
|
|
52
|
-
def built_associations
|
53
|
-
included_object
|
54
|
-
.class
|
55
|
-
.try(:reflect_on_all_associations)
|
56
|
-
&.select { |association| included_object.association(association.name).loaded? }
|
57
|
-
&.map(&:name)
|
58
|
-
end
|
59
|
-
|
60
58
|
def error
|
61
59
|
policy_message ||
|
62
60
|
I18n.t("actions.status.#{action_status.to_s.split('#').last}", default: nil)
|
63
61
|
end
|
64
62
|
|
65
|
-
def
|
66
|
-
|
67
|
-
return include_paths || {} if iri.anonymous?
|
68
|
-
|
69
|
-
includes = included_object.class.try(:preview_includes)&.presence || []
|
70
|
-
|
71
|
-
(includes.is_a?(Hash) ? [includes] : includes) + (built_associations || [])
|
63
|
+
def object
|
64
|
+
object_from_var || resource
|
72
65
|
end
|
73
66
|
|
74
|
-
def
|
75
|
-
|
67
|
+
def object_iri
|
68
|
+
iri_with_root(object_root_relative_iri)
|
76
69
|
end
|
77
70
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
@object || resource
|
71
|
+
def object_root_relative_iri
|
72
|
+
object&.iri&.anonymous? ? anonymous_object_root_relative_iri : object&.root_relative_iri
|
82
73
|
end
|
83
74
|
|
84
75
|
def parent
|
@@ -92,10 +83,10 @@ module LinkedRails
|
|
92
83
|
end
|
93
84
|
|
94
85
|
def policy_message
|
95
|
-
resource_policy.try(:message)
|
86
|
+
resource_policy.try(:message) unless policy_valid?
|
96
87
|
end
|
97
88
|
|
98
|
-
def root_relative_iri(_opts
|
89
|
+
def root_relative_iri(**_opts)
|
99
90
|
value = root_relative_iri_from_var
|
100
91
|
value = RDF::URI(value) unless value.blank? || value.is_a?(RDF::URI)
|
101
92
|
return @root_relative_iri = value if value
|
@@ -109,24 +100,30 @@ module LinkedRails
|
|
109
100
|
RDF::URI(value)
|
110
101
|
end
|
111
102
|
|
112
|
-
def preview_includes
|
113
|
-
[:target, included_object: form_resource_includes]
|
114
|
-
end
|
115
|
-
|
116
103
|
def singular_resource?
|
117
104
|
resource.try(:singular_resource?)
|
118
105
|
end
|
119
106
|
|
107
|
+
def policy_status
|
108
|
+
resource_policy.try(:action_status)
|
109
|
+
end
|
110
|
+
|
120
111
|
def iri_opts
|
121
|
-
|
112
|
+
return {} if resource.blank?
|
113
|
+
|
114
|
+
resource.try(:singular_resource?) ? resource.singular_iri_opts : resource.iri_opts
|
122
115
|
end
|
123
116
|
|
124
117
|
def iri_template
|
125
|
-
path_suffix =
|
118
|
+
path_suffix = "/#{action_path || tag}"
|
126
119
|
|
127
|
-
return @iri_template ||= URITemplate.new(path_suffix) if resource.blank?
|
120
|
+
return @iri_template ||= LinkedRails::URITemplate.new(path_suffix) if resource.blank?
|
128
121
|
|
129
|
-
|
122
|
+
base_template = resource.send(resource.try(:singular_resource?) ? :singular_iri_template : :iri_template)
|
123
|
+
@iri_template ||= iri_template_expand_path(
|
124
|
+
base_template.to_s.sub('display,', '').sub('sort%5B%5D*,', ''),
|
125
|
+
path_suffix
|
126
|
+
)
|
130
127
|
end
|
131
128
|
|
132
129
|
def rdf_type
|
@@ -143,6 +140,12 @@ module LinkedRails
|
|
143
140
|
|
144
141
|
private
|
145
142
|
|
143
|
+
def anonymous_object_root_relative_iri
|
144
|
+
object_iri = root_relative_iri.dup
|
145
|
+
object_iri.path += '/action_object'
|
146
|
+
object_iri
|
147
|
+
end
|
148
|
+
|
146
149
|
def description_fallback
|
147
150
|
LinkedRails.translate(:action, :description, self, false)
|
148
151
|
end
|
@@ -151,12 +154,18 @@ module LinkedRails
|
|
151
154
|
LinkedRails.translate(:action, :label, self)
|
152
155
|
end
|
153
156
|
|
157
|
+
def object_from_var
|
158
|
+
return @object unless @object.respond_to?(:call)
|
159
|
+
|
160
|
+
@object = list.instance_exec(&@object)
|
161
|
+
end
|
162
|
+
|
154
163
|
def policy_expired?
|
155
164
|
@policy_expired ||= policy && resource_policy.try(:expired?)
|
156
165
|
end
|
157
166
|
|
158
167
|
def policy_resource_fallback
|
159
|
-
|
168
|
+
object
|
160
169
|
end
|
161
170
|
|
162
171
|
def policy_valid?
|
@@ -184,6 +193,13 @@ module LinkedRails
|
|
184
193
|
@root_relative_iri
|
185
194
|
end
|
186
195
|
|
196
|
+
def target_url_fallback # rubocop:disable Metrics/AbcSize
|
197
|
+
base = (resource.try(:singular_resource?) ? resource.singular_iri : resource.iri).dup
|
198
|
+
base.path = "#{base.path.chomp('/')}/#{target_path}" if target_path.present?
|
199
|
+
base.query = Rack::Utils.parse_nested_query(base.query).merge(target_query).to_param if target_query.present?
|
200
|
+
base
|
201
|
+
end
|
202
|
+
|
187
203
|
def type_fallback
|
188
204
|
Vocab.schema.UpdateAction
|
189
205
|
end
|
@@ -202,25 +218,26 @@ module LinkedRails
|
|
202
218
|
)
|
203
219
|
end
|
204
220
|
|
221
|
+
def get_action_list(parent, user_context)
|
222
|
+
return parent.action_list(user_context) if parent.respond_to?(:action_list)
|
223
|
+
|
224
|
+
app_action_list(user_context)
|
225
|
+
end
|
226
|
+
|
205
227
|
def requested_index_resource(params, user_context)
|
206
|
-
parent = parent_from_params(params, user_context)
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
association_class: ::Actions::Item,
|
212
|
-
default_display: :grid,
|
213
|
-
default_title: I18n.t('actions.plural'),
|
214
|
-
parent: parent,
|
215
|
-
title: params[:title]
|
228
|
+
parent = parent_from_params!(params, user_context) if params.key?(:parent_iri)
|
229
|
+
|
230
|
+
default_collection_option(:collection_class).collection_or_view(
|
231
|
+
default_collection_options.merge(parent: parent),
|
232
|
+
index_collection_params(params, user_context)
|
216
233
|
)
|
217
234
|
end
|
218
235
|
|
219
236
|
def requested_single_resource(params, user_context)
|
220
237
|
return nil if params[:id].blank?
|
221
238
|
|
222
|
-
parent = parent_from_params(params, user_context)
|
223
|
-
action_list = parent
|
239
|
+
parent = parent_from_params!(params, user_context) if params.key?(:parent_iri)
|
240
|
+
action_list = get_action_list(parent, user_context)
|
224
241
|
|
225
242
|
action_list&.action(params[:id].to_sym)
|
226
243
|
end
|
@@ -7,14 +7,12 @@ module LinkedRails
|
|
7
7
|
class List
|
8
8
|
include ActiveModel::Model
|
9
9
|
include LinkedRails::Model
|
10
|
-
include DefaultActions
|
11
|
-
extend LinkedRails::Enhanceable
|
12
10
|
|
13
11
|
attr_accessor :resource, :user_context
|
14
12
|
class_attribute :_defined_actions, instance_reader: false, instance_writer: false
|
15
13
|
|
16
14
|
def actions
|
17
|
-
@actions ||= defined_actions.map { |tag, opts| action_item(tag, opts.dup) }
|
15
|
+
@actions ||= defined_actions.map { |tag, opts| action_item(tag, opts.dup) }.select(&:available?)
|
18
16
|
end
|
19
17
|
|
20
18
|
def action(tag)
|
@@ -34,9 +32,9 @@ module LinkedRails
|
|
34
32
|
private
|
35
33
|
|
36
34
|
def action_item(tag, options)
|
37
|
-
options[:tag] ||=
|
35
|
+
options[:tag] ||= tag
|
38
36
|
options[:list] ||= self
|
39
|
-
LinkedRails.actions_item_class.new(options.except(:
|
37
|
+
LinkedRails.actions_item_class.new(options.except(:action_name))
|
40
38
|
end
|
41
39
|
|
42
40
|
def association
|
@@ -52,12 +50,6 @@ module LinkedRails
|
|
52
50
|
end
|
53
51
|
|
54
52
|
class << self
|
55
|
-
def actionable_class
|
56
|
-
@actionable_class ||=
|
57
|
-
name.gsub('ActionList', '').safe_constantize ||
|
58
|
-
name.demodulize.gsub('ActionList', '').safe_constantize
|
59
|
-
end
|
60
|
-
|
61
53
|
def collection_actions
|
62
54
|
defined_actions[:collection]
|
63
55
|
end
|
@@ -77,26 +69,11 @@ module LinkedRails
|
|
77
69
|
|
78
70
|
private
|
79
71
|
|
80
|
-
def has_collection_action(action, opts = {}) # rubocop:disable Naming/PredicateName
|
81
|
-
opts[:http_method] ||= 'POST'
|
82
|
-
defined_actions[:collection][action] = opts
|
83
|
-
end
|
84
|
-
|
85
|
-
def has_resource_action(action, opts = {}) # rubocop:disable Naming/PredicateName
|
86
|
-
opts[:http_method] ||= 'POST'
|
87
|
-
defined_actions[:resource][action] = opts
|
88
|
-
end
|
89
|
-
|
90
|
-
def has_singular_action(action, opts = {}) # rubocop:disable Naming/PredicateName
|
91
|
-
opts[:http_method] ||= 'POST'
|
92
|
-
defined_actions[:singular][action] = opts
|
93
|
-
end
|
94
|
-
|
95
72
|
def initial_defined_actions(clone_from = {})
|
96
73
|
{
|
97
|
-
collection: clone_from[:collection].dup || {},
|
98
|
-
resource: clone_from[:resource].dup || {},
|
99
|
-
singular: clone_from[:singular].dup || {}
|
74
|
+
collection: clone_from[:collection].dup&.select { |_, value| value[:inherit] != false } || {},
|
75
|
+
resource: clone_from[:resource].dup&.select { |_, value| value[:inherit] != false } || {},
|
76
|
+
singular: clone_from[:singular].dup&.select { |_, value| value[:inherit] != false } || {}
|
100
77
|
}
|
101
78
|
end
|
102
79
|
|
@@ -106,8 +83,6 @@ module LinkedRails
|
|
106
83
|
self._defined_actions = initial_defined_actions(superclass.try(:_defined_actions) || {})
|
107
84
|
end
|
108
85
|
end
|
109
|
-
|
110
|
-
enhanceable :actionable_class, :Action
|
111
86
|
end
|
112
87
|
end
|
113
88
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pundit'
|
4
|
+
|
5
|
+
module LinkedRails
|
6
|
+
module Actions
|
7
|
+
class Object
|
8
|
+
include ActiveModel::Model
|
9
|
+
include LinkedRails::Model
|
10
|
+
|
11
|
+
attr_accessor :action
|
12
|
+
alias parent action
|
13
|
+
delegate :object, to: :action
|
14
|
+
|
15
|
+
def root_relative_iri
|
16
|
+
action.object_root_relative_iri
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def requested_resource(opts, user_context)
|
21
|
+
return super unless opts[:iri].include?('?')
|
22
|
+
|
23
|
+
parent_iri_with_query = [opts[:params][:parent_iri], opts[:iri].split('?').last].compact.join('?')
|
24
|
+
|
25
|
+
super(opts.merge(params: opts[:params].merge(parent_iri: parent_iri_with_query)), user_context)
|
26
|
+
end
|
27
|
+
|
28
|
+
def requested_single_resource(params, user_context)
|
29
|
+
return unless params.key?(:parent_iri)
|
30
|
+
|
31
|
+
parent = parent_from_params!(params, user_context)
|
32
|
+
|
33
|
+
object = parent&.object
|
34
|
+
object.instance_variable_set(:@iri, parent.object_iri)
|
35
|
+
object
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
class Collection
|
5
|
+
module Configuration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
private
|
10
|
+
|
11
|
+
def define_default_option_method(option)
|
12
|
+
attr_accessor "default_#{option}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_getter_option_method(option)
|
16
|
+
attr_writer option
|
17
|
+
|
18
|
+
define_method(option) do
|
19
|
+
resolve_collection_option(option)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
included do
|
25
|
+
attr_accessor :iri_template
|
26
|
+
|
27
|
+
LinkedRails::Model::Collections::COLLECTION_CUSTOMIZABLE_OPTIONS.each_key do |option|
|
28
|
+
define_default_option_method(option)
|
29
|
+
end
|
30
|
+
LinkedRails::Model::Collections::COLLECTION_OPTIONS.each_key do |option|
|
31
|
+
define_getter_option_method(option)
|
32
|
+
end
|
33
|
+
|
34
|
+
def display
|
35
|
+
resolve_collection_option(:display)&.to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def type
|
39
|
+
resolve_collection_option(:type)&.to_sym
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def resolve_collection_option(option)
|
46
|
+
var_name = :"@#{option}"
|
47
|
+
default_method_name = "default_#{option}"
|
48
|
+
|
49
|
+
var = instance_variable_defined?(var_name) ? instance_variable_get(var_name) : try(default_method_name)
|
50
|
+
|
51
|
+
var.respond_to?(:call) ? instance_exec(&var) : var
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|