linked_rails 0.0.2 → 0.0.4.pre.g2c6c26e86
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 +64 -55
- data/app/models/linked_rails/actions/list.rb +6 -31
- data/app/models/linked_rails/actions/object.rb +38 -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/actions/object_serializer.rb +9 -0
- 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 +26 -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 +201 -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 +131 -54
- 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 +28 -11
- 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 +80 -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,48 +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 form_resource_includes # rubocop:disable Metrics/CyclomaticComplexity
|
66
|
-
return {} if included_object.nil?
|
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 || [])
|
72
|
-
end
|
73
|
-
|
74
|
-
def included_object
|
75
|
-
object if include_object || object&.iri&.anonymous?
|
76
|
-
end
|
77
|
-
|
78
63
|
def object
|
79
64
|
@object = list.instance_exec(&@object) if @object.respond_to?(:call)
|
80
65
|
|
81
66
|
@object || resource
|
82
67
|
end
|
83
68
|
|
69
|
+
def object_iri
|
70
|
+
object&.iri&.anonymous? ? anonymous_object_iri : object&.iri
|
71
|
+
end
|
72
|
+
|
84
73
|
def parent
|
85
74
|
return @parent if instance_variable_defined?(:@parent)
|
86
75
|
|
@@ -92,10 +81,10 @@ module LinkedRails
|
|
92
81
|
end
|
93
82
|
|
94
83
|
def policy_message
|
95
|
-
resource_policy.try(:message)
|
84
|
+
resource_policy.try(:message) unless policy_valid?
|
96
85
|
end
|
97
86
|
|
98
|
-
def root_relative_iri(_opts
|
87
|
+
def root_relative_iri(**_opts)
|
99
88
|
value = root_relative_iri_from_var
|
100
89
|
value = RDF::URI(value) unless value.blank? || value.is_a?(RDF::URI)
|
101
90
|
return @root_relative_iri = value if value
|
@@ -109,24 +98,30 @@ module LinkedRails
|
|
109
98
|
RDF::URI(value)
|
110
99
|
end
|
111
100
|
|
112
|
-
def preview_includes
|
113
|
-
[:target, included_object: form_resource_includes]
|
114
|
-
end
|
115
|
-
|
116
101
|
def singular_resource?
|
117
102
|
resource.try(:singular_resource?)
|
118
103
|
end
|
119
104
|
|
105
|
+
def policy_status
|
106
|
+
resource_policy.try(:action_status)
|
107
|
+
end
|
108
|
+
|
120
109
|
def iri_opts
|
121
|
-
|
110
|
+
return {} if resource.blank?
|
111
|
+
|
112
|
+
resource.try(:singular_resource?) ? resource.singular_iri_opts : resource.iri_opts
|
122
113
|
end
|
123
114
|
|
124
115
|
def iri_template
|
125
|
-
path_suffix =
|
116
|
+
path_suffix = "/#{action_path || tag}"
|
126
117
|
|
127
|
-
return @iri_template ||= URITemplate.new(path_suffix) if resource.blank?
|
118
|
+
return @iri_template ||= LinkedRails::URITemplate.new(path_suffix) if resource.blank?
|
128
119
|
|
129
|
-
|
120
|
+
base_template = resource.send(resource.try(:singular_resource?) ? :singular_iri_template : :iri_template)
|
121
|
+
@iri_template ||= iri_template_expand_path(
|
122
|
+
base_template.to_s.sub('display,', '').sub('sort%5B%5D*,', ''),
|
123
|
+
path_suffix
|
124
|
+
)
|
130
125
|
end
|
131
126
|
|
132
127
|
def rdf_type
|
@@ -143,6 +138,12 @@ module LinkedRails
|
|
143
138
|
|
144
139
|
private
|
145
140
|
|
141
|
+
def anonymous_object_iri
|
142
|
+
object_iri = iri.dup
|
143
|
+
object_iri.path += '/action_object'
|
144
|
+
object_iri
|
145
|
+
end
|
146
|
+
|
146
147
|
def description_fallback
|
147
148
|
LinkedRails.translate(:action, :description, self, false)
|
148
149
|
end
|
@@ -156,7 +157,7 @@ module LinkedRails
|
|
156
157
|
end
|
157
158
|
|
158
159
|
def policy_resource_fallback
|
159
|
-
|
160
|
+
object
|
160
161
|
end
|
161
162
|
|
162
163
|
def policy_valid?
|
@@ -184,6 +185,13 @@ module LinkedRails
|
|
184
185
|
@root_relative_iri
|
185
186
|
end
|
186
187
|
|
188
|
+
def target_url_fallback # rubocop:disable Metrics/AbcSize
|
189
|
+
base = (resource.try(:singular_resource?) ? resource.singular_iri : resource.iri).dup
|
190
|
+
base.path = "#{base.path.chomp('/')}/#{target_path}" if target_path.present?
|
191
|
+
base.query = Rack::Utils.parse_nested_query(base.query).merge(target_query).to_param if target_query.present?
|
192
|
+
base
|
193
|
+
end
|
194
|
+
|
187
195
|
def type_fallback
|
188
196
|
Vocab.schema.UpdateAction
|
189
197
|
end
|
@@ -202,25 +210,26 @@ module LinkedRails
|
|
202
210
|
)
|
203
211
|
end
|
204
212
|
|
213
|
+
def get_action_list(parent, user_context)
|
214
|
+
return parent.action_list(user_context) if parent.respond_to?(:action_list)
|
215
|
+
|
216
|
+
app_action_list(user_context)
|
217
|
+
end
|
218
|
+
|
205
219
|
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]
|
220
|
+
parent = parent_from_params!(params, user_context) if params.key?(:parent_iri)
|
221
|
+
|
222
|
+
default_collection_option(:collection_class).collection_or_view(
|
223
|
+
default_collection_options.merge(parent: parent),
|
224
|
+
index_collection_params(params, user_context)
|
216
225
|
)
|
217
226
|
end
|
218
227
|
|
219
228
|
def requested_single_resource(params, user_context)
|
220
229
|
return nil if params[:id].blank?
|
221
230
|
|
222
|
-
parent = parent_from_params(params, user_context)
|
223
|
-
action_list = parent
|
231
|
+
parent = parent_from_params!(params, user_context) if params.key?(:parent_iri)
|
232
|
+
action_list = get_action_list(parent, user_context)
|
224
233
|
|
225
234
|
action_list&.action(params[:id].to_sym)
|
226
235
|
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,38 @@
|
|
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 iri
|
16
|
+
action.object_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
|
+
new(action: parent) if parent.object.anonymous_iri?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
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
|