labimotion 2.0.0 → 2.1.0.rc2
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/lib/labimotion/apis/generic_dataset_api.rb +20 -3
- data/lib/labimotion/apis/generic_element_api.rb +23 -3
- data/lib/labimotion/apis/generic_klass_api.rb +40 -1
- data/lib/labimotion/apis/segment_api.rb +5 -3
- data/lib/labimotion/entities/application_entity.rb +7 -80
- data/lib/labimotion/entities/dataset_entity.rb +8 -3
- data/lib/labimotion/entities/dataset_klass_entity.rb +3 -2
- data/lib/labimotion/entities/element_entity.rb +1 -1
- data/lib/labimotion/entities/element_klass_entity.rb +2 -2
- data/lib/labimotion/entities/element_revision_entity.rb +1 -1
- data/lib/labimotion/entities/eln_element_entity.rb +2 -2
- data/lib/labimotion/entities/generic_klass_entity.rb +8 -9
- data/lib/labimotion/entities/generic_public_entity.rb +5 -3
- data/lib/labimotion/entities/klass_revision_entity.rb +2 -1
- data/lib/labimotion/entities/properties_entity.rb +1 -0
- data/lib/labimotion/entities/segment_entity.rb +5 -2
- data/lib/labimotion/entities/segment_revision_entity.rb +2 -2
- data/lib/labimotion/entities/vocabulary_entity.rb +2 -2
- data/lib/labimotion/helpers/dataset_helpers.rb +6 -4
- data/lib/labimotion/helpers/element_helpers.rb +7 -4
- data/lib/labimotion/helpers/segment_helpers.rb +2 -2
- data/lib/labimotion/libs/data/mapper/Chemwiki.json +2 -2
- data/lib/labimotion/libs/properties_handler.rb +10 -0
- data/lib/labimotion/libs/vocabulary_handler.rb +8 -6
- data/lib/labimotion/models/concerns/datasetable.rb +3 -3
- data/lib/labimotion/models/concerns/generic_klass.rb +16 -0
- data/lib/labimotion/models/concerns/segmentable.rb +44 -7
- data/lib/labimotion/models/dataset_klass.rb +15 -2
- data/lib/labimotion/models/element.rb +7 -1
- data/lib/labimotion/models/element_klass.rb +10 -1
- data/lib/labimotion/models/segment_klass.rb +10 -4
- data/lib/labimotion/version.rb +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72992fcf1cd53788755bb3611e14712053e4b32e1891eb0c9a8bbdb2d3ce6d60
|
4
|
+
data.tar.gz: 4ef4a14c43343881dc69ea6ecab8fea6de0e4bd5dbee94ded1a0a1573baee931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cb01613d7756d8e37e166f05f59fc0146055461bb719fe2ce863dd812e2a7ff190988a62ad3f984162686756a31e028abcd6e0658fcd11fb5e17072c5c4c596
|
7
|
+
data.tar.gz: 8d0e9282cd00ab1c00cac2e5fb9c42e5e59a39e8a39f337943e866f96a11de56fb35ada9278a46204cd404fc40674b0be751111dddfd7c5ff1408ed1d5c4a6f4
|
@@ -11,19 +11,36 @@ module Labimotion
|
|
11
11
|
namespace :klasses do
|
12
12
|
desc 'get dataset klasses'
|
13
13
|
get do
|
14
|
-
list = klass_list(true)
|
14
|
+
list = klass_list(true, false)
|
15
15
|
present list.sort_by(&:place), with: Labimotion::DatasetKlassEntity, root: 'klass'
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
namespace :list_klass do
|
20
|
+
desc 'list Generic Dataset Klass'
|
21
|
+
params do
|
22
|
+
optional :is_active, type: Boolean, desc: 'Active or Inactive Dataset'
|
23
|
+
optional :displayed_in_list, type: Boolean, desc: 'Display in list format', default: true
|
24
|
+
end
|
25
|
+
get do
|
26
|
+
list = klass_list(params[:is_active], params[:displayed_in_list])
|
27
|
+
serialized_data = Labimotion::DatasetKlassEntity.represent(list, displayed_in_list: params[:displayed_in_list])
|
28
|
+
{ mc: 'ss00', data: serialized_data }
|
29
|
+
rescue StandardError => e
|
30
|
+
Labimotion.log_exception(e, current_user)
|
31
|
+
{ mc: 'se00', msg: e.message, data: [] }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Deprecated: This namespace is no longer used, but kept for backward compatibility. It is replaced by `list_klass`.
|
19
36
|
namespace :list_dataset_klass do
|
20
37
|
desc 'list Generic Dataset Klass'
|
21
38
|
params do
|
22
39
|
optional :is_active, type: Boolean, desc: 'Active or Inactive Dataset'
|
23
40
|
end
|
24
41
|
get do
|
25
|
-
list = klass_list(params[:is_active])
|
26
|
-
present list, with: Labimotion::DatasetKlassEntity, root: 'klass'
|
42
|
+
list = klass_list(params[:is_active], false)
|
43
|
+
present list, with: Labimotion::DatasetKlassEntity, root: 'klass', displayed_in_list: false
|
27
44
|
end
|
28
45
|
end
|
29
46
|
|
@@ -188,7 +188,7 @@ module Labimotion
|
|
188
188
|
get do
|
189
189
|
klass = Labimotion::Segment.find(params[:id])
|
190
190
|
list = klass.segments_revisions unless klass.nil?
|
191
|
-
present list&.
|
191
|
+
present list&.order(created_at: :desc)&.limit(10), with: Labimotion::SegmentRevisionEntity, root: 'revisions'
|
192
192
|
rescue StandardError => e
|
193
193
|
Labimotion.log_exception(e, current_user)
|
194
194
|
[]
|
@@ -221,6 +221,26 @@ module Labimotion
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|
224
|
+
namespace :list_element_klass do
|
225
|
+
desc 'list Generic Element Klass'
|
226
|
+
params do
|
227
|
+
optional :is_generic, type: Boolean, desc: 'Is Generic or Non-Generic Element'
|
228
|
+
optional :is_active, type: Boolean, desc: 'Active or Inactive Dataset'
|
229
|
+
optional :displayed_in_list, type: Boolean, desc: 'Display in list format', default: true
|
230
|
+
end
|
231
|
+
get do
|
232
|
+
scope = params[:displayed_in_list] ? Labimotion::ElementKlass.for_list_display : Labimotion::ElementKlass.all
|
233
|
+
scope = scope.where(is_generic: params[:is_generic]) if params.key?(:is_generic)
|
234
|
+
|
235
|
+
list = scope.sort_by(&:place)
|
236
|
+
present list, with: Labimotion::ElementKlassEntity, root: 'klass', displayed_in_list: params[:displayed_in_list]
|
237
|
+
rescue StandardError => e
|
238
|
+
Labimotion.log_exception(e, current_user)
|
239
|
+
raise e
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Deprecated: This namespace is no longer used, but kept for backward compatibility.
|
224
244
|
namespace :klasses_all do
|
225
245
|
desc 'get all klasses for admin function'
|
226
246
|
get do
|
@@ -266,7 +286,7 @@ module Labimotion
|
|
266
286
|
end
|
267
287
|
after_validation do
|
268
288
|
authenticate_admin!(params[:klass].gsub(/(Klass)/, 's').downcase)
|
269
|
-
|
289
|
+
fetch_klass(params[:klass], params[:id])
|
270
290
|
end
|
271
291
|
post do
|
272
292
|
deactivate_klass(params)
|
@@ -301,7 +321,7 @@ module Labimotion
|
|
301
321
|
end
|
302
322
|
after_validation do
|
303
323
|
authenticate_admin!(params[:klass].gsub(/(Klass)/, 's').downcase)
|
304
|
-
|
324
|
+
fetch_klass(params[:klass], params[:id])
|
305
325
|
end
|
306
326
|
post do
|
307
327
|
update_template(params, current_user)
|
@@ -6,6 +6,7 @@ require 'labimotion/libs/export_element'
|
|
6
6
|
module Labimotion
|
7
7
|
# Generic Element API
|
8
8
|
class GenericKlassAPI < Grape::API
|
9
|
+
helpers Labimotion::GenericHelpers
|
9
10
|
|
10
11
|
resource :generic_klass do
|
11
12
|
namespace :download_klass do
|
@@ -30,6 +31,44 @@ module Labimotion
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
34
|
+
namespace :de_activate do
|
35
|
+
desc 'activate or deactivate Generic Klass'
|
36
|
+
params do
|
37
|
+
requires :klass, type: String, desc: 'Klass', values: %w[ElementKlass SegmentKlass DatasetKlass]
|
38
|
+
requires :id, type: Integer, desc: 'Klass ID'
|
39
|
+
requires :is_active, type: Boolean, desc: 'Active or Inactive Klass'
|
40
|
+
end
|
41
|
+
after_validation do
|
42
|
+
authenticate_admin!(params[:klass].gsub(/(Klass)/, 's').downcase)
|
43
|
+
fetch_klass(params[:klass], params[:id])
|
44
|
+
end
|
45
|
+
post do
|
46
|
+
updated_klass = deactivate_klass(params)
|
47
|
+
entity_class = "Labimotion::#{params[:klass]}Entity".constantize
|
48
|
+
serialized_data = entity_class.represent(updated_klass)
|
49
|
+
{ mc: 'ss00', data: serialized_data }
|
50
|
+
rescue StandardError => e
|
51
|
+
Labimotion.log_exception(e, current_user)
|
52
|
+
{ mc: 'se00', msg: e.message, data: {} }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
namespace :fetch do
|
57
|
+
desc 'fetch Generic Klass by id'
|
58
|
+
params do
|
59
|
+
requires :id, type: Integer, desc: 'Klass ID'
|
60
|
+
requires :klass, type: String, desc: 'Klass', values: %w[ElementKlass SegmentKlass DatasetKlass]
|
61
|
+
end
|
62
|
+
get do
|
63
|
+
klass_obj = fetch_klass(params[:klass], params[:id])
|
64
|
+
entity_class = "Labimotion::#{params[:klass]}Entity".constantize
|
65
|
+
serialized_data = entity_class.represent(klass_obj)
|
66
|
+
{ mc: 'ss00', data: serialized_data }
|
67
|
+
rescue StandardError => e
|
68
|
+
Labimotion.log_exception(e, current_user)
|
69
|
+
{ mc: 'se00', msg: e.message, data: {} }
|
70
|
+
end
|
71
|
+
end
|
33
72
|
end
|
34
73
|
end
|
35
|
-
end
|
74
|
+
end
|
@@ -12,19 +12,21 @@ module Labimotion
|
|
12
12
|
optional :element, type: String, desc: "Klass Element, e.g. Sample, Reaction, Mof,..."
|
13
13
|
end
|
14
14
|
get do
|
15
|
-
list = klass_list(params[:element], true)
|
15
|
+
list = klass_list(params[:element], true, false)
|
16
16
|
present list, with: Labimotion::SegmentKlassEntity, root: 'klass'
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
# TODO: params[:displayed_in_list] will be used in the future to control the display format, set 'false' for now.
|
20
21
|
namespace :list_segment_klass do
|
21
22
|
desc 'list Generic Segment Klass'
|
22
23
|
params do
|
23
24
|
optional :is_active, type: Boolean, desc: 'Active or Inactive Segment'
|
25
|
+
optional :displayed_in_list, type: Boolean, desc: 'Display in list format', default: false
|
24
26
|
end
|
25
27
|
get do
|
26
|
-
list = klass_list(nil, params[:is_active])
|
27
|
-
present list, with: Labimotion::SegmentKlassEntity, root: 'klass'
|
28
|
+
list = klass_list(nil, params[:is_active], false)
|
29
|
+
present list, with: Labimotion::SegmentKlassEntity, root: 'klass', displayed_in_list: false
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
@@ -1,88 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
module Labimotion
|
4
4
|
## ApplicationEntity
|
5
|
-
class
|
6
|
-
|
5
|
+
# This class serves as the base entity for the Labimotion module,
|
6
|
+
# inheriting from the core ApplicationEntity and providing custom formatting.
|
7
|
+
class ApplicationEntity < ::Entities::ApplicationEntity
|
8
|
+
# Common condition for fields that should not be displayed in list views
|
9
|
+
DISPLAYED_IN_LIST_CONDITION = { unless: :displayed_in_list }.freeze
|
7
10
|
|
8
11
|
format_with(:eln_timestamp) do |datetime|
|
9
|
-
datetime.present? ? datetime
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.expose!(*args)
|
13
|
-
fields = args.first
|
14
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
15
|
-
options = merge_options(options) # merges additional params set in #with_options
|
16
|
-
expose_fields_with_anonymization!(fields, options)
|
17
|
-
end
|
18
|
-
|
19
|
-
# rubocop:disable Metrics/MethodLength
|
20
|
-
def self.expose_fields_with_anonymization!(fields, options)
|
21
|
-
anonymize_below = options[:anonymize_below] || 0
|
22
|
-
anonymize_with = options.key?(:anonymize_with) ? options[:anonymize_with] : '***'
|
23
|
-
|
24
|
-
Array(fields).each do |field|
|
25
|
-
expose(field, options) do |represented_object, _options|
|
26
|
-
if detail_levels[represented_object.class] < anonymize_below
|
27
|
-
anonymize_with
|
28
|
-
elsif respond_to?(field, true) # Entity has a method with the same name
|
29
|
-
send(field)
|
30
|
-
elsif represented_object.respond_to?(field)
|
31
|
-
represented_object.public_send(field)
|
32
|
-
else
|
33
|
-
represented_object[field] # works both for AR and Hash objects
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
private_class_method :expose_fields_with_anonymization!
|
39
|
-
# rubocop:enable Metrics/MethodLength
|
40
|
-
|
41
|
-
def self.expose_timestamps(timestamp_fields: %i[created_at updated_at], **additional_args)
|
42
|
-
timestamp_fields.each do |field|
|
43
|
-
expose field, format_with: :eln_timestamp, **additional_args
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# overridden method from Grape::Entity to support our custom anonymization options
|
48
|
-
# https://github.com/ruby-grape/grape-entity/blob/v0.7.1/lib/grape_entity/entity.rb#L565
|
49
|
-
def self.valid_options(options)
|
50
|
-
options.each_key do |key|
|
51
|
-
next if OPTIONS.include?(key) || CUSTOM_ENTITY_OPTIONS.include?(key)
|
52
|
-
|
53
|
-
raise ArgumentError, "#{key.inspect} is not a valid option."
|
54
|
-
end
|
55
|
-
|
56
|
-
options[:using] = options.delete(:with) if options.key?(:with)
|
57
|
-
options
|
58
|
-
end
|
59
|
-
private_class_method :valid_options
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def displayed_in_list?
|
64
|
-
options[:displayed_in_list] == true
|
65
|
-
end
|
66
|
-
|
67
|
-
def current_user
|
68
|
-
unless options[:current_user]
|
69
|
-
raise MissingCurrentUserError, "#{self.class} requires a current user to work properly"
|
70
|
-
end
|
71
|
-
|
72
|
-
options[:current_user]
|
73
|
-
end
|
74
|
-
|
75
|
-
def detail_levels
|
76
|
-
maximal_default_levels = Hash.new(10) # every requested detail level will be returned as 10
|
77
|
-
minimal_default_levels = Hash.new(0) # every requested detail level will be returned as 0
|
78
|
-
return maximal_default_levels if !options.key?(:detail_levels) || options[:detail_levels].empty?
|
79
|
-
|
80
|
-
# When explicitly configured detail levels are available, we want to return only those and all other
|
81
|
-
# requests (by using `detail_levels[SomeUnconfiguredModel]`) should return the minimum detail level
|
82
|
-
minimal_default_levels.merge(options[:detail_levels])
|
83
|
-
end
|
84
|
-
|
85
|
-
class MissingCurrentUserError < StandardError
|
12
|
+
datetime.present? ? datetime.strftime('%Y-%m-%d %H:%M:%S %Z') : nil
|
86
13
|
end
|
87
14
|
end
|
88
15
|
end
|
@@ -1,10 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
|
+
require 'labimotion/entities/properties_entity'
|
4
5
|
module Labimotion
|
5
6
|
# Dataset entity
|
6
|
-
class DatasetEntity < PropertiesEntity
|
7
|
-
expose :id, :dataset_klass_id, :
|
7
|
+
class DatasetEntity < Labimotion::PropertiesEntity
|
8
|
+
expose :id, :dataset_klass_id, :element_id, :element_type
|
9
|
+
expose :klass_ols, :klass_label, :klass_uuid
|
10
|
+
expose :properties, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
11
|
+
expose :properties_release, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
12
|
+
|
8
13
|
def klass_ols
|
9
14
|
object&.dataset_klass&.ols_term_id
|
10
15
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'labimotion/entities/generic_klass_entity'
|
3
4
|
module Labimotion
|
4
|
-
class DatasetKlassEntity < GenericKlassEntity
|
5
|
+
class DatasetKlassEntity < Labimotion::GenericKlassEntity
|
5
6
|
expose(
|
6
|
-
:ols_term_id
|
7
|
+
:ols_term_id
|
7
8
|
)
|
8
9
|
end
|
9
10
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'labimotion/entities/properties_entity'
|
4
4
|
## TODO: Refactor labimotion to use the same entities as chemotion
|
5
5
|
module Labimotion
|
6
|
-
class ElementEntity < PropertiesEntity
|
6
|
+
class ElementEntity < Labimotion::PropertiesEntity
|
7
7
|
with_options(anonymize_below: 0) do
|
8
8
|
expose! :can_copy, unless: :displayed_in_list
|
9
9
|
expose! :can_publish, unless: :displayed_in_list
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/generic_klass_entity'
|
4
4
|
|
5
5
|
module Labimotion
|
6
6
|
# ElementKlassEntity
|
7
|
-
class ElementKlassEntity < GenericKlassEntity
|
7
|
+
class ElementKlassEntity < Labimotion::GenericKlassEntity
|
8
8
|
expose :name, :icon_name, :klass_prefix, :is_generic
|
9
9
|
end
|
10
10
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
4
|
module Labimotion
|
5
5
|
# ElementRevisionEntity
|
6
|
-
class ElementRevisionEntity < ApplicationEntity
|
6
|
+
class ElementRevisionEntity < Labimotion::ApplicationEntity
|
7
7
|
expose :id, :element_id, :uuid, :name, :klass_uuid, :properties, :created_at
|
8
8
|
def created_at
|
9
9
|
object.created_at.strftime('%d.%m.%Y, %H:%M')
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
4
|
module Labimotion
|
5
5
|
## ElementEntity
|
6
|
-
class ElnElementEntity < ApplicationEntity
|
6
|
+
class ElnElementEntity < Labimotion::ApplicationEntity
|
7
7
|
with_options(anonymize_below: 0) do
|
8
8
|
expose! :created_by
|
9
9
|
expose! :id
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
4
|
module Labimotion
|
5
|
-
|
6
|
-
|
7
|
-
expose :
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
expose_timestamps(timestamp_fields: [
|
12
|
-
expose_timestamps(timestamp_fields: [:sync_time])
|
5
|
+
class GenericKlassEntity < Labimotion::ApplicationEntity
|
6
|
+
expose :id, :uuid, :label, :desc, :is_active, :version, :place
|
7
|
+
expose :released_at, :identifier, :sync_time
|
8
|
+
|
9
|
+
expose :properties_template, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
10
|
+
expose :properties_release, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
11
|
+
expose_timestamps(timestamp_fields: %i[released_at created_at updated_at sync_time])
|
13
12
|
end
|
14
13
|
end
|
@@ -10,15 +10,17 @@ module Labimotion
|
|
10
10
|
expose! :desc
|
11
11
|
expose! :icon_name
|
12
12
|
expose! :klass_prefix
|
13
|
-
expose
|
13
|
+
expose :klass_name do |obj|
|
14
|
+
obj[:name] || ''
|
15
|
+
end
|
14
16
|
expose! :label
|
15
17
|
expose! :identifier
|
16
18
|
expose! :version
|
17
19
|
expose! :released_at
|
18
|
-
expose
|
20
|
+
expose :properties_release, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
19
21
|
expose :element_klass do |obj|
|
20
22
|
if obj[:element_klass_id]
|
21
|
-
{ :
|
23
|
+
{ label: obj.element_klass.label, icon_name: obj.element_klass.icon_name, id: obj.element_klass_id }
|
22
24
|
else
|
23
25
|
{}
|
24
26
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'labimotion/entities/application_entity'
|
3
4
|
module Labimotion
|
4
5
|
# KlassRevisionEntity
|
5
|
-
class KlassRevisionEntity < ApplicationEntity
|
6
|
+
class KlassRevisionEntity < Labimotion::ApplicationEntity
|
6
7
|
expose :id, :uuid, :properties_release, :version, :released_at
|
7
8
|
|
8
9
|
expose :klass_id do |object|
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
|
+
require 'labimotion/entities/properties_entity'
|
4
5
|
module Labimotion
|
5
6
|
## Segment entity
|
6
|
-
class SegmentEntity < PropertiesEntity
|
7
|
-
expose :id, :segment_klass_id, :element_type, :element_id, :
|
7
|
+
class SegmentEntity < Labimotion::PropertiesEntity
|
8
|
+
expose :id, :segment_klass_id, :element_type, :element_id, :uuid, :klass_uuid, :klass_label
|
9
|
+
expose :properties, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
10
|
+
expose :properties_release, **DISPLAYED_IN_LIST_CONDITION, anonymize_with: {}
|
8
11
|
|
9
12
|
def klass_label
|
10
13
|
object.segment_klass.label
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
4
|
module Labimotion
|
5
|
-
class SegmentRevisionEntity < ApplicationEntity
|
5
|
+
class SegmentRevisionEntity < Labimotion::ApplicationEntity
|
6
6
|
expose :id, :segment_id, :uuid, :klass_uuid, :properties, :created_at
|
7
7
|
def created_at
|
8
8
|
object.created_at.strftime('%d.%m.%Y, %H:%M')
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'labimotion/entities/application_entity'
|
4
4
|
module Labimotion
|
5
5
|
# Dataset entity
|
6
|
-
class VocabularyEntity < ApplicationEntity
|
6
|
+
class VocabularyEntity < Labimotion::ApplicationEntity
|
7
7
|
expose :id, :identifier, :name, :label, :field_type, :opid, :term_id,
|
8
8
|
:field_id, :properties, :source, :source_id, :layer_id
|
9
9
|
expose :voc do |obj|
|
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'grape'
|
3
4
|
module Labimotion
|
4
|
-
|
5
|
+
## DatasetHelpers
|
5
6
|
module DatasetHelpers
|
6
7
|
extend Grape::API::Helpers
|
7
8
|
|
8
|
-
def klass_list(is_active)
|
9
|
+
def klass_list(is_active, displayed_in_list = false)
|
10
|
+
scope = displayed_in_list ? Labimotion::DatasetKlass.for_list_display : Labimotion::DatasetKlass.all
|
9
11
|
if is_active == true
|
10
|
-
|
12
|
+
scope.where(is_active: true).order('place') || []
|
11
13
|
else
|
12
|
-
|
14
|
+
scope.order('place') || []
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -93,12 +93,13 @@ module Labimotion
|
|
93
93
|
all_coll = Collection.get_all_collection_for_user(current_user.id)
|
94
94
|
element.collections << all_coll
|
95
95
|
element.save!
|
96
|
-
|
97
|
-
element.properties = update_vocabularies(_properties, current_user, element)
|
96
|
+
element.properties = update_sample_association(params[:properties], current_user, element)
|
97
|
+
# element.properties = update_vocabularies(_properties, current_user, element)
|
98
98
|
element.container = update_datamodel(params[:container], current_user)
|
99
99
|
element.save!
|
100
100
|
update_element_labels(element, params[:user_labels], current_user.id)
|
101
101
|
element.save_segments(segments: params[:segments], current_user_id: current_user.id)
|
102
|
+
element.save!
|
102
103
|
element
|
103
104
|
rescue StandardError => e
|
104
105
|
Labimotion.log_exception(e, current_user)
|
@@ -129,9 +130,11 @@ module Labimotion
|
|
129
130
|
attributes['klass_uuid'] = properties['klass_uuid']
|
130
131
|
element.update_columns(attributes)
|
131
132
|
end
|
133
|
+
# element.save_segments(segments: params[:segments], current_user_id: current_user.id)
|
134
|
+
element.reload
|
132
135
|
element.save_segments(segments: params[:segments], current_user_id: current_user.id)
|
133
136
|
element.reload
|
134
|
-
element.properties = update_vocabularies(element.properties, current_user, element)
|
137
|
+
# element.properties = update_vocabularies(element.properties, current_user, element)
|
135
138
|
## element.user_for_revision = current_user
|
136
139
|
element.save!
|
137
140
|
element
|
@@ -192,7 +195,7 @@ module Labimotion
|
|
192
195
|
def element_revisions(params)
|
193
196
|
klass = Labimotion::Element.find(params[:id])
|
194
197
|
list = klass.elements_revisions unless klass.nil?
|
195
|
-
list&.
|
198
|
+
list&.order(created_at: :desc)&.limit(10)
|
196
199
|
rescue StandardError => e
|
197
200
|
Labimotion.log_exception(e, current_user)
|
198
201
|
raise e
|
@@ -8,8 +8,8 @@ module Labimotion
|
|
8
8
|
module SegmentHelpers
|
9
9
|
extend Grape::API::Helpers
|
10
10
|
|
11
|
-
def klass_list(el_klass, is_active=false)
|
12
|
-
scope = Labimotion::SegmentKlass.all
|
11
|
+
def klass_list(el_klass, is_active = false, displayed_in_list = false)
|
12
|
+
scope = displayed_in_list ? Labimotion::SegmentKlass.for_list_display : Labimotion::SegmentKlass.all
|
13
13
|
scope = scope.where(is_active: is_active) if is_active.present? && is_active == true
|
14
14
|
scope = scope.joins(:element_klass).where(klass_element: params[:element], is_active: true).preload(:element_klass) if el_klass.present?
|
15
15
|
scope.order('place') || []
|
@@ -91,5 +91,15 @@ module Labimotion
|
|
91
91
|
Labimotion.log_exception(e)
|
92
92
|
properties
|
93
93
|
end
|
94
|
+
|
95
|
+
# Update field with value
|
96
|
+
def self.update_field_value!(properties, layer_key, field_index, value)
|
97
|
+
properties[Labimotion::Prop::LAYERS][layer_key][Labimotion::Prop::FIELDS][field_index]['value'] = value
|
98
|
+
end
|
99
|
+
|
100
|
+
# Delete field key
|
101
|
+
def self.delete_field_key!(properties, layer_key, field_index, key)
|
102
|
+
properties[Labimotion::Prop::LAYERS][layer_key][Labimotion::Prop::FIELDS][field_index].delete(key)
|
103
|
+
end
|
94
104
|
end
|
95
105
|
end
|
@@ -4,8 +4,10 @@ module Labimotion
|
|
4
4
|
class VocabularyHandler
|
5
5
|
class << self
|
6
6
|
def update_vocabularies(properties, current_user, element)
|
7
|
+
return properties if properties.nil? || !properties.is_a?(Hash) || properties[Labimotion::Prop::LAYERS].nil?
|
8
|
+
|
7
9
|
properties[Labimotion::Prop::LAYERS].each do |key, layer|
|
8
|
-
update_layer_vocabularies(layer, key, properties, current_user, element)
|
10
|
+
update_layer_vocabularies!(layer, key, properties, current_user, element)
|
9
11
|
end
|
10
12
|
properties
|
11
13
|
rescue StandardError => e
|
@@ -23,12 +25,12 @@ module Labimotion
|
|
23
25
|
|
24
26
|
private
|
25
27
|
|
26
|
-
def update_layer_vocabularies(layer, key, properties, current_user, element)
|
28
|
+
def update_layer_vocabularies!(layer, key, properties, current_user, element)
|
27
29
|
field_vocabularies = layer[Labimotion::Prop::FIELDS].select { |field| field['is_voc'] }
|
28
30
|
field_vocabularies.each do |field|
|
29
31
|
idx = layer[Labimotion::Prop::FIELDS].index(field)
|
30
32
|
val = get_vocabulary_value(field, current_user, element)
|
31
|
-
update_field_value(properties, key, idx, val)
|
33
|
+
update_field_value!(properties, key, idx, val)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -44,6 +46,7 @@ module Labimotion
|
|
44
46
|
get_segment_value(field, element)
|
45
47
|
when 'Dataset'
|
46
48
|
# TODO: Implement Dataset logic here
|
49
|
+
# TODO: Update datasetable.save_dataset
|
47
50
|
nil
|
48
51
|
end
|
49
52
|
end
|
@@ -91,9 +94,8 @@ module Labimotion
|
|
91
94
|
fields.find { |ss| ss['field'] == field['field_id'] }&.dig('value')
|
92
95
|
end
|
93
96
|
|
94
|
-
def update_field_value(properties, key, idx, val)
|
95
|
-
|
96
|
-
properties
|
97
|
+
def update_field_value!(properties, key, idx, val)
|
98
|
+
Labimotion::PropertiesHandler.update_field_value!(properties, key, idx, val)
|
97
99
|
end
|
98
100
|
|
99
101
|
def load_from_files
|
@@ -42,15 +42,15 @@ module Labimotion
|
|
42
42
|
props['identifier'] = klass.identifier if klass.identifier.present?
|
43
43
|
props['uuid'] = uuid
|
44
44
|
props['klass'] = 'Dataset'
|
45
|
+
props['klass_uuid'] = klass.uuid
|
45
46
|
props = Labimotion::VocabularyHandler.update_vocabularies(props, args[:current_user], args[:element])
|
46
47
|
|
47
48
|
ds = Labimotion::Dataset.find_by(element_type: self.class.name, element_id: id)
|
48
|
-
if ds.present? && (ds.klass_uuid !=
|
49
|
-
ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: args[:dataset_klass_id], properties: props, klass_uuid:
|
49
|
+
if ds.present? && (ds.klass_uuid != klass.uuid || ds.properties != props)
|
50
|
+
ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: args[:dataset_klass_id], properties: props, klass_uuid: klass.uuid)
|
50
51
|
end
|
51
52
|
return if ds.present?
|
52
53
|
|
53
|
-
props['klass_uuid'] = klass.uuid
|
54
54
|
Labimotion::Dataset.create!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: args[:dataset_klass_id], element_type: self.class.name, element_id: id, properties: props, klass_uuid: klass.uuid)
|
55
55
|
end
|
56
56
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Labimotion
|
4
|
+
## Generic Klass Helpers
|
5
|
+
module GenericKlass
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
# Scope for active and released templates
|
10
|
+
scope :active_and_released, -> { for_list_display.where(is_active: true).where.not(released_at: nil) }
|
11
|
+
|
12
|
+
# Scope for active, released, and generic templates (primarily for ElementKlass)
|
13
|
+
scope :active_released_generic, -> { active_and_released.where(is_generic: true) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -46,11 +46,17 @@ module Labimotion
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
def touch_vocabulary(current_user)
|
50
|
+
touch_element_properties(current_user) if instance_of?(::Labimotion::Element)
|
51
|
+
touch_segments_properties(current_user)
|
52
|
+
touch_analyses_properties(current_user)
|
53
|
+
end
|
54
|
+
|
49
55
|
def save_segments(**args) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
50
|
-
|
56
|
+
args_segments = args[:segments] || []
|
51
57
|
|
52
|
-
|
53
|
-
|
58
|
+
current_user = User.find_by(id: args[:current_user_id])
|
59
|
+
args_segments.each do |seg|
|
54
60
|
klass = Labimotion::SegmentKlass.find_by(id: seg['segment_klass_id'])
|
55
61
|
uuid = SecureRandom.uuid
|
56
62
|
props = seg['properties']
|
@@ -59,21 +65,52 @@ module Labimotion
|
|
59
65
|
props['uuid'] = uuid
|
60
66
|
props['klass'] = 'Segment'
|
61
67
|
props = Labimotion::SampleAssociation.update_sample_association(props, args[:current_user_id])
|
62
|
-
|
63
|
-
props = Labimotion::VocabularyHandler.update_vocabularies(props, current_user, self)
|
68
|
+
# props = Labimotion::VocabularyHandler.update_vocabularies(props, current_user, self)
|
64
69
|
segment = Labimotion::Segment.where(element_type: self.class.name, element_id: self.id, segment_klass_id: seg['segment_klass_id']).order(id: :desc).first
|
65
70
|
if segment.present? && (segment.klass_uuid != props['klass_uuid'] || segment.properties != props)
|
66
71
|
segment.update!(properties_release: klass.properties_release, properties: props, uuid: uuid, klass_uuid: props['klass_uuid'])
|
67
|
-
segments.push(segment)
|
72
|
+
# segments.push(segment)
|
68
73
|
Labimotion::Segment.where(element_type: self.class.name, element_id: self.id, segment_klass_id: seg['segment_klass_id']).where.not(id: segment.id).destroy_all
|
69
74
|
end
|
70
75
|
next if segment.present?
|
71
76
|
|
72
77
|
props['klass_uuid'] = klass.uuid
|
73
78
|
segment = Labimotion::Segment.create!(properties_release: klass.properties_release, segment_klass_id: seg['segment_klass_id'], element_type: self.class.name, element_id: self.id, properties: props, created_by: args[:current_user_id], uuid: uuid, klass_uuid: klass.uuid)
|
74
|
-
segments.push(segment)
|
79
|
+
# segments.push(segment)
|
75
80
|
end
|
81
|
+
|
82
|
+
self.reload
|
83
|
+
touch_vocabulary(current_user)
|
84
|
+
self.reload
|
76
85
|
segments
|
77
86
|
end
|
87
|
+
|
88
|
+
def touch_element_properties(current_user)
|
89
|
+
touch_properties_for_object(self, current_user)
|
90
|
+
end
|
91
|
+
|
92
|
+
def touch_segments_properties(current_user)
|
93
|
+
segments.each do |segment|
|
94
|
+
touch_properties_for_object(segment, current_user)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def touch_analyses_properties(current_user)
|
99
|
+
analyses.each do |analysis|
|
100
|
+
analysis.children.each do |child|
|
101
|
+
dataset = child.dataset
|
102
|
+
next if dataset.nil?
|
103
|
+
|
104
|
+
touch_properties_for_object(dataset, current_user)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# NOTE: Update bypassing validations, callbacks, and timestamp updates
|
110
|
+
def touch_properties_for_object(object, current_user)
|
111
|
+
props_dup = object.properties.deep_dup
|
112
|
+
Labimotion::VocabularyHandler.update_vocabularies(props_dup, current_user, self)
|
113
|
+
object.update_column(:properties, props_dup) if props_dup != object.properties
|
114
|
+
end
|
78
115
|
end
|
79
116
|
end
|
@@ -1,22 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'labimotion/models/concerns/generic_klass_revisions'
|
4
|
+
require 'labimotion/models/concerns/generic_klass'
|
3
5
|
|
4
6
|
module Labimotion
|
5
7
|
class DatasetKlass < ApplicationRecord
|
6
8
|
acts_as_paranoid
|
7
9
|
self.table_name = :dataset_klasses
|
8
10
|
include GenericKlassRevisions
|
11
|
+
include GenericKlass
|
9
12
|
has_many :datasets, dependent: :destroy, class_name: 'Labimotion::Dataset'
|
10
13
|
has_many :dataset_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::DatasetKlassesRevision'
|
11
14
|
|
15
|
+
# Scope for displayed_in_list - select only necessary columns for list view
|
16
|
+
scope :for_list_display, lambda {
|
17
|
+
select(:id, :uuid, :label, :desc, :is_active, :version, :place, :released_at,
|
18
|
+
:identifier, :sync_time, :created_at, :updated_at, :ols_term_id)
|
19
|
+
}
|
20
|
+
|
12
21
|
def self.init_seeds
|
13
|
-
|
22
|
+
gem_spec = Gem.loaded_specs['labimotion']
|
23
|
+
gem_root = gem_spec.gem_dir if gem_spec
|
24
|
+
seeds_path = File.join(gem_root, 'db', 'seeds', 'dataset_klasses.json')
|
14
25
|
seeds = JSON.parse(File.read(seeds_path))
|
15
26
|
|
16
27
|
seeds['chmo'].each do |term|
|
17
28
|
next if Labimotion::DatasetKlass.where(ols_term_id: term['id']).count.positive?
|
18
29
|
|
19
|
-
attributes = { ols_term_id: term['id'], label: "#{term['label']} (#{term['synonym']})",
|
30
|
+
attributes = { ols_term_id: term['id'], label: "#{term['label']} (#{term['synonym']})",
|
31
|
+
desc: "#{term['label']} (#{term['synonym']})", place: term['position'],
|
32
|
+
created_by: Admin.first&.id || 0 }
|
20
33
|
Labimotion::DatasetKlass.create!(attributes)
|
21
34
|
end
|
22
35
|
true
|
@@ -31,6 +31,7 @@ module Labimotion
|
|
31
31
|
|
32
32
|
belongs_to :element_klass, class_name: 'Labimotion::ElementKlass'
|
33
33
|
|
34
|
+
# has_ancestry ancestry_format: :materialized_path2
|
34
35
|
has_ancestry orphan_strategy: :adopt
|
35
36
|
|
36
37
|
has_many :collections_elements, inverse_of: :element, dependent: :destroy, class_name: 'Labimotion::CollectionsElement'
|
@@ -49,6 +50,7 @@ module Labimotion
|
|
49
50
|
scope :elements_updated_time_to, ->(time) { where('elements.updated_at <= ?', time) }
|
50
51
|
|
51
52
|
belongs_to :creator, foreign_key: :created_by, class_name: 'User'
|
53
|
+
before_validation :set_root_ancestry_if_nil
|
52
54
|
validates :creator, presence: true
|
53
55
|
|
54
56
|
has_many :elements_elements, foreign_key: :parent_id, class_name: 'Labimotion::ElementsElement'
|
@@ -71,7 +73,7 @@ module Labimotion
|
|
71
73
|
end
|
72
74
|
|
73
75
|
def analyses
|
74
|
-
container ? container.analyses :
|
76
|
+
container ? container.analyses : Container.none
|
75
77
|
end
|
76
78
|
|
77
79
|
def auto_set_short_label
|
@@ -148,5 +150,9 @@ module Labimotion
|
|
148
150
|
attachments.each(&:destroy!)
|
149
151
|
end
|
150
152
|
end
|
153
|
+
|
154
|
+
def set_root_ancestry_if_nil
|
155
|
+
self.ancestry ||= '/'
|
156
|
+
end
|
151
157
|
end
|
152
158
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'labimotion/conf'
|
3
4
|
require 'labimotion/models/concerns/generic_klass_revisions'
|
5
|
+
require 'labimotion/models/concerns/generic_klass'
|
4
6
|
require 'labimotion/models/concerns/workflow'
|
5
7
|
|
6
8
|
module Labimotion
|
@@ -8,11 +10,19 @@ module Labimotion
|
|
8
10
|
self.table_name = :element_klasses
|
9
11
|
acts_as_paranoid
|
10
12
|
include GenericKlassRevisions
|
13
|
+
include GenericKlass
|
11
14
|
include Workflow
|
12
15
|
has_many :elements, dependent: :destroy, class_name: 'Labimotion::Element'
|
13
16
|
has_many :segment_klasses, dependent: :destroy, class_name: 'Labimotion::SegmentKlass'
|
14
17
|
has_many :element_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::ElementKlassesRevision'
|
15
18
|
|
19
|
+
# Scope for displayed_in_list - select only necessary columns for list view
|
20
|
+
scope :for_list_display, lambda {
|
21
|
+
select(:id, :uuid, :label, :desc, :is_active, :version, :place, :released_at,
|
22
|
+
:identifier, :sync_time, :created_at, :updated_at, :name, :icon_name,
|
23
|
+
:klass_prefix, :is_generic)
|
24
|
+
}
|
25
|
+
|
16
26
|
def self.gen_klasses_json
|
17
27
|
klasses = where(is_active: true, is_generic: true).order('place')&.pluck(:name) || []
|
18
28
|
rescue ActiveRecord::StatementInvalid, PG::ConnectionBad, PG::UndefinedTable
|
@@ -24,6 +34,5 @@ module Labimotion
|
|
24
34
|
klasses&.to_json || []
|
25
35
|
)
|
26
36
|
end
|
27
|
-
|
28
37
|
end
|
29
38
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'labimotion/models/concerns/generic_klass_revisions'
|
4
|
+
require 'labimotion/models/concerns/generic_klass'
|
3
5
|
require 'labimotion/models/concerns/workflow'
|
4
6
|
|
5
7
|
module Labimotion
|
@@ -7,20 +9,24 @@ module Labimotion
|
|
7
9
|
self.table_name = :segment_klasses
|
8
10
|
acts_as_paranoid
|
9
11
|
include GenericKlassRevisions
|
12
|
+
include GenericKlass
|
10
13
|
include Workflow
|
11
14
|
belongs_to :element_klass, class_name: 'Labimotion::ElementKlass'
|
12
15
|
has_many :segments, dependent: :destroy, class_name: 'Labimotion::Segment'
|
13
16
|
has_many :segment_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::SegmentKlassesRevision'
|
14
17
|
|
18
|
+
# Scope for displayed_in_list - select only necessary columns for list view
|
19
|
+
scope :for_list_display, lambda {
|
20
|
+
select(:id, :uuid, :label, :desc, :is_active, :version, :place, :released_at,
|
21
|
+
:identifier, :sync_time, :created_at, :updated_at, :element_klass_id)
|
22
|
+
}
|
23
|
+
|
15
24
|
def self.gen_klasses_json
|
16
25
|
klasses = where(is_active: true)&.pluck(:name) || []
|
17
26
|
rescue ActiveRecord::StatementInvalid, PG::ConnectionBad, PG::UndefinedTable
|
18
27
|
klasses = []
|
19
28
|
ensure
|
20
|
-
|
21
|
-
Rails.root.join('config', 'segment_klass.json'),
|
22
|
-
klasses&.to_json || []
|
23
|
-
)
|
29
|
+
Rails.root.join('config', 'segment_klass.json').write(klasses&.to_json || [])
|
24
30
|
end
|
25
31
|
end
|
26
32
|
end
|
data/lib/labimotion/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: labimotion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.1.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chia-Lin Lin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-
|
12
|
+
date: 2025-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/labimotion/models/collections_element.rb
|
92
92
|
- lib/labimotion/models/concerns/attachment_converter.rb
|
93
93
|
- lib/labimotion/models/concerns/datasetable.rb
|
94
|
+
- lib/labimotion/models/concerns/generic_klass.rb
|
94
95
|
- lib/labimotion/models/concerns/generic_klass_revisions.rb
|
95
96
|
- lib/labimotion/models/concerns/generic_revisions.rb
|
96
97
|
- lib/labimotion/models/concerns/linked_properties.rb
|
@@ -143,9 +144,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
144
|
version: '0'
|
144
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
146
|
requirements:
|
146
|
-
- - "
|
147
|
+
- - ">"
|
147
148
|
- !ruby/object:Gem::Version
|
148
|
-
version:
|
149
|
+
version: 1.3.1
|
149
150
|
requirements: []
|
150
151
|
rubygems_version: 3.1.6
|
151
152
|
signing_key:
|