labimotion 0.1.6

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/lib/labimotion/api.rb +19 -0
  3. data/lib/labimotion/apis/converter_api.rb +68 -0
  4. data/lib/labimotion/apis/generic_dataset_api.rb +50 -0
  5. data/lib/labimotion/apis/generic_element_api.rb +339 -0
  6. data/lib/labimotion/apis/labimotion_hub_api.rb +53 -0
  7. data/lib/labimotion/apis/segment_api.rb +144 -0
  8. data/lib/labimotion/entities/application_entity.rb +88 -0
  9. data/lib/labimotion/entities/dataset_entity.rb +16 -0
  10. data/lib/labimotion/entities/dataset_klass_entity.rb +9 -0
  11. data/lib/labimotion/entities/element_entity.rb +108 -0
  12. data/lib/labimotion/entities/element_klass_entity.rb +10 -0
  13. data/lib/labimotion/entities/element_revision_entity.rb +57 -0
  14. data/lib/labimotion/entities/eln_element_entity.rb +110 -0
  15. data/lib/labimotion/entities/generic_entity.rb +54 -0
  16. data/lib/labimotion/entities/generic_klass_entity.rb +14 -0
  17. data/lib/labimotion/entities/generic_public_entity.rb +25 -0
  18. data/lib/labimotion/entities/klass_revision_entity.rb +20 -0
  19. data/lib/labimotion/entities/segment_entity.rb +62 -0
  20. data/lib/labimotion/entities/segment_klass_entity.rb +8 -0
  21. data/lib/labimotion/entities/segment_revision_entity.rb +55 -0
  22. data/lib/labimotion/helpers/converter_helpers.rb +13 -0
  23. data/lib/labimotion/helpers/dataset_helpers.rb +38 -0
  24. data/lib/labimotion/helpers/element_helpers.rb +268 -0
  25. data/lib/labimotion/helpers/generic_helpers.rb +252 -0
  26. data/lib/labimotion/helpers/repository_helpers.rb +14 -0
  27. data/lib/labimotion/helpers/sample_association_helpers.rb +126 -0
  28. data/lib/labimotion/helpers/search_helpers.rb +62 -0
  29. data/lib/labimotion/helpers/segment_helpers.rb +97 -0
  30. data/lib/labimotion/libs/converter.rb +325 -0
  31. data/lib/labimotion/libs/export_dataset.rb +121 -0
  32. data/lib/labimotion/libs/nmr_mapper.rb +265 -0
  33. data/lib/labimotion/libs/nmr_mapper_repo.rb +263 -0
  34. data/lib/labimotion/libs/template_hub.rb +55 -0
  35. data/lib/labimotion/models/collections_element.rb +42 -0
  36. data/lib/labimotion/models/concerns/attachment_converter.rb +42 -0
  37. data/lib/labimotion/models/concerns/datasetable.rb +50 -0
  38. data/lib/labimotion/models/concerns/generic_klass_revisions.rb +39 -0
  39. data/lib/labimotion/models/concerns/generic_revisions.rb +43 -0
  40. data/lib/labimotion/models/concerns/segmentable.rb +74 -0
  41. data/lib/labimotion/models/dataset.rb +14 -0
  42. data/lib/labimotion/models/dataset_klass.rb +25 -0
  43. data/lib/labimotion/models/dataset_klasses_revision.rb +9 -0
  44. data/lib/labimotion/models/datasets_revision.rb +9 -0
  45. data/lib/labimotion/models/element.rb +121 -0
  46. data/lib/labimotion/models/element_klass.rb +25 -0
  47. data/lib/labimotion/models/element_klasses_revision.rb +9 -0
  48. data/lib/labimotion/models/elements_element.rb +11 -0
  49. data/lib/labimotion/models/elements_revision.rb +8 -0
  50. data/lib/labimotion/models/elements_sample.rb +11 -0
  51. data/lib/labimotion/models/segment.rb +14 -0
  52. data/lib/labimotion/models/segment_klass.rb +24 -0
  53. data/lib/labimotion/models/segment_klasses_revision.rb +9 -0
  54. data/lib/labimotion/models/segments_revision.rb +9 -0
  55. data/lib/labimotion/utils/con_state.rb +13 -0
  56. data/lib/labimotion/utils/export.rb +112 -0
  57. data/lib/labimotion/utils/import.rb +186 -0
  58. data/lib/labimotion/utils/search.rb +112 -0
  59. data/lib/labimotion/utils/serializer.rb +78 -0
  60. data/lib/labimotion/version.rb +6 -0
  61. data/lib/labimotion.rb +95 -0
  62. metadata +119 -0
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Datasetable concern
4
+
5
+ module Labimotion
6
+ ## Datasetable concern
7
+ module Datasetable
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ has_one :dataset, as: :element, class_name: 'Labimotion::Dataset'
12
+ end
13
+
14
+ def not_dataset?
15
+ self.class.name == 'Container' && container_type != 'dataset'
16
+ end
17
+
18
+ def save_dataset(**args)
19
+ return if not_dataset?
20
+
21
+ klass = Labimotion::DatasetKlass.find_by(id: args[:dataset_klass_id])
22
+ uuid = SecureRandom.uuid
23
+ props = args[:properties]
24
+ props['eln'] = Chemotion::Application.config.version
25
+ props['labimotion'] = Labimotion::VERSION
26
+ ds = Labimotion::Dataset.find_by(element_type: self.class.name, element_id: id)
27
+ if ds.present? && (ds.klass_uuid != props['klass_uuid'] || ds.properties != props)
28
+ props['uuid'] = uuid
29
+ props['eln'] = Chemotion::Application.config.version
30
+ props['labimotion'] = Labimotion::VERSION
31
+ props['klass'] = 'Dataset'
32
+ ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: args[:dataset_klass_id], properties: props, klass_uuid: props['klass_uuid'])
33
+ end
34
+ return if ds.present?
35
+
36
+ props['uuid'] = uuid
37
+ props['klass_uuid'] = klass.uuid
38
+ props['eln'] = Chemotion::Application.config.version
39
+ props['labimotion'] = Labimotion::VERSION
40
+ props['klass'] = 'Dataset'
41
+ 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)
42
+ end
43
+
44
+ def destroy_datasetable
45
+ return if not_dataset?
46
+
47
+ Labimotion::Dataset.where(element_type: self.class.name, element_id: id).destroy_all
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ module GenericKlassRevisions
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ # has_many :element_klasses_revisions, dependent: :destroy
8
+ end
9
+
10
+ def create_klasses_revision(user_id=0)
11
+ properties_release = properties_template
12
+ # (properties_release['layers'] || {}).keys.each do |key|
13
+ # properties_release['layers'][key]['layer'] = properties_release['layers'][key]['key']
14
+ # end
15
+
16
+ if properties_release['flow'].present?
17
+ elements = (properties_release['flow']['elements'] || []).map do |el|
18
+ if el['data'].present? && el['data']['lKey'].present?
19
+ layer = properties_release['layers'][el['data']['lKey']]
20
+ el['data']['layer'] = layer if layer.present?
21
+ end
22
+ el
23
+ end
24
+ properties_release['flow']['elements'] = elements
25
+ end
26
+
27
+ self.update!({ uuid: properties_template['uuid'], properties_release: properties_release, released_at: DateTime.now })
28
+ reload
29
+ attributes = {
30
+ released_by: user_id,
31
+ uuid: uuid,
32
+ properties_release: properties_release,
33
+ released_at: released_at
34
+ }
35
+ attributes["#{self.class.name.underscore.split('/').last}_id"] = id
36
+ "#{self.class.name}esRevision".constantize.create(attributes)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # GenericRevisions concern
4
+ module Labimotion
5
+ module GenericRevisions
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ after_create :create_vault
9
+ after_update :save_to_vault
10
+ before_destroy :delete_attachments
11
+ end
12
+
13
+ def create_vault
14
+ save_to_vault unless self.class.name == 'Labimotion::Element'
15
+ end
16
+
17
+ def save_to_vault
18
+ attributes = {
19
+ uuid: uuid,
20
+ klass_uuid: klass_uuid,
21
+ properties: properties,
22
+ properties_release: properties_release
23
+ }
24
+ attributes["#{self.class.name.downcase.split('::').last}_id"] = id
25
+ attributes['name'] = name if self.class.name == 'Labimotion::Element'
26
+ "#{self.class.name}sRevision".constantize.create(attributes)
27
+ end
28
+
29
+ def delete_attachments
30
+ att_ids = []
31
+ properties && properties['layers']&.keys&.each do |key|
32
+ layer = properties['layers'][key]
33
+ field_uploads = layer['fields'].select { |ss| ss['type'] == 'upload' }
34
+ field_uploads.each do |field|
35
+ (field['value'] && field['value']['files'] || []).each do |file|
36
+ att_ids.push(file['aid']) unless file['aid'].nil?
37
+ end
38
+ end
39
+ end
40
+ Attachment.where(id: att_ids, attachable_id: id, attachable_type: %w[ElementProps SegmentProps]).destroy_all
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ # Segmentable concern
5
+ module Segmentable
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ has_many :segments, as: :element, dependent: :destroy, class_name: 'Labimotion::Segment'
9
+ end
10
+
11
+ def copy_segments(**args)
12
+ return if args[:segments].nil?
13
+
14
+ segments = save_segments(segments: args[:segments], current_user_id: args[:current_user_id])
15
+ segments.each do |segment|
16
+ properties = segment.properties
17
+ properties['layers'].keys.each do |key|
18
+ layer = properties['layers'][key]
19
+ field_uploads = layer['fields'].select { |ss| ss['type'] == 'upload' }
20
+ field_uploads&.each do |upload|
21
+ idx = properties['layers'][key]['fields'].index(upload)
22
+ files = upload["value"] && upload["value"]["files"]
23
+ files&.each_with_index do |fi, fdx|
24
+ aid = properties['layers'][key]['fields'][idx]['value']['files'][fdx]['aid']
25
+ unless aid.nil?
26
+ copied_att = Attachment.find(aid)&.copy(attachable_type: 'SegmentProps', attachable_id: segment.id, transferred: true)
27
+ unless copied_att.nil?
28
+ copied_att.save!
29
+ properties['layers'][key]['fields'][idx]['value']['files'][fdx]['aid'] = copied_att.id
30
+ properties['layers'][key]['fields'][idx]['value']['files'][fdx]['uid'] = copied_att.identifier
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ segment.update!(properties: properties)
37
+ end
38
+ end
39
+
40
+ def save_segments(**args) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
41
+ return if args[:segments].nil?
42
+
43
+ segments = []
44
+ args[:segments].each do |seg|
45
+ klass = Labimotion::SegmentKlass.find_by(id: seg['segment_klass_id'])
46
+ uuid = SecureRandom.uuid
47
+ props = seg['properties']
48
+ props['eln'] = Chemotion::Application.config.version
49
+ props['labimotion'] = Labimotion::VERSION
50
+ segment = Labimotion::Segment.find_by(element_type: self.class.name.split('::').last, element_id: self.id, segment_klass_id: seg['segment_klass_id'])
51
+ if segment.present? && (segment.klass_uuid != props['klass_uuid'] || segment.properties != props)
52
+ props['uuid'] = uuid
53
+ props['eln'] = Chemotion::Application.config.version
54
+ props['labimotion'] = Labimotion::VERSION
55
+ props['klass'] = 'Segment'
56
+
57
+ segment.update!(properties_release: klass.properties_release, properties: props, uuid: uuid, klass_uuid: props['klass_uuid'])
58
+ segments.push(segment)
59
+ end
60
+ next if segment.present?
61
+
62
+ props['uuid'] = uuid
63
+ props['klass_uuid'] = klass.uuid
64
+ props['eln'] = Chemotion::Application.config.version
65
+ props['labimotion'] = Labimotion::VERSION
66
+ props['klass'] = 'Segment'
67
+
68
+ segment = Labimotion::Segment.create!(properties_release: klass.properties_release, segment_klass_id: seg['segment_klass_id'], element_type: self.class.name.split('::').last, element_id: self.id, properties: props, created_by: args[:current_user_id], uuid: uuid, klass_uuid: klass.uuid)
69
+ segments.push(segment)
70
+ end
71
+ segments
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_revisions'
3
+
4
+ # ## This is the first version of the dataset class
5
+ module Labimotion
6
+ # ## This is the first version of the dataset class
7
+ class Dataset < ApplicationRecord
8
+ self.table_name = :datasets
9
+ acts_as_paranoid
10
+ include GenericRevisions
11
+ belongs_to :dataset_klass, class_name: 'Labimotion::DatasetKlass'
12
+ belongs_to :element, polymorphic: true, class_name: 'Labimotion::Element'
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_klass_revisions'
3
+
4
+ module Labimotion
5
+ class DatasetKlass < ApplicationRecord
6
+ acts_as_paranoid
7
+ self.table_name = :dataset_klasses
8
+ include GenericKlassRevisions
9
+ has_many :datasets, dependent: :destroy, class_name: 'Labimotion::Dataset'
10
+ has_many :dataset_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::DatasetKlassesRevision'
11
+
12
+ def self.init_seeds
13
+ seeds_path = File.join(Rails.root, 'db', 'seeds', 'json', 'dataset_klasses.json')
14
+ seeds = JSON.parse(File.read(seeds_path))
15
+
16
+ seeds['chmo'].each do |term|
17
+ next if Labimotion::DatasetKlass.where(ols_term_id: term['id']).count.positive?
18
+
19
+ attributes = { ols_term_id: term['id'], label: "#{term['label']} (#{term['synonym']})", desc: "#{term['label']} (#{term['synonym']})", place: term['position'], created_by: Admin.first&.id || 0 }
20
+ Labimotion::DatasetKlass.create!(attributes)
21
+ end
22
+ true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class DatasetKlassesRevision < ApplicationRecord
5
+ self.table_name = :dataset_klasses_revisions
6
+ acts_as_paranoid
7
+ has_one :dataset_klass, class_name: 'Labimotion::DatasetKlass'
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class DatasetsRevision < ApplicationRecord
5
+ acts_as_paranoid
6
+ self.table_name = :datasets_revisions
7
+ has_one :dataset, class_name: 'Labimotion::Dataset'
8
+ end
9
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_revisions'
3
+ require 'labimotion/models/concerns/segmentable'
4
+
5
+ module Labimotion
6
+ class Element < ApplicationRecord
7
+ acts_as_paranoid
8
+ self.table_name = :elements
9
+ include PgSearch
10
+ include ElementUIStateScopes
11
+ include Collectable
12
+ ## include AnalysisCodes
13
+ include Taggable
14
+ include Segmentable
15
+ include GenericRevisions
16
+
17
+ multisearchable against: %i[name short_label]
18
+
19
+ pg_search_scope :search_by_substring, against: %i[name short_label], using: { trigram: { threshold: 0.0001 } }
20
+
21
+ attr_accessor :can_copy
22
+
23
+ scope :by_name, ->(query) { where('name ILIKE ?', "%#{sanitize_sql_like(query)}%") }
24
+ scope :by_short_label, ->(query) { where('short_label ILIKE ?', "%#{sanitize_sql_like(query)}%") }
25
+ scope :by_klass_id_short_label, ->(klass_id, short_label) { where('element_klass_id = ? and short_label ILIKE ?', klass_id, "%#{sanitize_sql_like(short_label)}%") }
26
+ scope :by_sample_ids, ->(ids) { joins(:elements_samples).where('sample_id IN (?)', ids) }
27
+ scope :by_klass_id, ->(klass_id) { where('element_klass_id = ? ', klass_id) }
28
+
29
+ belongs_to :element_klass, class_name: 'Labimotion::ElementKlass'
30
+
31
+ has_many :collections_elements, inverse_of: :element, dependent: :destroy, class_name: 'Labimotion::CollectionsElement'
32
+ has_many :collections, through: :collections_elements
33
+ has_many :attachments, as: :attachable
34
+ has_many :elements_samples, dependent: :destroy, class_name: 'Labimotion::ElementsSample'
35
+ has_many :samples, through: :elements_samples, source: :sample
36
+ has_one :container, :as => :containable
37
+ has_many :elements_revisions, dependent: :destroy, class_name: 'Labimotion::ElementsRevision'
38
+
39
+ accepts_nested_attributes_for :collections_elements
40
+
41
+ scope :elements_created_time_from, ->(time) { where('elements.created_at >= ?', time) }
42
+ scope :elements_created_time_to, ->(time) { where('elements.created_at <= ?', time) }
43
+ scope :elements_updated_time_from, ->(time) { where('elements.updated_at >= ?', time) }
44
+ scope :elements_updated_time_to, ->(time) { where('elements.updated_at <= ?', time) }
45
+
46
+ belongs_to :creator, foreign_key: :created_by, class_name: 'User'
47
+ validates :creator, presence: true
48
+
49
+ has_many :elements_elements, foreign_key: :parent_id, class_name: 'Labimotion::ElementsElement'
50
+ has_many :elements, through: :elements_elements, source: :element, class_name: 'Labimotion::Element'
51
+
52
+ before_create :auto_set_short_label
53
+ after_create :update_counter
54
+ before_destroy :delete_attachment
55
+
56
+
57
+ def attachments
58
+ Attachment.where(attachable_id: self.id, attachable_type: 'Element')
59
+ end
60
+
61
+ def self.get_associated_samples(element_ids)
62
+ Labimotion::ElementsSample.where(element_id: element_ids).pluck(:sample_id)
63
+ end
64
+
65
+ def analyses
66
+ container ? container.analyses : []
67
+ end
68
+
69
+ def auto_set_short_label
70
+ prefix = element_klass.klass_prefix
71
+ if creator.counters[element_klass.name].nil?
72
+ creator.counters[element_klass.name] = '0'
73
+ creator.update_columns(counters: creator.counters)
74
+ creator.reload
75
+ end
76
+ counter = creator.counters[element_klass.name].to_i.succ
77
+ self.short_label = "#{creator.initials}-#{prefix}#{counter}"
78
+ end
79
+
80
+ def update_counter
81
+ creator.increment_counter element_klass.name
82
+ end
83
+
84
+ def self.get_associated_elements(element_ids)
85
+ pids = Labimotion::Element.where(id: element_ids).pluck :id
86
+ get_ids = proc do |eids|
87
+ eids.each do |p|
88
+ cs = Labimotion::Element.find_by(id: p)&.elements.where.not(id: pids).pluck :id
89
+ next if cs.empty?
90
+
91
+ pids = (pids << cs).flatten.uniq
92
+ get_ids.call(cs)
93
+ end
94
+ end
95
+ get_ids.call(pids)
96
+ pids
97
+ end
98
+
99
+ def thumb_svg
100
+ image_atts = attachments.select do |a_img|
101
+ a_img&.content_type&.match(Regexp.union(%w[jpg jpeg png tiff tif]))
102
+ end
103
+
104
+ attachment = image_atts[0] || attachments[0]
105
+ preview = attachment.read_thumbnail if attachment
106
+ preview && Base64.encode64(preview) || 'not available'
107
+ end
108
+
109
+ private
110
+
111
+ def delete_attachment
112
+ if Rails.env.production?
113
+ attachments.each do |attachment|
114
+ attachment.delay(run_at: 96.hours.from_now, queue: 'attachment_deletion').destroy!
115
+ end
116
+ else
117
+ attachments.each(&:destroy!)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_klass_revisions'
3
+
4
+ module Labimotion
5
+ class ElementKlass < ApplicationRecord
6
+ acts_as_paranoid
7
+ self.table_name = :element_klasses
8
+ include GenericKlassRevisions
9
+ has_many :elements, dependent: :destroy, class_name: 'Labimotion::Element'
10
+ has_many :segment_klasses, dependent: :destroy, class_name: 'Labimotion::SegmentKlass'
11
+ has_many :element_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::ElementKlassesRevision'
12
+
13
+ def self.gen_klasses_json
14
+ klasses = where(is_active: true, is_generic: true).order('place')&.pluck(:name) || []
15
+ rescue ActiveRecord::StatementInvalid, PG::ConnectionBad, PG::UndefinedTable
16
+ klasses = []
17
+ ensure
18
+ File.write(
19
+ Rails.root.join('config', 'klasses.json'),
20
+ klasses&.to_json || []
21
+ )
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class ElementKlassesRevision < ApplicationRecord
5
+ acts_as_paranoid
6
+ self.table_name = :element_klasses_revisions
7
+ has_one :element_klass, class_name: 'Labimotion::ElementKlass'
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Labimotion
3
+ class ElementsElement < ApplicationRecord
4
+ self.table_name = :elements_elements
5
+ acts_as_paranoid
6
+ belongs_to :element, class_name: 'Labimotion::Element'
7
+ belongs_to :parent, foreign_key: :parent_id, class_name: 'Labimotion::Element'
8
+
9
+ # include Tagging
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Labimotion
3
+ class ElementsRevision < ApplicationRecord
4
+ self.table_name = :elements_revisions
5
+ acts_as_paranoid
6
+ has_one :element, class_name: 'Labimotion::Element'
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class ElementsSample < ApplicationRecord
5
+ acts_as_paranoid
6
+ self.table_name = :elements_samples
7
+ has_one :element, class_name: 'Labimotion::Element'
8
+ belongs_to :sample
9
+ include Tagging
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_revisions'
3
+
4
+ module Labimotion
5
+ class Segment < ApplicationRecord
6
+ acts_as_paranoid
7
+ self.table_name = :segments
8
+ include GenericRevisions
9
+
10
+ belongs_to :segment_klass, class_name: 'Labimotion::SegmentKlass'
11
+ belongs_to :element, polymorphic: true, class_name: 'Labimotion::Element'
12
+ has_many :segments_revisions, dependent: :destroy, class_name: 'Labimotion::SegmentsRevision'
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ require 'labimotion/models/concerns/generic_klass_revisions'
3
+
4
+ module Labimotion
5
+ class SegmentKlass < ApplicationRecord
6
+ self.table_name = :segment_klasses
7
+ acts_as_paranoid
8
+ include GenericKlassRevisions
9
+ belongs_to :element_klass, class_name: 'Labimotion::ElementKlass'
10
+ has_many :segments, dependent: :destroy, class_name: 'Labimotion::Segment'
11
+ has_many :segment_klasses_revisions, dependent: :destroy, class_name: 'Labimotion::SegmentKlassesRevision'
12
+
13
+ def self.gen_klasses_json
14
+ klasses = where(is_active: true)&.pluck(:name) || []
15
+ rescue ActiveRecord::StatementInvalid, PG::ConnectionBad, PG::UndefinedTable
16
+ klasses = []
17
+ ensure
18
+ File.write(
19
+ Rails.root.join('config', 'segment_klass.json'),
20
+ klasses&.to_json || []
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class SegmentKlassesRevision < ApplicationRecord
5
+ acts_as_paranoid
6
+ self.table_name = :segment_klasses_revisions
7
+ has_one :segment_klass, class_name: 'Labimotion::SegmentKlass'
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ class SegmentsRevision < ApplicationRecord
5
+ acts_as_paranoid
6
+ self.table_name = :segments_revisions
7
+ has_one :segment, class_name: 'Labimotion::Segment'
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Labimotion
2
+ ## Converter State
3
+ class ConState
4
+ NONE = 0 ## Labimotion::ConState::NONE
5
+ WAIT = 1
6
+ NMR = 2
7
+ CONVERTED = 3
8
+ READ = 4
9
+ PROCESSED = 5
10
+ COMPLETED = 6
11
+ ERROR = 9
12
+ end
13
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labimotion
4
+ ## Export
5
+ class Export
6
+
7
+ def self.fetch_element_klasses(&fetch_many)
8
+ klasses = Labimotion::ElementKlass.where(is_active: true)
9
+ fetch_many.call(klasses, {'created_by' => 'User'})
10
+ end
11
+
12
+ def self.fetch_segment_klasses(&fetch_many)
13
+ klasses = Labimotion::SegmentKlass.where(is_active: true)
14
+ fetch_many.call(klasses, {
15
+ 'element_klass_id' => 'Labimotion::ElementKlass',
16
+ 'created_by' => 'User'
17
+ })
18
+ end
19
+
20
+ def self.fetch_dataset_klasses(&fetch_many)
21
+ klasses = Labimotion::DatasetKlass.where(is_active: true)
22
+ fetch_many.call(klasses, {'created_by' => 'User'})
23
+ end
24
+
25
+
26
+ def self.fetch_segments(element, attachments, &fetch_one)
27
+ element_type = element.class.name
28
+ segments = Labimotion::Segment.where("element_id = ? AND element_type = ?", element.id, element_type)
29
+ segments.each do |segment|
30
+ # segment = fetch_properties(segment)
31
+ segment, attachments = Labimotion::Export.fetch_properties(segment, attachments, &fetch_one)
32
+ # fetch_one.call(segment.segment_klass.element_klass)
33
+ # fetch_one.call(segment.segment_klass, {
34
+ # 'element_klass_id' => 'Labimotion::ElementKlass'
35
+ # })
36
+ fetch_one.call(segment, {
37
+ 'element_id' => segment.element_type,
38
+ 'segment_klass_id' => 'Labimotion::SegmentKlass',
39
+ 'created_by' => 'User'
40
+ })
41
+ end
42
+ [segments, attachments]
43
+ end
44
+
45
+ def self.fetch_datasets(dataset, &fetch_one)
46
+ return if dataset.nil?
47
+
48
+ fetch_one.call(dataset, {
49
+ 'element_id' => 'Container',
50
+ })
51
+ fetch_one.call(dataset, {
52
+ 'element_id' => dataset.element_type,
53
+ 'dataset_klass_id' => 'Labimotion::DatasetKlass',
54
+ })
55
+ [dataset]
56
+ end
57
+
58
+
59
+ def self.fetch_properties(instance, attachments, &fetch_one)
60
+ properties = instance.properties
61
+ properties['layers'].keys.each do |key|
62
+ layer = properties['layers'][key]
63
+
64
+ # field_samples = layer['fields'].select { |ss| ss['type'] == 'drag_sample' } -- TODO for elements
65
+ # field_elements = layer['fields'].select { |ss| ss['type'] == 'drag_element' } -- TODO for elements
66
+
67
+ field_molecules = layer['fields'].select { |ss| ss['type'] == 'drag_molecule' }
68
+ field_molecules.each do |field|
69
+ idx = properties['layers'][key]['fields'].index(field)
70
+ id = field["value"] && field["value"]["el_id"] unless idx.nil?
71
+ mol = Molecule.find(id) unless id.nil?
72
+ properties['layers'][key]['fields'][idx]['value']['el_id'] = fetch_one.call(mol) unless mol.nil?
73
+ end
74
+ field_uploads = layer['fields'].select { |ss| ss['type'] == 'upload' }
75
+ field_uploads.each do |upload|
76
+ idx = properties['layers'][key]['fields'].index(upload)
77
+ files = upload["value"] && upload["value"]["files"]
78
+ files&.each_with_index do |fi, fdx|
79
+ att = Attachment.find(fi['aid'])
80
+ attachments += [att]
81
+ properties['layers'][key]['fields'][idx]['value']['files'][fdx]['aid'] = fetch_one.call(att, {'attachable_id' => 'Labimotion::Segment'}) unless att.nil?
82
+ end
83
+ end
84
+
85
+ field_tables = properties['layers'][key]['fields'].select { |ss| ss['type'] == 'table' }
86
+ field_tables&.each do |field|
87
+ next unless field['sub_values'].present? && field['sub_fields'].present?
88
+ # field_table_samples = field['sub_fields'].select { |ss| ss['type'] == 'drag_sample' } -- not available yet
89
+ # field_table_uploads = field['sub_fields'].select { |ss| ss['type'] == 'upload' } -- not available yet
90
+ field_table_molecules = field['sub_fields'].select { |ss| ss['type'] == 'drag_molecule' }
91
+ if field_table_molecules.present?
92
+ col_ids = field_table_molecules.map { |x| x.values[0] }
93
+ col_ids.each do |col_id|
94
+ field['sub_values'].each do |sub_value|
95
+ next unless sub_value[col_id].present? && sub_value[col_id]['value'].present? && sub_value[col_id]['value']['el_id'].present?
96
+
97
+ svalue = sub_value[col_id]['value']
98
+ next unless svalue['el_id'].present? && svalue['el_inchikey'].present?
99
+
100
+ tmol = Molecule.find_by(id: svalue['el_id'])
101
+ sub_value[col_id]['value']['el_id'] = fetch_one.call(tmol) unless tmol.nil?
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ instance.properties = properties
109
+ [instance, attachments]
110
+ end
111
+ end
112
+ end