linked_rails 0.0.1 → 0.0.4.pre.g0ec6e30ca
Sign up to get free protection for your applications and to get access to all the features.
- 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 +7 -8
- data/lib/generators/linked_rails/install/templates/README +7 -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 +14 -7
- data/lib/linked_rails/controller/rendering.rb +48 -0
- data/lib/linked_rails/controller.rb +24 -4
- data/lib/linked_rails/enhanceable.rb +1 -1
- 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 -2
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +79 -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
|