linked_rails 0.0.2 → 0.0.4.pre.g2c6c26e86
Sign up to get free protection for your applications and to get access to all the features.
- 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 +107 -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 +53 -15
- 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 +5 -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 +49 -25
- 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 +11 -14
- data/app/models/linked_rails/menus/list.rb +30 -10
- 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 +3 -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 +4 -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 +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 +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 +14 -7
- 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/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 +14 -2
- data/lib/linked_rails/iri_mapper.rb +18 -40
- 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 -2
- data/lib/rdf/list.rb +9 -0
- data/lib/rdf/query_fix.rb +15 -0
- metadata +80 -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
@@ -3,10 +3,17 @@
|
|
3
3
|
module LinkedRails
|
4
4
|
class Form
|
5
5
|
class FieldFactory # rubocop:disable Metrics/ClassLength
|
6
|
+
DATABASE_ERRORS = [
|
7
|
+
'PG::ConnectionBad'.safe_constantize,
|
8
|
+
ActiveRecord::StatementInvalid,
|
9
|
+
ActiveRecord::ConnectionNotEstablished
|
10
|
+
].compact.freeze
|
6
11
|
MAX_STR_LEN = 255
|
7
12
|
VALIDATOR_SELECTORS = [
|
8
13
|
[:min_length, ActiveModel::Validations::LengthValidator, :minimum],
|
14
|
+
[:min_inclusive, ActiveModel::Validations::NumericalityValidator, :greater_than_or_equal_to],
|
9
15
|
[:max_length, ActiveModel::Validations::LengthValidator, :maximum],
|
16
|
+
[:max_inclusive, ActiveModel::Validations::NumericalityValidator, :less_than_or_equal_to],
|
10
17
|
[:pattern, ActiveModel::Validations::FormatValidator, :with],
|
11
18
|
[:presence, ActiveModel::Validations::PresenceValidator, nil],
|
12
19
|
[:sh_in, ActiveModel::Validations::InclusionValidator, :in]
|
@@ -15,7 +22,8 @@ module LinkedRails
|
|
15
22
|
|
16
23
|
attr_accessor :field_options, :form, :key
|
17
24
|
|
18
|
-
delegate :
|
25
|
+
delegate :abstract_form,
|
26
|
+
:form_options_iri,
|
19
27
|
:model_class,
|
20
28
|
:model_policy!,
|
21
29
|
:serializer_attributes,
|
@@ -24,29 +32,31 @@ module LinkedRails
|
|
24
32
|
to: :form
|
25
33
|
|
26
34
|
def condition_or_field
|
27
|
-
@condition_or_field
|
35
|
+
return @condition_or_field if instance_variable_defined?(:@condition_or_field)
|
36
|
+
|
37
|
+
alternatives = node_shapes_for(
|
28
38
|
key,
|
29
|
-
field,
|
30
39
|
property: field_options[:if] || [],
|
31
40
|
sh_not: field_options[:unless] || []
|
32
41
|
)
|
42
|
+
@condition_or_field =
|
43
|
+
if alternatives.count == 1
|
44
|
+
Condition.new(shape: alternatives.first, pass: field)
|
45
|
+
elsif alternatives.count.positive?
|
46
|
+
Condition.new(shape: SHACL::NodeShape.new(or: alternatives), pass: field)
|
47
|
+
else
|
48
|
+
field
|
49
|
+
end
|
33
50
|
end
|
34
51
|
|
35
52
|
private
|
36
53
|
|
37
54
|
def attr_column(name)
|
38
|
-
|
39
|
-
if model_class.is_delegated_attribute?(name)
|
40
|
-
model_class.class_for_delegated_attribute(name)
|
41
|
-
else
|
42
|
-
model_class
|
43
|
-
end
|
44
|
-
column_model.column_for_attribute(name)
|
55
|
+
model_class.column_for_attribute(name)
|
45
56
|
end
|
46
57
|
|
47
58
|
def attr_to_datatype # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
48
|
-
|
49
|
-
case attribute_type(name)
|
59
|
+
case attribute_type
|
50
60
|
when :string, :text
|
51
61
|
Vocab.xsd.string
|
52
62
|
when :integer
|
@@ -58,22 +68,26 @@ module LinkedRails
|
|
58
68
|
when :boolean
|
59
69
|
Vocab.xsd.boolean
|
60
70
|
when :decimal
|
61
|
-
decimal_data_type(
|
71
|
+
decimal_data_type(attribute_name)
|
62
72
|
when :file
|
63
73
|
Vocab.ll[:blob]
|
64
74
|
else
|
65
|
-
Vocab.xsd.string if model_class.try(:defined_enums)&.key?(
|
75
|
+
Vocab.xsd.string if model_class.try(:defined_enums)&.key?(attribute_name)
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
79
|
+
def attribute_name
|
80
|
+
serializer_attribute&.key&.to_s || key.to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
def attribute_type
|
84
|
+
model_class.try(:attribute_types).try(:[], attribute_name)&.type
|
85
|
+
rescue *DATABASE_ERRORS
|
72
86
|
:string
|
73
87
|
end
|
74
88
|
|
75
89
|
def attribute_validators
|
76
|
-
@attribute_validators ||= model_class
|
90
|
+
@attribute_validators ||= model_class&.validators&.select { |v| v.attributes.include?(model_attribute) }
|
77
91
|
end
|
78
92
|
|
79
93
|
def datatype
|
@@ -143,7 +157,7 @@ module LinkedRails
|
|
143
157
|
when Vocab.ontola['datatype/postalRange']
|
144
158
|
return Form::Field::PostalRangeInput
|
145
159
|
else
|
146
|
-
|
160
|
+
attribute_type == :text ? Form::Field::TextAreaInput : Form::Field::TextInput
|
147
161
|
end
|
148
162
|
end
|
149
163
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
@@ -168,6 +182,15 @@ module LinkedRails
|
|
168
182
|
@model_attribute ||= (model_class.try(:attribute_alias, key) || key).to_sym
|
169
183
|
end
|
170
184
|
|
185
|
+
def node_shapes_for(attr, property: [], sh_not: [])
|
186
|
+
alternatives = abstract_form ? [] : model_policy!.condition_alternatives(attr, field.permission_required?)
|
187
|
+
alternatives = [[]] if alternatives.empty? && (property.any? || sh_not.any?)
|
188
|
+
|
189
|
+
alternatives.map do |props|
|
190
|
+
SHACL::NodeShape.new(property: props + property, sh_not: sh_not)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
171
194
|
def normalized_key(key)
|
172
195
|
return key.to_s[0...-3].to_sym if key.to_s.ends_with?('_id')
|
173
196
|
return key.to_s[0...-4].pluralize.to_sym if key.to_s.ends_with?('_ids')
|
@@ -197,14 +220,15 @@ module LinkedRails
|
|
197
220
|
def validator(klass, option_key)
|
198
221
|
matched_validator = validator_by_class(klass)
|
199
222
|
|
200
|
-
option_key ? matched_validator&.options.try(:[], option_key) : matched_validator.present?
|
223
|
+
value = option_key ? matched_validator&.options.try(:[], option_key) : matched_validator.present?
|
224
|
+
|
225
|
+
value unless value.respond_to?(:call)
|
201
226
|
end
|
202
227
|
|
203
228
|
def validator_by_class(klass)
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
matched_validator if matched_validator.options[:if].blank? && matched_validator.options[:unless].blank?
|
229
|
+
attribute_validators&.detect do |validator|
|
230
|
+
validator.is_a?(klass) && validator.options[:if].blank? && validator.options[:unless].blank?
|
231
|
+
end
|
208
232
|
end
|
209
233
|
|
210
234
|
def validators
|
@@ -212,7 +236,7 @@ module LinkedRails
|
|
212
236
|
VALIDATOR_SELECTORS.map do |key, klass, option_key|
|
213
237
|
[key, validator(klass, option_key)]
|
214
238
|
end
|
215
|
-
]
|
239
|
+
].compact
|
216
240
|
end
|
217
241
|
end
|
218
242
|
end
|
@@ -6,19 +6,17 @@ module LinkedRails
|
|
6
6
|
attr_accessor :fields, :collapsible, :hidden, :footer
|
7
7
|
attr_writer :description, :key, :label
|
8
8
|
|
9
|
-
def initialize(attrs
|
10
|
-
super(attrs)
|
9
|
+
def initialize(**attrs)
|
10
|
+
super(**attrs)
|
11
11
|
self.fields = []
|
12
12
|
end
|
13
13
|
|
14
14
|
def description
|
15
|
-
@description
|
16
|
-
@description
|
15
|
+
@description.respond_to?(:call) ? @description.call : @description
|
17
16
|
end
|
18
17
|
|
19
18
|
def label
|
20
|
-
@label
|
21
|
-
@label
|
19
|
+
@label.respond_to?(:call) ? @label.call : @label
|
22
20
|
end
|
23
21
|
|
24
22
|
def rdf_type
|
@@ -6,13 +6,13 @@ module LinkedRails
|
|
6
6
|
attr_accessor :groups, :label, :description
|
7
7
|
attr_writer :key
|
8
8
|
|
9
|
-
def initialize(attrs
|
10
|
-
super(attrs)
|
9
|
+
def initialize(**attrs)
|
10
|
+
super(**attrs)
|
11
11
|
self.groups = []
|
12
12
|
end
|
13
13
|
|
14
|
-
def add_group(opts)
|
15
|
-
group = Form::Group.new(opts)
|
14
|
+
def add_group(**opts)
|
15
|
+
group = Form::Group.new(**opts)
|
16
16
|
groups << group
|
17
17
|
group
|
18
18
|
end
|
@@ -21,6 +21,10 @@ module LinkedRails
|
|
21
21
|
@footer_group ||= add_group(collapsible: false, footer: true, key: :footer)
|
22
22
|
end
|
23
23
|
|
24
|
+
def footer_group!
|
25
|
+
@footer_group
|
26
|
+
end
|
27
|
+
|
24
28
|
class << self
|
25
29
|
def iri
|
26
30
|
Vocab.form[:Page]
|
@@ -5,10 +5,11 @@ require 'pundit'
|
|
5
5
|
module LinkedRails
|
6
6
|
class Form # rubocop:disable Metrics/ClassLength
|
7
7
|
include LinkedRails::Model
|
8
|
+
include LinkedRails::Model::Cacheable
|
8
9
|
|
9
|
-
class_attribute :pages, :model_class
|
10
|
+
class_attribute :abstract_form, :pages, :model_class
|
10
11
|
|
11
|
-
def root_relative_iri(_opts
|
12
|
+
def root_relative_iri(**_opts)
|
12
13
|
self.class.form_iri_path
|
13
14
|
end
|
14
15
|
|
@@ -63,10 +64,6 @@ module LinkedRails
|
|
63
64
|
@serializer_reflections ||= serializer_class&.relationships_to_serialize || {}
|
64
65
|
end
|
65
66
|
|
66
|
-
def preview_includes
|
67
|
-
[pages: {groups: [fields: [:fail, :pass, shape: [:property, nested_shapes: :property]]]}]
|
68
|
-
end
|
69
|
-
|
70
67
|
private
|
71
68
|
|
72
69
|
def current_group
|
@@ -85,7 +82,7 @@ module LinkedRails
|
|
85
82
|
@default_page ||= page(:default)
|
86
83
|
end
|
87
84
|
|
88
|
-
def field(key, opts
|
85
|
+
def field(key, **opts)
|
89
86
|
current_group.fields << Form::FieldFactory.new(
|
90
87
|
field_options: opts,
|
91
88
|
form: self,
|
@@ -94,9 +91,10 @@ module LinkedRails
|
|
94
91
|
end
|
95
92
|
|
96
93
|
def find_form_class(params)
|
97
|
-
|
94
|
+
form_name = [params[:module], "#{params[:id]&.singularize}_forms"].compact.join('/').classify
|
95
|
+
requested_class = form_name.safe_constantize
|
98
96
|
|
99
|
-
|
97
|
+
requested_class if requested_class && requested_class < LinkedRails::Form
|
100
98
|
end
|
101
99
|
|
102
100
|
def footer
|
@@ -108,10 +106,10 @@ module LinkedRails
|
|
108
106
|
current_page.footer_group
|
109
107
|
end
|
110
108
|
|
111
|
-
def group(key, opts
|
109
|
+
def group(key, **opts)
|
112
110
|
opts[:collapsible] = true unless opts.key?(:collapsible)
|
113
111
|
opts[:key] = key
|
114
|
-
group = current_page.add_group(opts)
|
112
|
+
group = current_page.add_group(**opts)
|
115
113
|
@current_group = group
|
116
114
|
|
117
115
|
yield if block_given?
|
@@ -120,26 +118,24 @@ module LinkedRails
|
|
120
118
|
group
|
121
119
|
end
|
122
120
|
|
123
|
-
|
124
|
-
def has_many(key, opts = {})
|
121
|
+
def has_many(key, **opts)
|
125
122
|
opts[:input_field] = Form::Field::AssociationInput
|
126
123
|
opts[:max_count] = 99
|
127
|
-
field(key, opts)
|
124
|
+
field(key, **opts)
|
128
125
|
end
|
129
126
|
|
130
|
-
def has_one(key, opts
|
127
|
+
def has_one(key, **opts)
|
131
128
|
opts[:input_field] = Form::Field::AssociationInput
|
132
129
|
opts[:max_count] = 1
|
133
|
-
field(key, opts)
|
130
|
+
field(key, **opts)
|
134
131
|
end
|
135
|
-
# rubocop:enable Naming/PredicateName
|
136
132
|
|
137
133
|
def hidden(&block)
|
138
134
|
group(:hidden, collapsible: false, hidden: true, &block)
|
139
135
|
end
|
140
136
|
|
141
|
-
def page(key, opts
|
142
|
-
page = Form::Page.new(opts.merge(key: key))
|
137
|
+
def page(key, **opts)
|
138
|
+
page = Form::Page.new(**opts.merge(key: key))
|
143
139
|
@current_page = page
|
144
140
|
pages << @current_page
|
145
141
|
yield if block_given?
|
@@ -147,9 +143,9 @@ module LinkedRails
|
|
147
143
|
page
|
148
144
|
end
|
149
145
|
|
150
|
-
def resource(key, opts
|
146
|
+
def resource(key, **opts)
|
151
147
|
opts[:input_field] = Form::Field::ResourceField
|
152
|
-
field(key, opts)
|
148
|
+
field(key, **opts)
|
153
149
|
end
|
154
150
|
end
|
155
151
|
end
|
@@ -5,6 +5,27 @@ module LinkedRails
|
|
5
5
|
include ActiveModel::Model
|
6
6
|
include LinkedRails::Model
|
7
7
|
|
8
|
+
def save
|
9
|
+
Storage.hset(
|
10
|
+
:persistent,
|
11
|
+
:manifest,
|
12
|
+
URL.as_href(LinkedRails.iri) => web_manifest.to_json
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def web_manifest
|
17
|
+
web_manifest_base.merge(
|
18
|
+
ontola: web_manifest_ontola_section,
|
19
|
+
serviceworker: web_manifest_sw_section
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def allowed_external_sources
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
|
8
29
|
def app_name
|
9
30
|
Rails.application.railtie_name.chomp('_application').humanize
|
10
31
|
end
|
@@ -17,8 +38,27 @@ module LinkedRails
|
|
17
38
|
'#eef0f2'
|
18
39
|
end
|
19
40
|
|
41
|
+
def blob_preview_iri
|
42
|
+
return unless ActiveStorage::Blob.service.present?
|
43
|
+
|
44
|
+
"#{LinkedRails.iri(path: 'rails/active_storage/blobs/redirect')}/{signed_id}/preview"
|
45
|
+
end
|
46
|
+
|
47
|
+
def blob_upload_iri
|
48
|
+
return unless ActiveStorage::Blob.service.present?
|
49
|
+
|
50
|
+
LinkedRails.iri(path: 'rails/active_storage/direct_uploads')
|
51
|
+
end
|
52
|
+
|
20
53
|
def css_class; end
|
21
54
|
|
55
|
+
def csp_entries
|
56
|
+
{
|
57
|
+
connectSrc: [ActiveStorage::Blob.service.try(:bucket)&.url].compact,
|
58
|
+
scriptSrc: [ActiveStorage::Blob.service.try(:bucket)&.url].compact
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
22
62
|
def header_background
|
23
63
|
:primary
|
24
64
|
end
|
@@ -27,17 +67,16 @@ module LinkedRails
|
|
27
67
|
:white
|
28
68
|
end
|
29
69
|
|
30
|
-
def
|
31
|
-
[
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
]
|
70
|
+
def icons
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
|
74
|
+
def lang
|
75
|
+
:nl
|
37
76
|
end
|
38
77
|
|
39
78
|
def scope
|
40
|
-
|
79
|
+
LinkedRails.iri.to_s
|
41
80
|
end
|
42
81
|
|
43
82
|
def site_theme_color
|
@@ -52,51 +91,92 @@ module LinkedRails
|
|
52
91
|
app_name
|
53
92
|
end
|
54
93
|
|
94
|
+
def start_url
|
95
|
+
scope == '/' ? scope : "#{scope}/"
|
96
|
+
end
|
97
|
+
|
55
98
|
def theme; end
|
56
99
|
|
57
100
|
def theme_options
|
58
101
|
{}
|
59
102
|
end
|
60
103
|
|
61
|
-
def web_manifest
|
62
|
-
web_manifest_base.merge(
|
63
|
-
ontola: web_manifest_ontola_section,
|
64
|
-
serviceworker: web_manifest_sw_section
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
104
|
def web_manifest_base # rubocop:disable Metrics/MethodLength
|
69
105
|
{
|
70
106
|
background_color: background_color,
|
71
107
|
dir: :rtl,
|
72
108
|
display: :standalone,
|
73
|
-
|
109
|
+
icons: icons,
|
110
|
+
lang: lang,
|
74
111
|
name: app_name,
|
75
112
|
scope: scope,
|
76
113
|
short_name: app_name,
|
77
|
-
start_url:
|
114
|
+
start_url: start_url,
|
78
115
|
theme_color: site_theme_color
|
79
116
|
}
|
80
117
|
end
|
81
118
|
|
82
|
-
def web_manifest_ontola_section
|
119
|
+
def web_manifest_ontola_section # rubocop:disable Metrics/MethodLength
|
83
120
|
{
|
84
|
-
|
121
|
+
allowed_external_sources: allowed_external_sources,
|
122
|
+
blob_preview_iri: blob_preview_iri,
|
123
|
+
blob_upload_iri: blob_upload_iri,
|
124
|
+
csp: csp_entries,
|
85
125
|
header_background: header_background,
|
86
126
|
header_text: header_text,
|
87
|
-
|
127
|
+
preconnect: preconnect,
|
88
128
|
primary_color: site_theme_color,
|
89
129
|
secondary_color: site_secondary_color,
|
130
|
+
styled_headers: styled_headers,
|
90
131
|
theme: theme,
|
91
|
-
theme_options: theme_options.to_query
|
132
|
+
theme_options: theme_options.to_query,
|
133
|
+
tracking: tracking,
|
134
|
+
website_iri: LinkedRails.iri.to_s,
|
135
|
+
websocket_path: websocket_path
|
92
136
|
}
|
93
137
|
end
|
94
138
|
|
95
139
|
def web_manifest_sw_section
|
96
140
|
{
|
97
|
-
src: "#{scope}/sw.js
|
141
|
+
src: "#{scope.chomp('/')}/sw.js",
|
98
142
|
scope: scope
|
99
143
|
}
|
100
144
|
end
|
145
|
+
|
146
|
+
def websocket_path
|
147
|
+
Rails.application.config.try(:action_cable).try(:mount_path).try(:[], 1..-1)
|
148
|
+
end
|
149
|
+
|
150
|
+
def preconnect
|
151
|
+
[]
|
152
|
+
end
|
153
|
+
|
154
|
+
def styled_headers
|
155
|
+
false
|
156
|
+
end
|
157
|
+
|
158
|
+
def tracking
|
159
|
+
[]
|
160
|
+
end
|
161
|
+
|
162
|
+
class << self
|
163
|
+
def destroy(iri)
|
164
|
+
Storage.hdel(:persistent, :manifest, URL.as_href(iri))
|
165
|
+
end
|
166
|
+
|
167
|
+
def move(from, to)
|
168
|
+
Storage.hset(
|
169
|
+
:persistent,
|
170
|
+
:redirect_prefix,
|
171
|
+
URL.as_href(from) => URL.as_href(to)
|
172
|
+
)
|
173
|
+
|
174
|
+
data = Storage.hget(:persistent, :manifest, URL.as_href(from))
|
175
|
+
|
176
|
+
Storage.hset(:persistent, :manifest, URL.as_href(to), data) if data
|
177
|
+
|
178
|
+
destroy(from)
|
179
|
+
end
|
180
|
+
end
|
101
181
|
end
|
102
182
|
end
|
@@ -12,7 +12,7 @@ module LinkedRails
|
|
12
12
|
delegate :iri_opts, to: :parent
|
13
13
|
|
14
14
|
alias id iri
|
15
|
-
%i[action href image label
|
15
|
+
%i[action href image label iri_base].each do |method|
|
16
16
|
callable_variable(method, instance: :parent)
|
17
17
|
end
|
18
18
|
|
@@ -26,7 +26,7 @@ module LinkedRails
|
|
26
26
|
def iri_template
|
27
27
|
return parent.send(:iri_template) unless parent.is_a?(LinkedRails::Menus::List)
|
28
28
|
|
29
|
-
return URITemplate.new("#{iri_base}{/tag}{#fragment}") if iri_base
|
29
|
+
return LinkedRails::URITemplate.new("#{iri_base}{/tag}{#fragment}") if iri_base
|
30
30
|
|
31
31
|
iri_template_expand_path(parent.send(:iri_template), '{/tag}')
|
32
32
|
end
|
@@ -36,7 +36,7 @@ module LinkedRails
|
|
36
36
|
|
37
37
|
@menu_sequence ||=
|
38
38
|
LinkedRails::Sequence.new(
|
39
|
-
-> { menus
|
39
|
+
-> { menus },
|
40
40
|
id: menu_sequence_iri,
|
41
41
|
parent: self,
|
42
42
|
scope: false
|
@@ -52,6 +52,12 @@ module LinkedRails
|
|
52
52
|
sequence_iri
|
53
53
|
end
|
54
54
|
|
55
|
+
def menus
|
56
|
+
return @menus unless @menus.respond_to?(:call)
|
57
|
+
|
58
|
+
@menus = parent.instance_exec(&@menus).compact.each { |menu| menu.parent = self }
|
59
|
+
end
|
60
|
+
|
55
61
|
def rdf_type
|
56
62
|
type || Vocab.ontola[:MenuItem]
|
57
63
|
end
|
@@ -67,24 +73,15 @@ module LinkedRails
|
|
67
73
|
end
|
68
74
|
|
69
75
|
class << self
|
70
|
-
def base_includes
|
71
|
-
[action: :target]
|
72
|
-
end
|
73
|
-
|
74
76
|
def preview_includes
|
75
|
-
|
76
|
-
menu_sequence: [
|
77
|
-
members: base_includes +
|
78
|
-
[menu_sequence: [members: base_includes]]
|
79
|
-
]
|
80
|
-
]
|
77
|
+
[menu_sequence: [members: [menu_sequence: :members]]]
|
81
78
|
end
|
82
79
|
|
83
80
|
def requested_index_resource(params, user_context)
|
84
81
|
parent = parent_from_params(params, user_context)
|
85
82
|
return if parent.blank?
|
86
83
|
|
87
|
-
parent.menu_sequence
|
84
|
+
parent.try(:menu_sequence)
|
88
85
|
end
|
89
86
|
end
|
90
87
|
end
|
@@ -20,21 +20,28 @@ module LinkedRails
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def iri_opts
|
23
|
-
|
23
|
+
return {} if resource.blank?
|
24
|
+
|
25
|
+
resource.try(:singular_resource?) ? resource.singular_iri_opts : resource.iri_opts
|
24
26
|
end
|
25
27
|
|
26
28
|
def menus
|
27
|
-
@menus ||= available_menus.map(&method(:
|
29
|
+
@menus ||= available_menus.map(&method(:memoized_menu_item))
|
28
30
|
end
|
29
31
|
|
30
32
|
def menu(tag)
|
31
|
-
|
33
|
+
memoized_menu_item(tag, available_menus[tag].dup) if available_menus.key?(tag)
|
32
34
|
end
|
33
35
|
|
34
36
|
private
|
35
37
|
|
36
38
|
def default_label(tag, options)
|
37
|
-
I18n.t("menus.#{resource&.class&.name&.tableize}.#{tag}", options[:label_params])
|
39
|
+
I18n.t("menus.#{resource&.class&.name&.tableize}.#{tag}", **options[:label_params])
|
40
|
+
end
|
41
|
+
|
42
|
+
def memoized_menu_item(tag, options)
|
43
|
+
@memoized_menu_item ||= {}
|
44
|
+
@memoized_menu_item[tag] ||= menu_item(tag, options)
|
38
45
|
end
|
39
46
|
|
40
47
|
def menu_available?(_tag, options)
|
@@ -42,16 +49,20 @@ module LinkedRails
|
|
42
49
|
end
|
43
50
|
|
44
51
|
def menu_item(tag, options) # rubocop:disable Metrics/AbcSize
|
45
|
-
|
46
|
-
|
47
|
-
end
|
52
|
+
return unless show_menu_item?(tag, options)
|
53
|
+
|
48
54
|
options[:label_params] ||= {}
|
49
55
|
options[:label_params][:default] ||= ["menus.default.#{tag}".to_sym, tag.to_s.capitalize]
|
50
56
|
options[:label] ||= default_label(tag, options)
|
57
|
+
options[:action] = ontola_dialog_action(options[:href]) if options.delete(:dialog)
|
51
58
|
options.except!(:policy_resource, :policy, :policy_arguments, :label_params)
|
52
59
|
LinkedRails.menus_item_class.new(resource: resource, tag: tag, parent: self, **options)
|
53
60
|
end
|
54
61
|
|
62
|
+
def policy_verdict(policy, options)
|
63
|
+
policy.send(options[:policy], *options[:policy_arguments])
|
64
|
+
end
|
65
|
+
|
55
66
|
def resource_policy(policy_resource)
|
56
67
|
policy_resource ||= resource
|
57
68
|
policy_resource = instance_exec(&policy_resource) if policy_resource.respond_to?(:call)
|
@@ -61,8 +72,18 @@ module LinkedRails
|
|
61
72
|
@resource_policy[policy_resource] ||= Pundit.policy(user_context, policy_resource)
|
62
73
|
end
|
63
74
|
|
75
|
+
def show_menu_item?(_tag, options)
|
76
|
+
return true if options[:policy].blank?
|
77
|
+
|
78
|
+
policy = resource_policy(options[:policy_resource])
|
79
|
+
|
80
|
+
policy_verdict(policy, options)
|
81
|
+
end
|
82
|
+
|
64
83
|
def iri_template
|
65
|
-
|
84
|
+
base_template = resource.send(resource.try(:singular_resource?) ? :singular_iri_template : :iri_template)
|
85
|
+
|
86
|
+
@iri_template ||= iri_template_expand_path(base_template, '/menus')
|
66
87
|
end
|
67
88
|
|
68
89
|
class << self
|
@@ -88,7 +109,7 @@ module LinkedRails
|
|
88
109
|
_defined_menus || {}
|
89
110
|
end
|
90
111
|
|
91
|
-
def has_menu(tag, opts
|
112
|
+
def has_menu(tag, **opts)
|
92
113
|
defined_menus[tag] = opts
|
93
114
|
end
|
94
115
|
|
@@ -100,7 +121,6 @@ module LinkedRails
|
|
100
121
|
LinkedRails::Sequence.new(
|
101
122
|
menu_list.menus,
|
102
123
|
id: menu_list.iri,
|
103
|
-
member_includes: Item.preview_includes,
|
104
124
|
scope: false
|
105
125
|
)
|
106
126
|
end
|
@@ -9,7 +9,7 @@ module LinkedRails
|
|
9
9
|
|
10
10
|
def data
|
11
11
|
data = []
|
12
|
-
iri.each_statement do |statement|
|
12
|
+
iri.try(:each_statement) do |statement|
|
13
13
|
next unless include_data_statement?(statement)
|
14
14
|
|
15
15
|
statement.graph_name = ::RDF::Serializers.config.default_graph
|
@@ -41,6 +41,8 @@ module LinkedRails
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def include_data_statement?(statement)
|
44
|
+
return false if statement.subject.node? || statement.object.node?
|
45
|
+
|
44
46
|
statement.predicate != Vocab.rdfs.label &&
|
45
47
|
statement.predicate != Vocab.rdfs.range &&
|
46
48
|
statement.predicate != Vocab.rdfs.domain
|