labimotion 2.3.4 → 2.4.0.rc1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -39
  3. data/lib/labimotion/apis/element_variation_api.rb +3 -58
  4. data/lib/labimotion/apis/exporter_api.rb +19 -2
  5. data/lib/labimotion/apis/generic_dataset_api.rb +1 -3
  6. data/lib/labimotion/apis/generic_element_api.rb +38 -14
  7. data/lib/labimotion/apis/segment_api.rb +1 -5
  8. data/lib/labimotion/collection/import.rb +3 -36
  9. data/lib/labimotion/constants.rb +0 -6
  10. data/lib/labimotion/entities/application_entity.rb +1 -5
  11. data/lib/labimotion/entities/generic_klass_entity.rb +0 -11
  12. data/lib/labimotion/entities/properties_entity.rb +28 -0
  13. data/lib/labimotion/helpers/element_helpers.rb +9 -37
  14. data/lib/labimotion/helpers/generic_helpers.rb +4 -9
  15. data/lib/labimotion/helpers/param_helpers.rb +1 -0
  16. data/lib/labimotion/libs/converter.rb +23 -100
  17. data/lib/labimotion/libs/dataset_builder.rb +1 -1
  18. data/lib/labimotion/libs/linked_element.rb +193 -0
  19. data/lib/labimotion/libs/nmr_mapper.rb +4 -34
  20. data/lib/labimotion/models/concerns/attachment_converter.rb +0 -24
  21. data/lib/labimotion/models/concerns/datasetable.rb +5 -16
  22. data/lib/labimotion/models/concerns/element_fetchable.rb +2 -3
  23. data/lib/labimotion/models/concerns/segmentable.rb +5 -24
  24. data/lib/labimotion/models/element.rb +2 -3
  25. data/lib/labimotion/utils/mapper_utils.rb +5 -30
  26. data/lib/labimotion/utils/prop.rb +0 -8
  27. data/lib/labimotion/utils/units.rb +32 -67
  28. data/lib/labimotion/version.rb +1 -1
  29. data/lib/labimotion.rb +1 -13
  30. metadata +5 -26
  31. data/lib/labimotion/helpers/export_authorization_helpers.rb +0 -39
  32. data/lib/labimotion/libs/element_variation_column_set.rb +0 -426
  33. data/lib/labimotion/libs/element_variation_header.rb +0 -119
  34. data/lib/labimotion/libs/export_element_variations.rb +0 -245
  35. data/lib/labimotion/libs/export_tpa_segments.rb +0 -53
  36. data/lib/labimotion/libs/import_element_variations.rb +0 -411
  37. data/lib/labimotion/libs/klass_version.rb +0 -66
  38. data/lib/labimotion/libs/release_metadata.rb +0 -64
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'labimotion/utils/utils'
4
4
  require 'labimotion/libs/attachment_handler'
5
- require 'labimotion/libs/klass_version'
6
5
 
7
6
  module Labimotion
8
7
  # Segmentable concern
@@ -47,14 +46,6 @@ module Labimotion
47
46
  end
48
47
  end
49
48
 
50
- # The release a new segment was built on: its properties first, then the template the client
51
- # loaded, then the klass_uuid a copied row carried.
52
- def submitted_segment_uuid(seg, props)
53
- segment_klass = seg['segment_klass']
54
- [props['klass_uuid'], (segment_klass['uuid'] if segment_klass.is_a?(Hash)), seg['klass_uuid']]
55
- .map { |uuid| Labimotion::KlassVersion.string_uuid(uuid) }.find(&:present?)
56
- end
57
-
58
49
  def touch_vocabulary(current_user)
59
50
  touch_element_properties(current_user) if instance_of?(::Labimotion::Element)
60
51
  touch_segments_properties(current_user)
@@ -66,10 +57,7 @@ module Labimotion
66
57
 
67
58
  current_user = User.find_by(id: args[:current_user_id])
68
59
  args_segments.each do |seg|
69
- # A deleted template has already taken its segments with it, so there is nothing to save.
70
- klass = Labimotion::SegmentKlass.with_deleted.find_by(id: seg['segment_klass_id'])
71
- next if klass.nil? || klass.deleted_at.present?
72
-
60
+ klass = Labimotion::SegmentKlass.find_by(id: seg['segment_klass_id'])
73
61
  uuid = SecureRandom.uuid
74
62
  props = seg['properties']
75
63
  props['pkg'] = Labimotion::Utils.pkg(props['pkg'])
@@ -79,22 +67,15 @@ module Labimotion
79
67
  props = Labimotion::SampleAssociation.update_sample_association(props, args[:current_user_id])
80
68
  # props = Labimotion::VocabularyHandler.update_vocabularies(props, current_user, self)
81
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
82
- # Like an element update, an existing segment reads the release from its properties alone.
83
- submitted_uuid = segment.nil? ? submitted_segment_uuid(seg, props) : props['klass_uuid']
84
- klass_uuid, release =
85
- Labimotion::KlassVersion.for_record(klass, klass.segment_klasses_revisions, submitted_uuid, segment,
86
- client_release: seg['properties_release'])
87
- # props is persisted as submitted, so the resolved value goes back in: otherwise a
88
- # payload without klass_uuid stores a segment whose column and properties disagree.
89
- props['klass_uuid'] = klass_uuid if klass_uuid.present?
90
- if segment.present? && (segment.klass_uuid != klass_uuid || segment.properties != props)
91
- segment.update!(properties_release: release, properties: props, uuid: uuid, klass_uuid: klass_uuid, metadata: seg['metadata'] || {})
70
+ if segment.present? && (segment.klass_uuid != props['klass_uuid'] || segment.properties != props)
71
+ segment.update!(properties_release: klass.properties_release, properties: props, uuid: uuid, klass_uuid: props['klass_uuid'], metadata: seg['metadata'] || {})
92
72
  # segments.push(segment)
93
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
94
74
  end
95
75
  next if segment.present?
96
76
 
97
- segment = Labimotion::Segment.create!(properties_release: 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, metadata: seg['metadata'] || {})
77
+ props['klass_uuid'] = klass.uuid
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, metadata: seg['metadata'] || {})
98
79
  # segments.push(segment)
99
80
  end
100
81
 
@@ -141,10 +141,9 @@ module Labimotion
141
141
  joins(collections: :user).where(collections: { user_id: user_id })
142
142
  )
143
143
 
144
- # Shared elements — collection_shares hangs off Collection, not off
145
- # Element itself, so join through the collections association.
144
+ # Shared elements
146
145
  shared = apply_filters.call(
147
- left_joins(collections: :collection_shares).where(collection_shares: { shared_with_id: user_id })
146
+ left_joins(:collection_shares).where(collection_shares: { shared_with_id: user_id })
148
147
  )
149
148
 
150
149
  # Combine (remove duplicates), order, and limit
@@ -6,18 +6,8 @@ require 'zip'
6
6
  require 'labimotion/constants'
7
7
 
8
8
  module Labimotion
9
- # rubyzip 2.x does not detect encrypted entries and would inflate them as garbage
10
- class EncryptedZipError < Zip::Error; end
11
-
12
9
  class MapperUtils
13
10
  class << self
14
- # Read an entry and close its stream, so no handle on the stored file stays open
15
- def read_entry(entry)
16
- raise EncryptedZipError, "Encrypted zip entry: #{entry.name}" if entry.encrypted?
17
-
18
- entry.get_input_stream(&:read)
19
- end
20
-
21
11
  def load_config(config_json)
22
12
  JSON.parse(config_json)
23
13
  rescue JSON::ParserError => e
@@ -47,18 +37,7 @@ module Labimotion
47
37
  def extract_data_from_zip(zip_file_url, source_map)
48
38
  return nil if zip_file_url.nil?
49
39
 
50
- # nil means nothing to map; errors are raised so the caller can record ERROR
51
40
  process_zip_file(zip_file_url, source_map)
52
- end
53
-
54
- def check_if_bagit(zip_file_url)
55
- return nil if zip_file_url.nil?
56
- Zip::File.open(zip_file_url) do |zip_file|
57
- zip_file.each do |entry|
58
- return { is_bagit: true, metadata: nil } if bagit_metadata_file?(entry)
59
- end
60
- end
61
-
62
41
  rescue Zip::Error => e
63
42
  Rails.logger.error "Zip file error: #{e.message}"
64
43
  nil
@@ -188,12 +167,10 @@ module Labimotion
188
167
  def process_zip_file(zip_file_url, source_map)
189
168
  final_parameters = {}
190
169
 
191
- # Never close: closing can rewrite the stored file in place
192
- zip_file = Zip::File.new(zip_file_url)
193
- source_map['sourceSelector'].each do |source_name|
194
- result = process_source(zip_file, source_map[source_name], final_parameters)
195
- # A BagIt zip is mapped by the converter instead
196
- return result if result&.dig(:is_bagit)
170
+ Zip::File.open(zip_file_url) do |zip_file|
171
+ source_map['sourceSelector'].each do |source_name|
172
+ process_source(zip_file, source_map[source_name], final_parameters)
173
+ end
197
174
  end
198
175
 
199
176
  return { is_bagit: false, metadata: final_parameters } if final_parameters.present?
@@ -205,8 +182,6 @@ module Labimotion
205
182
  return if invalid_source_config?(source_config)
206
183
 
207
184
  zip_file.each do |entry|
208
- next if entry.directory?
209
-
210
185
  if source_file?(entry, source_config)
211
186
  process_file_entry(entry, source_config, final_parameters)
212
187
  elsif bagit_metadata_file?(entry)
@@ -216,7 +191,7 @@ module Labimotion
216
191
  end
217
192
 
218
193
  def process_file_entry(entry, source_config, final_parameters)
219
- file_content = read_entry(entry).force_encoding(Constants::File::ENCODING)
194
+ file_content = entry.get_input_stream.read.force_encoding(Constants::File::ENCODING)
220
195
  extracted_parameters = extract_parameters(file_content, source_config['parameters'])
221
196
  final_parameters.merge!(extracted_parameters) if extracted_parameters.present?
222
197
 
@@ -1,7 +1,6 @@
1
1
  module Labimotion
2
2
  ## Converter State
3
3
  class Prop
4
- CONVERTER_FIELD_UINT_PREFIX = '___unit___'.freeze
5
4
  LAYERS = 'layers'.freeze
6
5
  FIELDS = 'fields'.freeze
7
6
  SUBFIELDS = 'sub_fields'.freeze
@@ -19,17 +18,10 @@ module Labimotion
19
18
  SAMPLE = 'Sample'.freeze
20
19
  MOLECULE = 'Molecule'.freeze
21
20
  REACTION = 'Reaction'.freeze
22
- RESEARCH_PLAN = 'ResearchPlan'.freeze
23
- SCREEN = 'Screen'.freeze
24
21
  CONTAINER = 'Container'.freeze
25
22
  ELEMENTPROPS = 'ElementProps'.freeze
26
23
  SEGMENTPROPS = 'SegmentProps'.freeze
27
24
  DATASETPROPS = 'DatasetProps'.freeze
28
25
  UPLOADPROPS = [ELEMENTPROPS, SEGMENTPROPS, DATASETPROPS].freeze
29
- # att_type accepted by upload_generics_files => class name of the element it names
30
- UPLOAD_ELEMENT_TYPES = {
31
- ELEMENT => L_ELEMENT, SAMPLE => SAMPLE, REACTION => REACTION, RESEARCH_PLAN => RESEARCH_PLAN,
32
- SCREEN => SCREEN
33
- }.freeze
34
26
  end
35
27
  end
@@ -9,7 +9,7 @@ module Labimotion
9
9
  "default": "",
10
10
  "position": 10,
11
11
  "placeholder": "acceleration",
12
- "units": [{ "key": "mm_s2", "label": "mm/s²" }]
12
+ "units": [{ "key": "mm_s2", "label": "mm/s<sup>2</sup>" }]
13
13
  },
14
14
  {
15
15
  "type": "numeric",
@@ -59,10 +59,10 @@ module Labimotion
59
59
  "position": 38,
60
60
  "placeholder": "areal density",
61
61
  "units": [
62
- { "key": "kg_m2", "label": "kg m⁻²", "nm": 1 },
63
- { "key": "t_m2", "label": "t m⁻²", "nm": 0.001 },
64
- { "key": "kg_cm2", "label": "kg cm⁻²", "nm": 1e-4 },
65
- { "key": "g_m2", "label": "g m⁻²", "nm": 1000 }
62
+ { "key": "kg_m2", "label": "kg m<sup>-2</sup>", "nm": 1 },
63
+ { "key": "t_m2", "label": "t m<sup>-2</sup>", "nm": 0.001 },
64
+ { "key": "kg_cm2", "label": "kg cm<sup>-2</sup>", "nm": 1e-4 },
65
+ { "key": "g_m2", "label": "g m<sup>-2</sup>", "nm": 1000 }
66
66
  ]
67
67
  },
68
68
  {
@@ -97,7 +97,7 @@ module Labimotion
97
97
  "position": 60,
98
98
  "placeholder": "concentration",
99
99
  "units": [
100
- { "key": "ng_l", "label": "ng/L", "nm": 1000000000 },
100
+ { "key": "ng_l", "label": "ng/L", "nm": 1000000 },
101
101
  { "key": "mg_l", "label": "mg/L", "nm": 1000 },
102
102
  { "key": "g_l", "label": "g/L", "nm": 1 }
103
103
  ]
@@ -171,7 +171,7 @@ module Labimotion
171
171
  "position": 75,
172
172
  "placeholder": "density",
173
173
  "units": [
174
- { "key": "g_cm3", "label": "g/cm³", "nm": 1 },
174
+ { "key": "g_cm3", "label": "g/cm<sup>3</sup>", "nm": 1 },
175
175
  { "key": "kg_l", "label": "kg/l", "nm": 1 }
176
176
  ]
177
177
  },
@@ -198,8 +198,7 @@ module Labimotion
198
198
  { "key": "d", "label": "d", "nm": 1 },
199
199
  { "key": "h", "label": "h", "nm": 24 },
200
200
  { "key": "min", "label": "m", "nm": 1440 },
201
- { "key": "s", "label": "s", "nm": 86400 },
202
- { "key": "y", "label": "y", "nm": 0.0027378507871321013 }
201
+ { "key": "s", "label": "s", "nm": 86400 }
203
202
  ]
204
203
  },
205
204
  {
@@ -281,8 +280,7 @@ module Labimotion
281
280
  { "key": "eV", "label": "eV", "nm": 6.241509e21 },
282
281
  { "key": "keV", "label": "keV", "nm": 6.241509e18 },
283
282
  { "key": "j", "label": "J", "nm": 1000 },
284
- { "key": "k_j", "label": "kJ", "nm": 1 },
285
- { "key": "kWh", "label": "kWh", "nm": 2.7777778e-4 }
283
+ { "key": "k_j", "label": "kJ", "nm": 1 }
286
284
  ]
287
285
  },
288
286
  {
@@ -359,9 +357,9 @@ module Labimotion
359
357
  { "key": "k_min", "label": "K/min", "nm": 1 },
360
358
  { "key": "k_s", "label": "K/s", "nm": 0.016666666666667 },
361
359
  { "key": "k_h", "label": "K/h", "nm": 60 },
362
- { "key": "degc_min", "label": "°C min⁻¹", "nm": 1 },
363
- { "key": "degc_s", "label": "°C s⁻¹", "nm": 0.016666666666667 },
364
- { "key": "degc_h", "label": "°C h⁻¹", "nm": 60 }
360
+ { "key": "degc_min", "label": "°C min<sup>-1</sup>", "nm": 1 },
361
+ { "key": "degc_s", "label": "°C s<sup>-1</sup>", "nm": 0.016666666666667 },
362
+ { "key": "degc_h", "label": "°C h<sup>-1</sup>", "nm": 60 }
365
363
  ]
366
364
  },
367
365
  {
@@ -396,23 +394,7 @@ module Labimotion
396
394
  "units": [
397
395
  { "key": "g", "label": "g", "nm": 1 },
398
396
  { "key": "mg", "label": "mg", "nm": 1000 },
399
- { "key": "ug", "label": "µg", "nm": 1000000 },
400
- { "key": "kg", "label": "kg", "nm": 0.001 }
401
- ]
402
- },
403
- {
404
- "type": "numeric",
405
- "field": "mass_flow",
406
- "label": "Mass flow",
407
- "default": "",
408
- "position": 121,
409
- "placeholder": "mass flow",
410
- "units": [
411
- { "key": "g_min", "label": "g/min", "nm": 1 },
412
- { "key": "kg_h", "label": "kg/h", "nm": 0.06 },
413
- { "key": "kg_s", "label": "kg/s", "nm": 0.000016666666666667 },
414
- { "key": "g_s", "label": "g/s", "nm": 0.016666666666667 },
415
- { "key": "mg_s", "label": "mg/s", "nm": 16.666666666667 }
397
+ { "key": "ug", "label": "µg", "nm": 1000000 }
416
398
  ]
417
399
  },
418
400
  {
@@ -434,8 +416,8 @@ module Labimotion
434
416
  "position": 125,
435
417
  "placeholder": "mass loading",
436
418
  "units": [
437
- { "key": "g_cm2", "label": "g cm⁻²", "nm": 1 },
438
- { "key": "mg_cm2", "label": "mg cm⁻²", "nm": 1000 }
419
+ { "key": "g_cm2", "label": "g cm<sup>-2</sup>", "nm": 1 },
420
+ { "key": "mg_cm2", "label": "mg cm<sup>-2</sup>", "nm": 1000 }
439
421
  ]
440
422
  },
441
423
  {
@@ -458,7 +440,7 @@ module Labimotion
458
440
  "position": 127,
459
441
  "placeholder": "molar conductivity",
460
442
  "units": [
461
- { "key": "s_cm2_mol", "label": "S cm² mol⁻¹", "nm": 1 }
443
+ { "key": "s_cm2_mol", "label": "S cm<sup>2</sup> mol<sup>-1</sup>", "nm": 1 }
462
444
  ]
463
445
  },
464
446
  {
@@ -510,7 +492,6 @@ module Labimotion
510
492
  { "key": "atm", "label": "atm", "nm": 1 },
511
493
  { "key": "pa", "label": "Pa", "nm": 101325 },
512
494
  { "key": "kpa", "label": "kPa", "nm": 101.325 },
513
- { "key": "mpa", "label": "MPa", "nm": 0.101325 },
514
495
  { "key": "hpa", "label": "hPa", "nm": 1013.25 },
515
496
  { "key": "torr", "label": "Torr", "nm": 760 },
516
497
  { "key": "bar", "label": "bar", "nm": 1.01325 },
@@ -549,8 +530,8 @@ module Labimotion
549
530
  "position": 150,
550
531
  "placeholder": "Reaction rate",
551
532
  "units": [
552
- { "key": "mol_lmin", "label": "mol L⁻¹ min⁻¹", "nm": 1 },
553
- { "key": "mol_lsec", "label": "mol L⁻¹ s⁻¹", "nm": 0.016666666666667 }
533
+ { "key": "mol_lmin", "label": "mol L<sup>-1</sup> min<sup>-1</sup>", "nm": 1 },
534
+ { "key": "mol_lsec", "label": "mol L<sup>-1</sup> s<sup>-1</sup>", "nm": 0.016666666666667 }
554
535
  ]
555
536
  },
556
537
  {
@@ -577,22 +558,6 @@ module Labimotion
577
558
  { "key": "v_s", "label": "V/s", "nm": 1 }
578
559
  ]
579
560
  },
580
- {
581
- "type": "numeric",
582
- "field": "space_time_yield",
583
- "label": "Space-time yield",
584
- "default": "",
585
- "position": 156,
586
- "placeholder": "space-time yield",
587
- "units": [
588
- { "key": "kg_m3_d", "label": "kg/(m³*d)", "nm": 1 },
589
- { "key": "kg_m3_h", "label": "kg/(m³*h)", "nm": 0.041666666666667 },
590
- { "key": "g_l_h", "label": "g/(L*h)", "nm": 0.041666666666667 },
591
- { "key": "mg_ml_h", "label": "mg/(mL*h)", "nm": 0.041666666666667 },
592
- { "key": "g_l_min", "label": "g/(L*min)", "nm": 0.00069444444444444 },
593
- { "key": "g_m3_s", "label": "g/(m³*s)", "nm": 0.011574074074074 }
594
- ]
595
- },
596
561
  {
597
562
  "type": "numeric",
598
563
  "field": "specific_current",
@@ -603,9 +568,9 @@ module Labimotion
603
568
  "units": [
604
569
  { "key": "ma_g", "label": "mA/g", "nm": 1000, "unit_type": "mass" },
605
570
  { "key": "a_g", "label": "A/g", "nm": 1, "unit_type": "mass" },
606
- { "key": "ma_cm2", "label": "mA/cm²", "nm": 1000, "unit_type": "area" },
607
- { "key": "a_cm2", "label": "A/cm²", "nm": 1, "unit_type": "area" },
608
- { "key": "a_mm2", "label": "A/mm²", "nm": 0.01, "unit_type": "area" }
571
+ { "key": "ma_cm2", "label": "mA/cm<sup>2</sup>", "nm": 1000, "unit_type": "area" },
572
+ { "key": "a_cm2", "label": "A/cm<sup>2</sup>", "nm": 1, "unit_type": "area" },
573
+ { "key": "a_mm2", "label": "A/mm<sup>2</sup>", "nm": 0.01, "unit_type": "area" }
609
574
  ]
610
575
  },
611
576
  {
@@ -628,7 +593,7 @@ module Labimotion
628
593
  "position": 158,
629
594
  "placeholder": "Specific surface area",
630
595
  "units": [
631
- { "key": "m2_g", "label": "m²/g", "nm": 1 }
596
+ { "key": "m2_g", "label": "m<sup>2</sup>/g", "nm": 1 }
632
597
  ]
633
598
  },
634
599
  {
@@ -638,7 +603,7 @@ module Labimotion
638
603
  "default": "",
639
604
  "position": 160,
640
605
  "placeholder": "Specific Volume",
641
- "units": [{ "key": "cm3_g", "label": "cm³/g", "nm": 1 }]
606
+ "units": [{ "key": "cm3_g", "label": "cm<sup>3</sup>/g", "nm": 1 }]
642
607
  },
643
608
  {
644
609
  "type": "numeric",
@@ -677,10 +642,10 @@ module Labimotion
677
642
  "position": 170,
678
643
  "placeholder": "surface",
679
644
  "units": [
680
- { "key": "a_2", "label": "A²", "nm": 1.0e16 },
681
- { "key": "um_2", "label": "µm²", "nm": 1.0e8 },
682
- { "key": "mm_2", "label": "mm²", "nm": 100 },
683
- { "key": "cm_2", "label": "cm²", "nm": 1 }
645
+ { "key": "a_2", "label": "A<sup>2</sup>", "nm": 1.0e16 },
646
+ { "key": "um_2", "label": "µm<sup>2</sup>", "nm": 1.0e8 },
647
+ { "key": "mm_2", "label": "mm<sup>2</sup>", "nm": 100 },
648
+ { "key": "cm_2", "label": "cm<sup>2</sup>", "nm": 1 }
684
649
  ]
685
650
  },
686
651
  {
@@ -717,8 +682,8 @@ module Labimotion
717
682
  "position": 186,
718
683
  "placeholder": "tensile stress",
719
684
  "units": [
720
- { "key": "n_cm2", "label": "N cm⁻²", "nm": 1 },
721
- { "key": "n_mm2", "label": "N mm⁻²", "nm": 0.01 }
685
+ { "key": "n_cm2", "label": "N cm<sup>-2</sup>", "nm": 1 },
686
+ { "key": "n_mm2", "label": "N mm<sup>-2</sup>", "nm": 0.01 }
722
687
  ]
723
688
  },
724
689
  {
@@ -728,7 +693,7 @@ module Labimotion
728
693
  "default": "",
729
694
  "position": 190,
730
695
  "placeholder": "Turnover number",
731
- "units": [{ "key": "1_s", "label": "1/s", "nm": 1 }, { "key": "1_m", "label": "1/min", "nm": 60 }]
696
+ "units": [{ "key": "1_s", "label": "1/s", "nm": 1 }, { "key": "1_m", "label": "1/m", "nm": 60 }]
732
697
  },
733
698
  {
734
699
  "type": "numeric",
@@ -749,7 +714,7 @@ module Labimotion
749
714
  "default": "",
750
715
  "position": 205,
751
716
  "placeholder": "Kinematic Viscosity",
752
- "units": [{ "key": "m2_s", "label": "m²/s", "nm": 1 }]
717
+ "units": [{ "key": "m2_s", "label": "m<sup>2</sup>/s", "nm": 1 }]
753
718
  },
754
719
  {
755
720
  "type": "numeric",
@@ -802,6 +767,6 @@ module Labimotion
802
767
  { "key": "m3", "label": "m³", "nm": 0.000001 }
803
768
  ]
804
769
  }
805
- ]
770
+ ]
806
771
  end
807
772
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  ## Labimotion Version
4
4
  module Labimotion
5
- VERSION = '2.3.4'
5
+ VERSION = '2.4.0.rc1'
6
6
  end
data/lib/labimotion.rb CHANGED
@@ -13,11 +13,6 @@ module Labimotion
13
13
  Labimotion.logger.error(exception.backtrace.join("\n"))
14
14
  end
15
15
 
16
- # Report a rescued exception to Sentry, if the host app uses it
17
- def self.report_exception(exception)
18
- Sentry.capture_exception(exception) if defined?(Sentry)
19
- end
20
-
21
16
  autoload :MapperUtils, 'labimotion/utils/mapper_utils'
22
17
  autoload :Utils, 'labimotion/utils/utils'
23
18
 
@@ -73,7 +68,6 @@ module Labimotion
73
68
  autoload :ParamHelpers, 'labimotion/helpers/param_helpers'
74
69
  autoload :ConverterHelpers, 'labimotion/helpers/converter_helpers'
75
70
  autoload :ExporterHelpers, 'labimotion/helpers/exporter_helpers'
76
- autoload :ExportAuthorizationHelpers, 'labimotion/helpers/export_authorization_helpers'
77
71
  autoload :SampleAssociationHelpers, 'labimotion/helpers/sample_association_helpers'
78
72
  autoload :RepositoryHelpers, 'labimotion/helpers/repository_helpers'
79
73
  autoload :VocabularyHelpers, 'labimotion/helpers/vocabulary_helpers'
@@ -95,16 +89,10 @@ module Labimotion
95
89
  autoload :ExportDataset, 'labimotion/libs/export_dataset'
96
90
  autoload :SampleAssociation, 'labimotion/libs/sample_association'
97
91
  autoload :PropertiesHandler, 'labimotion/libs/properties_handler'
98
- autoload :KlassVersion, 'labimotion/libs/klass_version'
99
- autoload :ReleaseMetadata, 'labimotion/libs/release_metadata'
92
+ autoload :LinkedElement, 'labimotion/libs/linked_element'
100
93
  autoload :AttachmentHandler, 'labimotion/libs/attachment_handler'
101
94
  autoload :VocabularyHandler, 'labimotion/libs/vocabulary_handler'
102
95
  autoload :XlsxExporter, 'labimotion/libs/xlsx_exporter'
103
- autoload :ElementVariationColumnSet, 'labimotion/libs/element_variation_column_set'
104
- autoload :ElementVariationHeader, 'labimotion/libs/element_variation_header'
105
- autoload :ExportElementVariations, 'labimotion/libs/export_element_variations'
106
- autoload :ImportElementVariations, 'labimotion/libs/import_element_variations'
107
- autoload :ExportTpaSegments, 'labimotion/libs/export_tpa_segments'
108
96
 
109
97
  ######## Utils
110
98
  autoload :Prop, 'labimotion/utils/prop'
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.3.4
4
+ version: 2.4.0.rc1
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: 2026-11-03 00:00:00.000000000 Z
12
+ date: 2026-07-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: caxlsx
@@ -45,20 +45,6 @@ dependencies:
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '8.0'
48
- - !ruby/object:Gem::Dependency
49
- name: roo
50
- requirement: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.10'
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.10'
62
48
  description:
63
49
  email:
64
50
  - chia-lin.lin@kit.edu
@@ -114,7 +100,6 @@ files:
114
100
  - lib/labimotion/helpers/converter_helpers.rb
115
101
  - lib/labimotion/helpers/dataset_helpers.rb
116
102
  - lib/labimotion/helpers/element_helpers.rb
117
- - lib/labimotion/helpers/export_authorization_helpers.rb
118
103
  - lib/labimotion/helpers/exporter_helpers.rb
119
104
  - lib/labimotion/helpers/generic_helpers.rb
120
105
  - lib/labimotion/helpers/mtt_helpers.rb
@@ -131,17 +116,11 @@ files:
131
116
  - lib/labimotion/libs/data/vocab/Standard.json
132
117
  - lib/labimotion/libs/data/vocab/System.json
133
118
  - lib/labimotion/libs/dataset_builder.rb
134
- - lib/labimotion/libs/element_variation_column_set.rb
135
- - lib/labimotion/libs/element_variation_header.rb
136
119
  - lib/labimotion/libs/export_dataset.rb
137
120
  - lib/labimotion/libs/export_element.rb
138
- - lib/labimotion/libs/export_element_variations.rb
139
- - lib/labimotion/libs/export_tpa_segments.rb
140
- - lib/labimotion/libs/import_element_variations.rb
141
- - lib/labimotion/libs/klass_version.rb
121
+ - lib/labimotion/libs/linked_element.rb
142
122
  - lib/labimotion/libs/nmr_mapper.rb
143
123
  - lib/labimotion/libs/properties_handler.rb
144
- - lib/labimotion/libs/release_metadata.rb
145
124
  - lib/labimotion/libs/sample_association.rb
146
125
  - lib/labimotion/libs/template_hub.rb
147
126
  - lib/labimotion/libs/template_matcher.rb
@@ -226,9 +205,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
226
205
  version: '3.4'
227
206
  required_rubygems_version: !ruby/object:Gem::Requirement
228
207
  requirements:
229
- - - ">="
208
+ - - ">"
230
209
  - !ruby/object:Gem::Version
231
- version: '0'
210
+ version: 1.3.1
232
211
  requirements: []
233
212
  rubygems_version: 3.1.6
234
213
  signing_key:
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Labimotion
4
- # Gate shared by the routes that export an Element, Segment or Dataset to a file.
5
- # A segment or dataset is readable when the element that holds it is; a dataset
6
- # sits on an analysis container, so its element is that container's root element.
7
- module ExportAuthorizationHelpers
8
- # Answers 404 for a missing record and 401 unless the user passes the matrix
9
- # check for the record's family and may read the element that holds it.
10
- def authorize_export!(klass_name, record)
11
- error!('404 Not Found', 404) if record.nil?
12
- return if export_readable?(klass_name, record)
13
-
14
- error!('401 Unauthorized', 401)
15
- end
16
-
17
- # The matrix right that shows each family in the UI.
18
- EXPORT_MATRIX = { 'Element' => 'genericElement', 'Segment' => 'segment', 'Dataset' => 'genericDataset' }.freeze
19
-
20
- def export_readable?(klass_name, record)
21
- return false unless current_user.matrix_check_by_name(EXPORT_MATRIX.fetch(klass_name))
22
-
23
- policy = ElementPolicy.new(current_user, export_parent_element(klass_name, record))
24
- return policy.read? unless klass_name == 'Dataset'
25
-
26
- # A dataset holds analysis data, which a share below the dataset detail
27
- # level hides.
28
- policy.read? && policy.read_dataset?
29
- end
30
-
31
- def export_parent_element(klass_name, record)
32
- case klass_name
33
- when 'Element' then record
34
- when 'Segment' then record.element
35
- when 'Dataset' then record.element&.root_element
36
- end
37
- end
38
- end
39
- end