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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2be4b8936c18a5560a7aed2c4ca7ad3ea6f3fc17245b7442e3658255a0e84494
4
- data.tar.gz: 88f5beed8cea656e69f5e9ba13aaa3acbe92dddce489a131e5238b09ca63cc87
3
+ metadata.gz: 4397eed28e8f2c6f0e21e022191d842dbb7a42000a2efe72731a89ab8bf9e77b
4
+ data.tar.gz: 3ae429541da0f787d6d0f544307b5acfbf3e922d83c7fc7cd27e47738eb5880e
5
5
  SHA512:
6
- metadata.gz: 98cfc7e3e0f672a3371a6fc523fd58de260e2cde2e83696be0976ad44c2efc79ebdf60fd414969b996cfa09f7d4f2c384168fd04503f0713c6ccdf4f5905da87
7
- data.tar.gz: 22052eb592542f2e8a43368b6c08dac67e301352234f968ffc175a12d6af66133857876884b85ee1f35e449a4edcae3e37ff39c0233673f73323f9c7a39b8812
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: Entities::AttachmentEntity.represent(element&.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: Entities::AttachmentEntity.represent(element&.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', 'metadata'
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', 'metadata'
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', 'metadata'
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
- metadata: params[:metadata] || {},
86
- created_by: current_user.id
85
+ created_by: current_user.id,
87
86
  }
88
87
  element = Labimotion::Element.new(attributes)
89
88
 
90
- all_coll = Collection.get_all_collection_for_user(current_user.id)
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
- metadata = params[:metadata] || element.metadata || {}
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
- ctx = { att: nil, ols: nil, dsr: [] }
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
- # Never close: closing can rewrite the stored file in place
43
- zip_file = Zip::File.new(att.attachment_attacher.file.url)
44
- res = Labimotion::Converter.collect_metadata(zip_file, current_user)
45
- ctx[:ols] = res[:o] unless res&.dig(:o).nil?
46
- ctx[:dsr].push(res[:d]) unless res&.dig(:d).nil?
47
- ctx[:dsr].flatten!
48
- dataset = build_ds(att.attachable_id, ctx[:ols])
49
- update_ds(dataset, ctx[:dsr], current_user) if dataset.present?
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
- Labimotion::ConState::COMPLETED
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 = Labimotion::MapperUtils.read_entry(entry).force_encoding('UTF-8')
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
- state = Labimotion::Converter.handle_response(data[:a], response, current_user)
178
- # A failed dataset mapping also marks the source attachment as ERROR
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
+ }
@@ -44,8 +44,7 @@ module Labimotion
44
44
  element_id: container.id,
45
45
  properties: props,
46
46
  properties_release: klass.properties_release,
47
- klass_uuid: klass.uuid,
48
- metadata: klass.metadata
47
+ klass_uuid: klass.uuid
49
48
  )
50
49
  end
51
50
 
@@ -30,21 +30,7 @@ module Labimotion
30
30
 
31
31
  class << self
32
32
  def process_ds(id, current_user = {})
33
- ctx = { att: nil }
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
- # Return the state Converter.metadata stored; CONVERTED means still waiting for an analysis dataset
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 || ds.metadata != metadata)
54
- ds.update!(properties_release: klass.properties_release, uuid: uuid, dataset_klass_id: dataset_klass_id, properties: props, klass_uuid: klass.uuid, metadata: metadata)
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
- # Never close: closing can rewrite the stored file in place
130
- zip_file = Zip::File.new(zip_file_url)
131
- source_map['sourceSelector'].each do |source_name|
132
- result = process_source(zip_file, source_map[source_name], final_parameters)
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 = read_entry(entry).force_encoding(Constants::File::ENCODING)
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  ## Labimotion Version
4
4
  module Labimotion
5
- VERSION = '2.1.2'
5
+ VERSION = '2.2.0.rc1'
6
6
  end
data/lib/labimotion.rb CHANGED
@@ -13,11 +13,6 @@ module Labimotion
13
13
  Labimotion.logger.error(exception.backtrace.join("\n"))
14
14
  end
15
15
 
16
- # Report a rescued exception to Sentry, if the host app uses it
17
- def self.report_exception(exception)
18
- Sentry.capture_exception(exception) if defined?(Sentry)
19
- end
20
-
21
16
  autoload :MapperUtils, 'labimotion/utils/mapper_utils'
22
17
  autoload :Utils, 'labimotion/utils/utils'
23
18
 
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.1.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: 2026-10-01 00:00:00.000000000 Z
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: '0'
188
+ version: 1.3.1
188
189
  requirements: []
189
190
  rubygems_version: 3.1.6
190
191
  signing_key: