labimotion 1.4.1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) 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 +26 -0
  6. data/lib/labimotion/apis/standard_layer_api.rb +100 -0
  7. data/lib/labimotion/apis/vocabulary_api.rb +107 -0
  8. data/lib/labimotion/entities/dataset_entity.rb +2 -1
  9. data/lib/labimotion/entities/properties_entity.rb +167 -55
  10. data/lib/labimotion/entities/segment_entity.rb +1 -0
  11. data/lib/labimotion/entities/vocabulary_entity.rb +38 -0
  12. data/lib/labimotion/helpers/element_helpers.rb +8 -6
  13. data/lib/labimotion/helpers/param_helpers.rb +137 -82
  14. data/lib/labimotion/helpers/segment_helpers.rb +1 -1
  15. data/lib/labimotion/helpers/vocabulary_helpers.rb +16 -0
  16. data/lib/labimotion/libs/converter.rb +13 -33
  17. data/lib/labimotion/libs/data/vocab/Standard.json +385 -0
  18. data/lib/labimotion/libs/data/vocab/System.json +131 -0
  19. data/lib/labimotion/libs/nmr_mapper.rb +2 -1
  20. data/lib/labimotion/libs/sample_association.rb +4 -0
  21. data/lib/labimotion/libs/vocabulary_handler.rb +118 -0
  22. data/lib/labimotion/models/concerns/attachment_converter.rb +5 -4
  23. data/lib/labimotion/models/concerns/datasetable.rb +1 -0
  24. data/lib/labimotion/models/concerns/segmentable.rb +2 -0
  25. data/lib/labimotion/models/std_layer.rb +9 -0
  26. data/lib/labimotion/models/std_layers_revision.rb +9 -0
  27. data/lib/labimotion/models/vocabulary.rb +12 -0
  28. data/lib/labimotion/version.rb +1 -1
  29. data/lib/labimotion.rb +10 -0
  30. metadata +20 -5
@@ -6,94 +6,149 @@ module Labimotion
6
6
  ## Generic Helpers
7
7
  module ParamHelpers
8
8
  extend Grape::API::Helpers
9
- ## Element Klass Params
10
- params :upload_element_klass_params do
11
- requires :name, type: String, desc: 'Klass Name'
12
- optional :label, type: String, desc: 'Klass label'
13
- optional :desc, type: String, desc: 'Klass desc'
14
- optional :klass_prefix, type: String, desc: 'Klass klass_prefix'
15
- optional :icon_name, type: String, desc: 'Klass icon_name'
16
- requires :properties_template, type: Hash, desc: 'Klass template'
17
- optional :properties_release, type: Hash, desc: 'Klass release'
18
- optional :released_at, type: DateTime, desc: 'Klass released_at'
19
- requires :uuid, type: String, desc: 'Klass uuid'
20
- requires :place, type: Integer, desc: 'Klass place'
21
- requires :identifier, type: String, desc: 'Klass identifier'
22
- optional :sync_time, type: DateTime, desc: 'Klass sync_time'
23
- optional :version, type: String, desc: 'Klass version'
24
- end
9
+ ## Element Klass Params
10
+ params :upload_element_klass_params do
11
+ requires :name, type: String, desc: 'Klass Name'
12
+ optional :label, type: String, desc: 'Klass label'
13
+ optional :desc, type: String, desc: 'Klass desc'
14
+ optional :klass_prefix, type: String, desc: 'Klass klass_prefix'
15
+ optional :icon_name, type: String, desc: 'Klass icon_name'
16
+ requires :properties_template, type: Hash, desc: 'Klass template'
17
+ optional :properties_release, type: Hash, desc: 'Klass release'
18
+ optional :released_at, type: DateTime, desc: 'Klass released_at'
19
+ requires :uuid, type: String, desc: 'Klass uuid'
20
+ requires :place, type: Integer, desc: 'Klass place'
21
+ requires :identifier, type: String, desc: 'Klass identifier'
22
+ optional :sync_time, type: DateTime, desc: 'Klass sync_time'
23
+ optional :version, type: String, desc: 'Klass version'
24
+ end
25
25
 
26
- params :create_element_klass_params do
27
- requires :name, type: String, desc: 'Element Klass Name'
28
- requires :label, type: String, desc: 'Element Klass Label'
29
- requires :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
30
- optional :icon_name, type: String, desc: 'Element Klass Icon Name'
31
- optional :desc, type: String, desc: 'Element Klass Desc'
32
- optional :properties_template, type: Hash, desc: 'Element Klass properties template'
33
- end
26
+ params :create_element_klass_params do
27
+ requires :name, type: String, desc: 'Element Klass Name'
28
+ requires :label, type: String, desc: 'Element Klass Label'
29
+ requires :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
30
+ optional :icon_name, type: String, desc: 'Element Klass Icon Name'
31
+ optional :desc, type: String, desc: 'Element Klass Desc'
32
+ optional :properties_template, type: Hash, desc: 'Element Klass properties template'
33
+ end
34
34
 
35
- params :update_element_klass_params do
36
- requires :id, type: Integer, desc: 'Element Klass ID'
37
- optional :label, type: String, desc: 'Element Klass Label'
38
- optional :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
39
- optional :icon_name, type: String, desc: 'Element Klass Icon Name'
40
- optional :desc, type: String, desc: 'Element Klass Desc'
41
- optional :place, type: String, desc: 'Element Klass Place'
42
- end
35
+ params :update_element_klass_params do
36
+ requires :id, type: Integer, desc: 'Element Klass ID'
37
+ optional :label, type: String, desc: 'Element Klass Label'
38
+ optional :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
39
+ optional :icon_name, type: String, desc: 'Element Klass Icon Name'
40
+ optional :desc, type: String, desc: 'Element Klass Desc'
41
+ optional :place, type: String, desc: 'Element Klass Place'
42
+ end
43
43
 
44
- ## Element Params
45
- params :create_element_params do
46
- requires :element_klass, type: Hash
47
- requires :name, type: String
48
- optional :properties, type: Hash
49
- optional :properties_release, type: Hash
50
- optional :collection_id, type: Integer
51
- requires :container, type: Hash
52
- optional :user_labels, type: Array
53
- optional :segments, type: Array, desc: 'Segments'
54
- end
44
+ ## Element Params
45
+ params :create_element_params do
46
+ requires :element_klass, type: Hash
47
+ requires :name, type: String
48
+ optional :properties, type: Hash
49
+ optional :properties_release, type: Hash
50
+ optional :collection_id, type: Integer
51
+ requires :container, type: Hash
52
+ optional :user_labels, type: Array
53
+ optional :segments, type: Array, desc: 'Segments'
54
+ end
55
55
 
56
- params :update_element_params do
57
- requires :id, type: Integer, desc: 'element id'
58
- optional :name, type: String
59
- requires :properties, type: Hash
60
- optional :properties_release, type: Hash
61
- requires :container, type: Hash
62
- optional :user_labels, type: Array
63
- optional :segments, type: Array, desc: 'Segments'
64
- end
56
+ params :update_element_params do
57
+ requires :id, type: Integer, desc: 'element id'
58
+ optional :name, type: String
59
+ requires :properties, type: Hash
60
+ optional :properties_release, type: Hash
61
+ requires :container, type: Hash
62
+ optional :user_labels, type: Array
63
+ optional :segments, type: Array, desc: 'Segments'
64
+ end
65
65
 
66
- ## Segment Klass Params
67
- params :upload_segment_klass_params do
68
- requires :label, type: String, desc: 'Klass label'
69
- optional :desc, type: String, desc: 'Klass desc'
70
- requires :properties_template, type: Hash, desc: 'Klass template'
71
- optional :properties_release, type: Hash, desc: 'Klass release'
72
- optional :released_at, type: DateTime, desc: 'Klass released_at'
73
- requires :uuid, type: String, desc: 'Klass uuid'
74
- requires :place, type: Integer, desc: 'Klass place'
75
- requires :identifier, type: String, desc: 'Klass identifier'
76
- optional :sync_time, type: DateTime, desc: 'Klass sync_time'
77
- optional :version, type: String, desc: 'Klass version'
78
- requires :element_klass, type: Hash do
79
- use :upload_element_klass_params
80
- end
66
+ ## Segment Klass Params
67
+ params :upload_segment_klass_params do
68
+ requires :label, type: String, desc: 'Klass label'
69
+ optional :desc, type: String, desc: 'Klass desc'
70
+ requires :properties_template, type: Hash, desc: 'Klass template'
71
+ optional :properties_release, type: Hash, desc: 'Klass release'
72
+ optional :released_at, type: DateTime, desc: 'Klass released_at'
73
+ requires :uuid, type: String, desc: 'Klass uuid'
74
+ requires :place, type: Integer, desc: 'Klass place'
75
+ requires :identifier, type: String, desc: 'Klass identifier'
76
+ optional :sync_time, type: DateTime, desc: 'Klass sync_time'
77
+ optional :version, type: String, desc: 'Klass version'
78
+ requires :element_klass, type: Hash do
79
+ use :upload_element_klass_params
81
80
  end
81
+ end
82
82
 
83
- params :update_segment_klass_params do
84
- requires :id, type: Integer, desc: 'Segment Klass ID'
85
- optional :label, type: String, desc: 'Segment Klass Label'
86
- optional :desc, type: String, desc: 'Segment Klass Desc'
87
- optional :place, type: String, desc: 'Segment Klass Place', default: '100'
88
- optional :identifier, type: String, desc: 'Segment Identifier'
89
- end
83
+ params :update_segment_klass_params do
84
+ requires :id, type: Integer, desc: 'Segment Klass ID'
85
+ optional :label, type: String, desc: 'Segment Klass Label'
86
+ optional :desc, type: String, desc: 'Segment Klass Desc'
87
+ optional :place, type: String, desc: 'Segment Klass Place', default: '100'
88
+ optional :identifier, type: String, desc: 'Segment Identifier'
89
+ end
90
90
 
91
- params :create_segment_klass_params do
92
- requires :label, type: String, desc: 'Segment Klass Label'
93
- requires :element_klass, type: Integer, desc: 'Element Klass Id'
94
- optional :desc, type: String, desc: 'Segment Klass Desc'
95
- optional :place, type: String, desc: 'Segment Klass Place', default: '100'
96
- optional :properties_template, type: Hash, desc: 'Element Klass properties template'
97
- end
91
+ params :create_segment_klass_params do
92
+ requires :label, type: String, desc: 'Segment Klass Label'
93
+ requires :element_klass, type: Integer, desc: 'Element Klass Id'
94
+ optional :desc, type: String, desc: 'Segment Klass Desc'
95
+ optional :place, type: String, desc: 'Segment Klass Place', default: '100'
96
+ optional :properties_template, type: Hash, desc: 'Element Klass properties template'
97
+ end
98
+
99
+ params :create_std_layer_params do
100
+ requires :name, type: String, desc: 'Element Klass Name'
101
+ requires :label, type: String, desc: 'Element Klass Label'
102
+ requires :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
103
+ optional :icon_name, type: String, desc: 'Element Klass Icon Name'
104
+ optional :desc, type: String, desc: 'Element Klass Desc'
105
+ optional :properties_template, type: Hash, desc: 'Element Klass properties template'
106
+ end
107
+
108
+ params :std_layer_save do
109
+ requires :key, type: String, desc: 'key'
110
+ requires :cols, type: Integer, desc: 'key'
111
+ requires :label, type: String, desc: 'Label'
112
+ optional :position, type: Integer, desc: 'position'
113
+ optional :wf_position, type: Integer, desc: 'wf position'
114
+ optional :fields, type: Array, desc: 'fields'
115
+ optional :select_options, type: Hash, desc: 'selections'
116
+ end
117
+
118
+ params :std_layer_criteria do
119
+ requires :name, type: String, desc: 'Layer name'
120
+ end
121
+
122
+ params :vocab_save do
123
+ optional :name, type: String, desc: 'field'
124
+ optional :label, type: String, desc: 'Label'
125
+ optional :term_id, type: String, desc: 'ontology term_id'
126
+ requires :ontology, type: Hash, desc: 'ontology'
127
+ optional :source, type: String, desc: 'source'
128
+ optional :source_id, type: String, desc: 'source_id'
129
+ optional :layer_id, type: String, desc: 'layer_id'
130
+ optional :sub_fields, type: Array, desc: 'sub_fields'
131
+ optional :text_sub_fields, type: Array, desc: 'text_sub_fields'
132
+ requires :field_type, type: String, desc: 'field type'
133
+ requires :voc, type: Hash, desc: 'vocabulary references'
134
+ optional :select_options, type: Hash, desc: 'selections'
135
+ optional :option_layers, type: String, desc: 'option'
136
+ end
137
+
138
+ # params :vocabulary_save do
139
+ # requires :type, type: String, desc: 'type'
140
+ # requires :field, type: String, desc: 'field'
141
+ # optional :default, type: String, desc: 'default'
142
+ # optional :description, type: String, desc: 'description'
143
+ # optional :label, type: String, desc: 'label'
144
+ # optional :position, type: Integer, desc: 'position'
145
+ # optional :ontology, type: Hash, desc: 'ontology'
146
+ # optional :required, type: Boolean, desc: 'is required?'
147
+ # optional :sub_fields, type: Array, desc: 'sub_fields'
148
+ # optional :text_sub_fields, type: Array, desc: 'text_sub_fields'
149
+ # optional :source_type, type: String, desc: 'source type'
150
+ # optional :source_id, type: String, desc: 'source id'
151
+ # optional :layer_id, type: String, desc: 'layer id'
152
+ # end
98
153
  end
99
- end
154
+ end
@@ -72,7 +72,7 @@ module Labimotion
72
72
  # el_attributes['properties_template'] = response['element_klass']['properties_release']
73
73
  # Labimotion::ElementKlass.create!(el_attributes)
74
74
  attributes['element_klass_id'] = element_klass.id
75
- segment_klass = Labimotion::SegmentKlass.find_by(identifier: attributes['identifier'])
75
+ segment_klass = Labimotion::SegmentKlass.find_by(identifier: attributes['identifier']) if attributes['identifier'].present?
76
76
  if segment_klass.present?
77
77
  if segment_klass['uuid'] == attributes['uuid'] && segment_klass['version'] == attributes['version']
78
78
  return { status: 'success', message: "This segment: #{attributes['label']} has the latest version!" }
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ # Helper for associated sample
5
+ module VocabularyHelpers
6
+ extend Grape::API::Helpers
7
+
8
+ def update_vocabularies(properties, current_user, element)
9
+ Labimotion::VocabularyHandler.update_vocabularies(properties, current_user, element)
10
+ rescue StandardError => e
11
+ Labimotion.log_exception(e, current_user)
12
+ properties
13
+ end
14
+
15
+ end
16
+ end
@@ -28,7 +28,7 @@ module Labimotion
28
28
  dsr = []
29
29
  ols = nil
30
30
  Zip::File.open(att.attachment_attacher.file.url) do |zip_file|
31
- res = Labimotion::Converter.collect_metadata(zip_file) if att.filename.split('.')&.last == 'zip'
31
+ res = Labimotion::Converter.collect_metadata(zip_file, current_user) if att.filename.split('.')&.last == 'zip'
32
32
  ols = res[:o] unless res&.dig(:o).nil?
33
33
  dsr.push(res[:d]) unless res&.dig(:d).nil?
34
34
  end
@@ -92,7 +92,7 @@ module Labimotion
92
92
  { a: oa, f: folder }
93
93
  end
94
94
 
95
- def self.collect_metadata(zip_file) # rubocop: disable Metrics/PerceivedComplexity
95
+ def self.collect_metadata(zip_file, current_user = {}) # rubocop: disable Metrics/PerceivedComplexity
96
96
  dsr = []
97
97
  ols = nil
98
98
  zip_file.each do |entry|
@@ -114,7 +114,7 @@ module Labimotion
114
114
  { d: dsr, o: ols }
115
115
  end
116
116
 
117
- def self.handle_response(oat, response) # rubocop: disable Metrics/PerceivedComplexity
117
+ def self.handle_response(oat, response, current_user = {}) # rubocop: disable Metrics/PerceivedComplexity
118
118
  dsr = []
119
119
  ols = nil
120
120
 
@@ -123,10 +123,9 @@ module Labimotion
123
123
  tmp_file.write(response.parsed_response)
124
124
  tmp_file.rewind
125
125
 
126
- name = response&.headers && response&.headers['content-disposition']&.split('=')&.last
126
+ # name = response&.headers && response&.headers['content-disposition']&.split('=')&.last
127
127
  filename = oat.filename
128
128
  name = "#{File.basename(filename, '.*')}.zip"
129
-
130
129
  att = Attachment.new(
131
130
  filename: name,
132
131
  file_path: tmp_file.path,
@@ -140,7 +139,7 @@ module Labimotion
140
139
 
141
140
  att.save! if att.valid?
142
141
 
143
- process_ds(att.id)
142
+ process_ds(att.id, current_user)
144
143
  rescue StandardError => e
145
144
  raise e
146
145
  ensure
@@ -148,7 +147,7 @@ module Labimotion
148
147
  end
149
148
  end
150
149
 
151
- def self.process(data)
150
+ def self.process(data, current_user = {}) # rubocop: disable Metrics/PerceivedComplexity
152
151
  return data[:a].con_state if data[:a]&.attachable_type != 'Container'
153
152
  response = nil
154
153
  begin
@@ -165,25 +164,25 @@ module Labimotion
165
164
  )
166
165
  end
167
166
  if response.ok?
168
- Labimotion::Converter.handle_response(data[:a], response)
167
+ Labimotion::Converter.handle_response(data[:a], response, current_user)
169
168
  Labimotion::ConState::PROCESSED
170
169
  else
171
170
  Labimotion::Converter.logger.error ["Converter Response Error: id: [#{data[:a]&.id}], filename: [#{data[:a]&.filename}], response: #{response}"].join($INPUT_RECORD_SEPARATOR)
172
171
  Labimotion::ConState::ERROR
173
172
  end
174
173
  rescue StandardError => e
175
- Labimotion::Converter.logger.error ["process fail: [#{data[:a]&.id}]", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
174
+ Labimotion::Converter.logger.error ["process fail: #{data[:a]&.id}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
176
175
  Labimotion::ConState::ERROR
177
176
  ensure
178
177
  FileUtils.rm_f(ofile)
179
178
  end
180
179
  end
181
180
 
182
- def self.jcamp_converter(id)
181
+ def self.jcamp_converter(id, current_user = {})
183
182
  data = Labimotion::Converter.vor_conv(id)
184
183
  return if data.nil?
185
184
 
186
- Labimotion::Converter.process(data)
185
+ Labimotion::Converter.process(data, current_user)
187
186
  rescue StandardError => e
188
187
  Labimotion::Converter.logger.error ["jcamp_converter fail: #{id}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
189
188
  Labimotion::ConState::ERROR
@@ -243,27 +242,8 @@ module Labimotion
243
242
  fi['device'] = ds[:device] || ds[:value]
244
243
  new_prop[Labimotion::Prop::LAYERS][ds[:layer]][Labimotion::Prop::FIELDS][idx] = fi
245
244
  end
246
- new_prop.dig(Labimotion::Prop::LAYERS, 'general', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
247
- if fi['field'] == 'creator' && current_user.present?
248
- fi['value'] = current_user.name
249
- fi['system'] = current_user.name
250
- new_prop[Labimotion::Prop::LAYERS]['general'][Labimotion::Prop::FIELDS][idx] = fi
251
- end
252
- end
253
245
  element = Container.find(dataset.element_id)&.root_element
254
- element.present? && element&.class&.name == 'Sample' && new_prop.dig(Labimotion::Prop::LAYERS, 'sample_details', Labimotion::Prop::FIELDS)&.each_with_index do |fi, idx|
255
- if fi['field'] == 'id'
256
- fi['value'] = element.id
257
- fi['system'] = element.id
258
- new_prop[Labimotion::Prop::LAYERS]['sample_details'][Labimotion::Prop::FIELDS][idx] = fi
259
- end
260
-
261
- if fi['field'] == 'label'
262
- fi['value'] = element.short_label
263
- fi['system'] = element.short_label
264
- new_prop[Labimotion::Prop::LAYERS]['sample_details'][Labimotion::Prop::FIELDS][idx] = fi
265
- end
266
- end
246
+ new_prop = Labimotion::VocabularyHandler.update_vocabularies(new_prop, current_user, element)
267
247
  dataset.properties = new_prop
268
248
  dataset.save!
269
249
  end
@@ -325,13 +305,13 @@ module Labimotion
325
305
  res
326
306
  end
327
307
 
328
- def self.metadata(id)
308
+ def self.metadata(id, current_user)
329
309
  att = Attachment.find(id)
330
310
  return if att.nil? || att.attachable_id.nil? || att.attachable_type != Labimotion::Prop::CONTAINER
331
311
 
332
312
  ds = Labimotion::Dataset.find_by(element_type: Labimotion::Prop::CONTAINER, element_id: att.attachable_id)
333
313
  att.update_column(:con_state, Labimotion::ConState::COMPLETED) if ds.present?
334
- process_ds(att.id) if ds.nil?
314
+ process_ds(att.id, current_user) if ds.nil?
335
315
  end
336
316
  end
337
317
  end