linked_rails 0.0.2 → 0.0.4.pre.gaa82a222d
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
@@ -16,19 +16,6 @@ module LinkedRails
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
-
def attributes_from_filters(filters)
|
20
|
-
filters.each_with_object({}) do |(key, value), hash|
|
21
|
-
next unless value.count == 1
|
22
|
-
|
23
|
-
attribute = predicate_mapping[key]&.key
|
24
|
-
hash[attribute] = value.first if attribute
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def include_in_collection?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
19
|
def input_select_property
|
33
20
|
Vocab.schema.name
|
34
21
|
end
|
@@ -68,7 +55,7 @@ module LinkedRails
|
|
68
55
|
serializer
|
69
56
|
.attributes_to_serialize
|
70
57
|
.values
|
71
|
-
.select { |attr| attr.predicate.present? }
|
58
|
+
.select { |attr| attr.predicate.present? && !attr.predicate.is_a?(Proc) }
|
72
59
|
.map { |attr| [attr.predicate, attr] }
|
73
60
|
end
|
74
61
|
|
@@ -79,7 +66,7 @@ module LinkedRails
|
|
79
66
|
serializer
|
80
67
|
.relationships_to_serialize
|
81
68
|
.values
|
82
|
-
.select { |value| value.predicate.present? }
|
69
|
+
.select { |value| value.predicate.present? && !value.predicate.is_a?(Proc) }
|
83
70
|
.map { |value| [value.predicate, value] }
|
84
71
|
end
|
85
72
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Model
|
5
|
+
module Singularable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
attr_accessor :singular_resource
|
10
|
+
end
|
11
|
+
|
12
|
+
def root_relative_singular_iri(**opts)
|
13
|
+
RDF::URI(singular_iri_template.expand(singular_iri_opts.merge(opts)))
|
14
|
+
end
|
15
|
+
|
16
|
+
def root_relative_iri(**opts)
|
17
|
+
return super unless singular_iri?
|
18
|
+
|
19
|
+
root_relative_singular_iri(**opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
def singular_iri(**opts)
|
23
|
+
return iri_with_root(root_relative_singular_iri(**opts)) if opts.present?
|
24
|
+
|
25
|
+
@singular_iri ||= iri_with_root(root_relative_singular_iri)
|
26
|
+
end
|
27
|
+
|
28
|
+
def singular_iri?
|
29
|
+
anonymous_iri?
|
30
|
+
end
|
31
|
+
|
32
|
+
def singular_iri_opts
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
|
36
|
+
def singular_iri_template
|
37
|
+
self.class.singular_iri_template
|
38
|
+
end
|
39
|
+
|
40
|
+
def singular_resource?
|
41
|
+
singular_resource || false
|
42
|
+
end
|
43
|
+
|
44
|
+
class_methods do
|
45
|
+
delegate :singular_route_key, to: :model_name
|
46
|
+
|
47
|
+
def requested_singular_resource(_params, _user_context)
|
48
|
+
raise(NotImplementedError)
|
49
|
+
end
|
50
|
+
|
51
|
+
def singular_iri_template
|
52
|
+
@singular_iri_template ||= LinkedRails::URITemplate.new("{/parent_iri*}/#{singular_route_key}{#fragment}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -5,11 +5,6 @@ module LinkedRails
|
|
5
5
|
module Sorting
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
-
included do
|
9
|
-
class_attribute :default_sortings, instance_accessor: false, instance_predicate: false
|
10
|
-
self.default_sortings = [{key: Vocab.schema.dateCreated, direction: :desc}]
|
11
|
-
end
|
12
|
-
|
13
8
|
module ClassMethods
|
14
9
|
def default_sort_column
|
15
10
|
:created_at
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Model
|
5
|
+
module Tables
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :defined_columns
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def with_columns(opts)
|
14
|
+
initialize_columns
|
15
|
+
defined_columns.merge!(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize_columns
|
19
|
+
return if defined_columns && method(:defined_columns).owner == singleton_class
|
20
|
+
|
21
|
+
self.defined_columns = superclass.try(:defined_columns)&.dup || {}.with_indifferent_access
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/linked_rails/model.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'model/actionable'
|
3
4
|
require_relative 'model/collections'
|
4
5
|
require_relative 'model/dirty'
|
5
6
|
require_relative 'model/enhancements'
|
@@ -7,33 +8,42 @@ require_relative 'model/filtering'
|
|
7
8
|
require_relative 'model/indexable'
|
8
9
|
require_relative 'model/iri'
|
9
10
|
require_relative 'model/iri_mapping'
|
11
|
+
require_relative 'model/menuable'
|
10
12
|
require_relative 'model/serialization'
|
13
|
+
require_relative 'model/singularable'
|
11
14
|
require_relative 'model/sorting'
|
15
|
+
require_relative 'model/tables'
|
12
16
|
|
13
17
|
module LinkedRails
|
14
18
|
module Model
|
15
19
|
extend ActiveSupport::Concern
|
20
|
+
include Actionable
|
16
21
|
include Collections
|
17
22
|
include Dirty
|
18
23
|
include Enhancements
|
19
24
|
include Filtering
|
20
25
|
include Indexable
|
21
|
-
include
|
22
|
-
include
|
26
|
+
include IRI
|
27
|
+
include IRIMapping
|
28
|
+
include Menuable
|
23
29
|
include Serialization
|
30
|
+
include Singularable
|
24
31
|
include Sorting
|
32
|
+
include Tables
|
25
33
|
|
26
34
|
def build_child(klass, user_context: nil)
|
27
35
|
klass.build_new(parent: self, user_context: user_context)
|
28
36
|
end
|
29
37
|
|
30
|
-
def singular_resource?
|
31
|
-
false
|
32
|
-
end
|
33
|
-
|
34
38
|
module ClassMethods
|
35
39
|
def build_new(parent: nil, user_context: nil)
|
36
|
-
|
40
|
+
raise(ActiveRecord::RecordNotFound) if try(:abstract_class?)
|
41
|
+
|
42
|
+
new(**attributes_for_new(parent: parent, user_context: user_context))
|
43
|
+
end
|
44
|
+
|
45
|
+
def controller_class
|
46
|
+
@controller_class ||= "#{to_s.pluralize}Controller".safe_constantize || superclass.try(:controller_class)
|
37
47
|
end
|
38
48
|
|
39
49
|
def form_class
|
@@ -1,93 +1,171 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module LinkedRails
|
4
|
-
class ParamsParser
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
class ParamsParser # rubocop:disable Metrics/ClassLength
|
5
|
+
include ::Empathy::EmpJson::Helpers::Slices
|
6
|
+
include ::Empathy::EmpJson::Helpers::Primitives
|
7
|
+
include ::Empathy::EmpJson::Helpers::Values
|
8
|
+
|
9
|
+
attr_accessor :params, :slice, :user_context
|
10
|
+
delegate :filter_params, to: :collection_params_parser
|
11
|
+
|
12
|
+
def initialize(slice: nil, params: {}, user_context: nil)
|
13
|
+
self.slice = slice
|
14
|
+
self.params = params
|
15
|
+
self.user_context = user_context
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
|
18
|
+
def attributes_from_filters(klass)
|
19
|
+
ActionController::Parameters.new(
|
20
|
+
filter_params.each_with_object({}) do |(predicate, value), hash|
|
21
|
+
key_and_value = filter_to_param(klass, predicate, value)
|
22
|
+
hash[key_and_value.first] = key_and_value.second if key_and_value
|
23
|
+
end
|
24
|
+
)
|
25
|
+
end
|
14
26
|
|
15
|
-
|
16
|
-
|
27
|
+
def parse_param(klass, predicate, object)
|
28
|
+
field_options = serializer_field(klass, predicate) unless predicate == '_id'
|
29
|
+
if field_options.is_a?(FastJsonapi::Attribute)
|
30
|
+
parse_attribute(klass, field_options, emp_to_primitive(object))
|
31
|
+
elsif field_options.is_a?(FastJsonapi::Relationship)
|
32
|
+
parse_association(klass, field_options, emp_to_primitive(object))
|
33
|
+
end
|
34
|
+
end
|
17
35
|
|
18
|
-
|
19
|
-
|
20
|
-
|
36
|
+
# Recursively parses a resource from slice
|
37
|
+
def parse_resource(subject, klass)
|
38
|
+
(record_from_slice(slice, subject) || {}).reduce({}) do |h, (k, v)|
|
39
|
+
(v.is_a?(Array) ? v : [v]).each do |value|
|
40
|
+
param = parse_param(klass, RDF::URI(k), value)
|
41
|
+
param ? add_param(h, param.first, param.second) : h
|
42
|
+
end
|
43
|
+
h
|
21
44
|
end
|
22
45
|
end
|
23
46
|
|
24
|
-
|
25
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def add_param(hash, key, value) # rubocop:disable Metrics/MethodLength
|
50
|
+
case hash[key]
|
51
|
+
when nil
|
52
|
+
hash[key] = value
|
53
|
+
when Hash
|
54
|
+
hash[key].merge!(value)
|
55
|
+
when Array
|
56
|
+
hash[key].append(value)
|
57
|
+
else
|
58
|
+
hash[key] = [hash[key], value]
|
59
|
+
end
|
60
|
+
hash
|
61
|
+
end
|
26
62
|
|
27
|
-
|
63
|
+
def associated_class_from_params(reflection, object)
|
64
|
+
return reflection.klass unless reflection.polymorphic?
|
28
65
|
|
29
|
-
|
30
|
-
values[:filter] = filter if filter
|
66
|
+
query = slice.query(subject: object, predicate: Vocab.rdfv[:type])
|
31
67
|
|
32
|
-
|
33
|
-
values[:sort] = sort if sort
|
68
|
+
raise("No type given for '#{object}' referenced by polymorphic association '#{reflection.name}'") if query.empty?
|
34
69
|
|
35
|
-
|
70
|
+
iri_to_class(query.first.object)
|
71
|
+
end
|
36
72
|
|
37
|
-
|
73
|
+
def collection_params_parser
|
74
|
+
@collection_params_parser ||= LinkedRails::CollectionParamsParser.new(params.merge(user_context: user_context))
|
38
75
|
end
|
39
76
|
|
40
|
-
def
|
41
|
-
|
77
|
+
def filter_to_param(klass, predicate, value)
|
78
|
+
options = serializer_field(klass, predicate)
|
79
|
+
return unless value.count == 1 && options.present?
|
42
80
|
|
43
|
-
|
81
|
+
parsed_value = value.first.start_with?('http') ? RDF::URI(value.first) : RDF::Literal(value.first)
|
82
|
+
parse_param(
|
83
|
+
klass,
|
84
|
+
options.predicate,
|
85
|
+
parsed_value
|
86
|
+
)
|
87
|
+
end
|
44
88
|
|
45
|
-
|
46
|
-
|
89
|
+
def foreign_key_for_reflection(reflection)
|
90
|
+
if reflection.options[:through]
|
91
|
+
reflection.has_one? ? "#{reflection.name}_id" : "#{reflection.name.to_s.singularize}_ids"
|
92
|
+
elsif reflection.belongs_to?
|
93
|
+
reflection.foreign_key
|
94
|
+
end
|
95
|
+
end
|
47
96
|
|
48
|
-
|
97
|
+
def iri_to_class(iri)
|
98
|
+
iri.to_s.split(Vocab.app.to_s).pop&.classify&.safe_constantize ||
|
99
|
+
LinkedRails.linked_models.detect { |klass| klass.iri == iri }
|
49
100
|
end
|
50
101
|
|
51
|
-
def
|
52
|
-
|
102
|
+
def nested_attributes(object, klass, association, collection)
|
103
|
+
parsed = parse_nested_resource(object, klass)
|
104
|
+
nested_resources = collection ? {rand(1_000_000_000).to_s => parsed} : parsed
|
105
|
+
|
106
|
+
["#{association}_attributes", nested_resources]
|
107
|
+
end
|
53
108
|
|
54
|
-
|
55
|
-
|
56
|
-
|
109
|
+
def parse_association(klass, field_options, object)
|
110
|
+
association = field_options.association || field_options.key
|
111
|
+
reflection = klass.reflect_on_association(association) || raise("#{association} not found for #{name}")
|
57
112
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
113
|
+
if slice&.key?(object.to_s)
|
114
|
+
association_klass = associated_class_from_params(reflection, object)
|
115
|
+
nested_attributes(object, association_klass, association, reflection.collection?)
|
116
|
+
elsif object.iri?
|
117
|
+
parse_iri_param(object, reflection)
|
63
118
|
end
|
64
119
|
end
|
65
120
|
|
66
|
-
def
|
67
|
-
|
121
|
+
def parse_attribute(klass, field_options, value)
|
122
|
+
parsed_value = parse_enum_attribute(klass, field_options.key, value) || value
|
68
123
|
|
69
|
-
|
70
|
-
|
124
|
+
[field_options.key, parsed_value.to_s]
|
125
|
+
end
|
71
126
|
|
72
|
-
|
73
|
-
|
74
|
-
|
127
|
+
def parse_enum_attribute(klass, key, value)
|
128
|
+
opts = RDF::Serializers.serializer_for(klass)&.enum_options(key)
|
129
|
+
return if opts.blank?
|
130
|
+
|
131
|
+
|
132
|
+
opts.detect { |_k, options| options.iri == value }&.first&.to_s
|
75
133
|
end
|
76
134
|
|
77
|
-
|
135
|
+
def parse_iri_param(iri, reflection)
|
136
|
+
key = foreign_key_for_reflection(reflection)
|
137
|
+
value = parse_iri_param_value(iri, reflection) if key
|
138
|
+
|
139
|
+
[key, value.to_s] if value
|
140
|
+
end
|
78
141
|
|
79
|
-
def
|
80
|
-
|
142
|
+
def parse_iri_param_value(iri, reflection)
|
143
|
+
resource = LinkedRails.iri_mapper.resource_from_iri(iri, user_context)
|
81
144
|
|
82
|
-
|
83
|
-
|
145
|
+
resource&.try(reflection.association_primary_key)
|
146
|
+
end
|
147
|
+
|
148
|
+
def parse_nested_resource(object, klass)
|
149
|
+
resource = parse_resource(object, klass)
|
150
|
+
resource[:id] ||= nested_resource_id(object)
|
151
|
+
resource
|
152
|
+
end
|
153
|
+
|
154
|
+
def nested_resource_id(object)
|
155
|
+
return unless object.iri?
|
156
|
+
|
157
|
+
opts = LinkedRails.iri_mapper.opts_from_iri(object)
|
158
|
+
if opts[:class].method(:requested_single_resource).owner == LinkedRails::Model::IRIMapping::ClassMethods
|
159
|
+
opts[:params][:id]
|
160
|
+
else
|
161
|
+
opts[:class].requested_single_resource(opts[:params], nil)&.id
|
162
|
+
end
|
84
163
|
end
|
85
164
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
.with_indifferent_access
|
165
|
+
def serializer_field(klass, predicate)
|
166
|
+
field = klass.try(:predicate_mapping).try(:[], predicate)
|
167
|
+
Rails.logger.info("#{predicate} not found for #{klass || 'nil'}") if field.blank?
|
168
|
+
field
|
91
169
|
end
|
92
170
|
end
|
93
171
|
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
|
|