linked_rails 0.0.3 → 0.0.4.pre.g1faca9643
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +105 -22
- 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 +17 -21
- data/app/models/linked_rails/manifest.rb +102 -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 +6 -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/policies/linked_rails/form_policy.rb +13 -0
- data/app/policies/linked_rails/ontology_policy.rb +13 -0
- 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/app/workers/linked_rails/invalidation_stream_worker.rb +16 -0
- 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 +16 -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 +12 -7
- 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/errors/forbidden.rb +37 -0
- data/lib/linked_rails/errors.rb +3 -0
- 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 +11 -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/cacheable.rb +45 -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 +29 -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 +18 -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 +44 -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/storage.rb +32 -0
- 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/url.rb +11 -0
- data/lib/linked_rails/version.rb +1 -1
- data/lib/linked_rails/vocab.rb +9 -0
- data/lib/linked_rails.rb +40 -14
- data/lib/rails/welcome_controller.rb +3 -3
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +79 -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,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'model/actionable'
|
4
|
+
require_relative 'model/cacheable'
|
3
5
|
require_relative 'model/collections'
|
4
6
|
require_relative 'model/dirty'
|
5
7
|
require_relative 'model/enhancements'
|
@@ -7,33 +9,42 @@ require_relative 'model/filtering'
|
|
7
9
|
require_relative 'model/indexable'
|
8
10
|
require_relative 'model/iri'
|
9
11
|
require_relative 'model/iri_mapping'
|
12
|
+
require_relative 'model/menuable'
|
10
13
|
require_relative 'model/serialization'
|
14
|
+
require_relative 'model/singularable'
|
11
15
|
require_relative 'model/sorting'
|
16
|
+
require_relative 'model/tables'
|
12
17
|
|
13
18
|
module LinkedRails
|
14
19
|
module Model
|
15
20
|
extend ActiveSupport::Concern
|
21
|
+
include Actionable
|
16
22
|
include Collections
|
17
23
|
include Dirty
|
18
24
|
include Enhancements
|
19
25
|
include Filtering
|
20
26
|
include Indexable
|
21
|
-
include
|
22
|
-
include
|
27
|
+
include IRI
|
28
|
+
include IRIMapping
|
29
|
+
include Menuable
|
23
30
|
include Serialization
|
31
|
+
include Singularable
|
24
32
|
include Sorting
|
33
|
+
include Tables
|
25
34
|
|
26
35
|
def build_child(klass, user_context: nil)
|
27
36
|
klass.build_new(parent: self, user_context: user_context)
|
28
37
|
end
|
29
38
|
|
30
|
-
def singular_resource?
|
31
|
-
false
|
32
|
-
end
|
33
|
-
|
34
39
|
module ClassMethods
|
35
40
|
def build_new(parent: nil, user_context: nil)
|
36
|
-
|
41
|
+
raise(ActiveRecord::RecordNotFound) if try(:abstract_class?)
|
42
|
+
|
43
|
+
new(**attributes_for_new(parent: parent, user_context: user_context))
|
44
|
+
end
|
45
|
+
|
46
|
+
def controller_class
|
47
|
+
@controller_class ||= "#{to_s.pluralize}Controller".safe_constantize || superclass.try(:controller_class)
|
37
48
|
end
|
38
49
|
|
39
50
|
def form_class
|
@@ -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,18 @@ 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
|
+
|
49
|
+
def public_resource?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
41
53
|
def show?
|
42
54
|
false
|
43
55
|
end
|
@@ -64,25 +76,32 @@ module LinkedRails
|
|
64
76
|
end
|
65
77
|
end
|
66
78
|
|
67
|
-
def child_policy(klass, opts
|
68
|
-
Pundit.policy(user_context, record.build_child(klass, opts.merge(user_context: user_context)))
|
79
|
+
def child_policy(klass, **opts)
|
80
|
+
Pundit.policy(user_context, record.build_child(klass, **opts.merge(user_context: user_context)))
|
69
81
|
end
|
70
82
|
|
71
|
-
def forbid_with_message(message)
|
83
|
+
def forbid_with_message(message, status = nil)
|
84
|
+
forbid_with_status(status) if status
|
72
85
|
@message = message
|
73
86
|
false
|
74
87
|
end
|
75
88
|
|
89
|
+
def forbid_with_status(status, message = nil)
|
90
|
+
forbid_with_message(message) if message
|
91
|
+
@action_status = status
|
92
|
+
false
|
93
|
+
end
|
94
|
+
|
95
|
+
def params_parser(filters)
|
96
|
+
LinkedRails::ParamsParser.new(user_context: user_context, params: {filter: filters})
|
97
|
+
end
|
98
|
+
|
76
99
|
def parent_policy
|
77
100
|
return if record.try(:parent).blank?
|
78
101
|
|
79
102
|
@parent_policy ||= Pundit.policy(user_context, record.parent)
|
80
103
|
end
|
81
104
|
|
82
|
-
def policy_class
|
83
|
-
self.class.policy_class
|
84
|
-
end
|
85
|
-
|
86
105
|
def sanitize_array_attribute(attr)
|
87
106
|
[attr, attr => []]
|
88
107
|
end
|
@@ -118,17 +137,16 @@ module LinkedRails
|
|
118
137
|
end
|
119
138
|
|
120
139
|
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
|
140
|
+
def condition_alternatives(attr, permission_required)
|
141
|
+
raise("#{attr} not permitted by #{self}") if attribute_options(attr).blank? && permission_required
|
142
|
+
|
143
|
+
attribute_options(attr)
|
144
|
+
.select { |opts| opts[:conditions].present? }
|
145
|
+
.map { |opts| property_shapes(opts[:conditions]) }
|
146
|
+
end
|
147
|
+
|
148
|
+
def policy_class
|
149
|
+
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
132
150
|
end
|
133
151
|
|
134
152
|
def permitted_attributes
|
@@ -143,44 +161,24 @@ module LinkedRails
|
|
143
161
|
permitted_attributes.select { |opts| opts[:attributes].include?(attr) }
|
144
162
|
end
|
145
163
|
|
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
164
|
def initialize_permitted_attributes
|
163
165
|
return if _permitted_attributes && method(:_permitted_attributes).owner == singleton_class
|
164
166
|
|
165
167
|
self._permitted_attributes = superclass.try(:_permitted_attributes)&.dup || []
|
166
168
|
end
|
167
169
|
|
168
|
-
def permit_attributes(attrs, conditions
|
170
|
+
def permit_attributes(attrs, **conditions)
|
169
171
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {}}
|
170
172
|
end
|
171
173
|
|
172
|
-
def permit_array_attributes(attrs, conditions
|
174
|
+
def permit_array_attributes(attrs, **conditions)
|
173
175
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {array: true}}
|
174
176
|
end
|
175
177
|
|
176
|
-
def permit_nested_attributes(attrs, conditions
|
178
|
+
def permit_nested_attributes(attrs, **conditions)
|
177
179
|
permitted_attributes << {attributes: attrs, conditions: conditions, options: {nested: true}}
|
178
180
|
end
|
179
181
|
|
180
|
-
def policy_class
|
181
|
-
@policy_class ||= name.sub(/Policy/, '').classify.safe_constantize
|
182
|
-
end
|
183
|
-
|
184
182
|
def property_shapes(conditions)
|
185
183
|
conditions.map { |key, options| send("#{key}_shapes", options) }.flatten.compact
|
186
184
|
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
|
|