linked_rails 0.0.3 → 0.0.4.pre.g14b377f91

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.
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
@@ -2,5 +2,18 @@
2
2
 
3
3
  <% module_namespacing do -%>
4
4
  class <%= class_name %>Policy < ApplicationPolicy
5
+ permit_attributes %i[<%= attributes.reject(&:reference?).map { |attribute| attribute.name }.join(' ') %>]
6
+
7
+ def create?
8
+ false
9
+ end
10
+
11
+ def update?
12
+ false
13
+ end
14
+
15
+ def destroy?
16
+ false
17
+ end
5
18
  end
6
19
  <% end -%>
@@ -3,7 +3,11 @@
3
3
  <% module_namespacing do -%>
4
4
  class <%= class_name %>Serializer < ApplicationSerializer
5
5
  <% attributes.each do |attribute| -%>
6
- attribute :<%= attribute.name %>, predicate: LinkedRails.app_vocab[:<%= attribute.name %>]
6
+ <% if attribute.reference? -%>
7
+ has_one :<%= attribute.name %>, predicate: Vocab.app[:<%= attribute.name.camelize(:lower) %>]
8
+ <% else -%>
9
+ attribute :<%= attribute.name %>, predicate: Vocab.app[:<%= attribute.name.camelize(:lower) %>]
10
+ <% end -%>
7
11
  <% end -%>
8
12
  end
9
13
  <% end -%>
@@ -9,7 +9,7 @@ module LinkedRails
9
9
  def index_association; end
10
10
 
11
11
  def index_includes
12
- requested_resource.preview_includes
12
+ requested_resource!.try(:preview_includes)
13
13
  end
14
14
 
15
15
  def index_iri
@@ -10,8 +10,8 @@ module LinkedRails
10
10
  current_resource!
11
11
  .class
12
12
  .try(:reflect_on_all_associations)
13
- .select(&:collection?)
14
- .each { |association| current_resource!.association(association.name).reset }
13
+ &.select(&:collection?)
14
+ &.each { |association| current_resource!.association(association.name).reset }
15
15
  end
16
16
 
17
17
  def create_execute
@@ -50,7 +50,7 @@ module LinkedRails
50
50
  def requested_resource
51
51
  @requested_resource ||= controller_class.try(
52
52
  :requested_resource,
53
- LinkedRails.iri_mapper.route_params_to_opts(params.dup),
53
+ LinkedRails.iri_mapper.route_params_to_opts(params.dup, request.original_url),
54
54
  user_context
55
55
  )
56
56
  end
@@ -80,7 +80,7 @@ module LinkedRails
80
80
  end
81
81
 
82
82
  def update_meta
83
- changes_triples + changed_relations_triples
83
+ changes_triples(current_resource) + changed_relations_triples(current_resource)
84
84
  end
85
85
 
86
86
  def user_context
@@ -11,17 +11,13 @@ module LinkedRails
11
11
  end
12
12
 
13
13
  def params_parser
14
- @params_parser ||= LinkedRails::ParamsParser.new(params)
15
- end
16
-
17
- def parsed_filter_params
18
- filters = params_parser.filter_params
19
-
20
- ActionController::Parameters.new(controller_class.try(:attributes_from_filters, filters) || {})
14
+ @params_parser ||= LinkedRails::ParamsParser.new(params: params, user_context: user_context)
21
15
  end
22
16
 
23
17
  def permit_filter_params
24
- @permit_filter_params ||= parsed_filter_params.permit(*permit_param_keys)
18
+ @permit_filter_params ||=
19
+ policy(requested_resource || new_resource)
20
+ .permitted_attributes_from_filters(params_parser.filter_params)
25
21
  end
26
22
 
27
23
  def permit_params
@@ -37,11 +33,15 @@ module LinkedRails
37
33
  end
38
34
 
39
35
  def permit_params_with_filters
40
- permit_filter_params.merge(permit_params.to_h)
36
+ permitted = permit_filter_params.merge(permit_params.to_h)
37
+ permitted[:singular_resource] = true if params[:singular_route].to_s == 'true'
38
+ permitted
41
39
  end
42
40
 
43
41
  def resource_params
44
- return ActionController::Parameters.new if !params.key?(permit_param_key) && allow_empty_params?
42
+ empty_params = !params.key?(permit_param_key) || params[permit_param_key] == {}
43
+
44
+ return ActionController::Parameters.new if empty_params && allow_empty_params?
45
45
 
46
46
  params.require(permit_param_key)
47
47
  end
@@ -8,30 +8,20 @@ require_relative 'controller/params'
8
8
 
9
9
  module LinkedRails
10
10
  module Controller
11
- include Pundit
11
+ include Pundit::Authorization
12
12
  include LinkedRails::ActiveResponse::Controller::Collections
13
13
  include LinkedRails::ActiveResponse::Controller::CrudDefaults
14
14
  include LinkedRails::ActiveResponse::Controller::Params
15
15
 
16
- def _render_with_renderer_json(record, options)
17
- self.content_type = Mime[:json]
18
-
19
- return record if record.is_a?(String)
20
- return record.to_json if record.is_a?(Hash)
21
-
22
- serializer_opts = RDF::Serializers::Renderers.transform_opts(
23
- options,
24
- serializer_params
25
- )
26
-
27
- serializer = RDF::Serializers.serializer_for(record)&.new(record, serializer_opts)
28
- return record.to_json unless serializer
29
-
30
- Oj.dump(serializer.serializable_hash, mode: :compat)
16
+ def success_message_translation_key
17
+ "actions.#{Translate.translation_key(controller_class)}.#{action_name}.success"
31
18
  end
32
19
 
33
- def serializer_params
34
- {}
20
+ def success_message_translation_opts
21
+ {
22
+ default: [:"actions.default.#{action_name}.success", ''],
23
+ type: I18n.t("#{controller_class.model_name.collection}.type").capitalize
24
+ }
35
25
  end
36
26
  end
37
27
  end
@@ -37,7 +37,7 @@ module LinkedRails
37
37
  response_headers(opts)
38
38
  controller.respond_with_resource(
39
39
  resource: nil,
40
- meta: error_meta(opts[:resource]),
40
+ meta: error_meta(opts[:resource], opts[:errors] || {}),
41
41
  status: :unprocessable_entity
42
42
  )
43
43
  end
@@ -47,15 +47,22 @@ module LinkedRails
47
47
  controller.respond_with_resource(opts)
48
48
  end
49
49
 
50
- def redirect(**opts) # rubocop:disable Metrics/AbcSize
50
+ def redirect(**opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
51
51
  return super if controller.request.head?
52
52
 
53
+ opts[:status] ||= 200
54
+
53
55
  response_headers(opts)
54
56
  add_exec_action_header(
55
57
  controller.response.headers,
56
58
  ontola_redirect_action(opts[:location], reload: opts[:reload])
57
59
  )
58
- controller.head 200, content_type: content_type, location: opts[:location]
60
+ if opts[:meta].blank? || head_request?
61
+ controller.head(opts[:status], location: opts[:location], content_type: content_type)
62
+ else
63
+ opts[format] = []
64
+ controller.render opts
65
+ end
59
66
  end
60
67
 
61
68
  def resource(**opts) # rubocop:disable Metrics/AbcSize
@@ -89,10 +96,10 @@ module LinkedRails
89
96
  ]
90
97
  end
91
98
 
92
- def error_statements(iri, resource)
99
+ def error_statements(iri, resource, resource_errors)
93
100
  index = 0
94
- resource.errors.messages.map do |key, values|
95
- predicate = resource.class.predicate_for_key(key.to_s.split('.').first)
101
+ resource_errors.map do |key, values|
102
+ predicate = resource&.class&.predicate_for_key(key.to_s.split('.').first)
96
103
  if predicate
97
104
  error_statements_for(iri, predicate, values)
98
105
  else
@@ -106,16 +113,18 @@ module LinkedRails
106
113
  values.map { |value| [iri, predicate, value.sub(/\S/, &:upcase)] }
107
114
  end
108
115
 
109
- def error_meta(resource)
116
+ def error_meta(resource, custom_errors)
110
117
  form_iri = controller.request.headers['Request-Referrer']
111
- return [] unless form_iri && resource.respond_to?(:errors)
118
+ resource_errors = (resource.try(:errors)&.messages || {}).merge(custom_errors)
119
+
120
+ return [] unless form_iri && resource_errors.present?
112
121
 
113
122
  error_object = ::RDF::Node.new
114
123
  [
115
124
  error_mapping(form_iri, error_object),
116
125
  error_type(error_object),
117
126
  error_status(error_object)
118
- ] + error_statements(error_object, resource)
127
+ ] + error_statements(error_object, resource, resource_errors)
119
128
  end
120
129
 
121
130
  def error_type(error_object)
@@ -149,7 +158,7 @@ module LinkedRails
149
158
  error_statements_for(
150
159
  iri,
151
160
  ::RDF["_#{index}"],
152
- values.map { |value| resource.errors.full_message(key, value) }
161
+ values.map { |value| resource&.errors&.full_message(key, value) || value }
153
162
  )
154
163
  end
155
164
  end
@@ -5,7 +5,7 @@ module LinkedRails
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- def callable_variable(method, opts = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
8
+ def callable_variable(method, **opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
9
9
  variable ||= opts[:variable] || method
10
10
  default ||= opts[:default]
11
11
 
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class CollectionParamsParser
5
+ attr_reader :params, :user_context
6
+
7
+ def initialize(params)
8
+ @user_context = params[:user_context]
9
+ @params = params.is_a?(Hash) ? ActionController::Parameters.new(params) : params
10
+ end
11
+
12
+ def collection_params
13
+ return @collection_params if instance_variable_defined?(:@collection_params)
14
+
15
+ values = permit_params(:display, :page_size, :table_type, :title, :type)
16
+
17
+ filter = filter_params
18
+ values[:filter] = filter if filter
19
+
20
+ sort = sorting_params
21
+ values[:sort] = sort if sort
22
+
23
+ values[:user_context] = user_context if user_context
24
+
25
+ @collection_params = values
26
+ end
27
+
28
+ def collection_view_params
29
+ return @collection_view_params if instance_variable_defined?(:@collection_view_params)
30
+
31
+ values = permit_params(:page)
32
+
33
+ before = before_params
34
+ values[:before] = before if before
35
+
36
+ @collection_view_params = values
37
+ end
38
+
39
+ def filter_params # rubocop:disable Metrics/AbcSize
40
+ return @filter_params if instance_variable_defined?(:@filter_params)
41
+
42
+ values = permit_params(filter: [])[:filter] || permit_params(filter: {})[:filter]
43
+ return @filter_params = values if values.is_a?(Hash)
44
+ return @filter_params = {} if values.blank?
45
+
46
+ @filter_params = values.each_with_object({}) do |f, hash|
47
+ values = f.split('=')
48
+ key = RDF::URI(CGI.unescape(values.first))
49
+ hash[key] ||= []
50
+ hash[key] << CGI.unescape(values.second)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def before_params
57
+ return @before_params if instance_variable_defined?(:@before_params)
58
+
59
+ values = permit_params(before: [])[:before]
60
+ return @before_params = nil if values.blank?
61
+
62
+ @before_params = values.map do |f|
63
+ key, value = f.split('=')
64
+ {key: RDF::URI(CGI.unescape(key)), value: value}
65
+ end
66
+ end
67
+
68
+ def parse_filter_value(value)
69
+ return value if value.is_a?(Hash)
70
+
71
+ key, value = value.split('=')
72
+ {key: RDF::URI(CGI.unescape(key)), direction: value}
73
+ end
74
+
75
+ def permit_params(*keys)
76
+ params
77
+ .permit(*keys)
78
+ .to_h
79
+ .with_indifferent_access
80
+ end
81
+
82
+ def sorting_params
83
+ return @sorting_params if instance_variable_defined?(:@sorting_params)
84
+
85
+ values = permit_params(sort: [])[:sort]
86
+ return @sorting_params = nil if values.blank?
87
+
88
+ @sorting_params = values.map do |f|
89
+ parse_filter_value(f)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'default_actions/create'
4
+ require_relative 'default_actions/destroy'
5
+ require_relative 'default_actions/update'
6
+
7
+ module LinkedRails
8
+ module Controller
9
+ module Actionable
10
+ ACTION_METHOD_MAPPING = {
11
+ execute: :execute,
12
+ on_failure: :failure,
13
+ on_success: :success
14
+ }.freeze
15
+
16
+ extend ActiveSupport::Concern
17
+
18
+ included do
19
+ extend LinkedRails::Controller::DefaultActions::Create
20
+ extend LinkedRails::Controller::DefaultActions::Destroy
21
+ extend LinkedRails::Controller::DefaultActions::Update
22
+ end
23
+
24
+ class_methods do
25
+ def has_collection_action(action, **opts)
26
+ has_action(:collection, action, **opts)
27
+ end
28
+
29
+ def has_singular_action(action, **opts)
30
+ has_action(:singular, action, **opts)
31
+ end
32
+
33
+ def has_resource_action(action, **opts)
34
+ has_action(:resource, action, **opts)
35
+ end
36
+
37
+ private
38
+
39
+ # @param [:resource, :singular, :collection] type To which action list the action is added
40
+ # @param [symbol] action_key A key to identify the action
41
+ # @param [Hash] opts The options for the action
42
+ # @option opts [symbol] :action_name The name for the controller action for GETting this action.
43
+ # A route is automatically generated. Defaults to the action key
44
+ # @option opts [proc<string>, string] :action_path The path to be appended to the resource iri.
45
+ # Defaults to "#{action_key}_action"
46
+ # @option opts [proc<string>, string] :description The description of this action
47
+ # @option opts [symbol] :execute The controller method to use when this action is executed.
48
+ # Defaults to "#{action}_execute"
49
+ # @option opts [proc<boolean>, boolean] :favorite Whether or not this is a favorite action
50
+ # @option opts [proc<LinkedRails::Form>, LinkedRails::Form] :form The form for this action
51
+ # @option opts [proc<string>, string] :http_method The method to be used in the request.
52
+ # GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
53
+ # Defaults to POST
54
+ # @option opts [proc<string>, string] :image A fontawesome icon, prepended with 'fa-'
55
+ # @option opts [boolean] :inherit Whether descendant controllers should clone this action.
56
+ # Defaults to true
57
+ # @option opts [boolean] :one_click Whether the action can be executed with one click.
58
+ # Defaults to false
59
+ # @option opts [proc<string>, string] :label The label of the action
60
+ # @option opts [LinkedRails::Model] :object The object on which the action will be executed
61
+ # Defaults to the resource
62
+ # @option opts [symbol] :on_failure Callback when the execute method failed.
63
+ # Defaults to "#{action}_failure"
64
+ # @option opts [symbol] :on_success Callback when the execute method succeeded.
65
+ # Defaults to "#{action}_success"
66
+ # @option opts [symbol] :policy The method to be called on the policy of the policy_resource
67
+ # @option opts [Array<symbol>] :policy_arguments The arguments passed to the policy method
68
+ # @option opts [proc<LinkedRails::Model>, LinkedRails::Model] :policy_resource
69
+ # The resource on which a policy needs to be authorized.
70
+ # Defaults to the object
71
+ # @option opts [proc<RDF::URI>, RDF::URI] :predicate The relation between the resource and the action
72
+ # @option opts [proc<LinkedRails::Model>, LinkedRails::Model] :result
73
+ # @option opts [proc<string>, string] :submit_label The label for the submit button of the action
74
+ # @option opts [proc<string>, string] :target_url The url whereto the request will be made.
75
+ # Use target_path/target_query when the url starts with the iri of the resource, so a route can be generated.
76
+ # @option opts [string] :target_path The path appended to the iri of the resource to determine
77
+ # the url whereto the request will be made. A route is automatically generated.
78
+ # Defaults to the action key
79
+ # @option opts [hash] :target_query The query appended to the iri of the resource to determine
80
+ # @option opts [array<RDF::URI>, RDF::URI] :type The rdf type of the action.
81
+ # Defaults to schema.UpdateAction
82
+ def has_action(type, action_key, opts)
83
+ opts[:action_name] ||= "#{action_key}_action"
84
+ opts[:http_method] ||= 'POST'
85
+ opts[:target_path] ||= action_key if opts[:target_url].blank?
86
+
87
+ active_response(action_key, opts[:action_name])
88
+ define_action_show_method(action_key, opts)
89
+ define_action_execute_methods(action_key, opts)
90
+ controller_class.action_list.defined_actions[type][action_key] = opts
91
+ end
92
+
93
+ def define_action_execute_methods(action_key, opts)
94
+ ACTION_METHOD_MAPPING.each do |key, value|
95
+ define_action_execute_method(action_key, key, value, opts)
96
+ end
97
+ end
98
+
99
+ def define_action_execute_method(action, key, suffix, opts)
100
+ call_method = opts.delete(key)
101
+ method_name = :"#{action}_#{suffix}"
102
+ return if call_method.blank? || method_name == call_method
103
+
104
+ define_method(method_name) do
105
+ if call_method.is_a?(Symbol)
106
+ send(call_method)
107
+ else
108
+ instance_exec(&call_method)
109
+ end
110
+ end
111
+ end
112
+
113
+ def define_action_show_method(_action, opts)
114
+ define_method("#{opts[:action_name]}_success") do
115
+ respond_with_resource(show_success_options)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -6,10 +6,16 @@ module LinkedRails
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  def authorize_action
9
+ return authorize_action_item if current_resource!.is_a?(LinkedRails.actions_item_class)
10
+
9
11
  query = action_name == 'index' ? :show? : "#{params[:action].chomp('!')}?"
10
12
 
11
13
  authorize(current_resource!, query)
12
14
  end
15
+
16
+ def authorize_action_item
17
+ authorize(current_resource!.resource, :show?) if current_resource!.resource
18
+ end
13
19
  end
14
20
  end
15
21
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Controller
5
+ module DefaultActions
6
+ module Create
7
+ def has_collection_create_action(**overwrite)
8
+ has_collection_action(:create, **create_collection_options(**overwrite))
9
+ end
10
+
11
+ def has_singular_create_action(**overwrite)
12
+ has_singular_action(:create, **create_singular_options(**overwrite))
13
+ end
14
+
15
+ private
16
+
17
+ def create_collection_options(**overwrite)
18
+ default_create_options(
19
+ form: -> { resource.association_class.try(:form_class) },
20
+ object: -> { resource.child_resource },
21
+ policy: :create?
22
+ ).merge(overwrite)
23
+ end
24
+
25
+ def create_singular_options(**overwrite)
26
+ default_create_options(
27
+ form: -> { resource.class.try(:form_class) },
28
+ object: -> { resource },
29
+ policy: :create?
30
+ ).merge(overwrite)
31
+ end
32
+
33
+ def default_create_options(**overwrite) # rubocop:disable Metrics/MethodLength
34
+ {
35
+ action_name: :new,
36
+ action_path: :new,
37
+ execute: :create_execute,
38
+ http_method: :post,
39
+ image: 'fa-plus',
40
+ on_failure: :create_failure,
41
+ on_success: :create_success,
42
+ result: -> { result_class },
43
+ target_path: '',
44
+ type: lambda {
45
+ [Vocab.ontola["Create::#{result_class}"], Vocab.schema.CreateAction]
46
+ }
47
+ }.merge(overwrite)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Controller
5
+ module DefaultActions
6
+ module Destroy
7
+ def has_resource_destroy_action(**overwrite)
8
+ has_resource_action(:destroy, **destroy_resource_options(**overwrite))
9
+ end
10
+
11
+ def has_singular_destroy_action(**overwrite)
12
+ has_singular_action(:destroy, **destroy_singular_options(**overwrite))
13
+ end
14
+
15
+ private
16
+
17
+ def destroy_resource_options(**overwrite)
18
+ default_destroy_options(**overwrite)
19
+ end
20
+
21
+ def destroy_singular_options(**overwrite)
22
+ default_destroy_options(**overwrite)
23
+ end
24
+
25
+ def default_destroy_options(**overwrite) # rubocop:disable Metrics/MethodLength
26
+ {
27
+ action_name: :delete,
28
+ action_path: :delete,
29
+ execute: :destroy_execute,
30
+ http_method: :delete,
31
+ image: 'fa-close',
32
+ on_failure: :destroy_failure,
33
+ on_success: :destroy_success,
34
+ policy: :destroy?,
35
+ target_path: '',
36
+ type: [Vocab.schema.Action, Vocab.ontola[:DestroyAction]]
37
+ }.merge(overwrite)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Controller
5
+ module DefaultActions
6
+ module Update
7
+ def has_resource_update_action(**overwrite)
8
+ has_resource_action(:update, **update_resource_options(**overwrite))
9
+ end
10
+
11
+ def has_singular_update_action(**overwrite)
12
+ has_singular_action(:update, **update_singular_options(**overwrite))
13
+ end
14
+
15
+ private
16
+
17
+ def update_resource_options(**overwrite)
18
+ default_update_options(**overwrite)
19
+ end
20
+
21
+ def update_singular_options(**overwrite)
22
+ default_update_options(**overwrite)
23
+ end
24
+
25
+ def default_update_options(**overwrite) # rubocop:disable Metrics/MethodLength
26
+ {
27
+ action_name: :edit,
28
+ action_path: :edit,
29
+ execute: :update_execute,
30
+ form: -> { resource.class.try(:form_class) },
31
+ http_method: :put,
32
+ image: 'fa-pencil-square-o',
33
+ on_failure: :update_failure,
34
+ on_success: :update_success,
35
+ policy: :update?,
36
+ target_path: '',
37
+ type: Vocab.schema.UpdateAction
38
+ }.merge(overwrite)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Controller
5
+ module Delta
6
+ include LinkedRails::Helpers::DeltaHelper
7
+
8
+ def changes_triples(resource)
9
+ resource_serializer(resource)&.send(:repository).statements
10
+ end
11
+
12
+ def changed_relations_triples(resource, inverted = nil) # rubocop:disable Metrics/AbcSize
13
+ resource.previously_changed_relations.flat_map do |key, value|
14
+ if key.to_s.ends_with?('_collection')
15
+ changed_collection_triples(resource, key)
16
+ else
17
+ destructed = resource.send(:association_has_destructed?, key)
18
+ records = value.relationship_type == :has_many ? resource.send(key) : [resource.send(key)]
19
+ changed_relation_triples(value.predicate, destructed, records - [inverted], resource)
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def changed_relation_triples(predicate, destructed, resources, inverted)
27
+ related_resource_invalidations =
28
+ resources.flat_map do |resource|
29
+ resource_delta = invalidate_resource_delta(resource)
30
+ [resource_delta] + changed_relations_triples(resource, inverted)
31
+ end
32
+
33
+ return related_resource_invalidations unless predicate
34
+
35
+ if destructed
36
+ return related_resource_invalidations + [
37
+ [current_resource.iri, predicate, Vocab.sp[:Variable], delta_iri(:remove)]
38
+ ]
39
+ end
40
+
41
+ related_resource_invalidations + resources.map do |resource|
42
+ [current_resource.iri, predicate, resource.iri, delta_iri(:replace)]
43
+ end
44
+ end
45
+
46
+ def changed_collection_triples(resource, key)
47
+ collection = resource.send(key)
48
+ association = resource.association(collection.association)
49
+ if association.loaded?
50
+ [invalidate_collection_delta(collection)] +
51
+ association.reader.select { |r| r.previous_changes.present? }.flat_map(&method(:changes_triples))
52
+ else
53
+ [invalidate_collection_delta(collection)]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end