linked_rails 0.0.3 → 0.0.4.pre.g0ec6e30ca
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 +107 -22
- data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
- data/app/models/linked_rails/actions/item.rb +72 -55
- data/app/models/linked_rails/actions/list.rb +6 -31
- data/app/models/linked_rails/actions/object.rb +40 -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/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 +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 +28 -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 +203 -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 +140 -53
- 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 +35 -12
- 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 +78 -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
|