linked_rails 0.0.3 → 0.0.4.pre.ge1306665a

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 +8 -2
  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 +78 -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 +7 -8
  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 +133 -55
  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 +57 -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
@@ -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,78 @@
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) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
9
+ resource_serializer(resource)&.send(:repository).statements
10
+
11
+ # resource.previous_changes_by_predicate.map do |predicate, (_old_value, _new_value)|
12
+ # serializer_attributes = resource.class.predicate_mapping[predicate]
13
+ # next if serializer_attributes.is_a?(FastJsonapi::Relationship)
14
+ #
15
+ # attr_name = serializer_attributes.key
16
+ # serialized_value =
17
+ # serializer.class.attributes_to_serialize[attr_name]&.serialize(resource, serializer_params, {})
18
+ # (serialized_value.is_a?(Array) ? serialized_value : [serialized_value]).map do |value|
19
+ # change_triple(resource, predicate, value)
20
+ # end
21
+ # end.compact.flatten
22
+ end
23
+
24
+ def changed_relations_triples(resource, inverted = nil) # rubocop:disable Metrics/AbcSize
25
+ resource.previously_changed_relations.flat_map do |key, value|
26
+ if key.to_s.ends_with?('_collection')
27
+ changed_collection_triples(resource, key)
28
+ else
29
+ destructed = resource.send(:association_has_destructed?, key)
30
+ records = value.relationship_type == :has_many ? resource.send(key) : [resource.send(key)]
31
+ changed_relation_triples(value.predicate, destructed, records - [inverted], resource)
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def change_triple(resource, predicate, value)
39
+ if value.nil?
40
+ RDF::Statement.new(resource.iri, predicate, Vocab.sp[:Variable], graph_name: delta_iri(:remove))
41
+ else
42
+ RDF::Statement.new(resource.iri, predicate, value, graph_name: delta_iri(:replace))
43
+ end
44
+ end
45
+
46
+ def changed_relation_triples(predicate, destructed, resources, inverted)
47
+ related_resource_invalidations =
48
+ resources.flat_map do |resource|
49
+ resource_delta = invalidate_resource_delta(resource)
50
+ [resource_delta] + changed_relations_triples(resource, inverted)
51
+ end
52
+
53
+ return related_resource_invalidations unless predicate
54
+
55
+ if destructed
56
+ return related_resource_invalidations + [
57
+ [current_resource.iri, predicate, Vocab.sp[:Variable], delta_iri(:remove)]
58
+ ]
59
+ end
60
+
61
+ related_resource_invalidations + resources.map do |resource|
62
+ [current_resource.iri, predicate, resource.iri, delta_iri(:replace)]
63
+ end
64
+ end
65
+
66
+ def changed_collection_triples(resource, key)
67
+ collection = resource.send(key)
68
+ association = resource.association(collection.association)
69
+ if association.loaded?
70
+ [invalidate_collection_delta(collection)] +
71
+ association.reader.select { |r| r.previous_changes.present? }.flat_map(&method(:changes_triples))
72
+ else
73
+ [invalidate_collection_delta(collection)]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -6,12 +6,6 @@ module LinkedRails
6
6
  extend ActiveSupport::Concern
7
7
  include ActiveSupport::Rescuable
8
8
 
9
- included do
10
- rescue_from StandardError, with: :handle_and_report_error
11
- rescue_from ActiveRecord::RecordNotFound, with: :handle_error
12
- rescue_from Pundit::NotAuthorizedError, with: :handle_error
13
- end
14
-
15
9
  private
16
10
 
17
11
  def add_error_snackbar(error)
@@ -22,7 +16,14 @@ module LinkedRails
22
16
  !%w[GET HEAD].include?(request.method)
23
17
  end
24
18
 
19
+ def handle_and_report_error(error)
20
+ report_error(error) if error_status(error) == 500
21
+ handle_error(error)
22
+ end
23
+
25
24
  def handle_error(error)
25
+ raise(error) if response_body
26
+
26
27
  respond_to do |format|
27
28
  (LinkedRails::Renderers.rdf_content_types + [:json]).each do |type|
28
29
  format.send(type) { error_response_serializer(error, type) }
@@ -30,11 +31,10 @@ module LinkedRails
30
31
  end
31
32
  end
32
33
 
33
- def handle_and_report_error(error)
34
- raise if Rails.env.development? || Rails.env.test?
35
- raise if response_body
34
+ def report_error(error)
35
+ raise(error) if Rails.env.development? || Rails.env.test?
36
36
 
37
- handle_error(error)
37
+ Rails.logger.error(error)
38
38
  end
39
39
 
40
40
  def error_mode(exception)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Controller
5
+ module Rendering
6
+ def _render_with_renderer_json(record, options)
7
+ self.content_type = Mime[:json]
8
+
9
+ return record if record.is_a?(String)
10
+ return record.to_json if record.is_a?(Hash)
11
+
12
+ serializer_opts = RDF::Serializers::Renderers.transform_opts(
13
+ options,
14
+ serializer_params
15
+ )
16
+
17
+ serializer = RDF::Serializers.serializer_for(record)&.new(record, serializer_opts)
18
+ return record.to_json unless serializer
19
+
20
+ Oj.dump(serializer.serializable_hash, mode: :compat)
21
+ end
22
+
23
+ def resource_body(resource)
24
+ resource_serializer(resource).send(:render_emp_json)
25
+ end
26
+
27
+ def resource_hash(resource)
28
+ resource_serializer(resource).send(:emp_json_hash)
29
+ end
30
+
31
+ def resource_serializer(resource)
32
+ return if resource.nil?
33
+
34
+ serializer_options = RDF::Serializers::Renderers.transform_opts(
35
+ {include: resource&.try(:preview_includes)},
36
+ serializer_params
37
+ )
38
+ RDF::Serializers
39
+ .serializer_for(resource)
40
+ &.new(resource, serializer_options)
41
+ end
42
+
43
+ def serializer_params
44
+ {}
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,23 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'active_response/controller'
4
+ require_relative 'controller/actionable'
4
5
  require_relative 'controller/authorization'
5
6
  require_relative 'controller/error_handling'
7
+ require_relative 'controller/delta'
8
+ require_relative 'controller/rendering'
6
9
 
7
10
  module LinkedRails
8
11
  module Controller
9
12
  extend ActiveSupport::Concern
13
+ include ::ActiveResponse::Controller
10
14
 
11
15
  included do
12
16
  extend Enhanceable
13
17
 
14
18
  enhanceable :controller_class, :Controller
15
19
 
20
+ include ActionController::MimeResponds
16
21
  include LinkedRails::ActiveResponse::Controller
22
+ include LinkedRails::Controller::Actionable
17
23
  include LinkedRails::Controller::Authorization
18
24
  include LinkedRails::Controller::ErrorHandling
25
+ include LinkedRails::Controller::Rendering
26
+ include LinkedRails::Controller::Delta
19
27
  include LinkedRails::Helpers::OntolaActionsHelper
20
- include LinkedRails::Helpers::DeltaHelper
21
28
  include LinkedRails::Helpers::ResourceHelper
22
29
 
23
30
  before_action :set_manifest_header
@@ -34,9 +41,22 @@ module LinkedRails
34
41
  end
35
42
 
36
43
  module ClassMethods
37
- def controller_class
38
- @controller_class ||=
39
- name.sub(/Controller$/, '').classify.safe_constantize || try(:controller_name)&.classify&.safe_constantize
44
+ def controller_class(klass = nil)
45
+ if klass.present?
46
+ @controller_class = klass
47
+ else
48
+ @controller_class ||= compute_controller_class || superclass.try(:controller_class)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def compute_controller_class
55
+ klass =
56
+ name.sub(/Controller$/, '').classify.safe_constantize ||
57
+ try(:controller_name)&.classify&.safe_constantize
58
+
59
+ klass if klass&.include?(LinkedRails::Model)
40
60
  end
41
61
  end
42
62
  end