linked_rails 0.0.3 → 0.0.4.pre.g14b377f91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +104 -22
- 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 +5 -8
- data/lib/generators/linked_rails/install/templates/README +2 -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 +58 -0
- data/lib/linked_rails/controller/error_handling.rb +10 -10
- data/lib/linked_rails/controller/rendering.rb +48 -0
- data/lib/linked_rails/controller.rb +24 -4
- 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 +6 -18
- 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 +131 -54
- 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 -3
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +71 -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
@@ -1,93 +1,170 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module LinkedRails
|
4
|
-
class ParamsParser
|
5
|
-
|
4
|
+
class ParamsParser # rubocop:disable Metrics/ClassLength
|
5
|
+
include ::Empathy::EmpJson::Helpers::Slices
|
6
|
+
include ::Empathy::EmpJson::Helpers::Parsing
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
attr_accessor :params, :slice, :user_context
|
9
|
+
delegate :filter_params, to: :collection_params_parser
|
10
|
+
|
11
|
+
def initialize(slice: nil, params: {}, user_context: nil)
|
12
|
+
self.slice = slice
|
13
|
+
self.params = params
|
14
|
+
self.user_context = user_context
|
10
15
|
end
|
11
16
|
|
12
|
-
def
|
13
|
-
|
17
|
+
def attributes_from_filters(klass)
|
18
|
+
ActionController::Parameters.new(
|
19
|
+
filter_params.each_with_object({}) do |(predicate, value), hash|
|
20
|
+
key_and_value = filter_to_param(klass, predicate, value)
|
21
|
+
hash[key_and_value.first] = key_and_value.second if key_and_value
|
22
|
+
end
|
23
|
+
)
|
24
|
+
end
|
14
25
|
|
15
|
-
|
16
|
-
|
26
|
+
def parse_param(klass, predicate, object)
|
27
|
+
field_options = serializer_field(klass, predicate) unless predicate == '_id'
|
28
|
+
if field_options.is_a?(FastJsonapi::Attribute)
|
29
|
+
parse_attribute(klass, field_options, emp_to_primitive(object))
|
30
|
+
elsif field_options.is_a?(FastJsonapi::Relationship)
|
31
|
+
parse_association(klass, field_options, emp_to_primitive(object))
|
32
|
+
end
|
33
|
+
end
|
17
34
|
|
18
|
-
|
19
|
-
|
20
|
-
|
35
|
+
# Recursively parses a resource from slice
|
36
|
+
def parse_resource(subject, klass)
|
37
|
+
(record_from_slice(slice, subject) || {}).reduce({}) do |h, (k, v)|
|
38
|
+
(v.is_a?(Array) ? v : [v]).each do |value|
|
39
|
+
param = parse_param(klass, RDF::URI(k), value)
|
40
|
+
param ? add_param(h, param.first, param.second) : h
|
41
|
+
end
|
42
|
+
h
|
21
43
|
end
|
22
44
|
end
|
23
45
|
|
24
|
-
|
25
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def add_param(hash, key, value) # rubocop:disable Metrics/MethodLength
|
49
|
+
case hash[key]
|
50
|
+
when nil
|
51
|
+
hash[key] = value
|
52
|
+
when Hash
|
53
|
+
hash[key].merge!(value)
|
54
|
+
when Array
|
55
|
+
hash[key].append(value)
|
56
|
+
else
|
57
|
+
hash[key] = [hash[key], value]
|
58
|
+
end
|
59
|
+
hash
|
60
|
+
end
|
26
61
|
|
27
|
-
|
62
|
+
def associated_class_from_params(reflection, object)
|
63
|
+
return reflection.klass unless reflection.polymorphic?
|
28
64
|
|
29
|
-
|
30
|
-
values[:filter] = filter if filter
|
65
|
+
type = values_from_slice(slice, object, Vocab.rdfv[:type])
|
31
66
|
|
32
|
-
|
33
|
-
values[:sort] = sort if sort
|
67
|
+
raise("No type given for '#{object}' referenced by polymorphic association '#{reflection.name}'") if type.blank?
|
34
68
|
|
35
|
-
|
69
|
+
iri_to_class(type)
|
70
|
+
end
|
36
71
|
|
37
|
-
|
72
|
+
def collection_params_parser
|
73
|
+
@collection_params_parser ||= LinkedRails::CollectionParamsParser.new(params.merge(user_context: user_context))
|
38
74
|
end
|
39
75
|
|
40
|
-
def
|
41
|
-
|
76
|
+
def filter_to_param(klass, predicate, value)
|
77
|
+
options = serializer_field(klass, predicate)
|
78
|
+
return unless value.count == 1 && options.present?
|
42
79
|
|
43
|
-
|
80
|
+
parsed_value = value.first.start_with?('http') ? RDF::URI(value.first) : value.first
|
81
|
+
parse_param(
|
82
|
+
klass,
|
83
|
+
options.predicate,
|
84
|
+
object_to_value(parsed_value)
|
85
|
+
)
|
86
|
+
end
|
44
87
|
|
45
|
-
|
46
|
-
|
88
|
+
def foreign_key_for_reflection(reflection)
|
89
|
+
if reflection.options[:through]
|
90
|
+
reflection.has_one? ? "#{reflection.name}_id" : "#{reflection.name.to_s.singularize}_ids"
|
91
|
+
elsif reflection.belongs_to?
|
92
|
+
reflection.foreign_key
|
93
|
+
end
|
94
|
+
end
|
47
95
|
|
48
|
-
|
96
|
+
def iri_to_class(iri)
|
97
|
+
iri.to_s.split(Vocab.app.to_s).pop&.classify&.safe_constantize ||
|
98
|
+
LinkedRails.linked_models.detect { |klass| klass.iri == iri }
|
49
99
|
end
|
50
100
|
|
51
|
-
def
|
52
|
-
|
101
|
+
def nested_attributes(object, klass, association, collection)
|
102
|
+
parsed = parse_nested_resource(object, klass)
|
103
|
+
nested_resources = collection ? {rand(1_000_000_000).to_s => parsed} : parsed
|
104
|
+
|
105
|
+
["#{association}_attributes", nested_resources]
|
106
|
+
end
|
53
107
|
|
54
|
-
|
55
|
-
|
56
|
-
|
108
|
+
def parse_association(klass, field_options, object)
|
109
|
+
association = field_options.association || field_options.key
|
110
|
+
reflection = klass.reflect_on_association(association) || raise("#{association} not found for #{name}")
|
57
111
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
112
|
+
if slice&.key?(object.to_s)
|
113
|
+
association_klass = associated_class_from_params(reflection, object)
|
114
|
+
nested_attributes(object, association_klass, association, reflection.collection?)
|
115
|
+
elsif object.iri?
|
116
|
+
parse_iri_param(object, reflection)
|
63
117
|
end
|
64
118
|
end
|
65
119
|
|
66
|
-
def
|
67
|
-
|
120
|
+
def parse_attribute(klass, field_options, value)
|
121
|
+
parsed_value = parse_enum_attribute(klass, field_options.key, value) || value
|
68
122
|
|
69
|
-
|
70
|
-
|
123
|
+
[field_options.key, parsed_value.to_s]
|
124
|
+
end
|
71
125
|
|
72
|
-
|
73
|
-
|
74
|
-
|
126
|
+
def parse_enum_attribute(klass, key, value)
|
127
|
+
opts = RDF::Serializers.serializer_for(klass)&.enum_options(key)
|
128
|
+
return if opts.blank?
|
129
|
+
|
130
|
+
|
131
|
+
opts.detect { |_k, options| options.iri == value }&.first&.to_s
|
75
132
|
end
|
76
133
|
|
77
|
-
|
134
|
+
def parse_iri_param(iri, reflection)
|
135
|
+
key = foreign_key_for_reflection(reflection)
|
136
|
+
value = parse_iri_param_value(iri, reflection) if key
|
137
|
+
|
138
|
+
[key, value.to_s] if value
|
139
|
+
end
|
78
140
|
|
79
|
-
def
|
80
|
-
|
141
|
+
def parse_iri_param_value(iri, reflection)
|
142
|
+
resource = LinkedRails.iri_mapper.resource_from_iri(iri, user_context)
|
81
143
|
|
82
|
-
|
83
|
-
|
144
|
+
resource&.try(reflection.association_primary_key)
|
145
|
+
end
|
146
|
+
|
147
|
+
def parse_nested_resource(object, klass)
|
148
|
+
resource = parse_resource(object, klass)
|
149
|
+
resource[:id] ||= nested_resource_id(object)
|
150
|
+
resource
|
151
|
+
end
|
152
|
+
|
153
|
+
def nested_resource_id(object)
|
154
|
+
return unless object.iri?
|
155
|
+
|
156
|
+
opts = LinkedRails.iri_mapper.opts_from_iri(object)
|
157
|
+
if opts[:class].method(:requested_single_resource).owner == LinkedRails::Model::IRIMapping::ClassMethods
|
158
|
+
opts[:params][:id]
|
159
|
+
else
|
160
|
+
opts[:class].requested_single_resource(opts[:params], nil)&.id
|
161
|
+
end
|
84
162
|
end
|
85
163
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
.with_indifferent_access
|
164
|
+
def serializer_field(klass, predicate)
|
165
|
+
field = klass.try(:predicate_mapping).try(:[], predicate)
|
166
|
+
Rails.logger.info("#{predicate} not found for #{klass || 'nil'}") if field.blank?
|
167
|
+
field
|
91
168
|
end
|
92
169
|
end
|
93
170
|
end
|
@@ -22,7 +22,7 @@ module LinkedRails
|
|
22
22
|
module ClassMethods
|
23
23
|
private
|
24
24
|
|
25
|
-
def has_properties_shapes(properties)
|
25
|
+
def has_properties_shapes(properties)
|
26
26
|
properties.map do |key, boolean|
|
27
27
|
SHACL::PropertyShape.new(
|
28
28
|
path: policy_class.predicate_for_key(key),
|
@@ -32,7 +32,7 @@ module LinkedRails
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def has_values_shapes(values)
|
35
|
+
def has_values_shapes(values)
|
36
36
|
values.map do |key, value|
|
37
37
|
enum = RDF::Serializers.serializer_for(policy_class).enum_options(key).try(:[], value)
|
38
38
|
santized_value = enum ? -> { enum.iri } : value
|
data/lib/linked_rails/policy.rb
CHANGED
@@ -15,7 +15,7 @@ module LinkedRails
|
|
15
15
|
enhanceable :policy_class, :Policy
|
16
16
|
class_attribute :_permitted_attributes
|
17
17
|
|
18
|
-
attr_reader :message, :user_context, :record
|
18
|
+
attr_reader :action_status, :message, :user_context, :record
|
19
19
|
|
20
20
|
def initialize(user_context, record)
|
21
21
|
@user_context = user_context
|
@@ -23,12 +23,12 @@ module LinkedRails
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def create_child?(klass, opts
|
27
|
-
child_policy(klass, opts).create?
|
26
|
+
def create_child?(klass, **opts)
|
27
|
+
child_policy(klass, **opts).create?
|
28
28
|
end
|
29
29
|
|
30
|
-
def index_children?(klass, opts
|
31
|
-
child_policy(klass, opts).show?
|
30
|
+
def index_children?(klass, **opts)
|
31
|
+
child_policy(klass, **opts).show?
|
32
32
|
end
|
33
33
|
|
34
34
|
def permitted_attributes
|
@@ -38,6 +38,14 @@ module LinkedRails
|
|
38
38
|
.flatten
|
39
39
|
end
|
40
40
|
|
41
|
+
def permitted_attributes_from_filters(filters)
|
42
|
+
params_parser(filters).attributes_from_filters(policy_class).permit(permitted_attributes)
|
43
|
+
end
|
44
|
+
|
45
|
+
def policy_class
|
46
|
+
self.class.policy_class
|
47
|
+
end
|
48
|
+
|
41
49
|
def show?
|
42
50
|
false
|
43
51
|
end
|
@@ -64,25 +72,32 @@ module LinkedRails
|
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
67
|
-
def child_policy(klass, opts
|
68
|
-
Pundit.policy(user_context, record.build_child(klass, opts.merge(user_context: user_context)))
|
75
|
+
def child_policy(klass, **opts)
|
76
|
+
Pundit.policy(user_context, record.build_child(klass, **opts.merge(user_context: user_context)))
|
69
77
|
end
|
70
78
|
|
71
|
-
def forbid_with_message(message)
|
79
|
+
def forbid_with_message(message, status = nil)
|
80
|
+
forbid_with_status(status) if status
|
72
81
|
@message = message
|
73
82
|
false
|
74
83
|
end
|
75
84
|
|
85
|
+
def forbid_with_status(status, message = nil)
|
86
|
+
forbid_with_message(message) if message
|
87
|
+
@action_status = status
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
def params_parser(filters)
|
92
|
+
LinkedRails::ParamsParser.new(user_context: user_context, params: {filter: filters})
|
93
|
+
end
|
94
|
+
|
76
95
|
def parent_policy
|
77
96
|
return if record.try(:parent).blank?
|
78
97
|
|
79
98
|
@parent_policy ||= Pundit.policy(user_context, record.parent)
|
80
99
|
end
|
81
100
|
|
82
|
-
def policy_class
|
83
|
-
self.class.policy_class
|
84
|
-
end
|
85
|
-
|
86
101
|
def sanitize_array_attribute(attr)
|
87
102
|
[attr, attr => []]
|
88
103
|
end
|
@@ -118,17 +133,16 @@ module LinkedRails
|
|
118
133
|
end
|
119
134
|
|
120
135
|
module ClassMethods
|
121
|
-
def
|
122
|
-
raise("#{attr} not permitted by #{self}") if attribute_options(attr).blank? &&
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
136
|
+
def condition_alternatives(attr, permission_required)
|
137
|
+
raise("#{attr} not permitted by #{self}") if attribute_options(attr).blank? && permission_required
|
138
|
+
|
139
|
+
attribute_options(attr)
|
140
|
+
.select { |opts| opts[:conditions].present? }
|
141
|
+
.map { |opts| property_shapes(opts[:conditions]) }
|
142
|
+
end
|
143
|
+
|
144
|
+
def policy_class
|
145
|
+
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
132
146
|
end
|
133
147
|
|
134
148
|
def permitted_attributes
|
@@ -143,44 +157,24 @@ module LinkedRails
|
|
143
157
|
permitted_attributes.select { |opts| opts[:attributes].include?(attr) }
|
144
158
|
end
|
145
159
|
|
146
|
-
def condition_alternatives(attr)
|
147
|
-
attribute_options(attr)
|
148
|
-
.select { |opts| opts[:conditions].present? }
|
149
|
-
.map { |opts| opts[:conditions] }
|
150
|
-
end
|
151
|
-
|
152
|
-
def node_shapes_for(attr, property: [], sh_not: [])
|
153
|
-
alternatives = condition_alternatives(attr)
|
154
|
-
alternatives = [[]] if alternatives.empty? && (property.any? || sh_not.any?)
|
155
|
-
|
156
|
-
alternatives.map do |props|
|
157
|
-
properties = property_shapes(props) + property
|
158
|
-
SHACL::NodeShape.new(property: properties, sh_not: sh_not)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
160
|
def initialize_permitted_attributes
|
163
161
|
return if _permitted_attributes && method(:_permitted_attributes).owner == singleton_class
|
164
162
|
|
165
163
|
self._permitted_attributes = superclass.try(:_permitted_attributes)&.dup || []
|
166
164
|
end
|
167
165
|
|
168
|
-
def permit_attributes(attrs, conditions
|
166
|
+
def permit_attributes(attrs, **conditions)
|
169
167
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {}}
|
170
168
|
end
|
171
169
|
|
172
|
-
def permit_array_attributes(attrs, conditions
|
170
|
+
def permit_array_attributes(attrs, **conditions)
|
173
171
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {array: true}}
|
174
172
|
end
|
175
173
|
|
176
|
-
def permit_nested_attributes(attrs, conditions
|
174
|
+
def permit_nested_attributes(attrs, **conditions)
|
177
175
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {nested: true}}
|
178
176
|
end
|
179
177
|
|
180
|
-
def policy_class
|
181
|
-
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
182
|
-
end
|
183
|
-
|
184
178
|
def property_shapes(conditions)
|
185
179
|
conditions.map { |key, options| send("#{key}_shapes", options) }.flatten.compact
|
186
180
|
end
|
@@ -4,12 +4,12 @@ module LinkedRails
|
|
4
4
|
class RDFError
|
5
5
|
include ActiveModel::Model
|
6
6
|
|
7
|
-
attr_accessor :error, :iri, :status
|
8
|
-
delegate :message, to: :error
|
7
|
+
attr_accessor :error, :iri, :message, :status
|
9
8
|
|
10
9
|
def initialize(status, requested_url, original_error)
|
11
10
|
self.status = status
|
12
11
|
self.error = original_error.is_a?(StandardError) ? original_error : original_error.new
|
12
|
+
self.message = error.message unless Rails.env.production?
|
13
13
|
self.iri = ::RDF::URI(requested_url)
|
14
14
|
end
|
15
15
|
|
data/lib/linked_rails/routes.rb
CHANGED
@@ -4,7 +4,7 @@ require 'linked_rails/constraints/whitelist'
|
|
4
4
|
|
5
5
|
module LinkedRails
|
6
6
|
module Routes
|
7
|
-
def use_linked_rails(opts
|
7
|
+
def use_linked_rails(**opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
8
8
|
constraints(LinkedRails::Constraints::Whitelist) do
|
9
9
|
post 'spi/bulk', to: "#{opts.fetch(:bulk, 'linked_rails/bulk')}#show"
|
10
10
|
end
|
@@ -22,24 +22,29 @@ module LinkedRails
|
|
22
22
|
|
23
23
|
get '(*parent_iri)/actions', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#index"
|
24
24
|
get '(*parent_iri)/actions/:id', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show"
|
25
|
-
get '(*parent_iri)/
|
26
|
-
get '(*parent_iri)/edit', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :update
|
27
|
-
get '(*parent_iri)/delete', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :destroy
|
28
|
-
get '(*parent_iri)/trash', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :trash
|
29
|
-
get '(*parent_iri)/untrash', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :untrash
|
25
|
+
get '(*parent_iri)/action_object', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/objects#show"
|
30
26
|
end
|
31
27
|
|
32
|
-
def linked_resource(klass, controller: nil, nested: false, &block)
|
28
|
+
def linked_resource(klass, controller: nil, collection: true, nested: false, resource: true, &block) # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
33
29
|
options = route_options(klass, controller, nested, klass.route_key)
|
34
30
|
|
31
|
+
if collection
|
32
|
+
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
33
|
+
route_block(
|
34
|
+
klass,
|
35
|
+
:collection,
|
36
|
+
controller: options[:controller],
|
37
|
+
prefix: options[:parentable_path]
|
38
|
+
).call
|
39
|
+
end
|
40
|
+
|
41
|
+
return unless resource
|
42
|
+
|
35
43
|
resources(
|
36
44
|
options[:route_name],
|
37
45
|
active_controller_opts(options),
|
38
|
-
&route_block(klass, &block)
|
46
|
+
&route_block(klass, :resource, &block)
|
39
47
|
)
|
40
|
-
|
41
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create") if options[:creatable]
|
42
|
-
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
43
48
|
end
|
44
49
|
|
45
50
|
def singular_linked_resource(klass, controller: nil, nested: true, &block)
|
@@ -48,10 +53,8 @@ module LinkedRails
|
|
48
53
|
resource(
|
49
54
|
options[:route_name],
|
50
55
|
active_controller_opts(options).merge(singular_route: true),
|
51
|
-
&route_block(klass, &block)
|
56
|
+
&route_block(klass, :singular, &block)
|
52
57
|
)
|
53
|
-
|
54
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create", singular_route: true) if options[:creatable]
|
55
58
|
end
|
56
59
|
|
57
60
|
def find_tenant_route
|
@@ -60,6 +63,16 @@ module LinkedRails
|
|
60
63
|
|
61
64
|
private
|
62
65
|
|
66
|
+
def action_routes(controller, prefix, key, value)
|
67
|
+
path = value.fetch(:action_path, key)
|
68
|
+
action = value.fetch(:action_name)
|
69
|
+
get([prefix, path].compact.join('/'), action: action, action_key: key, controller: controller)
|
70
|
+
return if value[:target_path].nil?
|
71
|
+
|
72
|
+
method = value.fetch(:http_method).downcase
|
73
|
+
send(method, [prefix, value.fetch(:target_path)].compact.join('/'), action: key, controller: controller)
|
74
|
+
end
|
75
|
+
|
63
76
|
def active_controller_opts(route_options)
|
64
77
|
{
|
65
78
|
controller: route_options[:controller],
|
@@ -68,22 +81,20 @@ module LinkedRails
|
|
68
81
|
}
|
69
82
|
end
|
70
83
|
|
71
|
-
def
|
72
|
-
klass.enhanced_with?(LinkedRails::Enhancements::Creatable, :Routing)
|
73
|
-
end
|
74
|
-
|
75
|
-
def route_block(klass)
|
84
|
+
def route_block(klass, action_type, controller: nil, prefix: nil)
|
76
85
|
lambda do
|
77
|
-
|
78
|
-
|
86
|
+
klass.action_list.defined_actions[action_type].each do |key, value|
|
87
|
+
action_routes(controller, prefix, key, value)
|
88
|
+
end
|
79
89
|
yield if block_given?
|
80
90
|
end
|
81
91
|
end
|
82
92
|
|
83
93
|
def route_options(klass, controller, nested, path)
|
94
|
+
touch_controller(klass)
|
95
|
+
|
84
96
|
{
|
85
97
|
controller: controller || klass.name.tableize,
|
86
|
-
creatable: creatable(klass),
|
87
98
|
nested: nested,
|
88
99
|
only: %i[show],
|
89
100
|
parentable_path: "(*parent_iri)/#{path}",
|
@@ -91,6 +102,11 @@ module LinkedRails
|
|
91
102
|
route_name: klass.name.demodulize.tableize
|
92
103
|
}.with_indifferent_access
|
93
104
|
end
|
105
|
+
|
106
|
+
# Make sure all actions are initialized before generating the routes
|
107
|
+
def touch_controller(klass)
|
108
|
+
klass.controller_class
|
109
|
+
end
|
94
110
|
end
|
95
111
|
end
|
96
112
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Actionable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
has_many :favorite_actions,
|
10
|
+
predicate: Vocab.ontola[:favoriteAction] do |object|
|
11
|
+
object.try(:favorite_actions)
|
12
|
+
end
|
13
|
+
statements :action_triples
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def action_triples(object, _params)
|
18
|
+
if object.iri.anonymous? && !object.try(:singular_resource?)
|
19
|
+
[]
|
20
|
+
else
|
21
|
+
object.try(:action_triples) || []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Menuable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include_menus
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def inherited(target)
|
14
|
+
super
|
15
|
+
target.include_menus
|
16
|
+
end
|
17
|
+
|
18
|
+
def include_menus
|
19
|
+
serializable_class.try(:menu_class)&.defined_menus&.keys&.each do |menu|
|
20
|
+
has_one "#{menu}_menu",
|
21
|
+
predicate: Vocab.ontola["#{menu.to_s.camelize(:lower)}Menu"],
|
22
|
+
if: method(:named_object?),
|
23
|
+
polymorphic: true do |object, opts|
|
24
|
+
object.menu(menu, opts[:scope])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Singularable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
statements :same_as_statement
|
10
|
+
|
11
|
+
def self.same_as_statement(object, _params)
|
12
|
+
return [] unless object.try(:singular_resource?) && object.singular_iri != object.iri
|
13
|
+
|
14
|
+
[
|
15
|
+
RDF::Statement.new(
|
16
|
+
object.singular_iri,
|
17
|
+
Vocab.owl.sameAs,
|
18
|
+
object.iri,
|
19
|
+
graph_name: Vocab.ld[:supplant]
|
20
|
+
)
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|