linked_rails 0.0.3 → 0.0.4.pre.g14b377f91

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -674
  3. data/app/controllers/linked_rails/actions/objects_controller.rb +9 -0
  4. data/app/controllers/linked_rails/bulk_controller.rb +71 -21
  5. data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
  6. data/app/models/linked_rails/actions/item.rb +64 -55
  7. data/app/models/linked_rails/actions/list.rb +6 -31
  8. data/app/models/linked_rails/actions/object.rb +38 -0
  9. data/app/models/linked_rails/collection/configuration.rb +55 -0
  10. data/app/models/linked_rails/collection/filter.rb +1 -1
  11. data/app/models/linked_rails/collection/filter_field.rb +19 -2
  12. data/app/models/linked_rails/collection/filter_option.rb +1 -1
  13. data/app/models/linked_rails/collection/filterable.rb +6 -9
  14. data/app/models/linked_rails/collection/infinite.rb +113 -0
  15. data/app/models/linked_rails/collection/infinite_view.rb +1 -90
  16. data/app/models/linked_rails/collection/iri.rb +47 -43
  17. data/app/models/linked_rails/collection/iri_mapping.rb +15 -7
  18. data/app/models/linked_rails/collection/paginated.rb +46 -0
  19. data/app/models/linked_rails/collection/paginated_view.rb +1 -33
  20. data/app/models/linked_rails/collection/sortable.rb +1 -9
  21. data/app/models/linked_rails/collection/sorting.rb +1 -1
  22. data/app/models/linked_rails/collection/view.rb +51 -14
  23. data/app/models/linked_rails/collection.rb +53 -85
  24. data/app/models/linked_rails/creative_work.rb +1 -1
  25. data/app/models/linked_rails/entry_point.rb +8 -5
  26. data/app/models/linked_rails/enum_value.rb +40 -2
  27. data/app/models/linked_rails/form/field/association_input.rb +7 -1
  28. data/app/models/linked_rails/form/field/file_input.rb +1 -0
  29. data/app/models/linked_rails/form/field/resource_field.rb +2 -0
  30. data/{lib/linked_rails/enhancements/indexable/model.rb → app/models/linked_rails/form/field/url_input.rb} +3 -3
  31. data/app/models/linked_rails/form/field.rb +37 -13
  32. data/app/models/linked_rails/form/field_factory.rb +48 -18
  33. data/app/models/linked_rails/form/group.rb +4 -6
  34. data/app/models/linked_rails/form/page.rb +8 -4
  35. data/app/models/linked_rails/form.rb +16 -21
  36. data/app/models/linked_rails/manifest.rb +104 -22
  37. data/app/models/linked_rails/menus/item.rb +10 -13
  38. data/app/models/linked_rails/menus/list.rb +16 -7
  39. data/app/models/linked_rails/ontology/base.rb +3 -1
  40. data/app/models/linked_rails/ontology/class.rb +3 -3
  41. data/app/models/linked_rails/ontology.rb +5 -5
  42. data/app/models/linked_rails/property_query.rb +2 -0
  43. data/app/models/linked_rails/sequence.rb +4 -13
  44. data/app/models/linked_rails/shacl/property_shape.rb +1 -1
  45. data/app/models/linked_rails/web_page.rb +0 -4
  46. data/app/models/linked_rails/web_site.rb +0 -4
  47. data/app/models/linked_rails/widget.rb +4 -11
  48. data/app/policies/linked_rails/actions/object_policy.rb +11 -0
  49. data/app/policies/linked_rails/collection_policy.rb +2 -2
  50. data/app/serializers/linked_rails/actions/item_serializer.rb +5 -5
  51. data/app/serializers/linked_rails/actions/object_serializer.rb +9 -0
  52. data/app/serializers/linked_rails/collection/filter_field_serializer.rb +3 -2
  53. data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
  54. data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
  55. data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
  56. data/app/serializers/linked_rails/collection/view_serializer.rb +3 -3
  57. data/app/serializers/linked_rails/collection_serializer.rb +8 -7
  58. data/app/serializers/linked_rails/condition_serializer.rb +3 -3
  59. data/app/serializers/linked_rails/entry_point_serializer.rb +3 -3
  60. data/app/serializers/linked_rails/enum_value_serializer.rb +1 -0
  61. data/app/serializers/linked_rails/form/field/association_input_serializer.rb +1 -0
  62. data/app/serializers/linked_rails/form/field/file_input_serializer.rb +11 -0
  63. data/app/serializers/linked_rails/form/field_serializer.rb +3 -1
  64. data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
  65. data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
  66. data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
  67. data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
  68. data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
  69. data/app/serializers/linked_rails/property_query_serializer.rb +7 -0
  70. data/app/serializers/linked_rails/sequence_serializer.rb +2 -5
  71. data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
  72. data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
  73. data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
  74. data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
  75. data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
  76. data/app/serializers/linked_rails/widget_serializer.rb +3 -3
  77. data/lib/generators/linked_rails/install/install_generator.rb +5 -8
  78. data/lib/generators/linked_rails/install/templates/README +2 -0
  79. data/lib/generators/linked_rails/install/templates/app_menu_list.rb +36 -7
  80. data/lib/generators/linked_rails/install/templates/application_menu_list.rb +40 -1
  81. data/lib/generators/linked_rails/install/templates/initializer.rb +1 -2
  82. data/lib/generators/linked_rails/install/templates/locales.yml +14 -0
  83. data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
  84. data/lib/generators/linked_rails/install/templates/vocab.rb +1 -0
  85. data/lib/generators/linked_rails/install/templates/vocab.yml +2 -2
  86. data/lib/generators/linked_rails/model/model_generator.rb +0 -1
  87. data/lib/generators/linked_rails/model/templates/controller.rb.tt +5 -1
  88. data/lib/generators/linked_rails/model/templates/form.rb.tt +3 -0
  89. data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +15 -0
  90. data/lib/generators/linked_rails/model/templates/policy.rb.tt +13 -0
  91. data/lib/generators/linked_rails/model/templates/serializer.rb.tt +5 -1
  92. data/lib/linked_rails/active_response/controller/collections.rb +1 -1
  93. data/lib/linked_rails/active_response/controller/crud_defaults.rb +4 -4
  94. data/lib/linked_rails/active_response/controller/params.rb +10 -10
  95. data/lib/linked_rails/active_response/controller.rb +8 -18
  96. data/lib/linked_rails/active_response/responders/rdf.rb +19 -10
  97. data/lib/linked_rails/callable_variable.rb +1 -1
  98. data/lib/linked_rails/collection_params_parser.rb +93 -0
  99. data/lib/linked_rails/controller/actionable.rb +121 -0
  100. data/lib/linked_rails/controller/authorization.rb +6 -0
  101. data/lib/linked_rails/controller/default_actions/create.rb +52 -0
  102. data/lib/linked_rails/controller/default_actions/destroy.rb +42 -0
  103. data/lib/linked_rails/controller/default_actions/update.rb +43 -0
  104. data/lib/linked_rails/controller/delta.rb +58 -0
  105. data/lib/linked_rails/controller/error_handling.rb +10 -10
  106. data/lib/linked_rails/controller/rendering.rb +48 -0
  107. data/lib/linked_rails/controller.rb +24 -4
  108. data/lib/linked_rails/enhancements/creatable/controller.rb +1 -1
  109. data/lib/linked_rails/enhancements/destroyable/controller.rb +1 -1
  110. data/lib/linked_rails/enhancements/updatable/controller.rb +1 -1
  111. data/lib/linked_rails/enhancements.rb +0 -16
  112. data/lib/linked_rails/helpers/delta_helper.rb +26 -57
  113. data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
  114. data/lib/linked_rails/helpers/resource_helper.rb +4 -2
  115. data/lib/linked_rails/iri_mapper.rb +17 -39
  116. data/lib/linked_rails/middleware/error_handling.rb +51 -0
  117. data/lib/linked_rails/middleware/linked_data_params.rb +30 -151
  118. data/lib/linked_rails/model/actionable.rb +68 -0
  119. data/lib/linked_rails/model/collections.rb +201 -39
  120. data/lib/linked_rails/model/dirty.rb +6 -18
  121. data/lib/linked_rails/model/enhancements.rb +1 -6
  122. data/lib/linked_rails/model/filtering.rb +4 -6
  123. data/lib/linked_rails/model/indexable.rb +6 -16
  124. data/lib/linked_rails/model/iri.rb +28 -19
  125. data/lib/linked_rails/model/iri_mapping.rb +37 -8
  126. data/lib/linked_rails/model/menuable.rb +28 -0
  127. data/lib/linked_rails/model/serialization.rb +2 -15
  128. data/lib/linked_rails/model/singularable.rb +57 -0
  129. data/lib/linked_rails/model/sorting.rb +0 -5
  130. data/lib/linked_rails/model/tables.rb +26 -0
  131. data/lib/linked_rails/model.rb +17 -7
  132. data/lib/linked_rails/params_parser.rb +131 -54
  133. data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
  134. data/lib/linked_rails/policy.rb +40 -46
  135. data/lib/linked_rails/railtie.rb +11 -0
  136. data/lib/linked_rails/rdf_error.rb +2 -2
  137. data/lib/linked_rails/renderers.rb +1 -0
  138. data/lib/linked_rails/routes.rb +38 -22
  139. data/lib/linked_rails/serializer/actionable.rb +27 -0
  140. data/lib/linked_rails/serializer/menuable.rb +31 -0
  141. data/lib/linked_rails/serializer/singularable.rb +26 -0
  142. data/lib/linked_rails/serializer.rb +28 -11
  143. data/lib/linked_rails/test_methods.rb +114 -0
  144. data/lib/linked_rails/translate.rb +31 -9
  145. data/lib/linked_rails/types/iri_type.rb +37 -0
  146. data/lib/linked_rails/uri_template.rb +30 -0
  147. data/lib/linked_rails/version.rb +1 -1
  148. data/lib/linked_rails/vocab.rb +9 -0
  149. data/lib/linked_rails.rb +30 -13
  150. data/lib/rails/welcome_controller.rb +3 -3
  151. data/lib/rdf/list.rb +9 -0
  152. data/lib/rdf/query_fix.rb +15 -0
  153. metadata +71 -33
  154. data/app/models/linked_rails/actions/default_actions/create.rb +0 -60
  155. data/app/models/linked_rails/actions/default_actions/destroy.rb +0 -45
  156. data/app/models/linked_rails/actions/default_actions/update.rb +0 -50
  157. data/app/models/linked_rails/actions/default_actions.rb +0 -17
  158. data/lib/generators/linked_rails/install/templates/application_action_list.rb +0 -3
  159. data/lib/generators/linked_rails/model/templates/action_list.rb.tt +0 -6
  160. data/lib/linked_rails/enhancements/actionable/model.rb +0 -71
  161. data/lib/linked_rails/enhancements/actionable/serializer.rb +0 -25
  162. data/lib/linked_rails/enhancements/creatable/action.rb +0 -15
  163. data/lib/linked_rails/enhancements/destroyable/action.rb +0 -15
  164. data/lib/linked_rails/enhancements/destroyable/routing.rb +0 -19
  165. data/lib/linked_rails/enhancements/menuable/model.rb +0 -36
  166. data/lib/linked_rails/enhancements/menuable/serializer.rb +0 -33
  167. data/lib/linked_rails/enhancements/route_concerns.rb +0 -56
  168. data/lib/linked_rails/enhancements/singularable/controller.rb +0 -43
  169. data/lib/linked_rails/enhancements/singularable/model.rb +0 -47
  170. data/lib/linked_rails/enhancements/singularable/serializer.rb +0 -28
  171. data/lib/linked_rails/enhancements/tableable/model.rb +0 -28
  172. data/lib/linked_rails/enhancements/updatable/action.rb +0 -15
  173. data/lib/linked_rails/enhancements/updatable/routing.rb +0 -20
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Actions
5
+ class ObjectsController < LinkedRails.controller_parent_class
6
+ active_response :show
7
+ end
8
+ end
9
+ end
@@ -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
@@ -30,12 +31,16 @@ module LinkedRails
30
31
  @authorized_resources ||=
31
32
  params
32
33
  .require(:resources)
33
- .map { |param| param.permit(:include, :iri) }
34
+ .map { |param| resource_params(param) }
34
35
  .map(&method(:timed_authorized_resource))
35
36
  end
36
37
 
38
+ def client
39
+ nil
40
+ end
41
+
37
42
  def handle_resource_error(opts, error)
38
- log_resource_error(error)
43
+ log_resource_error(error, opts[:iri])
39
44
  status = error_status(error)
40
45
  body = error_body(status, error, opts[:iri]) if opts[:include].to_s == 'true'
41
46
 
@@ -50,7 +55,7 @@ module LinkedRails
50
55
  resource_body(error_resource(status, error, iri))
51
56
  end
52
57
 
53
- def log_resource_error(error)
58
+ def log_resource_error(error, _iri)
54
59
  return unless log_resource_error?(error)
55
60
 
56
61
  Rails.logger.error(error)
@@ -64,23 +69,25 @@ module LinkedRails
64
69
  def print_timings
65
70
  Rails.logger.debug(
66
71
  "\n CPU system user+system real inc status cache iri\n" \
67
- "#{timings.join("\n")}\n" \
72
+ "#{timing_lines.join("\n")}\n" \
68
73
  " User: #{current_user.class}(#{current_user.id})"
69
74
  )
70
75
  end
71
76
 
77
+ def send_timings
78
+ timings.each do |timing|
79
+ client.send_json(timing_json(timing))
80
+ end
81
+ end
82
+
72
83
  def require_doorkeeper_token?
73
84
  false
74
85
  end
75
86
 
76
- def resource_body(resource)
77
- return if resource.nil?
78
-
79
- serializer_options = RDF::Serializers::Renderers.transform_opts(
80
- {include: resource&.try(:preview_includes)},
81
- serializer_params
82
- )
83
- RDF::Serializers.serializer_for(resource).new(resource, serializer_options).send(:render_hndjson)
87
+ def resource_params(param)
88
+ params = param.permit(:include, :iri)
89
+ params[:iri] = URI(params[:iri])
90
+ params
84
91
  end
85
92
 
86
93
  def resource_response_body(iri, rack_body, status)
@@ -109,7 +116,7 @@ module LinkedRails
109
116
  fullpath = iri.query.blank? ? iri.path : "#{iri.path}?#{iri.query}"
110
117
 
111
118
  request.env.slice(*REQUEST_HEADERS).merge(
112
- 'HTTP_ACCEPT' => 'application/hex+x-ndjson',
119
+ 'HTTP_ACCEPT' => 'application/empathy+json',
113
120
  'HTTP_OPERATOR_ARG_GRAPH' => 'true',
114
121
  'ORIGINAL_FULLPATH' => fullpath
115
122
  )
@@ -134,16 +141,54 @@ module LinkedRails
134
141
 
135
142
  def term_from_vocab(iri)
136
143
  vocab = Vocab.for(iri)
137
- tag = iri.split(vocab.to_s).last
144
+ tag = iri.to_s.split(vocab.to_s).last
138
145
  vocab[tag]
139
146
  rescue NoMethodError
140
147
  nil
141
148
  end
142
149
 
150
+ def timing_json(timing) # rubocop:disable Metrics/MethodLength
151
+ route = Rails.application.routes.recognize_path(timing[:resource].to_s)
152
+
153
+ {
154
+ type: 'web',
155
+ timings: {
156
+ total_duration: timing[:time].total
157
+ },
158
+ default_labels: {
159
+ action: route[:action] || 'show',
160
+ controller: route[:controller] || 'subresource',
161
+ status: timing[:status],
162
+ include: timing[:include]
163
+ }
164
+ }
165
+ end
166
+
167
+ def timing_lines
168
+ timings.map do |timing|
169
+ include = timing[:include].to_s.ljust(5)
170
+ "#{timing[:time].to_s[0..-2]} - #{include} #{timing[:status]} #{timing[:cache]} #{timing[:resource]}"
171
+ end
172
+ end
173
+
174
+ def ontology_class(iri)
175
+ klass = LinkedRails.linked_models.detect do |model|
176
+ (model.iri.is_a?(Array) ? model.iri : [model.iri]).include?(iri)
177
+ end
178
+ LinkedRails.ontology_class_class.new(iri: iri, klass: klass)
179
+ end
180
+
181
+ def ontology_property(iri)
182
+ LinkedRails.ontology_property_class.new(iri: iri)
183
+ end
184
+
143
185
  def ontology_term_response(iri, term, include)
186
+ capital = term.relativize(term.vocab).to_s[0] =~ /[A-Z]/
187
+ resource = capital ? ontology_class(term) : ontology_property(term)
188
+
144
189
  resource_response(
145
190
  iri,
146
- body: include ? resource_body(LinkedRails.ontology_property_class.new(iri: term)) : nil,
191
+ body: include ? resource_body(resource) : nil,
147
192
  cache: :public,
148
193
  language: I18n.locale,
149
194
  status: 200
@@ -161,6 +206,8 @@ module LinkedRails
161
206
  language: response_language(headers),
162
207
  status: status
163
208
  )
209
+ rescue URI::InvalidURIError, ActionController::BadRequest
210
+ resource_response(iri)
164
211
  end
165
212
 
166
213
  def response_language(headers)
@@ -181,15 +228,18 @@ module LinkedRails
181
228
  def timed_authorized_resource(resource)
182
229
  res = nil
183
230
  time = Benchmark.measure { res = authorized_resource(resource) }
184
- unless Rails.env.production?
185
- include = resource[:include].to_s.ljust(5)
186
- timings << "#{time.to_s[0..-2]} - #{include} #{res[:status]} #{res[:cache]} #{resource[:iri]}"
187
- end
231
+ timings << {
232
+ time: time,
233
+ include: resource[:include],
234
+ status: res[:status],
235
+ cache: res[:cache],
236
+ resource: resource[:iri]
237
+ }
188
238
  res
189
239
  end
190
240
 
191
241
  def wrong_host?(iri)
192
- !iri.starts_with?(LinkedRails.iri)
242
+ !iri.to_s.starts_with?(LinkedRails.iri)
193
243
  end
194
244
  end
195
245
  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
- %i[description result type policy label image url include_object include_paths collection condition form completed
18
- tag http_method favorite path policy_resource predicate resource].each do |method|
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 completed
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) if action_status == Vocab.ontola[:DisabledActionStatus]
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
- resource&.iri_opts || {}
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 = path.blank? ? "/actions/#{tag}" : "/#{path}"
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
- @iri_template ||= iri_template_expand_path(resource.send(:iri_template), path_suffix)
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
- resource
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}/#{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
- action_list = parent ? parent.action_list(user_context) : app_action_list(user_context)
208
-
209
- LinkedRails.collection_class.new(
210
- association_base: action_list.actions,
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 ? parent.action_list(user_context) : app_action_list(user_context)
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] ||= options[:action_tag] || tag
35
+ options[:tag] ||= tag
38
36
  options[:list] ||= self
39
- LinkedRails.actions_item_class.new(options.except(:action_tag))
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
@@ -8,7 +8,7 @@ module LinkedRails
8
8
 
9
9
  attr_accessor :default_filter, :key, :value, :collection
10
10
 
11
- def iri(_opts = {})
11
+ def iri(**_opts)
12
12
  self
13
13
  end
14
14
  end
@@ -9,11 +9,12 @@ module LinkedRails
9
9
  include LinkedRails::CallableVariable
10
10
 
11
11
  attr_accessor :key, :klass, :collection
12
- attr_writer :options_array, :options_in
12
+ attr_writer :options_array, :options_in, :visible
13
13
  callable_variable(:options_array)
14
14
  callable_variable(:options_in)
15
+ callable_variable(:visible)
15
16
 
16
- def iri(_opts = {})
17
+ def iri(**_opts)
17
18
  self
18
19
  end
19
20
 
@@ -25,6 +26,22 @@ module LinkedRails
25
26
  attrs = option.is_a?(Hash) ? option : {value: option}
26
27
  Collection::FilterOption.new(attrs.merge(collection: collection, key: key))
27
28
  end
29
+
30
+ def visible?
31
+ has_options? && condition_valid?
32
+ end
33
+
34
+ private
35
+
36
+ def condition_valid?
37
+ return true if visible.nil?
38
+
39
+ visible
40
+ end
41
+
42
+ def has_options?
43
+ !!(options_in || options_array)
44
+ end
28
45
  end
29
46
  end
30
47
  end
@@ -9,7 +9,7 @@ module LinkedRails
9
9
 
10
10
  attr_accessor :collection, :count, :value, :key
11
11
 
12
- def iri(_opts = {})
12
+ def iri(**_opts)
13
13
  self
14
14
  end
15
15
  end