linked_rails 0.0.3 → 0.0.4.pre.g1faca9643

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 (181) 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 +105 -22
  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 +17 -21
  36. data/app/models/linked_rails/manifest.rb +102 -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 +6 -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/policies/linked_rails/form_policy.rb +13 -0
  51. data/app/policies/linked_rails/ontology_policy.rb +13 -0
  52. data/app/serializers/linked_rails/actions/item_serializer.rb +5 -5
  53. data/app/serializers/linked_rails/actions/object_serializer.rb +9 -0
  54. data/app/serializers/linked_rails/collection/filter_field_serializer.rb +3 -2
  55. data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
  56. data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
  57. data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
  58. data/app/serializers/linked_rails/collection/view_serializer.rb +3 -3
  59. data/app/serializers/linked_rails/collection_serializer.rb +8 -7
  60. data/app/serializers/linked_rails/condition_serializer.rb +3 -3
  61. data/app/serializers/linked_rails/entry_point_serializer.rb +3 -3
  62. data/app/serializers/linked_rails/enum_value_serializer.rb +1 -0
  63. data/app/serializers/linked_rails/form/field/association_input_serializer.rb +1 -0
  64. data/app/serializers/linked_rails/form/field/file_input_serializer.rb +11 -0
  65. data/app/serializers/linked_rails/form/field_serializer.rb +3 -1
  66. data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
  67. data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
  68. data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
  69. data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
  70. data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
  71. data/app/serializers/linked_rails/property_query_serializer.rb +7 -0
  72. data/app/serializers/linked_rails/sequence_serializer.rb +2 -5
  73. data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
  74. data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
  75. data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
  76. data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
  77. data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
  78. data/app/serializers/linked_rails/widget_serializer.rb +3 -3
  79. data/app/workers/linked_rails/invalidation_stream_worker.rb +16 -0
  80. data/lib/generators/linked_rails/install/install_generator.rb +5 -8
  81. data/lib/generators/linked_rails/install/templates/README +2 -0
  82. data/lib/generators/linked_rails/install/templates/app_menu_list.rb +36 -7
  83. data/lib/generators/linked_rails/install/templates/application_menu_list.rb +40 -1
  84. data/lib/generators/linked_rails/install/templates/initializer.rb +1 -2
  85. data/lib/generators/linked_rails/install/templates/locales.yml +16 -0
  86. data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
  87. data/lib/generators/linked_rails/install/templates/vocab.rb +1 -0
  88. data/lib/generators/linked_rails/install/templates/vocab.yml +2 -2
  89. data/lib/generators/linked_rails/model/model_generator.rb +0 -1
  90. data/lib/generators/linked_rails/model/templates/controller.rb.tt +5 -1
  91. data/lib/generators/linked_rails/model/templates/form.rb.tt +3 -0
  92. data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +15 -0
  93. data/lib/generators/linked_rails/model/templates/policy.rb.tt +13 -0
  94. data/lib/generators/linked_rails/model/templates/serializer.rb.tt +5 -1
  95. data/lib/linked_rails/active_response/controller/collections.rb +1 -1
  96. data/lib/linked_rails/active_response/controller/crud_defaults.rb +4 -4
  97. data/lib/linked_rails/active_response/controller/params.rb +10 -10
  98. data/lib/linked_rails/active_response/controller.rb +8 -18
  99. data/lib/linked_rails/active_response/responders/rdf.rb +19 -10
  100. data/lib/linked_rails/callable_variable.rb +1 -1
  101. data/lib/linked_rails/collection_params_parser.rb +93 -0
  102. data/lib/linked_rails/controller/actionable.rb +121 -0
  103. data/lib/linked_rails/controller/authorization.rb +6 -0
  104. data/lib/linked_rails/controller/default_actions/create.rb +52 -0
  105. data/lib/linked_rails/controller/default_actions/destroy.rb +42 -0
  106. data/lib/linked_rails/controller/default_actions/update.rb +43 -0
  107. data/lib/linked_rails/controller/delta.rb +58 -0
  108. data/lib/linked_rails/controller/error_handling.rb +12 -7
  109. data/lib/linked_rails/controller/rendering.rb +48 -0
  110. data/lib/linked_rails/controller.rb +24 -4
  111. data/lib/linked_rails/enhancements/creatable/controller.rb +1 -1
  112. data/lib/linked_rails/enhancements/destroyable/controller.rb +1 -1
  113. data/lib/linked_rails/enhancements/updatable/controller.rb +1 -1
  114. data/lib/linked_rails/enhancements.rb +0 -16
  115. data/lib/linked_rails/errors/forbidden.rb +37 -0
  116. data/lib/linked_rails/errors.rb +3 -0
  117. data/lib/linked_rails/helpers/delta_helper.rb +26 -57
  118. data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
  119. data/lib/linked_rails/helpers/resource_helper.rb +11 -2
  120. data/lib/linked_rails/iri_mapper.rb +17 -39
  121. data/lib/linked_rails/middleware/error_handling.rb +51 -0
  122. data/lib/linked_rails/middleware/linked_data_params.rb +30 -151
  123. data/lib/linked_rails/model/actionable.rb +68 -0
  124. data/lib/linked_rails/model/cacheable.rb +45 -0
  125. data/lib/linked_rails/model/collections.rb +201 -39
  126. data/lib/linked_rails/model/dirty.rb +6 -18
  127. data/lib/linked_rails/model/enhancements.rb +1 -6
  128. data/lib/linked_rails/model/filtering.rb +4 -6
  129. data/lib/linked_rails/model/indexable.rb +6 -16
  130. data/lib/linked_rails/model/iri.rb +29 -19
  131. data/lib/linked_rails/model/iri_mapping.rb +37 -8
  132. data/lib/linked_rails/model/menuable.rb +28 -0
  133. data/lib/linked_rails/model/serialization.rb +2 -15
  134. data/lib/linked_rails/model/singularable.rb +57 -0
  135. data/lib/linked_rails/model/sorting.rb +0 -5
  136. data/lib/linked_rails/model/tables.rb +26 -0
  137. data/lib/linked_rails/model.rb +18 -7
  138. data/lib/linked_rails/params_parser.rb +131 -54
  139. data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
  140. data/lib/linked_rails/policy.rb +44 -46
  141. data/lib/linked_rails/railtie.rb +11 -0
  142. data/lib/linked_rails/rdf_error.rb +2 -2
  143. data/lib/linked_rails/renderers.rb +1 -0
  144. data/lib/linked_rails/routes.rb +38 -22
  145. data/lib/linked_rails/serializer/actionable.rb +27 -0
  146. data/lib/linked_rails/serializer/menuable.rb +31 -0
  147. data/lib/linked_rails/serializer/singularable.rb +26 -0
  148. data/lib/linked_rails/serializer.rb +28 -11
  149. data/lib/linked_rails/storage.rb +32 -0
  150. data/lib/linked_rails/test_methods.rb +114 -0
  151. data/lib/linked_rails/translate.rb +31 -9
  152. data/lib/linked_rails/types/iri_type.rb +37 -0
  153. data/lib/linked_rails/uri_template.rb +30 -0
  154. data/lib/linked_rails/url.rb +11 -0
  155. data/lib/linked_rails/version.rb +1 -1
  156. data/lib/linked_rails/vocab.rb +9 -0
  157. data/lib/linked_rails.rb +40 -14
  158. data/lib/rails/welcome_controller.rb +3 -3
  159. data/lib/rdf/list.rb +9 -0
  160. data/lib/rdf/query_fix.rb +15 -0
  161. metadata +79 -33
  162. data/app/models/linked_rails/actions/default_actions/create.rb +0 -60
  163. data/app/models/linked_rails/actions/default_actions/destroy.rb +0 -45
  164. data/app/models/linked_rails/actions/default_actions/update.rb +0 -50
  165. data/app/models/linked_rails/actions/default_actions.rb +0 -17
  166. data/lib/generators/linked_rails/install/templates/application_action_list.rb +0 -3
  167. data/lib/generators/linked_rails/model/templates/action_list.rb.tt +0 -6
  168. data/lib/linked_rails/enhancements/actionable/model.rb +0 -71
  169. data/lib/linked_rails/enhancements/actionable/serializer.rb +0 -25
  170. data/lib/linked_rails/enhancements/creatable/action.rb +0 -15
  171. data/lib/linked_rails/enhancements/destroyable/action.rb +0 -15
  172. data/lib/linked_rails/enhancements/destroyable/routing.rb +0 -19
  173. data/lib/linked_rails/enhancements/menuable/model.rb +0 -36
  174. data/lib/linked_rails/enhancements/menuable/serializer.rb +0 -33
  175. data/lib/linked_rails/enhancements/route_concerns.rb +0 -56
  176. data/lib/linked_rails/enhancements/singularable/controller.rb +0 -43
  177. data/lib/linked_rails/enhancements/singularable/model.rb +0 -47
  178. data/lib/linked_rails/enhancements/singularable/serializer.rb +0 -28
  179. data/lib/linked_rails/enhancements/tableable/model.rb +0 -28
  180. data/lib/linked_rails/enhancements/updatable/action.rb +0 -15
  181. data/lib/linked_rails/enhancements/updatable/routing.rb +0 -20
@@ -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
@@ -7,9 +7,7 @@ module LinkedRails
7
7
  include ActiveSupport::Rescuable
8
8
 
9
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
10
+ rescue_from LinkedRails::Errors::Forbidden, with: :handle_error
13
11
  end
14
12
 
15
13
  private
@@ -22,7 +20,14 @@ module LinkedRails
22
20
  !%w[GET HEAD].include?(request.method)
23
21
  end
24
22
 
23
+ def handle_and_report_error(error)
24
+ report_error(error) if error_status(error) == 500
25
+ handle_error(error)
26
+ end
27
+
25
28
  def handle_error(error)
29
+ raise(error) if response_body
30
+
26
31
  respond_to do |format|
27
32
  (LinkedRails::Renderers.rdf_content_types + [:json]).each do |type|
28
33
  format.send(type) { error_response_serializer(error, type) }
@@ -30,11 +35,10 @@ module LinkedRails
30
35
  end
31
36
  end
32
37
 
33
- def handle_and_report_error(error)
34
- raise if Rails.env.development? || Rails.env.test?
35
- raise if response_body
38
+ def report_error(error)
39
+ raise(error) if Rails.env.development? || Rails.env.test?
36
40
 
37
- handle_error(error)
41
+ Rails.logger.error(error)
38
42
  end
39
43
 
40
44
  def error_mode(exception)
@@ -69,6 +73,7 @@ module LinkedRails
69
73
  'Doorkeeper::Errors::InvalidGrantReuse' => 422,
70
74
  'LinkedRails::Auth::Errors::Expired' => 410,
71
75
  'LinkedRails::Auth::Errors::Unauthorized' => 401,
76
+ 'LinkedRails::Errors::Forbidden' => 403,
72
77
  'Pundit::NotAuthorizedError' => 403
73
78
  }
74
79
  end
@@ -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
@@ -7,7 +7,7 @@ module LinkedRails
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- active_response :create
10
+ has_collection_create_action
11
11
  end
12
12
  end
13
13
  end
@@ -7,7 +7,7 @@ module LinkedRails
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- active_response :destroy
10
+ has_resource_destroy_action
11
11
  end
12
12
  end
13
13
  end
@@ -7,7 +7,7 @@ module LinkedRails
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- active_response :update
10
+ has_resource_update_action
11
11
  end
12
12
  end
13
13
  end
@@ -1,22 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'enhancements/route_concerns'
4
-
5
- require_relative 'enhancements/actionable/model'
6
- require_relative 'enhancements/actionable/serializer'
7
- require_relative 'enhancements/creatable/action'
8
3
  require_relative 'enhancements/creatable/controller'
9
- require_relative 'enhancements/destroyable/action'
10
4
  require_relative 'enhancements/destroyable/controller'
11
- require_relative 'enhancements/destroyable/routing'
12
- require_relative 'enhancements/indexable/model'
13
- require_relative 'enhancements/menuable/model'
14
- require_relative 'enhancements/menuable/serializer'
15
- require_relative 'enhancements/singularable/controller'
16
- require_relative 'enhancements/singularable/model'
17
- require_relative 'enhancements/singularable/serializer'
18
- require_relative 'enhancements/tableable/model'
19
- require_relative 'enhancements/updatable/action'
20
5
  require_relative 'enhancements/updatable/controller'
21
- require_relative 'enhancements/updatable/routing'
22
6
  require_relative 'enhancements/updatable/serializer'
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Errors
5
+ class Forbidden < StandardError
6
+ attr_reader :query, :record, :policy, :action
7
+
8
+ # @param [Hash] options
9
+ # @option options [String] query The action of the request
10
+ # @option options [ActiveRecord::Base] record The record that was requested
11
+ # @option options [Policy] policy The policy that raised the exception
12
+ # @option options [String] message Override the default error message
13
+ # @return [String] the message
14
+ def initialize(**options)
15
+ @query = options.fetch(:query).to_s
16
+ @record = options[:record]
17
+ @policy = options[:policy]
18
+ @action = @query[-1] == '?' ? @query[0..-2] : @query
19
+ @message = options[:message]
20
+
21
+ raise StandardError if @query.blank? && @message.blank?
22
+
23
+ super(@message || default_message)
24
+ end
25
+
26
+ private
27
+
28
+ def default_message
29
+ I18n.t(
30
+ "pundit.#{@policy.class.to_s.underscore}.#{@query}",
31
+ action: @action,
32
+ default: I18n.t('errors.access_denied')
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/forbidden'