labimotion 1.4.1 → 2.0.0.rc6

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/labimotion/apis/generic_element_api.rb +1 -0
  3. data/lib/labimotion/apis/generic_klass_api.rb +3 -2
  4. data/lib/labimotion/apis/labimotion_api.rb +13 -0
  5. data/lib/labimotion/apis/standard_api.rb +25 -0
  6. data/lib/labimotion/apis/standard_layer_api.rb +87 -0
  7. data/lib/labimotion/apis/vocabulary_api.rb +93 -0
  8. data/lib/labimotion/constants.rb +21 -0
  9. data/lib/labimotion/entities/dataset_entity.rb +1 -1
  10. data/lib/labimotion/entities/element_entity.rb +1 -0
  11. data/lib/labimotion/entities/properties_entity.rb +229 -56
  12. data/lib/labimotion/entities/segment_entity.rb +0 -1
  13. data/lib/labimotion/entities/vocabulary_entity.rb +28 -0
  14. data/lib/labimotion/helpers/element_helpers.rb +8 -6
  15. data/lib/labimotion/helpers/generic_helpers.rb +6 -1
  16. data/lib/labimotion/helpers/param_helpers.rb +121 -82
  17. data/lib/labimotion/helpers/segment_helpers.rb +1 -1
  18. data/lib/labimotion/helpers/vocabulary_helpers.rb +16 -0
  19. data/lib/labimotion/libs/converter.rb +12 -33
  20. data/lib/labimotion/libs/data/mapper/Chemwiki.json +236 -0
  21. data/lib/labimotion/libs/data/mapper/Source.json +78 -0
  22. data/lib/labimotion/libs/data/vocab/Standard.json +385 -0
  23. data/lib/labimotion/libs/data/vocab/System.json +131 -0
  24. data/lib/labimotion/libs/dataset_builder.rb +70 -0
  25. data/lib/labimotion/libs/export_dataset.rb +165 -66
  26. data/lib/labimotion/libs/nmr_mapper.rb +204 -246
  27. data/lib/labimotion/libs/sample_association.rb +4 -0
  28. data/lib/labimotion/libs/vocabulary_handler.rb +118 -0
  29. data/lib/labimotion/models/concerns/attachment_converter.rb +5 -4
  30. data/lib/labimotion/models/concerns/datasetable.rb +1 -0
  31. data/lib/labimotion/models/concerns/segmentable.rb +2 -0
  32. data/lib/labimotion/models/element.rb +3 -0
  33. data/lib/labimotion/models/std_layer.rb +9 -0
  34. data/lib/labimotion/models/std_layers_revision.rb +9 -0
  35. data/lib/labimotion/models/vocabulary.rb +12 -0
  36. data/lib/labimotion/utils/mapper_utils.rb +169 -0
  37. data/lib/labimotion/utils/utils.rb +22 -0
  38. data/lib/labimotion/version.rb +1 -1
  39. data/lib/labimotion.rb +13 -3
  40. metadata +25 -5
@@ -1,300 +1,258 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'labimotion/libs/dataset_builder'
3
4
  require 'labimotion/version'
5
+ require 'labimotion/utils/mapper_utils'
4
6
  require 'labimotion/utils/utils'
5
7
 
6
8
  module Labimotion
7
9
  ## NmrMapper
8
10
  class NmrMapper
9
- def self.process_ds(id, current_user = {})
10
- att = Attachment.find_by(id: id, con_state: Labimotion::ConState::NMR)
11
- return if att.nil?
12
-
13
- result = is_brucker_binary(id)
14
- if result[:is_bagit] == true
15
- att.update_column(:con_state, Labimotion::ConState::CONVERTED)
16
- Labimotion::Converter.metadata(id)
17
- Labimotion::ConState::COMPLETED
18
- elsif result[:metadata] == nil
19
- Labimotion::ConState::NONE
20
- else
21
- ds = Container.find_by(id: att.attachable_id)
22
- return if ds.nil? || ds.parent&.container_type != 'analysis'
23
-
24
- data = process(att, id, result[:metadata])
25
- generate_ds(id, att.attachable_id, data, current_user)
26
- Labimotion::ConState::COMPLETED
11
+ # Constants specific to NMR mapping
12
+ module Constants
13
+ # Duplicate fields that need special handling
14
+ DUP_FIELDS = %w[time version].freeze
15
+
16
+ # Field groups for different processing stages
17
+ FG_FINALIZE = %w[set.temperature general.date general.time software.Name software.Version].freeze
18
+ FG_SYSTEM = %w[general.creator sample_details.label sample_details.id].freeze
19
+
20
+ # Valid NMR nuclei types
21
+ OBSERVED = %w[1H 13C].freeze
22
+
23
+ # OLS terms for different NMR types
24
+ module OlsTerms
25
+ NMR_1H = 'CHMO:0000593'
26
+ NMR_13C = 'CHMO:0000595'
27
27
  end
28
28
  end
29
29
 
30
- def self.is_brucker_binary(id)
31
- att = Attachment.find_by(id: id, con_state: Labimotion::ConState::NMR)
32
- return if att.nil?
33
-
34
- if att&.attachment_attacher&.file&.url
35
- Zip::File.open(att.attachment_attacher.file.url) do |zip_file|
36
- zip_file.each do |entry|
37
- if entry.name.include?('/pdata/') && entry.name.include?('parm.txt')
38
- metadata = entry.get_input_stream.read.force_encoding('UTF-8')
39
- return { is_bagit: false, metadata: metadata }
40
- elsif entry.name.include?('metadata/') && entry.name.include?('converter.json')
41
- return { is_bagit: true, metadata: nil }
42
- end
43
- end
44
- end
45
- end
46
- { is_bagit: false, metadata: nil }
47
- end
30
+ class << self
31
+ def process_ds(id, current_user = {})
32
+ att = find_attachment(id)
33
+ return Labimotion::ConState::NONE if att.nil?
48
34
 
49
- def self.process(att, id, content)
50
- return if att.nil? || content.nil?
35
+ result = process(att)
36
+ return Labimotion::ConState::NONE if result.nil?
51
37
 
52
- lines = content.split("\n").reject(&:empty?)
53
- metadata = {}
54
- lines.map do |ln|
55
- arr = ln.split(/\s+/)
56
- metadata[arr[0]] = arr[1..-1].join(' ') if arr.length > 1
38
+ handle_process_result(result, att, id, current_user)
57
39
  end
58
- ols = 'CHMO:0000593' if metadata['NUC1'] == '1H'
59
- ols = 'CHMO:0000595' if metadata['NUC1'] == '13C'
60
-
61
- { content: { metadata: metadata, ols: ols } }
62
- # if content.present? && att.present?
63
- # Labimotion::NmrMapper.ts('write', att.attachable_id,
64
- # content: { metadata: metadata, ols: ols })
65
- # end
66
- end
67
40
 
68
- def self.fetch_content(id)
69
- atts = Attachment.where(attachable_id: id)
70
- return if atts.nil?
41
+ def process(att)
42
+ config = Labimotion::MapperUtils.load_brucker_config
43
+ return if config.nil?
44
+
45
+ attacher = att&.attachment_attacher
46
+ extracted_data = Labimotion::MapperUtils.extract_data_from_zip(attacher&.file&.url, config['sourceMap'])
47
+ return if extracted_data.nil?
71
48
 
72
- atts.each do |att|
73
- content = Labimotion::NmrMapper.ts('read', att.id)
74
- return content if content.present?
49
+ extracted_data[:parameters] = config['sourceMap']['parameters']
50
+ extracted_data
75
51
  end
76
- end
77
52
 
53
+ def generate_ds(_id, cid, data, current_user = {}, element = nil)
54
+ return if data.nil? || cid.nil?
78
55
 
79
- def self.generate_ds(id, cid, data, current_user = {})
80
- return if data.nil? || cid.nil?
56
+ obj = Labimotion::NmrMapper.build_ds(cid, data[:content])
57
+ return if obj.nil? || obj[:ols].nil?
81
58
 
82
- obj = Labimotion::NmrMapper.build_ds(cid, data[:content])
83
- return if obj.nil? || obj[:ols].nil?
59
+ Labimotion::NmrMapper.update_ds(cid, obj, current_user, element)
60
+ end
84
61
 
85
- Labimotion::NmrMapper.update_ds_1h(cid, obj, current_user) if obj[:ols] == 'CHMO:0000593'
86
- Labimotion::NmrMapper.update_ds_1h(cid, obj, current_user) if obj[:ols] == 'CHMO:0000595'
87
- end
62
+ def update_ds(_cid, obj, current_user, element)
63
+ dataset = obj[:dataset]
64
+ dataset.properties = process_prop(obj, current_user, element)
65
+ dataset.save!
66
+ end
88
67
 
89
- def self.update_ds_13c(id, obj)
90
- # dataset = obj[:dataset]
91
- # metadata = obj[:metadata]
92
- # new_prop = dataset.properties
68
+ def build_ds(id, content)
69
+ ds = find_container(id)
70
+ return if ds.nil? || content.nil?
93
71
 
94
- # dataset.properties = new_prop
95
- # dataset.save!
96
- end
72
+ Labimotion::DatasetBuilder.build(ds, content)
73
+ end
97
74
 
98
- def self.set_data(prop, field, idx, layer_name, field_name, value)
99
- return if field['field'] != field_name || value&.empty?
75
+ private
100
76
 
101
- field['value'] = value
102
- prop[Labimotion::Prop::LAYERS][layer_name][Labimotion::Prop::FIELDS][idx] = field
103
- prop
104
- end
77
+ def finalize_ds(new_prop)
78
+ Constants::FG_FINALIZE.each do |field_path|
79
+ field = Labimotion::Utils.find_field(new_prop, field_path)
80
+ next unless field
105
81
 
106
- def self.update_ds_1h(id, obj, current_user)
107
- dataset = obj[:dataset]
108
- metadata = obj[:metadata]
109
- new_prop = dataset.properties
110
- new_prop.dig(Labimotion::Prop::LAYERS, 'general', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
111
- # new_prop = set_data(new_prop, fi, idx, 'general', 'title', metadata['NAME'])
112
- if fi['field'] == 'title' && metadata['NAME'].present?
113
- ## fi['label'] = fi['label']
114
- fi['value'] = metadata['NAME']
115
- fi['device'] = metadata['NAME']
116
- fi['dkey'] = 'NAME'
117
- new_prop[Labimotion::Prop::LAYERS]['general'][Labimotion::Prop::FIELDS][idx] = fi
82
+ update_finalized_field(field)
118
83
  end
84
+ new_prop
85
+ end
119
86
 
120
- if fi['field'] == 'date' && metadata['Date_'].present?
121
- ## fi['label'] = fi['label']
122
- fi['value'] = metadata['Date_']
123
- fi['device'] = metadata['Date_']
124
- fi['dkey'] = 'Date_'
125
- new_prop[Labimotion::Prop::LAYERS]['general'][Labimotion::Prop::FIELDS][idx] = fi
126
- end
87
+ def sys_to_ds(new_prop, element, current_user)
88
+ Constants::FG_SYSTEM.each do |field_path|
89
+ field = Labimotion::Utils.find_field(new_prop, field_path)
90
+ next unless field
127
91
 
128
- if fi['field'] == 'time' && metadata['Time'].present?
129
- ## fi['label'] = fi['label']
130
- fi['value'] = metadata['Time']
131
- fi['device'] = metadata['Time']
132
- fi['dkey'] = 'Time'
133
- new_prop[Labimotion::Prop::LAYERS]['general'][Labimotion::Prop::FIELDS][idx] = fi
92
+ update_system_field(field, current_user, element)
134
93
  end
94
+ new_prop
95
+ end
96
+
97
+ def params_to_ds(obj, new_prop)
98
+ metadata = obj[:metadata]
99
+ parameters = obj[:parameters]
100
+
101
+ parameters.each do |param_key, field_path|
102
+ next if skip_parameter?(metadata, param_key)
135
103
 
136
- if fi['field'] == 'creator' && current_user.present?
137
- ## fi['label'] = fi['label']
138
- fi['value'] = current_user.name
139
- new_prop[Labimotion::Prop::LAYERS]['general'][Labimotion::Prop::FIELDS][idx] = fi
104
+ update_param_field(new_prop, field_path, param_key, metadata)
140
105
  end
106
+ new_prop
141
107
  end
142
- element = Container.find(id)&.root_element
143
- element.present? && element&.class&.name == 'Sample' && new_prop.dig(Labimotion::Prop::LAYERS, 'sample_details',
144
- Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
145
- if fi['field'] == 'label'
146
- fi['value'] = element.short_label
147
- new_prop[Labimotion::Prop::LAYERS]['sample_details'][Labimotion::Prop::FIELDS][idx] = fi
148
- end
149
- if fi['field'] == 'id'
150
- fi['value'] = element.id
151
- new_prop[Labimotion::Prop::LAYERS]['sample_details'][Labimotion::Prop::FIELDS][idx] = fi
152
- end
108
+
109
+ def process_prop(obj, current_user, element)
110
+ new_prop = obj[:dataset].properties
111
+ new_prop
112
+ .then { |prop| params_to_ds(obj, prop) }
113
+ .then { |prop| sys_to_ds(prop, element, current_user) }
114
+ .then { |prop| finalize_ds(prop) }
115
+ .then { |prop| Labimotion::VocabularyHandler.update_vocabularies(prop, current_user, element) }
153
116
  end
154
117
 
155
- new_prop.dig(Labimotion::Prop::LAYERS, 'instrument', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
156
- if fi['field'] == 'instrument' && metadata['INSTRUM'].present?
157
- ## fi['label'] = fi['label']
158
- fi['value'] = metadata['INSTRUM']
159
- fi['device'] = metadata['INSTRUM']
160
- fi['dkey'] = 'INSTRUM'
161
- new_prop[Labimotion::Prop::LAYERS]['instrument'][Labimotion::Prop::FIELDS][idx] = fi
162
- end
118
+ def find_attachment(id)
119
+ Attachment.find_by(id: id, con_state: Labimotion::ConState::NMR)
163
120
  end
164
121
 
165
- new_prop.dig(Labimotion::Prop::LAYERS, 'equipment', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
166
- if fi['field'] == 'probehead' && metadata['PROBHD'].present?
167
- ## fi['label'] = fi['label']
168
- fi['value'] = metadata['PROBHD']
169
- fi['device'] = metadata['PROBHD']
170
- fi['dkey'] = 'PROBHD'
171
- new_prop[Labimotion::Prop::LAYERS]['equipment'][Labimotion::Prop::FIELDS][idx] = fi
122
+ def handle_process_result(result, att, id, current_user)
123
+ if result[:is_bagit]
124
+ handle_bagit_result(att, id, current_user)
125
+ elsif invalid_metadata?(result)
126
+ Labimotion::ConState::NONE
127
+ else
128
+ handle_nmr_result(result, att, current_user)
172
129
  end
173
130
  end
174
131
 
175
- new_prop.dig(Labimotion::Prop::LAYERS, 'sample_preparation', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
176
- if fi['field'] == 'solvent' && metadata['SOLVENT'].present?
177
- ## fi['label'] = fi['label']
178
- fi['value'] = metadata['SOLVENT']
179
- fi['device'] = metadata['SOLVENT']
180
- fi['dkey'] = 'SOLVENT'
181
- fi['value'] = 'chloroform-D1 (CDCl3)' if metadata['SOLVENT'] == 'CDCl3'
182
- new_prop[Labimotion::Prop::LAYERS]['sample_preparation'][Labimotion::Prop::FIELDS][idx] = fi
183
- end
132
+ def handle_bagit_result(att, id, current_user)
133
+ att.update_column(:con_state, Labimotion::ConState::CONVERTED)
134
+ Labimotion::Converter.metadata(id, current_user)
135
+ Labimotion::ConState::COMPLETED
184
136
  end
185
137
 
186
- new_prop.dig(Labimotion::Prop::LAYERS, 'set', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
187
- if fi['field'] == 'temperature' && metadata['TE'].present?
188
- ## fi['label'] = fi['label']
189
- fi['value'] = metadata['TE'].split(/\s+/).first
190
- fi['device'] = metadata['TE']
191
- fi['dkey'] = 'TE'
192
- fi['value_system'] = metadata['TE'].split(/\s+/).last
193
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
194
- end
195
- if fi['field'] == 'ns' && metadata['NS'].present?
196
- ## fi['label'] = fi['label']
197
- fi['value'] = metadata['NS']
198
- fi['device'] = metadata['NS']
199
- fi['dkey'] = 'NS'
200
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
201
- end
202
- if fi['field'] == 'PULPROG' && metadata['PULPROG'].present?
203
- ## fi['label'] = fi['label']
204
- fi['value'] = metadata['PULPROG']
205
- fi['device'] = metadata['PULPROG']
206
- fi['dkey'] = 'PULPROG'
207
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
208
- end
209
- if fi['field'] == 'td' && metadata['TD'].present?
210
- ## fi['label'] = fi['label']
211
- fi['value'] = metadata['TD']
212
- fi['device'] = metadata['TD']
213
- fi['dkey'] = 'TD'
214
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
215
- end
216
- if fi['field'] == 'done' && metadata['D1'].present?
217
- ## fi['label'] = fi['label']
218
- fi['value'] = metadata['D1']
219
- fi['device'] = metadata['D1']
220
- fi['dkey'] = 'D1'
221
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
222
- end
223
- if fi['field'] == 'sf' && metadata['SF'].present?
224
- ## fi['label'] = fi['label']
225
- fi['value'] = metadata['SF']
226
- fi['device'] = metadata['SF']
227
- fi['dkey'] = 'SF'
228
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
138
+ def invalid_metadata?(result)
139
+ result[:metadata].nil? ||
140
+ Constants::OBSERVED.exclude?(result[:metadata]['NUC1'])
141
+ end
142
+
143
+ def handle_nmr_result(result, att, current_user)
144
+ ds = find_container(att.attachable_id)
145
+ return Labimotion::ConState::NONE unless valid_container?(ds)
146
+
147
+ prepare_mapper_result(ds, result, current_user)
148
+ Labimotion::ConState::COMPLETED
149
+ end
150
+
151
+ def find_container(cid)
152
+ Container.find_by(id: cid)
153
+ end
154
+
155
+ def valid_container?(container)
156
+ container.present? &&
157
+ container.parent&.container_type == 'analysis' &&
158
+ container.root_element.present?
159
+ end
160
+
161
+ def prepare_mapper_result(container, result, current_user)
162
+ metadata = result[:metadata]
163
+ ols = determine_ols_term(metadata['NUC1'])
164
+
165
+ data = {
166
+ content: {
167
+ metadata: metadata,
168
+ ols: ols,
169
+ parameters: result[:parameters]
170
+ }
171
+ }
172
+
173
+ generate_ds(nil, container.id, data, current_user, container.root_element)
174
+ end
175
+
176
+ def determine_ols_term(nuc1)
177
+ case nuc1
178
+ when '1H' then Constants::OlsTerms::NMR_1H
179
+ when '13C' then Constants::OlsTerms::NMR_13C
229
180
  end
230
- if fi['field'] == 'sfoone' && metadata['SFO1'].present?
231
- ## fi['label'] = fi['label']
232
- fi['value'] = metadata['SFO1']
233
- fi['device'] = metadata['SFO1']
234
- fi['dkey'] = 'SFO1'
235
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
181
+ end
182
+
183
+ def skip_parameter?(metadata, param_key)
184
+ metadata[param_key.to_s].blank? &&
185
+ Constants::DUP_FIELDS.exclude?(param_key.to_s.downcase)
186
+ end
187
+
188
+ def update_param_field(properties, field_path, param_key, metadata)
189
+ field = Labimotion::Utils.find_field(properties, field_path)
190
+ return unless field
191
+
192
+ update_field_value(field, param_key, metadata)
193
+ update_field_extend(field, param_key, metadata)
194
+ end
195
+
196
+ def update_duplicate_field(field_name, metadata)
197
+ case field_name
198
+ when 'time' then metadata['DATE']
199
+ when 'Version' then metadata['TITLE']
236
200
  end
237
- if fi['field'] == 'sfotwo' && metadata['SFO2'].present?
238
- ## fi['label'] = fi['label']
239
- fi['value'] = metadata['SFO2']
240
- fi['device'] = metadata['SFO2']
241
- fi['dkey'] = 'SFO2'
242
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
201
+ end
202
+
203
+ def update_field_value(field, param_key, metadata)
204
+ field['value'] = format_field_value(field, param_key, metadata)
205
+ rescue StandardError => e
206
+ Rails.logger.error "Error converting value for #{param_key}: #{e.message}"
207
+ field['value'] = ''
208
+ end
209
+
210
+ def format_field_value(field, param_key, metadata)
211
+ if field['type'] == 'integer'
212
+ Integer(metadata[param_key.to_s])
213
+ elsif Constants::DUP_FIELDS.include?(param_key.to_s.downcase)
214
+ update_duplicate_field(field['field'], metadata)
215
+ else
216
+ metadata[param_key.to_s]
243
217
  end
244
- if fi['field'] == 'nucone' && metadata['NUC1'].present?
245
- ## fi['label'] = fi['label']
246
- fi['value'] = metadata['NUC1']
247
- fi['device'] = metadata['NUC1']
248
- fi['dkey'] = 'NUC1'
249
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
218
+ end
219
+
220
+ def update_finalized_field(field)
221
+ case field['field']
222
+ when 'temperature'
223
+ field['value_system'] = 'K'
224
+ when 'date', 'time'
225
+ field['value'] = Labimotion::MapperUtils.format_timestamp(field['value'], field['field'])
226
+ when 'Name'
227
+ field['value'] = 'TopSpin' if field['value'].to_s.include?('TopSpin')
228
+ when 'Version'
229
+ field['value'] = field['value'].to_s.split('TopSpin').last.strip if field['value'].to_s.include?('TopSpin')
250
230
  end
251
- if fi['field'] == 'nuctwo' && metadata['NUC2'].present?
252
- ## fi['label'] = fi['label']
253
- fi['value'] = metadata['NUC2']
254
- fi['device'] = metadata['NUC2']
255
- fi['dkey'] = 'NUC2'
256
- new_prop[Labimotion::Prop::LAYERS]['set'][Labimotion::Prop::FIELDS][idx] = fi
231
+ end
232
+
233
+ def update_system_field(field, current_user, element)
234
+ field['value'] = determine_field_value(field['field'], current_user, element)
235
+ end
236
+
237
+ def determine_field_value(field_name, current_user, element)
238
+ case field_name
239
+ when 'creator'
240
+ current_user&.name if current_user.present?
241
+ when 'label', 'id'
242
+ get_sample_value(field_name, element)
257
243
  end
258
244
  end
259
- dataset.properties = new_prop
260
- dataset.save!
261
- end
262
245
 
263
- def self.ts(method, identifier, params = nil)
264
- Rails.cache.send(method, "#{Labimotion::NmrMapper.new.class.name}#{identifier}", params)
265
- end
246
+ def get_sample_value(field_name, element)
247
+ return unless element.present? && element.is_a?(Sample)
266
248
 
267
- def self.clean(id)
268
- Labimotion::NmrMapper.ts('delete', id)
269
- end
249
+ field_name == 'label' ? element.short_label : element.id
250
+ end
270
251
 
271
- def self.build_ds(id, content)
272
- ds = Container.find_by(id: id)
273
- return if ds.nil? || content.nil?
274
-
275
- ols = content[:ols]
276
- metadata = content[:metadata]
277
-
278
- return if ols.nil? || metadata.nil?
279
-
280
- klass = Labimotion::DatasetKlass.find_by(ols_term_id: ols)
281
- return if klass.nil?
282
-
283
- uuid = SecureRandom.uuid
284
- props = klass.properties_release
285
- props['uuid'] = uuid
286
- props['pkg'] = Labimotion::Utils.pkg(props['pkg'])
287
- props['klass'] = 'Dataset'
288
- dataset = Labimotion::Dataset.create!(
289
- uuid: uuid,
290
- dataset_klass_id: klass.id,
291
- element_type: 'Container',
292
- element_id: ds.id,
293
- properties: props,
294
- properties_release: klass.properties_release,
295
- klass_uuid: klass.uuid,
296
- )
297
- { dataset: dataset, metadata: metadata, ols: ols }
252
+ def update_field_extend(field, param_key, metadata)
253
+ field['device'] = metadata[param_key.to_s]
254
+ field['dkey'] = param_key.to_s
255
+ end
298
256
  end
299
257
  end
300
258
  end
@@ -78,6 +78,8 @@ module Labimotion
78
78
  field_samples = layer[Labimotion::Prop::FIELDS].select { |ss| ss['type'] == Labimotion::FieldType::DRAG_SAMPLE }
79
79
  field_samples.each do |field|
80
80
  idx = properties[Labimotion::Prop::LAYERS][key][Labimotion::Prop::FIELDS].index(field)
81
+ return if field.is_a?(String) || properties.is_a?(String)
82
+
81
83
  sid = field.dig('value', 'el_id')
82
84
  next if sid.blank?
83
85
 
@@ -100,6 +102,8 @@ module Labimotion
100
102
  field_elements = layer[Labimotion::Prop::FIELDS].select { |ss| ss['type'] == Labimotion::FieldType::DRAG_ELEMENT }
101
103
  field_elements.each do |field|
102
104
  idx = properties[Labimotion::Prop::LAYERS][key][Labimotion::Prop::FIELDS].index(field)
105
+ next if field['value'].is_a?(String)
106
+
103
107
  sid = field.dig('value', 'el_id')
104
108
  next if element.nil? || sid.blank? || sid == element.id
105
109
 
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class VocabularyHandler
5
+ class << self
6
+ def update_vocabularies(properties, current_user, element)
7
+ properties[Labimotion::Prop::LAYERS].each do |key, layer|
8
+ update_layer_vocabularies(layer, key, properties, current_user, element)
9
+ end
10
+ properties
11
+ rescue StandardError => e
12
+ Labimotion.log_exception(e, current_user)
13
+ properties
14
+ end
15
+
16
+ def load_all_vocabularies
17
+ load_from_files + load_from_database
18
+ end
19
+
20
+ def load_app_vocabularies
21
+ load_from_files
22
+ end
23
+
24
+ private
25
+
26
+ def update_layer_vocabularies(layer, key, properties, current_user, element)
27
+ field_vocabularies = layer[Labimotion::Prop::FIELDS].select { |field| field['is_voc'] }
28
+ field_vocabularies.each do |field|
29
+ idx = layer[Labimotion::Prop::FIELDS].index(field)
30
+ val = get_vocabulary_value(field, current_user, element)
31
+ update_field_value(properties, key, idx, val) if val.present?
32
+ end
33
+ end
34
+
35
+ def get_vocabulary_value(field, current_user, element)
36
+ case field['source']
37
+ when 'System'
38
+ get_system_value(field)
39
+ when 'User'
40
+ get_user_value(field, current_user)
41
+ when 'Element'
42
+ get_element_value(field, element)
43
+ when 'Segment'
44
+ get_segment_value(field, element)
45
+ when 'Dataset'
46
+ # TODO: Implement Dataset logic here
47
+ nil
48
+ end
49
+ end
50
+
51
+ def get_system_value(field)
52
+ current_time = Time.now.strftime('%d/%m/%Y %H:%M')
53
+ case field['identifier']
54
+ when 'dateTime-update'
55
+ current_time
56
+ when 'dateTime-create'
57
+ current_time if field['value'].blank?
58
+ end
59
+ end
60
+
61
+ def get_user_value(field, current_user)
62
+ current_user.name if field['identifier'] == 'user-name' && current_user.present?
63
+ end
64
+
65
+ def get_element_value(field, element)
66
+ case field['identifier']
67
+ when 'element-id'
68
+ element.id.to_s
69
+ when 'element-short_label'
70
+ element.short_label if element.has_attribute?(:short_label)
71
+ when 'element-name'
72
+ element.name if element.has_attribute?(:name)
73
+ when 'element-class'
74
+ element.class.name === 'Labimotion::Element' ? element.element_klass.label : element.class.name
75
+ else
76
+ ek = element.element_klass
77
+ return if ek.nil? || ek.identifier != field['source_id']
78
+
79
+ el_prop = element.properties
80
+ fields = el_prop[Labimotion::Prop::LAYERS][field['layer_id']][Labimotion::Prop::FIELDS]
81
+ fields.find { |ss| ss['field'] == field['field_id'] }&.dig('value')
82
+ end
83
+ end
84
+
85
+ def get_segment_value(field, element)
86
+ segments = element.segments.joins(:segment_klass).find_by('segment_klasses.identifier = ?', field['source_id'])
87
+ return if segments.nil?
88
+
89
+ seg_prop = segments.properties
90
+ fields = seg_prop[Labimotion::Prop::LAYERS][field['layer_id']][Labimotion::Prop::FIELDS]
91
+ fields.find { |ss| ss['field'] == field['field_id'] }&.dig('value')
92
+ end
93
+
94
+ def update_field_value(properties, key, idx, val)
95
+ properties[Labimotion::Prop::LAYERS][key][Labimotion::Prop::FIELDS][idx]['value'] = val
96
+ properties
97
+ end
98
+
99
+ def load_from_files
100
+ merged_data = []
101
+ merged_data.concat(load_json_file('System.json'))
102
+ merged_data.concat(load_json_file('Standard.json'))
103
+ merged_data
104
+ end
105
+
106
+ def load_json_file(filename)
107
+ file_path = File.join(__dir__, 'data', 'vocab', filename)
108
+ file_content = File.read(file_path)
109
+ JSON.parse(file_content)
110
+ end
111
+
112
+ def load_from_database
113
+ vocabularies = Labimotion::Vocabulary.all.sort_by(&:name)
114
+ Labimotion::VocabularyEntity.represent(vocabularies, serializable: true)
115
+ end
116
+ end
117
+ end
118
+ end