labimotion 2.1.2 → 2.2.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.
- checksums.yaml +4 -4
- data/lib/labimotion/apis/generic_element_api.rb +2 -2
- data/lib/labimotion/collection/import.rb +3 -3
- data/lib/labimotion/helpers/element_helpers.rb +5 -9
- data/lib/labimotion/helpers/param_helpers.rb +0 -4
- data/lib/labimotion/libs/converter.rb +18 -30
- data/lib/labimotion/libs/data/layer/StdDataset.json +212 -0
- data/lib/labimotion/libs/dataset_builder.rb +1 -2
- data/lib/labimotion/libs/nmr_mapper.rb +2 -31
- data/lib/labimotion/models/concerns/attachment_converter.rb +0 -24
- data/lib/labimotion/models/concerns/datasetable.rb +2 -3
- data/lib/labimotion/models/concerns/generic_klass_revisions.rb +3 -2
- data/lib/labimotion/utils/mapper_utils.rb +11 -20
- data/lib/labimotion/version.rb +1 -1
- data/lib/labimotion.rb +0 -5
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4397eed28e8f2c6f0e21e022191d842dbb7a42000a2efe72731a89ab8bf9e77b
|
|
4
|
+
data.tar.gz: 3ae429541da0f787d6d0f544307b5acfbf3e922d83c7fc7cd27e47738eb5880e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12a5d77d600daaf1a45640ab5ff7d253a608cd683fac28a5286019a7990e85cb7c1f0c957240fab625d3dbb703196dcb918b652bcc86457c6ac88cc085990ea0
|
|
7
|
+
data.tar.gz: 28453642570e3e177c0c2684590cdb715016c4043645d9f2e097eca0a4f41e9e3ff30564df8a0b7d5800bfb36a2fd224aa40cb91a107a2bc53adddc1db133070
|
|
@@ -474,7 +474,7 @@ module Labimotion
|
|
|
474
474
|
detail_levels: ElementDetailLevelCalculator.new(user: current_user, element: element).detail_levels,
|
|
475
475
|
policy: @element_policy
|
|
476
476
|
),
|
|
477
|
-
attachments:
|
|
477
|
+
attachments: attach_thumbnail(element&.attachments)
|
|
478
478
|
}
|
|
479
479
|
rescue StandardError => e
|
|
480
480
|
Labimotion.log_exception(e, current_user)
|
|
@@ -517,7 +517,7 @@ module Labimotion
|
|
|
517
517
|
element,
|
|
518
518
|
detail_levels: ElementDetailLevelCalculator.new(user: current_user, element: element).detail_levels,
|
|
519
519
|
),
|
|
520
|
-
attachments:
|
|
520
|
+
attachments: attach_thumbnail(element&.attachments),
|
|
521
521
|
}
|
|
522
522
|
rescue StandardError => e
|
|
523
523
|
Labimotion.log_exception(e, current_user)
|
|
@@ -69,7 +69,7 @@ module Labimotion
|
|
|
69
69
|
|
|
70
70
|
dataset = Labimotion::Dataset.create!(
|
|
71
71
|
fields.slice(
|
|
72
|
-
'properties', 'properties_release'
|
|
72
|
+
'properties', 'properties_release'
|
|
73
73
|
).merge(
|
|
74
74
|
## created_by: current_user_id,
|
|
75
75
|
element: element,
|
|
@@ -112,7 +112,7 @@ module Labimotion
|
|
|
112
112
|
|
|
113
113
|
segment = Labimotion::Segment.create!(
|
|
114
114
|
fields.slice(
|
|
115
|
-
'properties', 'properties_release'
|
|
115
|
+
'properties', 'properties_release'
|
|
116
116
|
).merge(
|
|
117
117
|
created_by: current_user_id,
|
|
118
118
|
element: element,
|
|
@@ -149,7 +149,7 @@ module Labimotion
|
|
|
149
149
|
|
|
150
150
|
element = Labimotion::Element.create!(
|
|
151
151
|
fields.slice(
|
|
152
|
-
'name', 'properties', 'properties_release'
|
|
152
|
+
'name', 'properties', 'properties_release'
|
|
153
153
|
).merge(
|
|
154
154
|
created_by: current_user_id,
|
|
155
155
|
element_klass: element_klass,
|
|
@@ -82,18 +82,16 @@ module Labimotion
|
|
|
82
82
|
klass_uuid: klass[:uuid],
|
|
83
83
|
properties: properties,
|
|
84
84
|
properties_release: params[:properties_release],
|
|
85
|
-
|
|
86
|
-
created_by: current_user.id
|
|
85
|
+
created_by: current_user.id,
|
|
87
86
|
}
|
|
88
87
|
element = Labimotion::Element.new(attributes)
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
element.collections << all_coll
|
|
92
|
-
|
|
93
|
-
if params[:collection_id] && params[:collection_id] != all_coll.id
|
|
89
|
+
if params[:collection_id]
|
|
94
90
|
collection = current_user.collections.find(params[:collection_id])
|
|
95
91
|
element.collections << collection
|
|
96
92
|
end
|
|
93
|
+
all_coll = Collection.get_all_collection_for_user(current_user.id)
|
|
94
|
+
element.collections << all_coll
|
|
97
95
|
element.save!
|
|
98
96
|
element.properties = update_sample_association(params[:properties], current_user, element)
|
|
99
97
|
# element.properties = update_vocabularies(_properties, current_user, element)
|
|
@@ -118,8 +116,7 @@ module Labimotion
|
|
|
118
116
|
params.delete(:user_labels)
|
|
119
117
|
attributes = declared(params.except(:segments), include_missing: false)
|
|
120
118
|
properties['pkg'] = Labimotion::Utils.pkg(properties['pkg'])
|
|
121
|
-
|
|
122
|
-
if element.klass_uuid != properties['klass_uuid'] || element.properties != properties || element.name != params[:name] || element.metadata != metadata
|
|
119
|
+
if element.klass_uuid != properties['klass_uuid'] || element.properties != properties || element.name != params[:name]
|
|
123
120
|
properties['klass'] = 'Element'
|
|
124
121
|
uuid = SecureRandom.uuid
|
|
125
122
|
properties['uuid'] = uuid
|
|
@@ -131,7 +128,6 @@ module Labimotion
|
|
|
131
128
|
attributes['properties']['uuid'] = uuid
|
|
132
129
|
attributes['uuid'] = uuid
|
|
133
130
|
attributes['klass_uuid'] = properties['klass_uuid']
|
|
134
|
-
attributes['metadata'] = metadata
|
|
135
131
|
attributes['updated_at'] = Time.current
|
|
136
132
|
element.update_columns(attributes)
|
|
137
133
|
end
|
|
@@ -13,7 +13,6 @@ module Labimotion
|
|
|
13
13
|
optional :desc, type: String, desc: 'Klass desc'
|
|
14
14
|
optional :klass_prefix, type: String, desc: 'Klass klass_prefix'
|
|
15
15
|
optional :icon_name, type: String, desc: 'Klass icon_name'
|
|
16
|
-
optional :metadata, type: Hash, desc: 'Klass metadata'
|
|
17
16
|
requires :properties_template, type: Hash, desc: 'Klass template'
|
|
18
17
|
optional :properties_release, type: Hash, desc: 'Klass release'
|
|
19
18
|
optional :released_at, type: DateTime, desc: 'Klass released_at'
|
|
@@ -30,7 +29,6 @@ module Labimotion
|
|
|
30
29
|
requires :klass_prefix, type: String, desc: 'Element Klass Short Label Prefix'
|
|
31
30
|
optional :icon_name, type: String, desc: 'Element Klass Icon Name'
|
|
32
31
|
optional :desc, type: String, desc: 'Element Klass Desc'
|
|
33
|
-
optional :metadata, type: Hash, desc: 'Element Klass metadata'
|
|
34
32
|
optional :properties_template, type: Hash, desc: 'Element Klass properties template'
|
|
35
33
|
end
|
|
36
34
|
|
|
@@ -71,7 +69,6 @@ module Labimotion
|
|
|
71
69
|
params :upload_segment_klass_params do
|
|
72
70
|
requires :label, type: String, desc: 'Klass label'
|
|
73
71
|
optional :desc, type: String, desc: 'Klass desc'
|
|
74
|
-
optional :metadata, type: Hash, desc: 'Klass metadata'
|
|
75
72
|
requires :properties_template, type: Hash, desc: 'Klass template'
|
|
76
73
|
optional :properties_release, type: Hash, desc: 'Klass release'
|
|
77
74
|
optional :released_at, type: DateTime, desc: 'Klass released_at'
|
|
@@ -98,7 +95,6 @@ module Labimotion
|
|
|
98
95
|
requires :element_klass, type: Integer, desc: 'Element Klass Id'
|
|
99
96
|
optional :desc, type: String, desc: 'Segment Klass Desc'
|
|
100
97
|
optional :place, type: String, desc: 'Segment Klass Place', default: '100'
|
|
101
|
-
optional :metadata, type: Hash, desc: 'Klass metadata'
|
|
102
98
|
optional :properties_template, type: Hash, desc: 'Element Klass properties template'
|
|
103
99
|
end
|
|
104
100
|
|
|
@@ -6,7 +6,6 @@ require 'json'
|
|
|
6
6
|
require 'date'
|
|
7
7
|
require 'labimotion/version'
|
|
8
8
|
require 'labimotion/utils/utils'
|
|
9
|
-
require 'labimotion/utils/mapper_utils'
|
|
10
9
|
require 'labimotion/helpers/converter_helpers'
|
|
11
10
|
|
|
12
11
|
# rubocop: disable Metrics/AbcSize
|
|
@@ -21,36 +20,27 @@ module Labimotion
|
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
def self.process_ds(id, current_user = {})
|
|
24
|
-
|
|
25
|
-
# Savepoint: a failure leaves no half-built dataset and keeps the caller's transaction usable
|
|
26
|
-
Attachment.transaction(requires_new: true) { map_ds(id, current_user, ctx) }
|
|
27
|
-
rescue StandardError => e
|
|
28
|
-
Labimotion::Converter.logger.error ["Att ID: #{ctx[:att]&.id}, OLS: #{ctx[:ols]}", "DSR: #{ctx[:dsr]}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
|
|
29
|
-
Labimotion.report_exception(e)
|
|
30
|
-
# Terminal state: do not fail the request, and do not retry on the next save
|
|
31
|
-
ctx[:att]&.update_column(:con_state, Labimotion::ConState::ERROR)
|
|
32
|
-
Labimotion::ConState::ERROR
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def self.map_ds(id, current_user, ctx)
|
|
36
|
-
att = ctx[:att] = Attachment.find_by(id: id, con_state: Labimotion::ConState::CONVERTED)
|
|
23
|
+
att = Attachment.find_by(id: id, con_state: Labimotion::ConState::CONVERTED)
|
|
37
24
|
return if att.nil? || att.attachable_id.nil? || att.attachable_type != 'Container' || att.filename.split('.')&.last != 'zip'
|
|
38
25
|
|
|
39
26
|
eln_ds = Container.find_by(id: att.attachable_id, container_type: 'dataset')
|
|
40
27
|
return if eln_ds.nil? || eln_ds.parent.nil? || eln_ds.parent&.container_type != 'analysis'
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
dsr = []
|
|
30
|
+
ols = nil
|
|
31
|
+
Zip::File.open(att.attachment_attacher.file.url) do |zip_file|
|
|
32
|
+
res = Labimotion::Converter.collect_metadata(zip_file, current_user) if att.filename.split('.')&.last == 'zip'
|
|
33
|
+
ols = res[:o] unless res&.dig(:o).nil?
|
|
34
|
+
dsr.push(res[:d]) unless res&.dig(:d).nil?
|
|
35
|
+
end
|
|
36
|
+
dsr.flatten!
|
|
37
|
+
dataset = build_ds(att.attachable_id, ols)
|
|
38
|
+
update_ds(dataset, dsr, current_user) if dataset.present?
|
|
50
39
|
att.update_column(:con_state, Labimotion::ConState::COMPLETED)
|
|
51
|
-
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
Labimotion::Converter.logger.error ["Att ID: #{att&.id}, OLS: #{ols}", "DSR: #{dsr}", e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR)
|
|
42
|
+
raise e
|
|
52
43
|
end
|
|
53
|
-
private_class_method :map_ds
|
|
54
44
|
|
|
55
45
|
def self.uri(api_name)
|
|
56
46
|
url = Rails.configuration.converter.url
|
|
@@ -109,7 +99,7 @@ module Labimotion
|
|
|
109
99
|
zip_file.each do |entry|
|
|
110
100
|
next unless entry.name == 'metadata/converter.json'
|
|
111
101
|
|
|
112
|
-
metadata =
|
|
102
|
+
metadata = entry.get_input_stream.read.force_encoding('UTF-8')
|
|
113
103
|
jdata = JSON.parse(metadata)
|
|
114
104
|
|
|
115
105
|
ols = jdata['ols']
|
|
@@ -174,9 +164,8 @@ module Labimotion
|
|
|
174
164
|
)
|
|
175
165
|
end
|
|
176
166
|
if response.ok?
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
state == Labimotion::ConState::ERROR ? state : Labimotion::ConState::PROCESSED
|
|
167
|
+
Labimotion::Converter.handle_response(data[:a], response, current_user)
|
|
168
|
+
Labimotion::ConState::PROCESSED
|
|
180
169
|
else
|
|
181
170
|
Labimotion::Converter.logger.error ["Converter Response Error: id: [#{data[:a]&.id}], filename: [#{data[:a]&.filename}], response: #{response}"].join($INPUT_RECORD_SEPARATOR)
|
|
182
171
|
Labimotion::ConState::ERROR
|
|
@@ -233,8 +222,7 @@ module Labimotion
|
|
|
233
222
|
element_id: cds.id,
|
|
234
223
|
properties: props,
|
|
235
224
|
properties_release: klass.properties_release,
|
|
236
|
-
klass_uuid: klass.uuid
|
|
237
|
-
metadata: klass.metadata
|
|
225
|
+
klass_uuid: klass.uuid
|
|
238
226
|
)
|
|
239
227
|
end
|
|
240
228
|
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
{
|
|
2
|
+
"layers": {
|
|
3
|
+
"std_general": {
|
|
4
|
+
"wf": false,
|
|
5
|
+
"key": "std_general",
|
|
6
|
+
"std": true,
|
|
7
|
+
"cols": 4,
|
|
8
|
+
"color": "default",
|
|
9
|
+
"label": "Standard General description",
|
|
10
|
+
"style": "panel_generic_heading",
|
|
11
|
+
"fields": [
|
|
12
|
+
{
|
|
13
|
+
"type": "text",
|
|
14
|
+
"field": "title",
|
|
15
|
+
"label": "title",
|
|
16
|
+
"default": "",
|
|
17
|
+
"ontology": {
|
|
18
|
+
"id": "afo:class:http://purl.allotrope.org/ontologies/result#AFR_0001080",
|
|
19
|
+
"iri": "http://purl.allotrope.org/ontologies/result#AFR_0001080",
|
|
20
|
+
"type": "class",
|
|
21
|
+
"label": "title",
|
|
22
|
+
"obo_id": "AFR:0001080",
|
|
23
|
+
"short_form": "AFR_0001080",
|
|
24
|
+
"description": [
|
|
25
|
+
"A title is a prefix or suffix added to a personal name. A title can be a title of honor, that is a title bestowed as an award, a honorary title (academic), that is a recognition of contributions by a non-employee or employee, a hereditary title, that is a title that remains in a family or a job title, that is a designation of a person's position in an organization. [Wikipedia]"
|
|
26
|
+
],
|
|
27
|
+
"ontology_name": "afo",
|
|
28
|
+
"ontology_prefix": "AFO"
|
|
29
|
+
},
|
|
30
|
+
"position": 1,
|
|
31
|
+
"required": false,
|
|
32
|
+
"sub_fields": [],
|
|
33
|
+
"text_sub_fields": []
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "text",
|
|
37
|
+
"field": "data_type",
|
|
38
|
+
"label": "Type of the data ",
|
|
39
|
+
"default": "",
|
|
40
|
+
"readonly": true,
|
|
41
|
+
"position": 2,
|
|
42
|
+
"required": false,
|
|
43
|
+
"sub_fields": [],
|
|
44
|
+
"description": "Ontologies!!!! type of entity",
|
|
45
|
+
"placeholder": "e.g. sample or reaction analysis",
|
|
46
|
+
"text_sub_fields": []
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "text",
|
|
50
|
+
"field": "date",
|
|
51
|
+
"label": "date",
|
|
52
|
+
"default": "",
|
|
53
|
+
"position": 3,
|
|
54
|
+
"required": false,
|
|
55
|
+
"sub_fields": [],
|
|
56
|
+
"text_sub_fields": []
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "text",
|
|
60
|
+
"field": "time",
|
|
61
|
+
"label": "starting time",
|
|
62
|
+
"default": "",
|
|
63
|
+
"position": 4,
|
|
64
|
+
"required": false,
|
|
65
|
+
"sub_fields": [],
|
|
66
|
+
"text_sub_fields": []
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "text",
|
|
70
|
+
"field": "contributor",
|
|
71
|
+
"label": "contributor",
|
|
72
|
+
"default": "",
|
|
73
|
+
"position": 5,
|
|
74
|
+
"required": false,
|
|
75
|
+
"sub_fields": [],
|
|
76
|
+
"description": "",
|
|
77
|
+
"text_sub_fields": []
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "text",
|
|
81
|
+
"field": "creator",
|
|
82
|
+
"label": "creator",
|
|
83
|
+
"default": "",
|
|
84
|
+
"position": 6,
|
|
85
|
+
"required": false,
|
|
86
|
+
"sub_fields": [],
|
|
87
|
+
"description": "the person who upload the analysis",
|
|
88
|
+
"text_sub_fields": []
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"type": "text",
|
|
92
|
+
"field": "operator",
|
|
93
|
+
"label": "operator",
|
|
94
|
+
"default": "",
|
|
95
|
+
"position": 7,
|
|
96
|
+
"required": false,
|
|
97
|
+
"sub_fields": [],
|
|
98
|
+
"text_sub_fields": []
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "text",
|
|
102
|
+
"field": "comments",
|
|
103
|
+
"label": "comments",
|
|
104
|
+
"default": "",
|
|
105
|
+
"position": 8,
|
|
106
|
+
"required": false,
|
|
107
|
+
"sub_fields": [],
|
|
108
|
+
"text_sub_fields": []
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"opid": 8,
|
|
112
|
+
"type": "text",
|
|
113
|
+
"field": "Producer",
|
|
114
|
+
"label": "Producer of the sample",
|
|
115
|
+
"is_voc": true,
|
|
116
|
+
"source": "Segment",
|
|
117
|
+
"default": "",
|
|
118
|
+
"field_id": "Producer",
|
|
119
|
+
"layer_id": "bsi",
|
|
120
|
+
"ontology": {
|
|
121
|
+
"id": "schema:property:https://schema.org/producer",
|
|
122
|
+
"iri": "https://schema.org/producer",
|
|
123
|
+
"type": "property",
|
|
124
|
+
"label": "producer",
|
|
125
|
+
"obo_id": "schema:producer",
|
|
126
|
+
"short_form": "schema_producer",
|
|
127
|
+
"description": [
|
|
128
|
+
"The person or organization who produced the work (e.g. music album, movie, TV/radio series etc.)."
|
|
129
|
+
],
|
|
130
|
+
"ontology_name": "schema",
|
|
131
|
+
"ontology_prefix": "schema"
|
|
132
|
+
},
|
|
133
|
+
"position": 9,
|
|
134
|
+
"source_id": "dce363d5-56d0-4324-9914-0476be999016",
|
|
135
|
+
"identifier": "357b7cd3-ca47-49e0-be47-154d907c2cf5",
|
|
136
|
+
"sub_fields": [],
|
|
137
|
+
"text_sub_fields": []
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
"position": -2,
|
|
141
|
+
"condition": "",
|
|
142
|
+
"wf_position": 0
|
|
143
|
+
},
|
|
144
|
+
"std_sample_details": {
|
|
145
|
+
"wf": false,
|
|
146
|
+
"key": "std_sample_details",
|
|
147
|
+
"cols": 3,
|
|
148
|
+
"std": true,
|
|
149
|
+
"color": "none",
|
|
150
|
+
"label": "Standard Sample details",
|
|
151
|
+
"style": "panel_generic_heading",
|
|
152
|
+
"fields": [
|
|
153
|
+
{
|
|
154
|
+
"type": "text",
|
|
155
|
+
"field": "label",
|
|
156
|
+
"label": "label",
|
|
157
|
+
"default": "",
|
|
158
|
+
"position": 1,
|
|
159
|
+
"required": false,
|
|
160
|
+
"sub_fields": [],
|
|
161
|
+
"text_sub_fields": []
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"type": "text",
|
|
165
|
+
"field": "id",
|
|
166
|
+
"label": "id",
|
|
167
|
+
"default": "",
|
|
168
|
+
"position": 2,
|
|
169
|
+
"required": false,
|
|
170
|
+
"sub_fields": [],
|
|
171
|
+
"text_sub_fields": []
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"type": "text",
|
|
175
|
+
"field": "amount",
|
|
176
|
+
"label": "amount",
|
|
177
|
+
"default": "",
|
|
178
|
+
"position": 3,
|
|
179
|
+
"required": false,
|
|
180
|
+
"sub_fields": [],
|
|
181
|
+
"text_sub_fields": []
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"type": "text",
|
|
185
|
+
"field": "volume",
|
|
186
|
+
"label": "volume",
|
|
187
|
+
"default": "",
|
|
188
|
+
"position": 4,
|
|
189
|
+
"required": false,
|
|
190
|
+
"sub_fields": [],
|
|
191
|
+
"text_sub_fields": []
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"type": "text",
|
|
195
|
+
"field": "size",
|
|
196
|
+
"label": "size",
|
|
197
|
+
"default": "",
|
|
198
|
+
"position": 5,
|
|
199
|
+
"required": false,
|
|
200
|
+
"sub_fields": [],
|
|
201
|
+
"text_sub_fields": []
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
"position": -1,
|
|
205
|
+
"timeRecord": "",
|
|
206
|
+
"wf_position": 0
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"version": "0.1",
|
|
210
|
+
"select_options": {
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -30,21 +30,7 @@ module Labimotion
|
|
|
30
30
|
|
|
31
31
|
class << self
|
|
32
32
|
def process_ds(id, current_user = {})
|
|
33
|
-
|
|
34
|
-
# Savepoint: a failure leaves no half-built dataset and keeps the caller's transaction usable
|
|
35
|
-
Attachment.transaction(requires_new: true) { map_ds(id, current_user, ctx) }
|
|
36
|
-
rescue StandardError => e
|
|
37
|
-
Labimotion.log_exception(e, current_user)
|
|
38
|
-
# Not a readable zip: nothing to map, and not an error
|
|
39
|
-
return Labimotion::ConState::NONE if invalid_archive?(e, ctx[:att])
|
|
40
|
-
|
|
41
|
-
# Terminal state: do not fail the request, and do not retry on the next save
|
|
42
|
-
Labimotion.report_exception(e)
|
|
43
|
-
Labimotion::ConState::ERROR
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def map_ds(id, current_user, ctx)
|
|
47
|
-
att = ctx[:att] = find_attachment(id)
|
|
33
|
+
att = find_attachment(id)
|
|
48
34
|
return Labimotion::ConState::NONE if att.nil?
|
|
49
35
|
|
|
50
36
|
result = process(att)
|
|
@@ -146,20 +132,6 @@ module Labimotion
|
|
|
146
132
|
Attachment.find_by(id: id, con_state: Labimotion::ConState::NMR)
|
|
147
133
|
end
|
|
148
134
|
|
|
149
|
-
# True when the upload itself is not a readable zip. A missing or changed file, an encrypted zip
|
|
150
|
-
# or an unsupported compression method is not covered and stays ERROR.
|
|
151
|
-
def invalid_archive?(error, att)
|
|
152
|
-
return false unless error.instance_of?(Zip::Error) || error.is_a?(Zip::DecompressionError)
|
|
153
|
-
|
|
154
|
-
file = att&.attachment_attacher&.file
|
|
155
|
-
path = file&.url
|
|
156
|
-
on_disk = path && File.size?(path)
|
|
157
|
-
return false if on_disk.nil?
|
|
158
|
-
|
|
159
|
-
recorded = file.size
|
|
160
|
-
recorded.nil? || recorded == on_disk
|
|
161
|
-
end
|
|
162
|
-
|
|
163
135
|
def handle_process_result(result, att, id, current_user)
|
|
164
136
|
if result[:is_bagit]
|
|
165
137
|
handle_bagit_result(att, id, current_user)
|
|
@@ -173,8 +145,7 @@ module Labimotion
|
|
|
173
145
|
def handle_bagit_result(att, id, current_user)
|
|
174
146
|
att.update_column(:con_state, Labimotion::ConState::CONVERTED)
|
|
175
147
|
Labimotion::Converter.metadata(id, current_user)
|
|
176
|
-
|
|
177
|
-
Attachment.find_by(id: id)&.con_state || Labimotion::ConState::NONE
|
|
148
|
+
Labimotion::ConState::COMPLETED
|
|
178
149
|
end
|
|
179
150
|
|
|
180
151
|
def invalid_metadata?(result)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'zip'
|
|
4
|
-
|
|
5
3
|
module Labimotion
|
|
6
4
|
module AttachmentConverter
|
|
7
5
|
ACCEPTED_FORMATS = (Rails.configuration.try(:converter).try(:ext) || []).freeze
|
|
@@ -29,8 +27,6 @@ module Labimotion
|
|
|
29
27
|
|
|
30
28
|
return if attachable_id.nil? && con_state != Labimotion::ConState::WAIT
|
|
31
29
|
|
|
32
|
-
# No attachable_id-changed guard: an attachment created already attached must still be processed.
|
|
33
|
-
# Each branch leaves its pending state, so the work runs once.
|
|
34
30
|
current_user = User.find_by(id: created_by)
|
|
35
31
|
case con_state
|
|
36
32
|
when Labimotion::ConState::NMR
|
|
@@ -43,26 +39,6 @@ module Labimotion
|
|
|
43
39
|
Labimotion::Converter.metadata(id, current_user)
|
|
44
40
|
end
|
|
45
41
|
end
|
|
46
|
-
|
|
47
|
-
# Run the zip mapping again for an attachment in ERROR, e.g. after its file was restored.
|
|
48
|
-
# Returns the new con_state.
|
|
49
|
-
def reprocess_converter!
|
|
50
|
-
return con_state unless has_attribute?(:con_state) && File.extname(filename.to_s.downcase) == '.zip'
|
|
51
|
-
|
|
52
|
-
path = attachment_attacher&.file&.url
|
|
53
|
-
return con_state unless path && File.size?(path)
|
|
54
|
-
|
|
55
|
-
self.con_state = converter_output?(path) ? Labimotion::ConState::CONVERTED : Labimotion::ConState::NMR
|
|
56
|
-
update_column(:con_state, con_state)
|
|
57
|
-
exec_converter
|
|
58
|
-
reload.con_state
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
private def converter_output?(path)
|
|
62
|
-
!Zip::File.new(path).find_entry('metadata/converter.json').nil?
|
|
63
|
-
rescue Zip::Error
|
|
64
|
-
false # not a readable zip: the NMR mapper classifies it
|
|
65
|
-
end
|
|
66
42
|
end
|
|
67
43
|
end
|
|
68
44
|
end
|
|
@@ -29,7 +29,6 @@ module Labimotion
|
|
|
29
29
|
properties: ods.properties,
|
|
30
30
|
properties_release: ods.properties_release,
|
|
31
31
|
klass_uuid: ods.klass_uuid,
|
|
32
|
-
metadata: ods.metadata || {}
|
|
33
32
|
)
|
|
34
33
|
end
|
|
35
34
|
|
|
@@ -50,8 +49,8 @@ module Labimotion
|
|
|
50
49
|
props = Labimotion::VocabularyHandler.update_vocabularies(props, dataset_args[:current_user], dataset_args[:element])
|
|
51
50
|
|
|
52
51
|
ds = Labimotion::Dataset.find_by(element_type: self.class.name, element_id: id)
|
|
53
|
-
if ds.present? && (ds.klass_uuid != klass.uuid || ds.properties != props
|
|
54
|
-
ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: dataset_klass_id, properties: props, klass_uuid: klass.uuid
|
|
52
|
+
if ds.present? && (ds.klass_uuid != klass.uuid || ds.properties != props)
|
|
53
|
+
ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: dataset_klass_id, properties: props, klass_uuid: klass.uuid)
|
|
55
54
|
end
|
|
56
55
|
return if ds.present?
|
|
57
56
|
|
|
@@ -9,6 +9,7 @@ module Labimotion
|
|
|
9
9
|
before_save :check_identifier
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
def check_identifier
|
|
13
14
|
self.identifier = identifier || SecureRandom.uuid if self.has_attribute?(:identifier)
|
|
14
15
|
end
|
|
@@ -33,7 +34,7 @@ module Labimotion
|
|
|
33
34
|
properties_release: properties_release,
|
|
34
35
|
released_at: DateTime.now,
|
|
35
36
|
updated_by: current_user&.id,
|
|
36
|
-
released_by: current_user&.id
|
|
37
|
+
released_by: current_user&.id,
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
self.update!(klass_attributes)
|
|
@@ -45,7 +46,7 @@ module Labimotion
|
|
|
45
46
|
created_by: updated_by,
|
|
46
47
|
properties_release: properties_release,
|
|
47
48
|
released_at: released_at,
|
|
48
|
-
metadata: metadata
|
|
49
|
+
metadata: metadata
|
|
49
50
|
}
|
|
50
51
|
attributes["#{self.class.name.underscore.split('/').last}_id"] = id
|
|
51
52
|
"#{self.class.name}esRevision".constantize.create(attributes)
|
|
@@ -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,8 +37,13 @@ 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)
|
|
41
|
+
rescue Zip::Error => e
|
|
42
|
+
Rails.logger.error "Zip file error: #{e.message}"
|
|
43
|
+
nil
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
Rails.logger.error "Unexpected error extracting metadata: #{e.message}"
|
|
46
|
+
nil
|
|
52
47
|
end
|
|
53
48
|
|
|
54
49
|
def extract_parameters(file_content, parameter_names)
|
|
@@ -126,12 +121,10 @@ module Labimotion
|
|
|
126
121
|
def process_zip_file(zip_file_url, source_map)
|
|
127
122
|
final_parameters = {}
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# A BagIt zip is mapped by the converter instead
|
|
134
|
-
return result if result&.dig(:is_bagit)
|
|
124
|
+
Zip::File.open(zip_file_url) do |zip_file|
|
|
125
|
+
source_map['sourceSelector'].each do |source_name|
|
|
126
|
+
process_source(zip_file, source_map[source_name], final_parameters)
|
|
127
|
+
end
|
|
135
128
|
end
|
|
136
129
|
|
|
137
130
|
return { is_bagit: false, metadata: final_parameters } if final_parameters.present?
|
|
@@ -143,8 +136,6 @@ module Labimotion
|
|
|
143
136
|
return if invalid_source_config?(source_config)
|
|
144
137
|
|
|
145
138
|
zip_file.each do |entry|
|
|
146
|
-
next if entry.directory?
|
|
147
|
-
|
|
148
139
|
if source_file?(entry, source_config)
|
|
149
140
|
process_file_entry(entry, source_config['parameters'], final_parameters)
|
|
150
141
|
elsif bagit_metadata_file?(entry)
|
|
@@ -154,7 +145,7 @@ module Labimotion
|
|
|
154
145
|
end
|
|
155
146
|
|
|
156
147
|
def process_file_entry(entry, parameters, final_parameters)
|
|
157
|
-
file_content =
|
|
148
|
+
file_content = entry.get_input_stream.read.force_encoding(Constants::File::ENCODING)
|
|
158
149
|
extracted_parameters = extract_parameters(file_content, parameters)
|
|
159
150
|
final_parameters.merge!(extracted_parameters) if extracted_parameters.present?
|
|
160
151
|
end
|
data/lib/labimotion/version.rb
CHANGED
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
|
|
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.
|
|
4
|
+
version: 2.2.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:
|
|
12
|
+
date: 2025-12-25 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: caxlsx
|
|
@@ -98,6 +98,7 @@ files:
|
|
|
98
98
|
- lib/labimotion/helpers/vocabulary_helpers.rb
|
|
99
99
|
- lib/labimotion/libs/attachment_handler.rb
|
|
100
100
|
- lib/labimotion/libs/converter.rb
|
|
101
|
+
- lib/labimotion/libs/data/layer/StdDataset.json
|
|
101
102
|
- lib/labimotion/libs/data/mapper/Chemwiki.json
|
|
102
103
|
- lib/labimotion/libs/data/mapper/Source.json
|
|
103
104
|
- lib/labimotion/libs/data/vocab/Standard.json
|
|
@@ -182,9 +183,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
182
183
|
version: '3.4'
|
|
183
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
185
|
requirements:
|
|
185
|
-
- - "
|
|
186
|
+
- - ">"
|
|
186
187
|
- !ruby/object:Gem::Version
|
|
187
|
-
version:
|
|
188
|
+
version: 1.3.1
|
|
188
189
|
requirements: []
|
|
189
190
|
rubygems_version: 3.1.6
|
|
190
191
|
signing_key:
|