linked_rails 0.0.3 → 0.0.4
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/app/controllers/linked_rails/bulk_controller.rb +26 -6
- data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
- data/app/models/linked_rails/actions/item.rb +46 -30
- data/app/models/linked_rails/actions/list.rb +6 -25
- 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 +5 -1
- data/app/models/linked_rails/collection/filter_option.rb +1 -1
- data/app/models/linked_rails/collection/filterable.rb +3 -8
- data/app/models/linked_rails/collection/infinite.rb +102 -0
- data/app/models/linked_rails/collection/infinite_view.rb +1 -90
- data/app/models/linked_rails/collection/iri.rb +33 -52
- data/app/models/linked_rails/collection/iri_mapping.rb +14 -6
- data/app/models/linked_rails/collection/paginated.rb +45 -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 +15 -5
- data/app/models/linked_rails/collection.rb +33 -67
- 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 +39 -1
- data/app/models/linked_rails/form/field/resource_field.rb +2 -0
- data/app/models/linked_rails/form/field.rb +6 -8
- data/app/models/linked_rails/form/field_factory.rb +21 -10
- data/app/models/linked_rails/form/group.rb +2 -2
- data/app/models/linked_rails/form/page.rb +4 -4
- data/app/models/linked_rails/form.rb +13 -15
- data/app/models/linked_rails/manifest.rb +8 -2
- data/app/models/linked_rails/menus/item.rb +1 -1
- data/app/models/linked_rails/menus/list.rb +3 -2
- data/app/models/linked_rails/ontology/base.rb +1 -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/sequence.rb +2 -2
- data/app/models/linked_rails/shacl/property_shape.rb +1 -1
- data/app/models/linked_rails/widget.rb +1 -1
- data/app/serializers/linked_rails/actions/item_serializer.rb +2 -1
- data/app/serializers/linked_rails/collection_serializer.rb +7 -2
- data/app/serializers/linked_rails/entry_point_serializer.rb +1 -1
- data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
- 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 +12 -0
- 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 +1 -1
- data/lib/linked_rails/active_response/controller/collections.rb +1 -1
- data/lib/linked_rails/active_response/controller/crud_defaults.rb +3 -3
- data/lib/linked_rails/active_response/controller/params.rb +5 -5
- data/lib/linked_rails/active_response/controller.rb +11 -0
- 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 +118 -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.rb +20 -3
- 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 -3
- data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
- data/lib/linked_rails/helpers/resource_helper.rb +1 -1
- data/lib/linked_rails/iri_mapper.rb +17 -39
- data/lib/linked_rails/middleware/linked_data_params.rb +7 -127
- data/lib/linked_rails/model/actionable.rb +69 -0
- data/lib/linked_rails/model/collections.rb +195 -39
- data/lib/linked_rails/model/dirty.rb +1 -1
- data/lib/linked_rails/model/enhancements.rb +1 -6
- data/lib/linked_rails/model/filtering.rb +2 -4
- data/lib/linked_rails/model/indexable.rb +5 -15
- data/lib/linked_rails/model/iri.rb +15 -17
- data/lib/linked_rails/model/iri_mapping.rb +35 -6
- data/lib/linked_rails/model/menuable.rb +34 -0
- data/lib/linked_rails/model/serialization.rb +0 -9
- data/lib/linked_rails/model/singularable.rb +55 -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 +13 -5
- data/lib/linked_rails/params_parser.rb +131 -55
- data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
- data/lib/linked_rails/policy.rb +24 -17
- data/lib/linked_rails/rdf_error.rb +2 -2
- data/lib/linked_rails/routes.rb +37 -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 +23 -10
- data/lib/linked_rails/test_methods.rb +114 -0
- data/lib/linked_rails/translate.rb +19 -9
- data/lib/linked_rails/uri_template.rb +30 -0
- data/lib/linked_rails/version.rb +1 -1
- data/lib/linked_rails/vocab.rb +8 -0
- data/lib/linked_rails.rb +25 -12
- data/lib/rails/welcome_controller.rb +3 -3
- data/lib/rdf/query_fix.rb +15 -0
- metadata +22 -25
- 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/indexable/model.rb +0 -10
- 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,169 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module LinkedRails
|
|
4
|
-
class ParamsParser
|
|
5
|
-
|
|
4
|
+
class ParamsParser # rubocop:disable Metrics/ClassLength
|
|
5
|
+
attr_accessor :params, :graph, :user_context
|
|
6
6
|
|
|
7
|
-
def initialize(params)
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
def initialize(graph: nil, params: {}, user_context: nil)
|
|
8
|
+
self.graph = graph
|
|
9
|
+
self.params = params
|
|
10
|
+
self.user_context = user_context
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
def attributes_from_filters(klass)
|
|
14
|
+
ActionController::Parameters.new(
|
|
15
|
+
collection_params_parser.filter_params.each_with_object({}) do |(predicate, value), hash|
|
|
16
|
+
key_and_value = filter_to_param(klass, predicate, value)
|
|
17
|
+
hash[key_and_value.first] = key_and_value.second if key_and_value
|
|
18
|
+
end
|
|
19
|
+
)
|
|
20
|
+
end
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
def parse_param(klass, predicate, object)
|
|
23
|
+
field_options = serializer_field(klass, predicate)
|
|
24
|
+
if field_options.is_a?(FastJsonapi::Attribute)
|
|
25
|
+
parse_attribute(klass, field_options, object.value)
|
|
26
|
+
elsif field_options.is_a?(FastJsonapi::Relationship)
|
|
27
|
+
parse_association(klass, field_options, object)
|
|
21
28
|
end
|
|
22
29
|
end
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
# Recursively parses a resource from graph
|
|
32
|
+
def parse_resource(subject, klass)
|
|
33
|
+
graph
|
|
34
|
+
.query([subject])
|
|
35
|
+
.map { |statement| parse_statement(statement, klass) }
|
|
36
|
+
.compact
|
|
37
|
+
.reduce({}) { |h, (k, v)| add_param(h, k, v) }
|
|
38
|
+
end
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def add_param(hash, key, value) # rubocop:disable Metrics/MethodLength
|
|
43
|
+
case hash[key]
|
|
44
|
+
when nil
|
|
45
|
+
hash[key] = value
|
|
46
|
+
when Hash
|
|
47
|
+
hash[key].merge!(value)
|
|
48
|
+
when Array
|
|
49
|
+
hash[key].append(value)
|
|
50
|
+
else
|
|
51
|
+
hash[key] = [hash[key], value]
|
|
52
|
+
end
|
|
53
|
+
hash
|
|
54
|
+
end
|
|
28
55
|
|
|
29
|
-
|
|
30
|
-
|
|
56
|
+
def associated_class_from_params(reflection, object)
|
|
57
|
+
return reflection.klass unless reflection.polymorphic?
|
|
31
58
|
|
|
32
|
-
|
|
33
|
-
values[:sort] = sort if sort
|
|
59
|
+
query = graph.query(subject: object, predicate: Vocab.rdfv[:type])
|
|
34
60
|
|
|
35
|
-
|
|
61
|
+
raise("No type given for '#{object}' referenced by polymorphic association '#{reflection.name}'") if query.empty?
|
|
36
62
|
|
|
37
|
-
|
|
63
|
+
iri_to_class(query.first.object)
|
|
38
64
|
end
|
|
39
65
|
|
|
40
|
-
def
|
|
41
|
-
|
|
66
|
+
def collection_params_parser
|
|
67
|
+
@collection_params_parser ||= LinkedRails::CollectionParamsParser.new(params.merge(user_context: user_context))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def filter_to_param(klass, predicate, value)
|
|
71
|
+
options = serializer_field(klass, predicate)
|
|
72
|
+
return unless value.count == 1 && options.present?
|
|
73
|
+
|
|
74
|
+
parsed_value = value.first.start_with?('http') ? RDF::URI(value.first) : RDF::Literal(value.first)
|
|
75
|
+
parse_param(
|
|
76
|
+
klass,
|
|
77
|
+
options.predicate,
|
|
78
|
+
parsed_value
|
|
79
|
+
)
|
|
80
|
+
end
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
def foreign_key_for_reflection(reflection)
|
|
83
|
+
if reflection.options[:through]
|
|
84
|
+
reflection.has_one? ? "#{reflection.name}_id" : "#{reflection.name.to_s.singularize}_ids"
|
|
85
|
+
elsif reflection.belongs_to?
|
|
86
|
+
reflection.foreign_key
|
|
87
|
+
end
|
|
88
|
+
end
|
|
44
89
|
|
|
45
|
-
|
|
46
|
-
|
|
90
|
+
def iri_to_class(iri)
|
|
91
|
+
iri.to_s.split(Vocab.app.to_s).pop&.classify&.safe_constantize ||
|
|
92
|
+
LinkedRails.linked_models.detect { |klass| klass.iri == iri }
|
|
93
|
+
end
|
|
47
94
|
|
|
48
|
-
|
|
95
|
+
def nested_attributes(object, klass, association, collection)
|
|
96
|
+
nested_resources =
|
|
97
|
+
if graph.query([object, Vocab.rdfv[:first], nil]).present?
|
|
98
|
+
nested_attributes_from_list(object, klass)
|
|
99
|
+
else
|
|
100
|
+
parsed = parse_nested_resource(object, klass)
|
|
101
|
+
collection ? {rand(1_000_000_000).to_s => parsed} : parsed
|
|
102
|
+
end
|
|
103
|
+
["#{association}_attributes", nested_resources]
|
|
49
104
|
end
|
|
50
105
|
|
|
51
|
-
def
|
|
52
|
-
|
|
106
|
+
def nested_attributes_from_list(object, klass)
|
|
107
|
+
Hash[
|
|
108
|
+
RDF::List.new(subject: object, graph: graph)
|
|
109
|
+
.map { |nested| [rand(1_000_000_000).to_s, parse_nested_resource(nested, klass)] }
|
|
110
|
+
]
|
|
111
|
+
end
|
|
53
112
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
113
|
+
def parse_association(klass, field_options, object)
|
|
114
|
+
association = field_options.association || field_options.key
|
|
115
|
+
reflection = klass.reflect_on_association(association) || raise("#{association} not found for #{name}")
|
|
57
116
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
117
|
+
if graph&.has_subject?(object)
|
|
118
|
+
association_klass = associated_class_from_params(reflection, object)
|
|
119
|
+
nested_attributes(object, association_klass, association, reflection.collection?)
|
|
120
|
+
elsif object.iri?
|
|
121
|
+
parse_iri_param(object, reflection)
|
|
63
122
|
end
|
|
64
123
|
end
|
|
65
124
|
|
|
66
|
-
def
|
|
67
|
-
|
|
125
|
+
def parse_attribute(klass, field_options, value)
|
|
126
|
+
parsed_value = parse_blob_attribute(value) || parse_enum_attribute(klass, field_options.key, value) || value
|
|
68
127
|
|
|
69
|
-
|
|
70
|
-
|
|
128
|
+
[field_options.key, parsed_value]
|
|
129
|
+
end
|
|
71
130
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
end
|
|
131
|
+
def parse_blob_attribute(value)
|
|
132
|
+
params["<#{value}>"] if value.starts_with?(Vocab.ll['blobs/'])
|
|
75
133
|
end
|
|
76
134
|
|
|
77
|
-
|
|
135
|
+
def parse_enum_attribute(klass, key, value)
|
|
136
|
+
opts = RDF::Serializers.serializer_for(klass)&.enum_options(key)
|
|
137
|
+
return if opts.blank?
|
|
138
|
+
|
|
139
|
+
opts.detect { |_k, options| options.iri == value }&.first&.to_s
|
|
140
|
+
end
|
|
78
141
|
|
|
79
|
-
def
|
|
80
|
-
|
|
142
|
+
def parse_iri_param(iri, reflection)
|
|
143
|
+
resource = LinkedRails.iri_mapper.resource_from_iri(iri, user_context)
|
|
144
|
+
return unless resource
|
|
145
|
+
|
|
146
|
+
key = foreign_key_for_reflection(reflection)
|
|
147
|
+
|
|
148
|
+
value = resource&.try(reflection.association_primary_key) if key
|
|
149
|
+
|
|
150
|
+
[key, value] if value
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def parse_nested_resource(object, klass)
|
|
154
|
+
resource = parse_resource(object, klass)
|
|
155
|
+
resource[:id] ||= LinkedRails.iri_mapper.opts_from_iri(object)[:params][:id] if object.iri?
|
|
156
|
+
resource
|
|
157
|
+
end
|
|
81
158
|
|
|
82
|
-
|
|
83
|
-
|
|
159
|
+
def parse_statement(statement, klass)
|
|
160
|
+
parse_param(klass, statement.predicate, statement.object)
|
|
84
161
|
end
|
|
85
162
|
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.with_indifferent_access
|
|
163
|
+
def serializer_field(klass, predicate)
|
|
164
|
+
field = klass.try(:predicate_mapping).try(:[], predicate)
|
|
165
|
+
Rails.logger.info("#{predicate} not found for #{klass || 'nil'}") if field.blank?
|
|
166
|
+
field
|
|
91
167
|
end
|
|
92
168
|
end
|
|
93
169
|
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,11 +23,11 @@ module LinkedRails
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def create_child?(klass, opts
|
|
26
|
+
def create_child?(klass, **opts)
|
|
27
27
|
child_policy(klass, opts).create?
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def index_children?(klass, opts
|
|
30
|
+
def index_children?(klass, **opts)
|
|
31
31
|
child_policy(klass, opts).show?
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -38,6 +38,10 @@ module LinkedRails
|
|
|
38
38
|
.flatten
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def policy_class
|
|
42
|
+
self.class.policy_class
|
|
43
|
+
end
|
|
44
|
+
|
|
41
45
|
def show?
|
|
42
46
|
false
|
|
43
47
|
end
|
|
@@ -64,25 +68,28 @@ module LinkedRails
|
|
|
64
68
|
end
|
|
65
69
|
end
|
|
66
70
|
|
|
67
|
-
def child_policy(klass, opts
|
|
71
|
+
def child_policy(klass, **opts)
|
|
68
72
|
Pundit.policy(user_context, record.build_child(klass, opts.merge(user_context: user_context)))
|
|
69
73
|
end
|
|
70
74
|
|
|
71
|
-
def forbid_with_message(message)
|
|
75
|
+
def forbid_with_message(message, status = nil)
|
|
76
|
+
forbid_with_status(status) if status
|
|
72
77
|
@message = message
|
|
73
78
|
false
|
|
74
79
|
end
|
|
75
80
|
|
|
81
|
+
def forbid_with_status(status, message = nil)
|
|
82
|
+
forbid_with_message(message) if message
|
|
83
|
+
@action_status = status
|
|
84
|
+
false
|
|
85
|
+
end
|
|
86
|
+
|
|
76
87
|
def parent_policy
|
|
77
88
|
return if record.try(:parent).blank?
|
|
78
89
|
|
|
79
90
|
@parent_policy ||= Pundit.policy(user_context, record.parent)
|
|
80
91
|
end
|
|
81
92
|
|
|
82
|
-
def policy_class
|
|
83
|
-
self.class.policy_class
|
|
84
|
-
end
|
|
85
|
-
|
|
86
93
|
def sanitize_array_attribute(attr)
|
|
87
94
|
[attr, attr => []]
|
|
88
95
|
end
|
|
@@ -118,7 +125,7 @@ module LinkedRails
|
|
|
118
125
|
end
|
|
119
126
|
|
|
120
127
|
module ClassMethods
|
|
121
|
-
def condition_for(attr, pass, shape_opts
|
|
128
|
+
def condition_for(attr, pass, **shape_opts)
|
|
122
129
|
raise("#{attr} not permitted by #{self}") if attribute_options(attr).blank? && pass.permission_required?
|
|
123
130
|
|
|
124
131
|
alternatives = node_shapes_for(attr, **shape_opts)
|
|
@@ -131,6 +138,10 @@ module LinkedRails
|
|
|
131
138
|
end
|
|
132
139
|
end
|
|
133
140
|
|
|
141
|
+
def policy_class
|
|
142
|
+
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
|
143
|
+
end
|
|
144
|
+
|
|
134
145
|
def permitted_attributes
|
|
135
146
|
initialize_permitted_attributes
|
|
136
147
|
|
|
@@ -165,22 +176,18 @@ module LinkedRails
|
|
|
165
176
|
self._permitted_attributes = superclass.try(:_permitted_attributes)&.dup || []
|
|
166
177
|
end
|
|
167
178
|
|
|
168
|
-
def permit_attributes(attrs, conditions
|
|
179
|
+
def permit_attributes(attrs, **conditions)
|
|
169
180
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {}}
|
|
170
181
|
end
|
|
171
182
|
|
|
172
|
-
def permit_array_attributes(attrs, conditions
|
|
183
|
+
def permit_array_attributes(attrs, **conditions)
|
|
173
184
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {array: true}}
|
|
174
185
|
end
|
|
175
186
|
|
|
176
|
-
def permit_nested_attributes(attrs, conditions
|
|
187
|
+
def permit_nested_attributes(attrs, **conditions)
|
|
177
188
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {nested: true}}
|
|
178
189
|
end
|
|
179
190
|
|
|
180
|
-
def policy_class
|
|
181
|
-
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
|
182
|
-
end
|
|
183
|
-
|
|
184
191
|
def property_shapes(conditions)
|
|
185
192
|
conditions.map { |key, options| send("#{key}_shapes", options) }.flatten.compact
|
|
186
193
|
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,28 @@ 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)/new', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :create
|
|
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
|
|
30
25
|
end
|
|
31
26
|
|
|
32
|
-
def linked_resource(klass, controller: nil, nested: false, &block)
|
|
27
|
+
def linked_resource(klass, controller: nil, collection: true, nested: false, resource: true, &block) # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
|
33
28
|
options = route_options(klass, controller, nested, klass.route_key)
|
|
34
29
|
|
|
30
|
+
if collection
|
|
31
|
+
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
|
32
|
+
route_block(
|
|
33
|
+
klass,
|
|
34
|
+
:collection,
|
|
35
|
+
controller: options[:controller],
|
|
36
|
+
prefix: options[:parentable_path]
|
|
37
|
+
).call
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
return unless resource
|
|
41
|
+
|
|
35
42
|
resources(
|
|
36
43
|
options[:route_name],
|
|
37
44
|
active_controller_opts(options),
|
|
38
|
-
&route_block(klass, &block)
|
|
45
|
+
&route_block(klass, :resource, &block)
|
|
39
46
|
)
|
|
40
|
-
|
|
41
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create") if options[:creatable]
|
|
42
|
-
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def singular_linked_resource(klass, controller: nil, nested: true, &block)
|
|
@@ -48,10 +52,8 @@ module LinkedRails
|
|
|
48
52
|
resource(
|
|
49
53
|
options[:route_name],
|
|
50
54
|
active_controller_opts(options).merge(singular_route: true),
|
|
51
|
-
&route_block(klass, &block)
|
|
55
|
+
&route_block(klass, :singular, &block)
|
|
52
56
|
)
|
|
53
|
-
|
|
54
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create", singular_route: true) if options[:creatable]
|
|
55
57
|
end
|
|
56
58
|
|
|
57
59
|
def find_tenant_route
|
|
@@ -60,6 +62,16 @@ module LinkedRails
|
|
|
60
62
|
|
|
61
63
|
private
|
|
62
64
|
|
|
65
|
+
def action_routes(controller, prefix, key, value)
|
|
66
|
+
path = value.fetch(:action_path, key)
|
|
67
|
+
action = value.fetch(:action_name)
|
|
68
|
+
get([prefix, path].compact.join('/'), action: action, action_key: key, controller: controller)
|
|
69
|
+
return if value[:target_path].nil?
|
|
70
|
+
|
|
71
|
+
method = value.fetch(:http_method).downcase
|
|
72
|
+
send(method, [prefix, value.fetch(:target_path)].compact.join('/'), action: key, controller: controller)
|
|
73
|
+
end
|
|
74
|
+
|
|
63
75
|
def active_controller_opts(route_options)
|
|
64
76
|
{
|
|
65
77
|
controller: route_options[:controller],
|
|
@@ -68,22 +80,20 @@ module LinkedRails
|
|
|
68
80
|
}
|
|
69
81
|
end
|
|
70
82
|
|
|
71
|
-
def
|
|
72
|
-
klass.enhanced_with?(LinkedRails::Enhancements::Creatable, :Routing)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def route_block(klass)
|
|
83
|
+
def route_block(klass, action_type, controller: nil, prefix: nil)
|
|
76
84
|
lambda do
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
klass.action_list.defined_actions[action_type].each do |key, value|
|
|
86
|
+
action_routes(controller, prefix, key, value)
|
|
87
|
+
end
|
|
79
88
|
yield if block_given?
|
|
80
89
|
end
|
|
81
90
|
end
|
|
82
91
|
|
|
83
92
|
def route_options(klass, controller, nested, path)
|
|
93
|
+
touch_controller(klass)
|
|
94
|
+
|
|
84
95
|
{
|
|
85
96
|
controller: controller || klass.name.tableize,
|
|
86
|
-
creatable: creatable(klass),
|
|
87
97
|
nested: nested,
|
|
88
98
|
only: %i[show],
|
|
89
99
|
parentable_path: "(*parent_iri)/#{path}",
|
|
@@ -91,6 +101,11 @@ module LinkedRails
|
|
|
91
101
|
route_name: klass.name.demodulize.tableize
|
|
92
102
|
}.with_indifferent_access
|
|
93
103
|
end
|
|
104
|
+
|
|
105
|
+
# Make sure all actions are initialized before generating the routes
|
|
106
|
+
def touch_controller(klass)
|
|
107
|
+
klass.controller_class
|
|
108
|
+
end
|
|
94
109
|
end
|
|
95
110
|
end
|
|
96
111
|
|
|
@@ -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.ll[:supplant]
|
|
20
|
+
)
|
|
21
|
+
]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'serializer/actionable'
|
|
4
|
+
require_relative 'serializer/menuable'
|
|
5
|
+
require_relative 'serializer/singularable'
|
|
6
|
+
|
|
3
7
|
module LinkedRails
|
|
4
8
|
module Serializer
|
|
5
9
|
extend ActiveSupport::Concern
|
|
6
10
|
|
|
7
11
|
included do
|
|
8
12
|
include RDF::Serializers::ObjectSerializer
|
|
13
|
+
include Serializer::Actionable
|
|
14
|
+
include Serializer::Menuable
|
|
15
|
+
include Serializer::Singularable
|
|
16
|
+
|
|
9
17
|
extend Enhanceable
|
|
10
18
|
|
|
11
19
|
enhanceable :serializable_class, :Serializer
|
|
@@ -15,7 +23,7 @@ module LinkedRails
|
|
|
15
23
|
set_id :iri
|
|
16
24
|
|
|
17
25
|
attribute :rdf_type, predicate: Vocab.rdfv.type, datatype: Vocab.xsd.anyURI
|
|
18
|
-
attribute :created_at, predicate: Vocab.schema
|
|
26
|
+
attribute :created_at, predicate: Vocab.schema.dateCreated do |object|
|
|
19
27
|
object.try(:created_at)
|
|
20
28
|
end
|
|
21
29
|
end
|
|
@@ -58,8 +66,7 @@ module LinkedRails
|
|
|
58
66
|
]
|
|
59
67
|
end
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
def has_one(key, opts = {})
|
|
69
|
+
def has_one(key, **opts)
|
|
63
70
|
opts[:id_method_name] = :iri
|
|
64
71
|
|
|
65
72
|
return super if block_given?
|
|
@@ -69,7 +76,7 @@ module LinkedRails
|
|
|
69
76
|
end
|
|
70
77
|
end
|
|
71
78
|
|
|
72
|
-
def has_many(key, opts
|
|
79
|
+
def has_many(key, **opts)
|
|
73
80
|
opts[:id_method_name] = :iri
|
|
74
81
|
|
|
75
82
|
return super if block_given?
|
|
@@ -78,7 +85,6 @@ module LinkedRails
|
|
|
78
85
|
object.send(key)
|
|
79
86
|
end
|
|
80
87
|
end
|
|
81
|
-
# rubocop:enable Naming/PredicateName
|
|
82
88
|
|
|
83
89
|
def named_object?(object)
|
|
84
90
|
!object.iri.anonymous?
|
|
@@ -88,6 +94,11 @@ module LinkedRails
|
|
|
88
94
|
false
|
|
89
95
|
end
|
|
90
96
|
|
|
97
|
+
def secret_attribute(key, **opts)
|
|
98
|
+
opts[:if] = method(:never)
|
|
99
|
+
attribute(key, **opts)
|
|
100
|
+
end
|
|
101
|
+
|
|
91
102
|
def serializable_class
|
|
92
103
|
@serializable_class ||= name.gsub('Serializer', '').safe_constantize
|
|
93
104
|
end
|
|
@@ -100,16 +111,18 @@ module LinkedRails
|
|
|
100
111
|
end
|
|
101
112
|
end
|
|
102
113
|
|
|
103
|
-
def with_collection(name, opts
|
|
114
|
+
def with_collection(name, **opts) # rubocop:disable Metrics/AbcSize
|
|
104
115
|
collection_name = "#{name.to_s.singularize}_collection"
|
|
105
|
-
page_size = opts.delete(:page_size)
|
|
106
|
-
display = opts.delete(:display)
|
|
107
116
|
opts[:association] ||= name
|
|
108
117
|
opts[:polymorphic] ||= true
|
|
109
118
|
opts[:if] ||= method(:named_object?)
|
|
110
119
|
|
|
111
|
-
|
|
112
|
-
|
|
120
|
+
collection_opts = {}
|
|
121
|
+
collection_opts[:page_size] = opts.delete(:page_size) if opts.key?(:page_size)
|
|
122
|
+
collection_opts[:display] = opts.delete(:display) if opts.key?(:display)
|
|
123
|
+
|
|
124
|
+
has_one collection_name, **opts do |object, params|
|
|
125
|
+
object.send(collection_name, **collection_opts.merge(user_context: params[:scope]))
|
|
113
126
|
end
|
|
114
127
|
end
|
|
115
128
|
|