linked_rails 0.0.1 → 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.
- checksums.yaml +4 -4
- data/LICENSE +21 -674
- data/app/controllers/linked_rails/actions/objects_controller.rb +9 -0
- data/app/controllers/linked_rails/bulk_controller.rb +71 -21
- data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
- data/app/models/linked_rails/actions/item.rb +64 -55
- data/app/models/linked_rails/actions/list.rb +6 -31
- data/app/models/linked_rails/actions/object.rb +38 -0
- data/app/models/linked_rails/collection/configuration.rb +55 -0
- data/app/models/linked_rails/collection/filter.rb +1 -1
- data/app/models/linked_rails/collection/filter_field.rb +19 -2
- data/app/models/linked_rails/collection/filter_option.rb +1 -1
- data/app/models/linked_rails/collection/filterable.rb +6 -9
- data/app/models/linked_rails/collection/infinite.rb +113 -0
- data/app/models/linked_rails/collection/infinite_view.rb +1 -90
- data/app/models/linked_rails/collection/iri.rb +47 -43
- data/app/models/linked_rails/collection/iri_mapping.rb +15 -7
- data/app/models/linked_rails/collection/paginated.rb +46 -0
- data/app/models/linked_rails/collection/paginated_view.rb +1 -33
- data/app/models/linked_rails/collection/sortable.rb +1 -9
- data/app/models/linked_rails/collection/sorting.rb +1 -1
- data/app/models/linked_rails/collection/view.rb +51 -14
- data/app/models/linked_rails/collection.rb +53 -85
- data/app/models/linked_rails/creative_work.rb +1 -1
- data/app/models/linked_rails/entry_point.rb +8 -5
- data/app/models/linked_rails/enum_value.rb +40 -2
- data/app/models/linked_rails/form/field/association_input.rb +7 -1
- data/app/models/linked_rails/form/field/file_input.rb +1 -0
- data/app/models/linked_rails/form/field/resource_field.rb +2 -0
- data/{lib/linked_rails/enhancements/indexable/model.rb → app/models/linked_rails/form/field/url_input.rb} +3 -3
- data/app/models/linked_rails/form/field.rb +37 -13
- data/app/models/linked_rails/form/field_factory.rb +48 -18
- data/app/models/linked_rails/form/group.rb +4 -6
- data/app/models/linked_rails/form/page.rb +8 -4
- data/app/models/linked_rails/form.rb +16 -21
- data/app/models/linked_rails/manifest.rb +8 -2
- data/app/models/linked_rails/menus/item.rb +10 -13
- data/app/models/linked_rails/menus/list.rb +16 -7
- data/app/models/linked_rails/ontology/base.rb +3 -1
- data/app/models/linked_rails/ontology/class.rb +3 -3
- data/app/models/linked_rails/ontology.rb +5 -5
- data/app/models/linked_rails/property_query.rb +2 -0
- data/app/models/linked_rails/sequence.rb +4 -13
- data/app/models/linked_rails/shacl/property_shape.rb +1 -1
- data/app/models/linked_rails/web_page.rb +0 -4
- data/app/models/linked_rails/web_site.rb +0 -4
- data/app/models/linked_rails/widget.rb +4 -11
- data/app/policies/linked_rails/actions/object_policy.rb +11 -0
- data/app/policies/linked_rails/collection_policy.rb +2 -2
- data/app/serializers/linked_rails/actions/item_serializer.rb +5 -5
- data/app/serializers/linked_rails/actions/object_serializer.rb +9 -0
- data/app/serializers/linked_rails/collection/filter_field_serializer.rb +3 -2
- data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/view_serializer.rb +3 -3
- data/app/serializers/linked_rails/collection_serializer.rb +8 -7
- data/app/serializers/linked_rails/condition_serializer.rb +3 -3
- data/app/serializers/linked_rails/entry_point_serializer.rb +3 -3
- data/app/serializers/linked_rails/enum_value_serializer.rb +1 -0
- data/app/serializers/linked_rails/form/field/association_input_serializer.rb +1 -0
- data/app/serializers/linked_rails/form/field/file_input_serializer.rb +11 -0
- data/app/serializers/linked_rails/form/field_serializer.rb +3 -1
- data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
- data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
- data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
- data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
- data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
- data/app/serializers/linked_rails/property_query_serializer.rb +7 -0
- data/app/serializers/linked_rails/sequence_serializer.rb +2 -5
- data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
- data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
- data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
- data/app/serializers/linked_rails/widget_serializer.rb +3 -3
- data/lib/generators/linked_rails/install/install_generator.rb +7 -8
- data/lib/generators/linked_rails/install/templates/README +7 -0
- data/lib/generators/linked_rails/install/templates/app_menu_list.rb +36 -7
- data/lib/generators/linked_rails/install/templates/application_menu_list.rb +40 -1
- data/lib/generators/linked_rails/install/templates/initializer.rb +1 -2
- data/lib/generators/linked_rails/install/templates/locales.yml +14 -0
- data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
- data/lib/generators/linked_rails/install/templates/vocab.rb +1 -0
- data/lib/generators/linked_rails/install/templates/vocab.yml +2 -2
- data/lib/generators/linked_rails/model/model_generator.rb +0 -1
- data/lib/generators/linked_rails/model/templates/controller.rb.tt +5 -1
- data/lib/generators/linked_rails/model/templates/form.rb.tt +3 -0
- data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +15 -0
- data/lib/generators/linked_rails/model/templates/policy.rb.tt +13 -0
- data/lib/generators/linked_rails/model/templates/serializer.rb.tt +5 -1
- data/lib/linked_rails/active_response/controller/collections.rb +1 -1
- data/lib/linked_rails/active_response/controller/crud_defaults.rb +4 -4
- data/lib/linked_rails/active_response/controller/params.rb +10 -10
- data/lib/linked_rails/active_response/controller.rb +8 -18
- data/lib/linked_rails/active_response/responders/rdf.rb +19 -10
- data/lib/linked_rails/callable_variable.rb +1 -1
- data/lib/linked_rails/collection_params_parser.rb +93 -0
- data/lib/linked_rails/controller/actionable.rb +121 -0
- data/lib/linked_rails/controller/authorization.rb +6 -0
- data/lib/linked_rails/controller/default_actions/create.rb +52 -0
- data/lib/linked_rails/controller/default_actions/destroy.rb +42 -0
- data/lib/linked_rails/controller/default_actions/update.rb +43 -0
- data/lib/linked_rails/controller/delta.rb +78 -0
- data/lib/linked_rails/controller/error_handling.rb +11 -9
- data/lib/linked_rails/controller/rendering.rb +48 -0
- data/lib/linked_rails/controller.rb +24 -4
- data/lib/linked_rails/enhanceable.rb +1 -1
- data/lib/linked_rails/enhancements/creatable/controller.rb +1 -1
- data/lib/linked_rails/enhancements/destroyable/controller.rb +1 -1
- data/lib/linked_rails/enhancements/updatable/controller.rb +1 -1
- data/lib/linked_rails/enhancements.rb +0 -16
- data/lib/linked_rails/helpers/delta_helper.rb +26 -57
- data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
- data/lib/linked_rails/helpers/resource_helper.rb +4 -2
- data/lib/linked_rails/iri_mapper.rb +17 -39
- data/lib/linked_rails/middleware/error_handling.rb +51 -0
- data/lib/linked_rails/middleware/linked_data_params.rb +30 -151
- data/lib/linked_rails/model/actionable.rb +68 -0
- data/lib/linked_rails/model/collections.rb +201 -39
- data/lib/linked_rails/model/dirty.rb +7 -8
- data/lib/linked_rails/model/enhancements.rb +1 -6
- data/lib/linked_rails/model/filtering.rb +4 -6
- data/lib/linked_rails/model/indexable.rb +6 -16
- data/lib/linked_rails/model/iri.rb +28 -19
- data/lib/linked_rails/model/iri_mapping.rb +37 -8
- data/lib/linked_rails/model/menuable.rb +28 -0
- data/lib/linked_rails/model/serialization.rb +2 -15
- data/lib/linked_rails/model/singularable.rb +57 -0
- data/lib/linked_rails/model/sorting.rb +0 -5
- data/lib/linked_rails/model/tables.rb +26 -0
- data/lib/linked_rails/model.rb +17 -7
- data/lib/linked_rails/params_parser.rb +133 -55
- data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
- data/lib/linked_rails/policy.rb +40 -46
- data/lib/linked_rails/railtie.rb +11 -0
- data/lib/linked_rails/rdf_error.rb +2 -2
- data/lib/linked_rails/renderers.rb +1 -0
- data/lib/linked_rails/routes.rb +38 -22
- data/lib/linked_rails/serializer/actionable.rb +27 -0
- data/lib/linked_rails/serializer/menuable.rb +31 -0
- data/lib/linked_rails/serializer/singularable.rb +26 -0
- data/lib/linked_rails/serializer.rb +28 -11
- data/lib/linked_rails/test_methods.rb +114 -0
- data/lib/linked_rails/translate.rb +31 -9
- data/lib/linked_rails/types/iri_type.rb +37 -0
- data/lib/linked_rails/uri_template.rb +30 -0
- data/lib/linked_rails/version.rb +1 -1
- data/lib/linked_rails/vocab.rb +9 -0
- data/lib/linked_rails.rb +30 -13
- data/lib/rails/welcome_controller.rb +3 -2
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +58 -33
- data/app/models/linked_rails/actions/default_actions/create.rb +0 -60
- data/app/models/linked_rails/actions/default_actions/destroy.rb +0 -45
- data/app/models/linked_rails/actions/default_actions/update.rb +0 -50
- data/app/models/linked_rails/actions/default_actions.rb +0 -17
- data/lib/generators/linked_rails/install/templates/application_action_list.rb +0 -3
- data/lib/generators/linked_rails/model/templates/action_list.rb.tt +0 -6
- data/lib/linked_rails/enhancements/actionable/model.rb +0 -71
- data/lib/linked_rails/enhancements/actionable/serializer.rb +0 -25
- data/lib/linked_rails/enhancements/creatable/action.rb +0 -15
- data/lib/linked_rails/enhancements/destroyable/action.rb +0 -15
- data/lib/linked_rails/enhancements/destroyable/routing.rb +0 -19
- data/lib/linked_rails/enhancements/menuable/model.rb +0 -36
- data/lib/linked_rails/enhancements/menuable/serializer.rb +0 -33
- data/lib/linked_rails/enhancements/route_concerns.rb +0 -56
- data/lib/linked_rails/enhancements/singularable/controller.rb +0 -43
- data/lib/linked_rails/enhancements/singularable/model.rb +0 -47
- data/lib/linked_rails/enhancements/singularable/serializer.rb +0 -28
- data/lib/linked_rails/enhancements/tableable/model.rb +0 -28
- data/lib/linked_rails/enhancements/updatable/action.rb +0 -15
- data/lib/linked_rails/enhancements/updatable/routing.rb +0 -20
@@ -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
|
-
|
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
|
-
|
95
|
-
predicate = resource
|
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
|
-
|
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
|
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
|
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
|
@@ -4,11 +4,7 @@ module LinkedRails
|
|
4
4
|
module Controller
|
5
5
|
module ErrorHandling
|
6
6
|
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
rescue_from StandardError, with: :handle_and_report_error
|
9
|
-
rescue_from ActiveRecord::RecordNotFound, with: :handle_error
|
10
|
-
rescue_from Pundit::NotAuthorizedError, with: :handle_error
|
11
|
-
end
|
7
|
+
include ActiveSupport::Rescuable
|
12
8
|
|
13
9
|
private
|
14
10
|
|
@@ -20,7 +16,14 @@ module LinkedRails
|
|
20
16
|
!%w[GET HEAD].include?(request.method)
|
21
17
|
end
|
22
18
|
|
19
|
+
def handle_and_report_error(error)
|
20
|
+
report_error(error) if error_status(error) == 500
|
21
|
+
handle_error(error)
|
22
|
+
end
|
23
|
+
|
23
24
|
def handle_error(error)
|
25
|
+
raise(error) if response_body
|
26
|
+
|
24
27
|
respond_to do |format|
|
25
28
|
(LinkedRails::Renderers.rdf_content_types + [:json]).each do |type|
|
26
29
|
format.send(type) { error_response_serializer(error, type) }
|
@@ -28,11 +31,10 @@ module LinkedRails
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
|
-
def
|
32
|
-
raise if Rails.env.development? || Rails.env.test?
|
33
|
-
raise if response_body
|
34
|
+
def report_error(error)
|
35
|
+
raise(error) if Rails.env.development? || Rails.env.test?
|
34
36
|
|
35
|
-
|
37
|
+
Rails.logger.error(error)
|
36
38
|
end
|
37
39
|
|
38
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
|
-
|
39
|
-
|
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
|