labimotion 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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