labimotion 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/labimotion/api.rb +19 -0
- data/lib/labimotion/apis/converter_api.rb +68 -0
- data/lib/labimotion/apis/generic_dataset_api.rb +50 -0
- data/lib/labimotion/apis/generic_element_api.rb +339 -0
- data/lib/labimotion/apis/labimotion_hub_api.rb +53 -0
- data/lib/labimotion/apis/segment_api.rb +144 -0
- data/lib/labimotion/entities/application_entity.rb +88 -0
- data/lib/labimotion/entities/dataset_entity.rb +16 -0
- data/lib/labimotion/entities/dataset_klass_entity.rb +9 -0
- data/lib/labimotion/entities/element_entity.rb +108 -0
- data/lib/labimotion/entities/element_klass_entity.rb +10 -0
- data/lib/labimotion/entities/element_revision_entity.rb +57 -0
- data/lib/labimotion/entities/eln_element_entity.rb +110 -0
- data/lib/labimotion/entities/generic_entity.rb +54 -0
- data/lib/labimotion/entities/generic_klass_entity.rb +14 -0
- data/lib/labimotion/entities/generic_public_entity.rb +25 -0
- data/lib/labimotion/entities/klass_revision_entity.rb +20 -0
- data/lib/labimotion/entities/segment_entity.rb +62 -0
- data/lib/labimotion/entities/segment_klass_entity.rb +8 -0
- data/lib/labimotion/entities/segment_revision_entity.rb +55 -0
- data/lib/labimotion/helpers/converter_helpers.rb +13 -0
- data/lib/labimotion/helpers/dataset_helpers.rb +38 -0
- data/lib/labimotion/helpers/element_helpers.rb +268 -0
- data/lib/labimotion/helpers/generic_helpers.rb +252 -0
- data/lib/labimotion/helpers/repository_helpers.rb +14 -0
- data/lib/labimotion/helpers/sample_association_helpers.rb +126 -0
- data/lib/labimotion/helpers/search_helpers.rb +62 -0
- data/lib/labimotion/helpers/segment_helpers.rb +97 -0
- data/lib/labimotion/libs/converter.rb +325 -0
- data/lib/labimotion/libs/export_dataset.rb +121 -0
- data/lib/labimotion/libs/nmr_mapper.rb +265 -0
- data/lib/labimotion/libs/nmr_mapper_repo.rb +263 -0
- data/lib/labimotion/libs/template_hub.rb +55 -0
- data/lib/labimotion/models/collections_element.rb +42 -0
- data/lib/labimotion/models/concerns/attachment_converter.rb +42 -0
- data/lib/labimotion/models/concerns/datasetable.rb +50 -0
- data/lib/labimotion/models/concerns/generic_klass_revisions.rb +39 -0
- data/lib/labimotion/models/concerns/generic_revisions.rb +43 -0
- data/lib/labimotion/models/concerns/segmentable.rb +74 -0
- data/lib/labimotion/models/dataset.rb +14 -0
- data/lib/labimotion/models/dataset_klass.rb +25 -0
- data/lib/labimotion/models/dataset_klasses_revision.rb +9 -0
- data/lib/labimotion/models/datasets_revision.rb +9 -0
- data/lib/labimotion/models/element.rb +121 -0
- data/lib/labimotion/models/element_klass.rb +25 -0
- data/lib/labimotion/models/element_klasses_revision.rb +9 -0
- data/lib/labimotion/models/elements_element.rb +11 -0
- data/lib/labimotion/models/elements_revision.rb +8 -0
- data/lib/labimotion/models/elements_sample.rb +11 -0
- data/lib/labimotion/models/segment.rb +14 -0
- data/lib/labimotion/models/segment_klass.rb +24 -0
- data/lib/labimotion/models/segment_klasses_revision.rb +9 -0
- data/lib/labimotion/models/segments_revision.rb +9 -0
- data/lib/labimotion/utils/con_state.rb +13 -0
- data/lib/labimotion/utils/export.rb +112 -0
- data/lib/labimotion/utils/import.rb +186 -0
- data/lib/labimotion/utils/search.rb +112 -0
- data/lib/labimotion/utils/serializer.rb +78 -0
- data/lib/labimotion/version.rb +6 -0
- data/lib/labimotion.rb +95 -0
- metadata +119 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'grape'
|
3
|
+
# require 'labimotion/models/segment_klass'
|
4
|
+
module Labimotion
|
5
|
+
## ElementHelpers
|
6
|
+
module SearchHelpers
|
7
|
+
extend Grape::API::Helpers
|
8
|
+
|
9
|
+
def serialization_elements(result, page, page_size, element_ids, params)
|
10
|
+
# klasses = Labimotion::ElementKlass.where(is_active: true, is_generic: true)
|
11
|
+
# klasses.each do |klass|
|
12
|
+
# element_ids_for_klass = Element.where(id: element_ids, element_klass_id: klass.id).pluck(:id)
|
13
|
+
# paginated_element_ids = Kaminari.paginate_array(element_ids_for_klass).page(page).per(page_size)
|
14
|
+
# serialized_elements = Element.find(paginated_element_ids).map do |element|
|
15
|
+
# Labimotion::ElementEntity.represent(element, displayed_in_list: true).serializable_hash
|
16
|
+
# end
|
17
|
+
|
18
|
+
# result["#{klass.name}s"] = {
|
19
|
+
# elements: serialized_elements,
|
20
|
+
# totalElements: element_ids_for_klass.size,
|
21
|
+
# page: page,
|
22
|
+
# pages: pages(element_ids_for_klass.size),
|
23
|
+
# perPage: page_size,
|
24
|
+
# ids: element_ids_for_klass,
|
25
|
+
# }
|
26
|
+
# end
|
27
|
+
# result
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def gl_elements_search(col, params)
|
32
|
+
# element_scope = Element.joins(:collections_elements).where(
|
33
|
+
# 'collections_elements.collection_id = ? and collections_elements.element_type = (?)', collection.id, params[:selection][:genericElName]
|
34
|
+
# )
|
35
|
+
# if params[:selection][:searchName].present?
|
36
|
+
# element_scope = element_scope.where('name like (?)',
|
37
|
+
# "%#{params[:selection][:searchName]}%")
|
38
|
+
# end
|
39
|
+
# if params[:selection][:searchShowLabel].present?
|
40
|
+
# element_scope = element_scope.where('short_label like (?)', "%#{params[:selection][:searchShowLabel]}%")
|
41
|
+
# end
|
42
|
+
# if params[:selection][:searchProperties].present?
|
43
|
+
# params[:selection][:searchProperties] && params[:selection][:searchProperties][:layers] && params[:selection][:searchProperties][:layers].keys.each do |lk|
|
44
|
+
# layer = params[:selection][:searchProperties][:layers][lk]
|
45
|
+
# qs = layer[:fields].select { |f| f[:value].present? || f[:type] == 'input-group' }
|
46
|
+
# qs.each do |f|
|
47
|
+
# if f[:type] == 'input-group'
|
48
|
+
# sfs = f[:sub_fields].map { |e| { id: e[:id], value: e[:value] } }
|
49
|
+
# query = { "#{lk}": { fields: [{ field: f[:field].to_s, sub_fields: sfs }] } } if sfs.length > 0
|
50
|
+
# elsif f[:type] == 'checkbox' || f[:type] == 'integer' || f[:type] == 'system-defined'
|
51
|
+
# query = { "#{lk}": { fields: [{ field: f[:field].to_s, value: f[:value] }] } }
|
52
|
+
# else
|
53
|
+
# query = { "#{lk}": { fields: [{ field: f[:field].to_s, value: f[:value].to_s }] } }
|
54
|
+
# end
|
55
|
+
# element_scope = element_scope.where('properties @> ?', query.to_json)
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
# element_scope
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'grape'
|
3
|
+
require 'labimotion/models/segment_klass'
|
4
|
+
module Labimotion
|
5
|
+
## ElementHelpers
|
6
|
+
module SegmentHelpers
|
7
|
+
extend Grape::API::Helpers
|
8
|
+
|
9
|
+
def klass_list(el_klass, is_active=false)
|
10
|
+
scope = SegmentKlass.all
|
11
|
+
scope = scope.where(is_active: is_active) if is_active.present? && is_active == true
|
12
|
+
scope = scope.joins(:element_klass).where(klass_element: params[:element], is_active: true) if el_klass.present?
|
13
|
+
scope.order('place') || []
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_segment_klass(current_user, params)
|
17
|
+
place = params[:place]
|
18
|
+
begin
|
19
|
+
place = place.to_i if place.present? && place.to_i == place.to_f
|
20
|
+
rescue StandardError
|
21
|
+
place = 100
|
22
|
+
end
|
23
|
+
|
24
|
+
uuid = SecureRandom.uuid
|
25
|
+
template = { uuid: uuid, layers: {}, select_options: {} }
|
26
|
+
attributes = declared(params, include_missing: false)
|
27
|
+
attributes[:properties_template]['uuid'] = uuid if attributes[:properties_template].present?
|
28
|
+
template = (attributes[:properties_template].presence || template)
|
29
|
+
template['eln'] = Chemotion::Application.config.version
|
30
|
+
template['labimotion'] = Labimotion::VERSION
|
31
|
+
template['klass'] = 'SegmentKlass'
|
32
|
+
attributes.merge!(properties_template: template, element_klass: @klass, created_by: current_user.id,
|
33
|
+
place: place)
|
34
|
+
attributes[:is_active] = false
|
35
|
+
attributes[:uuid] = uuid
|
36
|
+
attributes[:released_at] = DateTime.now
|
37
|
+
attributes[:properties_release] = attributes[:properties_template]
|
38
|
+
klass = Labimotion::SegmentKlass.create!(attributes)
|
39
|
+
klass.reload
|
40
|
+
klass.create_klasses_revision(current_user.id)
|
41
|
+
klass
|
42
|
+
rescue => e
|
43
|
+
Labimotion.log_exception(e, current_user)
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_segment_klass(current_user, params)
|
48
|
+
segment = fetch_klass('SegmentKlass', params[:id])
|
49
|
+
place = params[:place]
|
50
|
+
begin
|
51
|
+
place = place.to_i if place.present? && place.to_i == place.to_f
|
52
|
+
rescue StandardError
|
53
|
+
place = 100
|
54
|
+
end
|
55
|
+
attributes = declared(params, include_missing: false)
|
56
|
+
attributes.delete(:id)
|
57
|
+
attributes[:place] = place
|
58
|
+
segment&.update!(attributes)
|
59
|
+
segment
|
60
|
+
rescue => e
|
61
|
+
Labimotion.log_exception(e, current_user)
|
62
|
+
raise e
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_repo_klass(params, current_user)
|
66
|
+
response = Labimotion::TemplateHub.fetch_identifier('SegmentKlass', params[:identifier])
|
67
|
+
byebug
|
68
|
+
attributes = response.slice('label', 'desc', 'uuid', 'identifier', 'released_at') # .except(:id, :is_active, :place, :created_by, :created_at, :updated_at)
|
69
|
+
attributes['properties_template'] = response['properties_release']
|
70
|
+
attributes['place'] = ((Labimotion::SegmentKlass.all.length * 10) || 0) + 10
|
71
|
+
attributes['is_active'] = false
|
72
|
+
attributes['updated_by'] = current_user.id
|
73
|
+
attributes['sync_by'] = current_user.id
|
74
|
+
attributes['sync_time'] = DateTime.now
|
75
|
+
|
76
|
+
element_klass = Labimotion::ElementKlass.find_by(identifier: response['element_klass']['identifier'])
|
77
|
+
element_klass = Labimotion::ElementKlass.find_by(name: response['element_klass']['name']) if element_klass.nil?
|
78
|
+
if element_klass.nil?
|
79
|
+
el_attributes = response['element_klass'].slice('name', 'label', 'desc', 'uuid', 'identifier', 'icon_name', 'klass_prefix', 'is_generic', 'released_at')
|
80
|
+
el_attributes['properties_template'] = response['element_klass']['properties_release']
|
81
|
+
Labimotion::ElementKlass.create!(el_attributes)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
if Labimotion::SegmentKlass.find_by(ols_term_id: attributes['ols_term_id']).present?
|
86
|
+
ds = Labimotion::SegmentKlass.find_by(ols_term_id: attributes['ols_term_id'])
|
87
|
+
ds.update!(attributes)
|
88
|
+
else
|
89
|
+
attributes['created_by'] = current_user.id
|
90
|
+
Labimotion::SegmentKlass.create!(attributes)
|
91
|
+
end
|
92
|
+
rescue => e
|
93
|
+
Labimotion.log_exception(e, current_user)
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,325 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'date'
|
7
|
+
require 'labimotion/version'
|
8
|
+
|
9
|
+
# rubocop: disable Metrics/AbcSize
|
10
|
+
# rubocop: disable Metrics/MethodLength
|
11
|
+
# rubocop: disable Metrics/ClassLength
|
12
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
13
|
+
|
14
|
+
module Labimotion
|
15
|
+
class Converter
|
16
|
+
|
17
|
+
def self.logger
|
18
|
+
@@converter_logger ||= Logger.new(Rails.root.join('log/converter.log')) # rubocop:disable Style/ClassVars
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.uri(api_name)
|
22
|
+
url = Rails.configuration.converter.url
|
23
|
+
"#{url}#{api_name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.timeout
|
27
|
+
Rails.configuration.try(:converter).try(:timeout) || 30
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.extname
|
31
|
+
'.jdx'
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.client_id
|
35
|
+
Rails.configuration.converter.profile || ''
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.secret_key
|
39
|
+
Rails.configuration.converter.secret_key || ''
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.auth
|
43
|
+
{ username: client_id, password: secret_key }
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.date_time
|
47
|
+
DateTime.now.strftime('%Q')
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.signature(jbody)
|
51
|
+
md5 = Digest::MD5.new
|
52
|
+
md5.update jbody
|
53
|
+
mdhex = md5.hexdigest
|
54
|
+
mdall = mdhex << secret_key
|
55
|
+
@signature = Digest::SHA1.hexdigest mdall
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.header(opt = {})
|
59
|
+
opt || {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.vor_conv(id)
|
63
|
+
conf = Rails.configuration.try(:converter).try(:url)
|
64
|
+
oa = Attachment.find(id)
|
65
|
+
folder = Rails.root.join('tmp/uploads/converter')
|
66
|
+
FileUtils.mkdir_p(folder)
|
67
|
+
return nil if conf.nil? || oa.nil?
|
68
|
+
|
69
|
+
{ a: oa, f: folder }
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.collect_metadata(zip_file) # rubocop: disable Metrics/PerceivedComplexity
|
73
|
+
dsr = []
|
74
|
+
ols = nil
|
75
|
+
zip_file.each do |entry|
|
76
|
+
next unless entry.name == 'metadata/converter.json'
|
77
|
+
|
78
|
+
metadata = entry.get_input_stream.read.force_encoding('UTF-8')
|
79
|
+
jdata = JSON.parse(metadata)
|
80
|
+
|
81
|
+
ols = jdata['ols']
|
82
|
+
matches = jdata['matches']
|
83
|
+
matches&.each do |match|
|
84
|
+
idf = match['identifier']
|
85
|
+
idr = match['result']
|
86
|
+
if idf&.class == Hash && idr&.class == Hash && !idf['outputLayer'].nil? && !idf['outputKey'].nil? && !idr['value'].nil? # rubocop:disable Layout/LineLength
|
87
|
+
dsr.push(layer: idf['outputLayer'], field: idf['outputKey'], value: idr['value'])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
{ d: dsr, o: ols }
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.handle_response(oat, response) # rubocop: disable Metrics/PerceivedComplexity
|
95
|
+
dsr = []
|
96
|
+
ols = nil
|
97
|
+
|
98
|
+
begin
|
99
|
+
tmp_file = Tempfile.new(encoding: 'ascii-8bit')
|
100
|
+
tmp_file.write(response.parsed_response)
|
101
|
+
tmp_file.rewind
|
102
|
+
|
103
|
+
name = response&.headers && response&.headers['content-disposition']&.split('=')&.last
|
104
|
+
filename = oat.filename
|
105
|
+
name = "#{File.basename(filename, '.*')}.zip" if name.nil?
|
106
|
+
|
107
|
+
att = Attachment.new(
|
108
|
+
filename: name,
|
109
|
+
file_path: tmp_file.path,
|
110
|
+
## content_type: file[:type],
|
111
|
+
attachable_id: oat.attachable_id,
|
112
|
+
attachable_type: 'Container',
|
113
|
+
con_state: Labimotion::ConState::CONVERTED,
|
114
|
+
created_by: oat.created_by,
|
115
|
+
created_for: oat.created_for,
|
116
|
+
)
|
117
|
+
# att.attachment_attacher.attach(tmp_file)
|
118
|
+
if att.valid? && Labimotion::IS_RAILS5 == false
|
119
|
+
att.attachment_attacher.create_derivatives
|
120
|
+
att.save!
|
121
|
+
end
|
122
|
+
if att.valid? && Labimotion::IS_RAILS5 == true
|
123
|
+
primary_store = Rails.configuration.storage.primary_store
|
124
|
+
att.update!(storage: primary_store)
|
125
|
+
end
|
126
|
+
|
127
|
+
Zip::File.open(tmp_file.path) do |zip_file|
|
128
|
+
res = Labimotion::Converter.collect_metadata(zip_file) if name.split('.')&.last == 'zip'
|
129
|
+
ols = res[:o] unless res&.dig(:o).nil?
|
130
|
+
dsr.push(res[:d]) unless res&.dig(:d).nil?
|
131
|
+
end
|
132
|
+
|
133
|
+
dsr.flatten!
|
134
|
+
if dsr.length.positive? && name.split('.')&.last == 'zip'
|
135
|
+
Labimotion::Converter.ts('write', att.attachable_id, ols: ols, info: dsr)
|
136
|
+
end
|
137
|
+
rescue StandardError => e
|
138
|
+
raise e
|
139
|
+
ensure
|
140
|
+
tmp_file&.close
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.process(data)
|
145
|
+
return if data[:a]&.attachable_type != 'Container'
|
146
|
+
|
147
|
+
response = nil
|
148
|
+
begin
|
149
|
+
ofile = Rails.root.join(data[:f], data[:a].filename)
|
150
|
+
FileUtils.cp(data[:a].store.path, ofile)
|
151
|
+
File.open(ofile, 'r') do |f|
|
152
|
+
body = { file: f }
|
153
|
+
response = HTTParty.post(
|
154
|
+
uri('conversions'),
|
155
|
+
basic_auth: auth,
|
156
|
+
body: body,
|
157
|
+
timeout: timeout,
|
158
|
+
)
|
159
|
+
end
|
160
|
+
if response.ok?
|
161
|
+
Labimotion::Converter.handle_response(data[:a], response)
|
162
|
+
else
|
163
|
+
Labimotion::Converter.logger.error ["Converter Response Error: id: [#{data[:a]&.id}], filename: [#{data[:a]&.filename}], response: #{response}"].join($INPUT_RECORD_SEPARATOR)
|
164
|
+
end
|
165
|
+
response
|
166
|
+
rescue StandardError => e
|
167
|
+
raise e
|
168
|
+
ensure
|
169
|
+
FileUtils.rm_f(ofile)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.jcamp_converter(id)
|
174
|
+
resp = nil
|
175
|
+
begin
|
176
|
+
data = Labimotion::Converter.vor_conv(id)
|
177
|
+
return if data.nil?
|
178
|
+
|
179
|
+
resp = Labimotion::Converter.process(data)
|
180
|
+
resp&.success? ? Labimotion::ConState::PROCESSED : Labimotion::ConState::ERROR
|
181
|
+
rescue StandardError => e
|
182
|
+
Labimotion::ConState::ERROR
|
183
|
+
Labimotion::Converter.logger.error ["jcamp_converter fail: #{id}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.generate_ds(att_id, current_user = {})
|
188
|
+
dsr_info = Labimotion::Converter.fetch_dsr(att_id)
|
189
|
+
begin
|
190
|
+
return unless dsr_info && dsr_info[:info]&.length.positive?
|
191
|
+
dataset = Labimotion::Converter.build_ds(att_id, dsr_info[:ols])
|
192
|
+
Labimotion::Converter.update_ds(dataset, dsr_info[:info], current_user)
|
193
|
+
rescue StandardError => e
|
194
|
+
Labimotion::Converter.logger.error ["Att ID: #{att_id}, OLS: #{dsr_info[:ols]}", "DSR: #{dsr_info[:info]}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
|
195
|
+
ensure
|
196
|
+
Labimotion::Converter.clean_dsr(att_id)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.build_ds(att_id, ols)
|
201
|
+
cds = Container.find_by(id: att_id)
|
202
|
+
dataset = Labimotion::Dataset.find_by(element_type: 'Container', element_id: cds.id)
|
203
|
+
return dataset unless dataset.nil?
|
204
|
+
|
205
|
+
klass = Labimotion::DatasetKlass.find_by(ols_term_id: ols)
|
206
|
+
return if klass.nil?
|
207
|
+
|
208
|
+
uuid = SecureRandom.uuid
|
209
|
+
props = klass.properties_release
|
210
|
+
props['uuid'] = uuid
|
211
|
+
props['eln'] = Chemotion::Application.config.version
|
212
|
+
props['labimotion'] = Labimotion::VERSION
|
213
|
+
props['klass'] = 'Dataset'
|
214
|
+
Labimotion::Dataset.create!(
|
215
|
+
uuid: uuid,
|
216
|
+
dataset_klass_id: klass.id,
|
217
|
+
element_type: 'Container',
|
218
|
+
element_id: cds.id,
|
219
|
+
properties: props,
|
220
|
+
properties_release: klass.properties_release,
|
221
|
+
klass_uuid: klass.uuid
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.update_ds(dataset, dsr, current_user = nil) # rubocop: disable Metrics/PerceivedComplexity
|
226
|
+
layers = dataset.properties['layers'] || {}
|
227
|
+
new_prop = dataset.properties
|
228
|
+
dsr.each do |ds|
|
229
|
+
layer = layers[ds[:layer]]
|
230
|
+
fields = layer['fields'].select{ |f| f['field'] == ds[:field] }
|
231
|
+
fi = fields&.first
|
232
|
+
idx = layer['fields'].find_index(fi)
|
233
|
+
fi['value'] = ds[:value]
|
234
|
+
fi['device'] = ds[:device] || ds[:value]
|
235
|
+
new_prop['layers'][ds[:layer]]['fields'][idx] = fi
|
236
|
+
end
|
237
|
+
new_prop.dig('layers', 'general', 'fields')&.each_with_index do |fi, idx|
|
238
|
+
if fi['field'] == 'creator' && current_user.present?
|
239
|
+
fi['label'] = fi['label']
|
240
|
+
fi['value'] = current_user.name
|
241
|
+
fi['system'] = current_user.name
|
242
|
+
new_prop['layers']['general']['fields'][idx] = fi
|
243
|
+
end
|
244
|
+
end
|
245
|
+
element = Container.find(dataset.element_id)&.root_element
|
246
|
+
element.present? && element&.class&.name == 'Sample' && new_prop.dig('layers', 'sample_details', 'fields')&.each_with_index do |fi, idx|
|
247
|
+
if fi['field'] == 'id'
|
248
|
+
fi['value'] = element.id
|
249
|
+
fi['system'] = element.id
|
250
|
+
new_prop['layers']['general']['fields'][idx] = fi
|
251
|
+
end
|
252
|
+
|
253
|
+
if fi['field'] == 'label'
|
254
|
+
fi['value'] = element.short_label
|
255
|
+
fi['system'] = element.short_label
|
256
|
+
new_prop['layers']['general']['fields'][idx] = fi
|
257
|
+
end
|
258
|
+
end
|
259
|
+
dataset.properties = new_prop
|
260
|
+
dataset.save!
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.ts(method, identifier, params = nil)
|
264
|
+
Rails.cache.send(method, "#{Labimotion::Converter.new.class.name}#{identifier}", params)
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.fetch_dsr(att_id)
|
268
|
+
Labimotion::Converter.ts('read', att_id)
|
269
|
+
end
|
270
|
+
|
271
|
+
def self.clean_dsr(att_id)
|
272
|
+
Labimotion::Converter.ts('delete', att_id)
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.fetch_options
|
276
|
+
options = { basic_auth: auth, timeout: timeout }
|
277
|
+
response = HTTParty.get(uri('options'), options)
|
278
|
+
response.parsed_response if response.code == 200
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.delete_profile(id)
|
282
|
+
options = { basic_auth: auth, timeout: timeout }
|
283
|
+
response = HTTParty.delete("#{uri('profiles')}/#{id}", options)
|
284
|
+
response.parsed_response if response.code == 200
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.create_profile(data)
|
288
|
+
options = { basic_auth: auth, timeout: timeout, body: data.to_json, headers: { 'Content-Type' => 'application/json' } }
|
289
|
+
response = HTTParty.post(uri('profiles'), options)
|
290
|
+
response.parsed_response if response.code == 201
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.update_profile(data)
|
294
|
+
options = { basic_auth: auth, timeout: timeout, body: data.to_json, headers: { 'Content-Type' => 'application/json' } }
|
295
|
+
response = HTTParty.put("#{uri('profiles')}/#{data[:id]}", options)
|
296
|
+
response.parsed_response if response.code == 200
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.fetch_profiles
|
300
|
+
options = { basic_auth: auth, timeout: timeout }
|
301
|
+
response = HTTParty.get(uri('profiles'), options)
|
302
|
+
response.parsed_response if response.code == 200
|
303
|
+
end
|
304
|
+
|
305
|
+
def self.create_tables(tmpfile)
|
306
|
+
res = {}
|
307
|
+
File.open(tmpfile.path, 'r') do |file|
|
308
|
+
body = { file: file }
|
309
|
+
response = HTTParty.post(
|
310
|
+
uri('tables'),
|
311
|
+
basic_auth: auth,
|
312
|
+
body: body,
|
313
|
+
timeout: timeout,
|
314
|
+
)
|
315
|
+
res = response.parsed_response
|
316
|
+
end
|
317
|
+
res
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# rubocop: enable Metrics/AbcSize
|
323
|
+
# rubocop: enable Metrics/MethodLength
|
324
|
+
# rubocop: enable Metrics/ClassLength
|
325
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'export_table'
|
3
|
+
|
4
|
+
module Labimotion
|
5
|
+
## ExportDataset
|
6
|
+
class ExportDataset
|
7
|
+
DEFAULT_ROW_WIDTH = 100
|
8
|
+
DEFAULT_ROW_HEIGHT = 20
|
9
|
+
|
10
|
+
def initialize(**args)
|
11
|
+
@xfile = Axlsx::Package.new
|
12
|
+
@file_extension = 'xlsx'
|
13
|
+
@xfile.workbook.styles.fonts.first.name = 'Calibri'
|
14
|
+
end
|
15
|
+
|
16
|
+
def res_name(id)
|
17
|
+
element_name = Container.find(id)&.root_element&.short_label
|
18
|
+
ols = ols_name(id)
|
19
|
+
"#{element_name}_#{ols.gsub(' ', '_')}.xlsx"
|
20
|
+
end
|
21
|
+
|
22
|
+
def ols_name(id)
|
23
|
+
ds = Labimotion::Dataset.find_by(element_id: id, element_type: 'Container')
|
24
|
+
return nil if ds.nil?
|
25
|
+
|
26
|
+
name = ds.dataset_klass.label
|
27
|
+
|
28
|
+
match = name.match(/\((.*?)\)/)
|
29
|
+
name = match && match.length > 2 ? match[1] : name
|
30
|
+
|
31
|
+
name = '1H NMR' if ds.dataset_klass.ols_term_id == 'CHMO:0000593'
|
32
|
+
name = '13C NMR' if ds.dataset_klass.ols_term_id == 'CHMO:0000595'
|
33
|
+
name.slice(0, 26)
|
34
|
+
end
|
35
|
+
|
36
|
+
def description(ds, id)
|
37
|
+
wb = @xfile.workbook
|
38
|
+
sheet = @xfile.workbook.add_worksheet(name: 'Description')
|
39
|
+
header_style = sheet.styles.add_style(sz: 12, fg_color: 'FFFFFF', bg_color: '00008B', border: { style: :thick, color: 'FF777777', edges: [:bottom] })
|
40
|
+
sheet.add_row(['File name', res_name(id)])
|
41
|
+
sheet.add_row(['Time', Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")] )
|
42
|
+
sheet.add_row([''])
|
43
|
+
sheet.add_row(['Fields description of sheet:' + ds.dataset_klass.label])
|
44
|
+
sheet.add_row(['Fields', 'Field description'], style: header_style)
|
45
|
+
sheet.add_row(['Layer Label', 'The label of the layer'])
|
46
|
+
sheet.add_row(['Field Label', 'The label of the field'])
|
47
|
+
sheet.add_row(['Value', 'The current value of the field'])
|
48
|
+
sheet.add_row(['Unit', 'The unit of the field'])
|
49
|
+
sheet.add_row(['Name', 'The key of the field, can be used to identify the field'])
|
50
|
+
sheet.add_row(['Type', 'The type of the field'])
|
51
|
+
sheet.add_row(['From device?', '[Yes] if the field is from the device, [No] if the field is manually entered by the user, [SYS] if the field is automatically generated by the system'])
|
52
|
+
sheet.add_row(['Device source', 'The source tag of the device file, available only if the ontology term is 1H NMR or 13C NMR'])
|
53
|
+
sheet.add_row(['Device data', 'The original device data, can not be changed after data uploaded'])
|
54
|
+
sheet.add_row([''])
|
55
|
+
sheet.add_row([''])
|
56
|
+
sheet.add_row([''])
|
57
|
+
sheet.add_row(['', '(This file is automatically generated by the system.)'])
|
58
|
+
end
|
59
|
+
|
60
|
+
def export(id)
|
61
|
+
ds = Labimotion::Dataset.find_by(element_id: id, element_type: 'Container')
|
62
|
+
return if ds.nil?
|
63
|
+
|
64
|
+
description(ds, id)
|
65
|
+
|
66
|
+
wb = @xfile.workbook
|
67
|
+
name = ols_name(id)
|
68
|
+
return if name.nil?
|
69
|
+
|
70
|
+
sheet = @xfile.workbook.add_worksheet(name: name)
|
71
|
+
sheet.add_row([ds.dataset_klass.label])
|
72
|
+
header_style = sheet.styles.add_style(sz: 12, fg_color: 'FFFFFF', bg_color: '00008B', border: { style: :thick, color: 'FF777777', edges: [:bottom] })
|
73
|
+
layer_style = sheet.styles.add_style(b: true, bg_color: 'CEECF5')
|
74
|
+
sheet.add_row(header, style: header_style)
|
75
|
+
|
76
|
+
layers = ds.properties['layers'] || {}
|
77
|
+
layer_keys = layers.keys.sort_by { |key| layers[key]['position'] }
|
78
|
+
layer_keys.each do |key|
|
79
|
+
layer = layers[key]
|
80
|
+
sheet.add_row([layer['label'], ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], style: layer_style)
|
81
|
+
sorted_fields = layer['fields'].sort_by { |obj| obj['position'] }
|
82
|
+
sorted_fields.each do |field|
|
83
|
+
next if field['type'] == 'dummy'
|
84
|
+
|
85
|
+
type = field['type']
|
86
|
+
from_device = field['device'].present? ? 'Yes' : 'No'
|
87
|
+
from_device = field['system'].present? ? 'SYS' : from_device
|
88
|
+
type = "#{field['type']}-#{field['option_layers']}" if field['type'] == 'select' || field['type'] == 'system-defined'
|
89
|
+
|
90
|
+
show_value = field['value'] =~ /\A\d+,\d+\z/ ? field['value']&.gsub(',', '.') : field['value']
|
91
|
+
sheet.add_row([' ', field['label'], show_value, field['value_system'], field['field'], type, from_device, field['dkey'], field['system'] || field['device']].freeze)
|
92
|
+
end
|
93
|
+
# sheet.column_widths nil, nil, nil, nil, 0, 0, 0, 0, 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def spectra(id)
|
98
|
+
wb = @xfile.workbook
|
99
|
+
gds = Labimotion::Dataset.find_by(element_id: id, element_type: 'Container')
|
100
|
+
cds = Container.find(id)
|
101
|
+
cds.attachments.where(aasm_state: 'csv').each do |att|
|
102
|
+
name = File.basename(att.filename, '.csv')
|
103
|
+
sheet = @xfile.workbook.add_worksheet(name: name)
|
104
|
+
File.open(att.store.path) do |fi|
|
105
|
+
fi.each_line do |line|
|
106
|
+
sheet.add_row(line.split(','))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def header
|
113
|
+
['Layer Label', 'Field Label', 'Value', 'Unit', 'Name', 'Type', 'from device?', 'Device source', 'Device data'].freeze
|
114
|
+
end
|
115
|
+
|
116
|
+
def read
|
117
|
+
@xfile.to_stream.read
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|