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
data/lib/linked_rails/routes.rb
CHANGED
@@ -4,7 +4,7 @@ require 'linked_rails/constraints/whitelist'
|
|
4
4
|
|
5
5
|
module LinkedRails
|
6
6
|
module Routes
|
7
|
-
def use_linked_rails(opts
|
7
|
+
def use_linked_rails(**opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
8
8
|
constraints(LinkedRails::Constraints::Whitelist) do
|
9
9
|
post 'spi/bulk', to: "#{opts.fetch(:bulk, 'linked_rails/bulk')}#show"
|
10
10
|
end
|
@@ -22,24 +22,29 @@ module LinkedRails
|
|
22
22
|
|
23
23
|
get '(*parent_iri)/actions', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#index"
|
24
24
|
get '(*parent_iri)/actions/:id', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show"
|
25
|
-
get '(*parent_iri)/
|
26
|
-
get '(*parent_iri)/edit', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :update
|
27
|
-
get '(*parent_iri)/delete', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :destroy
|
28
|
-
get '(*parent_iri)/trash', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :trash
|
29
|
-
get '(*parent_iri)/untrash', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/items#show", id: :untrash
|
25
|
+
get '(*parent_iri)/action_object', to: "#{opts.fetch(:actions, 'linked_rails/actions')}/objects#show"
|
30
26
|
end
|
31
27
|
|
32
|
-
def linked_resource(klass, controller: nil, nested: false, &block)
|
28
|
+
def linked_resource(klass, controller: nil, collection: true, nested: false, resource: true, &block) # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
33
29
|
options = route_options(klass, controller, nested, klass.route_key)
|
34
30
|
|
31
|
+
if collection
|
32
|
+
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
33
|
+
route_block(
|
34
|
+
klass,
|
35
|
+
:collection,
|
36
|
+
controller: options[:controller],
|
37
|
+
prefix: options[:parentable_path]
|
38
|
+
).call
|
39
|
+
end
|
40
|
+
|
41
|
+
return unless resource
|
42
|
+
|
35
43
|
resources(
|
36
44
|
options[:route_name],
|
37
45
|
active_controller_opts(options),
|
38
|
-
&route_block(klass, &block)
|
46
|
+
&route_block(klass, :resource, &block)
|
39
47
|
)
|
40
|
-
|
41
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create") if options[:creatable]
|
42
|
-
get(options[:parentable_path], to: "#{options[:controller]}#index")
|
43
48
|
end
|
44
49
|
|
45
50
|
def singular_linked_resource(klass, controller: nil, nested: true, &block)
|
@@ -48,10 +53,8 @@ module LinkedRails
|
|
48
53
|
resource(
|
49
54
|
options[:route_name],
|
50
55
|
active_controller_opts(options).merge(singular_route: true),
|
51
|
-
&route_block(klass, &block)
|
56
|
+
&route_block(klass, :singular, &block)
|
52
57
|
)
|
53
|
-
|
54
|
-
post(options[:parentable_path], to: "#{options[:controller]}#create", singular_route: true) if options[:creatable]
|
55
58
|
end
|
56
59
|
|
57
60
|
def find_tenant_route
|
@@ -60,6 +63,16 @@ module LinkedRails
|
|
60
63
|
|
61
64
|
private
|
62
65
|
|
66
|
+
def action_routes(controller, prefix, key, value)
|
67
|
+
path = value.fetch(:action_path, key)
|
68
|
+
action = value.fetch(:action_name)
|
69
|
+
get([prefix, path].compact.join('/'), action: action, action_key: key, controller: controller)
|
70
|
+
return if value[:target_path].nil?
|
71
|
+
|
72
|
+
method = value.fetch(:http_method).downcase
|
73
|
+
send(method, [prefix, value.fetch(:target_path)].compact.join('/'), action: key, controller: controller)
|
74
|
+
end
|
75
|
+
|
63
76
|
def active_controller_opts(route_options)
|
64
77
|
{
|
65
78
|
controller: route_options[:controller],
|
@@ -68,22 +81,20 @@ module LinkedRails
|
|
68
81
|
}
|
69
82
|
end
|
70
83
|
|
71
|
-
def
|
72
|
-
klass.enhanced_with?(LinkedRails::Enhancements::Creatable, :Routing)
|
73
|
-
end
|
74
|
-
|
75
|
-
def route_block(klass)
|
84
|
+
def route_block(klass, action_type, controller: nil, prefix: nil)
|
76
85
|
lambda do
|
77
|
-
|
78
|
-
|
86
|
+
klass.action_list.defined_actions[action_type].each do |key, value|
|
87
|
+
action_routes(controller, prefix, key, value)
|
88
|
+
end
|
79
89
|
yield if block_given?
|
80
90
|
end
|
81
91
|
end
|
82
92
|
|
83
93
|
def route_options(klass, controller, nested, path)
|
94
|
+
touch_controller(klass)
|
95
|
+
|
84
96
|
{
|
85
97
|
controller: controller || klass.name.tableize,
|
86
|
-
creatable: creatable(klass),
|
87
98
|
nested: nested,
|
88
99
|
only: %i[show],
|
89
100
|
parentable_path: "(*parent_iri)/#{path}",
|
@@ -91,6 +102,11 @@ module LinkedRails
|
|
91
102
|
route_name: klass.name.demodulize.tableize
|
92
103
|
}.with_indifferent_access
|
93
104
|
end
|
105
|
+
|
106
|
+
# Make sure all actions are initialized before generating the routes
|
107
|
+
def touch_controller(klass)
|
108
|
+
klass.controller_class
|
109
|
+
end
|
94
110
|
end
|
95
111
|
end
|
96
112
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Actionable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
has_many :favorite_actions,
|
10
|
+
predicate: Vocab.ontola[:favoriteAction] do |object|
|
11
|
+
object.try(:favorite_actions)
|
12
|
+
end
|
13
|
+
statements :action_triples
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def action_triples(object, _params)
|
18
|
+
if object.iri.anonymous? && !object.try(:singular_resource?)
|
19
|
+
[]
|
20
|
+
else
|
21
|
+
object.try(:action_triples) || []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Menuable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include_menus
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def inherited(target)
|
14
|
+
super
|
15
|
+
target.include_menus
|
16
|
+
end
|
17
|
+
|
18
|
+
def include_menus
|
19
|
+
serializable_class.try(:menu_class)&.defined_menus&.keys&.each do |menu|
|
20
|
+
has_one "#{menu}_menu",
|
21
|
+
predicate: Vocab.ontola["#{menu.to_s.camelize(:lower)}Menu"],
|
22
|
+
if: method(:named_object?),
|
23
|
+
polymorphic: true do |object, opts|
|
24
|
+
object.menu(menu, opts[:scope])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Serializer
|
5
|
+
module Singularable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
statements :same_as_statement
|
10
|
+
|
11
|
+
def self.same_as_statement(object, _params)
|
12
|
+
return [] unless object.try(:singular_resource?) && object.singular_iri != object.iri
|
13
|
+
|
14
|
+
[
|
15
|
+
RDF::Statement.new(
|
16
|
+
object.singular_iri,
|
17
|
+
Vocab.owl.sameAs,
|
18
|
+
object.iri,
|
19
|
+
graph_name: Vocab.ld[:supplant]
|
20
|
+
)
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -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
|
+
include Empathy::EmpJson::Serializer
|
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,28 +94,36 @@ 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
|
94
105
|
|
95
106
|
def serialize_image(obj)
|
96
|
-
if obj.is_a?(String) || obj.is_a?(Symbol)
|
107
|
+
if (obj.is_a?(String) || obj.is_a?(Symbol)) && !obj.to_s.include?('http')
|
97
108
|
RDF::URI(obj.to_s.gsub(/^fa-/, 'http://fontawesome.io/icon/'))
|
98
109
|
else
|
99
110
|
obj.presence
|
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
|
+
collection_opts[:table_type] = opts.delete(:table_type) if opts.key?(:table_type)
|
124
|
+
|
125
|
+
has_one collection_name, **opts do |object, params|
|
126
|
+
object.send(collection_name, **collection_opts.merge(user_context: params[:scope]))
|
113
127
|
end
|
114
128
|
end
|
115
129
|
|
@@ -135,3 +149,6 @@ module LinkedRails
|
|
135
149
|
end
|
136
150
|
end
|
137
151
|
end
|
152
|
+
|
153
|
+
RDF::Serializers::NilSerializer.include(Empathy::EmpJson::Serializer)
|
154
|
+
RDF::Serializers::ListSerializer.include(Empathy::EmpJson::Serializer)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
module LinkedRails
|
6
|
+
class Storage
|
7
|
+
REDIS_DB = {
|
8
|
+
cache: LinkedRails.cache_redis_database,
|
9
|
+
persistent: LinkedRails.persistent_redis_database,
|
10
|
+
stream: LinkedRails.stream_redis_database
|
11
|
+
}.freeze
|
12
|
+
KEYS = {
|
13
|
+
manifest: 'cache:Manifest',
|
14
|
+
redirect_exact: 'cache:Redirect:Exact',
|
15
|
+
redirect_prefix: 'cache:Redirect:Prefix'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
%i[xadd].each do |method|
|
20
|
+
define_method(method) do |db, *args|
|
21
|
+
Redis.new(db: REDIS_DB.fetch(db)).send(method, *args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
%i[hset hdel hget].each do |method|
|
26
|
+
define_method(method) do |db, key, *args|
|
27
|
+
Redis.new(db: REDIS_DB.fetch(db)).send(method, KEYS.fetch(key), *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module TestMethods
|
5
|
+
def expect_disabled_form(iri: requested_iri, error: 'This action is currently not available')
|
6
|
+
assert_response 200
|
7
|
+
expect_triple(iri, NS.schema.actionStatus, NS.ontola[:DisabledActionStatus])
|
8
|
+
expect_triple(iri, NS.schema.error, error) if error
|
9
|
+
end
|
10
|
+
|
11
|
+
def expect_enabled_form(iri: requested_iri)
|
12
|
+
assert_response 200
|
13
|
+
expect_triple(iri, NS.schema.actionStatus, NS.schema.PotentialActionStatus)
|
14
|
+
end
|
15
|
+
|
16
|
+
def expect_errors(iri, errors)
|
17
|
+
error_response = expect_triple(iri, NS.ll[:errorResponse], nil).first.object
|
18
|
+
assert_equal expect_triple(error_response, nil, nil).count, errors.count + 2
|
19
|
+
errors.each do |key, value|
|
20
|
+
expect_triple(error_response, key, value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def expect_header(key, value)
|
25
|
+
expect(response.headers[key]).to(include(value))
|
26
|
+
end
|
27
|
+
|
28
|
+
def expect_ontola_action(redirect: nil, snackbar: nil, reload: nil)
|
29
|
+
if redirect
|
30
|
+
expect_header('Exec-Action', "actions/redirect?#{{location: redirect, reload: reload}.compact.to_param}")
|
31
|
+
end
|
32
|
+
expect_header('Exec-Action', "actions/snackbar?#{{text: snackbar}.to_param}") if snackbar
|
33
|
+
|
34
|
+
expect_ontola_action_count([redirect, snackbar].compact.size)
|
35
|
+
end
|
36
|
+
|
37
|
+
def expect_ontola_action_count(count)
|
38
|
+
if count.zero?
|
39
|
+
assert_nil response.headers['Exec-Action']
|
40
|
+
else
|
41
|
+
assert_equal count, response.headers['Exec-Action'].count("\n"), response.headers['Exec-Action']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Tests if the property {path} starting at {start} resolves to {value}.
|
46
|
+
# If multiple solutions are present only one has to match to pass.
|
47
|
+
#
|
48
|
+
# @param [IRI] start The node to start at
|
49
|
+
# @param [Array] path The property path to traverse
|
50
|
+
# @param [IRI|IRI[]] value The value to match at the end, pass an array to
|
51
|
+
# match multiple values.
|
52
|
+
def expect_path(start, path, value) # rubocop:disable Metrics/AbcSize
|
53
|
+
match = path.each_with_index.reduce(start) do |node, (path_seg, i)|
|
54
|
+
obj = [*node].map { |cur_node| rdf_body.query([cur_node, path_seg, nil, nil]).map(&:object) }.flatten
|
55
|
+
break (obj & [*value]).present? if path.length - 1 == i
|
56
|
+
|
57
|
+
nodes = obj.filter { |o| o.is_a?(RDF::Resource) }
|
58
|
+
break false if nodes.blank?
|
59
|
+
|
60
|
+
nodes
|
61
|
+
end
|
62
|
+
|
63
|
+
segs = path.map(&:to_s).join(', ')
|
64
|
+
assert match,
|
65
|
+
"Expected to find '#{value}' from '#{start}' through '[#{segs}]' in\n#{response.body}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def expect_resource_type(type, iri: requested_iri)
|
69
|
+
expect_triple(iri, RDF[:type], type)
|
70
|
+
end
|
71
|
+
|
72
|
+
def expect_sequence(subject, predicate)
|
73
|
+
expect_triple(subject, predicate, nil).first.object
|
74
|
+
end
|
75
|
+
|
76
|
+
def expect_sequence_member(subject, index, object)
|
77
|
+
expect_triple(subject, RDF[:"_#{index}"], object)
|
78
|
+
object
|
79
|
+
end
|
80
|
+
|
81
|
+
def expect_sequence_size(subject, expected_count)
|
82
|
+
count =
|
83
|
+
expect_triple(subject, nil, nil)
|
84
|
+
.select { |s| s.predicate.to_s.starts_with?('http://www.w3.org/1999/02/22-rdf-syntax-ns#_') }
|
85
|
+
.count
|
86
|
+
assert_equal expected_count, count
|
87
|
+
end
|
88
|
+
|
89
|
+
def expect_triple(subject, predicate, object, graph = NS.ll[:supplant])
|
90
|
+
statement = RDF::Statement(subject, predicate, object, graph_name: graph)
|
91
|
+
match = rdf_body.query(statement)
|
92
|
+
assert match.present?, "Expected to find #{statement} in\n#{response.body}"
|
93
|
+
match
|
94
|
+
end
|
95
|
+
|
96
|
+
def refute_triple(subject, predicate, object, graph = nil)
|
97
|
+
statement = RDF::Statement(subject, predicate, object, graph_name: graph)
|
98
|
+
assert_not rdf_body.query([subject, predicate, object, graph]).present?,
|
99
|
+
"Expected not to find #{statement} in\n#{response.body}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def requested_iri
|
103
|
+
RDF::URI(request.original_url.sub(".#{request.format.symbol}", ''))
|
104
|
+
end
|
105
|
+
|
106
|
+
def rdf_body
|
107
|
+
@rdf_body ||= RDF::Graph.new << RDF::Reader
|
108
|
+
.for(content_type: response.headers['Content-Type'])
|
109
|
+
.new(response.body)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
ActiveSupport::TestCase.include(LinkedRails::TestMethods)
|
@@ -62,28 +62,38 @@ module LinkedRails # rubocop:disable Metrics/ModuleLength
|
|
62
62
|
end
|
63
63
|
|
64
64
|
Translate.translations_for(:action, :description) do |object, fallback|
|
65
|
+
result_class = object.list.send(:result_class)
|
66
|
+
klass_iri = result_class.iri.is_a?(Array) ? result_class.iri.first : result_class.iri
|
67
|
+
type = LinkedRails.translate(:class, :label, klass_iri)&.downcase
|
68
|
+
|
65
69
|
I18n.t(
|
66
|
-
"actions.#{Translate.translation_key(object)}.#{object.tag}.description",
|
70
|
+
"actions.#{Translate.translation_key(object.resource)}.#{object.tag}.description",
|
67
71
|
default: [
|
68
72
|
:"actions.default.#{object.tag}.description",
|
69
73
|
fallback ? object.tag.to_s.humanize : ''
|
70
|
-
]
|
74
|
+
],
|
75
|
+
type: type
|
71
76
|
)
|
72
77
|
end
|
73
78
|
|
74
79
|
Translate.translations_for(:action, :label) do |object, fallback|
|
80
|
+
result_class = object.list.send(:result_class)
|
81
|
+
klass_iri = result_class.iri.is_a?(Array) ? result_class.iri.first : result_class.iri
|
82
|
+
type = LinkedRails.translate(:class, :label, klass_iri)&.downcase
|
83
|
+
|
75
84
|
I18n.t(
|
76
|
-
"actions.#{Translate.translation_key(object)}.#{object.tag}.label",
|
85
|
+
"actions.#{Translate.translation_key(object.resource)}.#{object.tag}.label",
|
77
86
|
default: [
|
78
87
|
:"actions.default.#{object.tag}.label",
|
79
88
|
fallback ? object.tag.to_s.humanize : ''
|
80
|
-
]
|
89
|
+
],
|
90
|
+
type: type
|
81
91
|
)
|
82
92
|
end
|
83
93
|
|
84
94
|
Translate.translations_for(:action, :submit) do |object, fallback|
|
85
95
|
I18n.t(
|
86
|
-
"actions.#{Translate.translation_key(object)}.#{object.tag}.submit",
|
96
|
+
"actions.#{Translate.translation_key(object.resource)}.#{object.tag}.submit",
|
87
97
|
default: [
|
88
98
|
:"actions.default.#{object.tag}.submit",
|
89
99
|
fallback ? object.tag.to_s.humanize : ''
|
@@ -93,7 +103,7 @@ module LinkedRails # rubocop:disable Metrics/ModuleLength
|
|
93
103
|
|
94
104
|
Translate.translations_for(:enum, :label) do |object|
|
95
105
|
I18n.t(
|
96
|
-
"enums.#{Translate.translation_key(object)}.#{object.attr}.#{object.key}",
|
106
|
+
"enums.#{Translate.translation_key(object.klass)}.#{object.attr}.#{object.key}",
|
97
107
|
default: [
|
98
108
|
:"enums.#{object.attr}.#{object.key}",
|
99
109
|
object.key.to_s.humanize
|
@@ -125,6 +135,18 @@ module LinkedRails # rubocop:disable Metrics/ModuleLength
|
|
125
135
|
end
|
126
136
|
end
|
127
137
|
|
138
|
+
Translate.translations_for(:field, :placeholder) do |object, fallback|
|
139
|
+
if object.model_attribute.present?
|
140
|
+
I18n.t(
|
141
|
+
"forms.#{Translate.translation_key(object.model_class)}.#{object.model_attribute}.placeholder",
|
142
|
+
default: [
|
143
|
+
:"forms.default.#{object.model_attribute}.placeholder",
|
144
|
+
fallback ? object.model_attribute.to_s.humanize : ''
|
145
|
+
]
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
128
150
|
Translate.translations_for(:field, :label) do |object, fallback|
|
129
151
|
if object.model_attribute.present?
|
130
152
|
I18n.t(
|
@@ -148,14 +170,14 @@ module LinkedRails # rubocop:disable Metrics/ModuleLength
|
|
148
170
|
Translate.translations_for(:class, :label) do |object|
|
149
171
|
I18n.t(
|
150
172
|
Translate.key_for_iri(object, :label),
|
151
|
-
default: (object.label || Translate.tag_for_iri(object)).to_s.underscore.humanize
|
173
|
+
default: (object.try(:label) || Translate.tag_for_iri(object)).to_s.underscore.humanize
|
152
174
|
)
|
153
175
|
end
|
154
176
|
|
155
177
|
Translate.translations_for(:class, :plural_label) do |object|
|
156
178
|
I18n.t(
|
157
179
|
Translate.key_for_iri(object, :plural_label),
|
158
|
-
default: (object.label || Translate.tag_for_iri(object)).to_s.tableize.humanize
|
180
|
+
default: (object.try(:label) || Translate.tag_for_iri(object)).to_s.tableize.humanize
|
159
181
|
)
|
160
182
|
end
|
161
183
|
|
@@ -170,7 +192,7 @@ module LinkedRails # rubocop:disable Metrics/ModuleLength
|
|
170
192
|
Translate.translations_for(:property, :label) do |object|
|
171
193
|
I18n.t(
|
172
194
|
Translate.key_for_iri(object, :label),
|
173
|
-
default: (object.label || Translate.tag_for_iri(object)).to_s.underscore.humanize
|
195
|
+
default: (object.try(:label) || Translate.tag_for_iri(object)).to_s.underscore.humanize
|
174
196
|
)
|
175
197
|
end
|
176
198
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Types
|
5
|
+
class IRI < ActiveRecord::Type::Value
|
6
|
+
def type
|
7
|
+
:string
|
8
|
+
end
|
9
|
+
|
10
|
+
def cast(value)
|
11
|
+
RDF::URI(value) if value.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize(value)
|
15
|
+
value.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module QuoteIRI
|
21
|
+
def quote(value)
|
22
|
+
return super unless value.is_a?(RDF::URI) || value.is_a?(URI)
|
23
|
+
|
24
|
+
super(value.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def type_cast(value)
|
28
|
+
return super unless value.is_a?(RDF::URI) || value.is_a?(URI)
|
29
|
+
|
30
|
+
super(value.to_s)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if ActiveRecord::ConnectionAdapters.const_defined?(:PostgreSQLAdapter)
|
36
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(LinkedRails::QuoteIRI)
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri_template'
|
4
|
+
|
5
|
+
module LinkedRails
|
6
|
+
class URITemplate < URITemplate::RFC6570
|
7
|
+
ARRAY_SUFFIX = '%5B%5D'
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def normalize_variables(vars)
|
12
|
+
variables
|
13
|
+
.select { |var| var.ends_with?(ARRAY_SUFFIX) }
|
14
|
+
.each_with_object(super.with_indifferent_access) do |var, hash|
|
15
|
+
key = var.sub(ARRAY_SUFFIX, '')
|
16
|
+
hash[var] = normalize_array_value(hash[key]) if hash.key?(key)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def normalize_array_value(original_value)
|
21
|
+
return original_value unless original_value.is_a?(Hash)
|
22
|
+
|
23
|
+
original_value.map do |key, values|
|
24
|
+
(values.is_a?(Array) ? values : [values]).map do |value|
|
25
|
+
"#{CGI.escape(key.to_s)}=#{value}"
|
26
|
+
end
|
27
|
+
end.flatten
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/linked_rails/version.rb
CHANGED
data/lib/linked_rails/vocab.rb
CHANGED
@@ -19,6 +19,14 @@ module LinkedRails
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class << self
|
22
|
+
def app_vocabulary(key)
|
23
|
+
vocabulary = send(key)
|
24
|
+
|
25
|
+
LinkedRails::Vocab.define_singleton_method :app do
|
26
|
+
vocabulary
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
22
30
|
def define_shortcut(key)
|
23
31
|
define_singleton_method(key) do
|
24
32
|
options = RDF::Vocabulary.vocab_map.fetch(key)
|
@@ -74,6 +82,7 @@ module LinkedRails
|
|
74
82
|
register(:fhir, 'http://hl7.org/fhir/')
|
75
83
|
register(:form, 'https://ns.ontola.io/form#')
|
76
84
|
register(:libro, 'https://ns.ontola.io/libro/')
|
85
|
+
register(:ld, 'http://purl.org/linked-delta/')
|
77
86
|
register(:ll, 'http://purl.org/link-lib/')
|
78
87
|
register(:ontola, 'https://ns.ontola.io/core#')
|
79
88
|
register(:sp, 'http://spinrdf.org/sp#')
|