labimotion 2.3.3 → 2.3.4
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/CHANGELOG.md +19 -3
- data/lib/labimotion/apis/exporter_api.rb +2 -19
- data/lib/labimotion/apis/generic_element_api.rb +5 -14
- data/lib/labimotion/helpers/element_helpers.rb +10 -4
- data/lib/labimotion/helpers/export_authorization_helpers.rb +39 -0
- data/lib/labimotion/helpers/generic_helpers.rb +9 -4
- data/lib/labimotion/libs/converter.rb +1 -1
- data/lib/labimotion/libs/dataset_builder.rb +1 -1
- data/lib/labimotion/libs/release_metadata.rb +12 -4
- data/lib/labimotion/utils/prop.rb +7 -0
- data/lib/labimotion/version.rb +1 -1
- data/lib/labimotion.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f2a9943b6c1fd9c1d0e09f9b2917985db173634db909a8a3eb3b80ad99d61d4
|
|
4
|
+
data.tar.gz: 828d2be1b26596f926f2e7f4ff06a05925ef7cae8dad9db06f5318b5c5ce527e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2566c6dc15a6acc91cb3cbc9264946b34c7a99be61c02a5916aea8de366bbc7e0b928319ff63b994b0b5fe48d82b6a5ee1a9c8a7e19b4e2a158471a9b9436a2f
|
|
7
|
+
data.tar.gz: ee020ae64b55ff37621cecc819a4675808b815530b3aa8bcea2c49a3b5aa2107779a1297424f986648ecdd2c477adbf5dcdc72b7327430bbe2091ef63414611c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# LabIMotion Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [2.3.4]
|
|
4
|
+
> Unreleased
|
|
5
|
+
* Bug fixes:
|
|
6
|
+
* `upload_generics_files` stays on the element it was authorized for ([chemotion#684](https://github.com/ComPlat/chemotion/issues/684)). `delfiles` detached any generic-element attachment by id; it now only detaches the updated element's own. Uploads take `ElementProps`/`SegmentProps` from the server instead of the `type` the client sends in `elInfo`/`seInfo`, and the segment lookup also matches the element type, so an upload authorized for sample 5 no longer reaches the segment of reaction 5 or generic element 5. `att_type` is limited to `Element`, `Sample`, `Reaction`, `ResearchPlan` and `Screen` (400 otherwise, instead of `constantize` on the request value; the client's `CellLineSample`, which already failed in `constantize`, now gets the 400). `elfiles`, `attfiles` and `delfiles` are only handled for `Element`: an `elfiles` upload authorized for a sample used to write into the generic element with the same id. No client change.
|
|
7
|
+
* `GET /generic_elements/export` checks read permission before building the docx (labimotion#358, port of labimotion#336). It exported any Element, Segment or Dataset by id to any signed-in user. It now answers 404 for a missing record and 401 unless the user passes the matrix check (`genericElement` for an element, `segment` for a segment, `genericDataset` for a dataset) and `ElementPolicy#read?` on the element that holds the record: the element itself, a segment's element, or the root element of a dataset's container. A dataset also needs `ElementPolicy#read_dataset?`, so a share below the dataset detail level cannot export one. The table xlsx export (`GET /exporter/table_xlsx/:id`), which already ran these checks for elements and segments, now shares them through the new `Labimotion::ExportAuthorizationHelpers`.
|
|
8
|
+
* A dataset the gem builds itself — by the converter, or through `Labimotion::DatasetBuilder` — stores the metadata of its klass's active release (labimotion#343, port of labimotion#342). Both builders stored the klass's own `metadata`, which follows every save, drafts included, so a dataset created after a draft save got the released layers with the draft's layer groups and group restrictions, and the form then used them. A klass with no revision matching its uuid still uses its own `metadata`. `Labimotion::ReleaseMetadata.for_klass` returns that value for one klass.
|
|
9
|
+
|
|
10
|
+
## [2.3.3]
|
|
11
|
+
> 2026-10-19
|
|
12
|
+
* Bug fixes:
|
|
13
|
+
* New records and element Reload build from the release's metadata (labimotion#326, port of labimotion#321 and labimotion#324, [chem-generic-ui#1438](https://github.com/cllde8/chem-generic-ui/issues/1438), port of [chem-generic-ui#1430](https://github.com/cllde8/chem-generic-ui/issues/1430)). A klass's `metadata` follows every save, drafts included, so a new element, segment or dataset, and an element brought up to the release by Reload, combined the released layers with the draft's layer groups and restrictions. Klass payloads now carry `metadata_release`: the metadata of the klass's active release, read from its revision row, or `null` when no revision matches the klass's uuid. Sent by `generic_elements/klass`, `segments/list_segment_klass` (nested element klasses included), `generic_dataset/klasses`, and on the nested `element_klass` of the element `GET`, create and update responses, with one revision query per klass family; every other payload is unchanged. A client reading `metadata_release ?? metadata` builds from one version. Read-only: no migration.
|
|
14
|
+
|
|
15
|
+
## [2.3.2]
|
|
16
|
+
> 2026-10-02
|
|
17
|
+
* Bug fixes:
|
|
18
|
+
* A copied element, segment or dataset keeps the template release its properties were built on (labimotion#301, labimotion#303). Saves used to stamp every new segment and every dataset save with the klass's current `uuid` and `properties_release`, and an element with whatever the client sent, so a copy of a v1.0.0 record was labelled v2.0.0 and the client never offered Reload. `Labimotion::KlassVersion` now resolves the submitted `properties['klass_uuid']` against the klass's current release and its `*_klasses_revisions`, deleted revisions included, and stores that uuid together with the matching `properties_release`. A new record whose uuid is missing or unknown follows the current release; an existing record keeps its stored uuid when none is sent, then the uuid its stored `properties_release` names, and follows the current release only when it has neither, and a uuid this instance never released (a record imported from an instance with its own release history) keeps the release stored with the record. A new element whose properties carry no uuid follows the template the client built it on; a new segment does the same, and a copied one falls back to the `klass_uuid` of the row it was copied from. The collection import stamps the release the archive names instead of the importing instance's current one: it tries the uuid inside the archived `properties_release`, then `properties['klass_uuid']`, then the `klass_uuid` column, and stores the first one this instance knows with the local release; when none resolves, the archived release keeps the uuid it names (or, naming none, the first uuid the archive carries), and the imported properties carry the same `klass_uuid` as the column. A `klass_uuid` that is not a string is ignored, and a dataset whose klass changed follows the new klass and ignores the client's release. Element create returns 404 when the template is missing or deleted, element update resolves a soft-deleted template (`with_deleted`) before writing anything, and segments and datasets of a deleted template are skipped on save. A new record whose `klass_uuid` this instance cannot resolve keeps it with the `properties_release` the client sent, only when that release names the same uuid. No migration and no client change.
|
|
19
|
+
|
|
20
|
+
## [2.3.0]
|
|
21
|
+
> 2026-08-26
|
|
4
22
|
* Features and enhancements:
|
|
5
23
|
* Element variations can be exported to and imported from Excel (`.xlsx`). The exported workbook is itself the import template: `GET /api/v1/element_variations/:element_id/export` and `POST /api/v1/element_variations/:element_id/import`.
|
|
6
24
|
* The exported sheet carries the grid's grouped header -- group, sub-group and field rows, merged as the grid draws them -- above the hidden key and unit rows. Workbooks from the earlier single-row header still import.
|
|
@@ -8,8 +26,6 @@
|
|
|
8
26
|
* `number`, `integer` and `system-defined` columns accept numbers only. A cell holding anything else is cleared with a warning rather than stored as text, which also cleans up text those columns already hold.
|
|
9
27
|
* Import warnings name the cell they came from (`Cell I6: ...`), so the user can go straight to it in the spreadsheet.
|
|
10
28
|
* Bug fixes:
|
|
11
|
-
* New records and element Reload build from the release's metadata (labimotion#326, port of labimotion#321 and labimotion#324, [chem-generic-ui#1438](https://github.com/cllde8/chem-generic-ui/issues/1438), port of [chem-generic-ui#1430](https://github.com/cllde8/chem-generic-ui/issues/1430)). A klass's `metadata` follows every save, drafts included, so a new element, segment or dataset, and an element brought up to the release by Reload, combined the released layers with the draft's layer groups and restrictions. Klass payloads now carry `metadata_release`: the metadata of the klass's active release, read from its revision row, or `null` when no revision matches the klass's uuid. Sent by `generic_elements/klass`, `segments/list_segment_klass` (nested element klasses included), `generic_dataset/klasses`, and on the nested `element_klass` of the element `GET`, create and update responses, with one revision query per klass family; every other payload is unchanged. A client reading `metadata_release ?? metadata` builds from one version. Read-only: no migration.
|
|
12
|
-
* A copied element, segment or dataset keeps the template release its properties were built on (labimotion#301, labimotion#303). Saves used to stamp every new segment and every dataset save with the klass's current `uuid` and `properties_release`, and an element with whatever the client sent, so a copy of a v1.0.0 record was labelled v2.0.0 and the client never offered Reload. `Labimotion::KlassVersion` now resolves the submitted `properties['klass_uuid']` against the klass's current release and its `*_klasses_revisions`, deleted revisions included, and stores that uuid together with the matching `properties_release`. A new record whose uuid is missing or unknown follows the current release; an existing record keeps its stored uuid when none is sent, then the uuid its stored `properties_release` names, and follows the current release only when it has neither, and a uuid this instance never released (a record imported from an instance with its own release history) keeps the release stored with the record. A new element whose properties carry no uuid follows the template the client built it on; a new segment does the same, and a copied one falls back to the `klass_uuid` of the row it was copied from. The collection import stamps the release the archive names instead of the importing instance's current one: it tries the uuid inside the archived `properties_release`, then `properties['klass_uuid']`, then the `klass_uuid` column, and stores the first one this instance knows with the local release; when none resolves, the archived release keeps the uuid it names (or, naming none, the first uuid the archive carries), and the imported properties carry the same `klass_uuid` as the column. A `klass_uuid` that is not a string is ignored, and a dataset whose klass changed follows the new klass and ignores the client's release. Element create returns 404 when the template is missing or deleted, element update resolves a soft-deleted template (`with_deleted`) before writing anything, and segments and datasets of a deleted template are skipped on save. A new record whose `klass_uuid` this instance cannot resolve keeps it with the `properties_release` the client sent, only when that release names the same uuid. No migration and no client change.
|
|
13
29
|
* `fetch_for_user`: the shared-records branch joined `collection_shares` directly on the element model (an association that only exists on `Collection`), raising `ActiveRecord::ConfigurationError` — rescued into empty search results. Now joins through `collections`. Fixed for both the basic elements (`ElementFetchable`) and the generic element (`Labimotion::Element`), so `search_by_like` and `search_basic_by_like` return shared records again.
|
|
14
30
|
* Dependencies:
|
|
15
31
|
* Added `roo` (~> 2.10) for reading the uploaded workbook.
|
|
@@ -8,6 +8,7 @@ module Labimotion
|
|
|
8
8
|
|
|
9
9
|
helpers Labimotion::ParamHelpers
|
|
10
10
|
helpers Labimotion::ExporterHelpers
|
|
11
|
+
helpers Labimotion::ExportAuthorizationHelpers
|
|
11
12
|
|
|
12
13
|
resource :exporter do
|
|
13
14
|
resource :table_xlsx do
|
|
@@ -46,9 +47,7 @@ module Labimotion
|
|
|
46
47
|
klass = fetch_klass
|
|
47
48
|
@element = klass.find_by(id: params[:id])
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
authorize_element_access!
|
|
50
|
+
authorize_export!(params[:klass], @element)
|
|
52
51
|
rescue ActiveRecord::RecordNotFound
|
|
53
52
|
error!('404 Not Found', 404)
|
|
54
53
|
rescue NameError => e
|
|
@@ -61,22 +60,6 @@ module Labimotion
|
|
|
61
60
|
Labimotion::Utils.resolve_class(params[:klass])
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
# Authorize element access based on user permissions
|
|
65
|
-
def authorize_element_access!
|
|
66
|
-
element_policy = if params[:klass] == 'Element'
|
|
67
|
-
ElementPolicy.new(current_user,
|
|
68
|
-
@element)
|
|
69
|
-
else
|
|
70
|
-
ElementPolicy.new(current_user,
|
|
71
|
-
@element.element)
|
|
72
|
-
end
|
|
73
|
-
matrix_name = params[:klass] == 'Element' ? 'genericElement' : 'segment'
|
|
74
|
-
|
|
75
|
-
return if current_user.matrix_check_by_name(matrix_name) && element_policy.read?
|
|
76
|
-
|
|
77
|
-
error!('401 Unauthorized', 401)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
63
|
# Fetch layer from element properties
|
|
81
64
|
def fetch_layer
|
|
82
65
|
properties = @element.properties
|
|
@@ -17,6 +17,7 @@ module Labimotion
|
|
|
17
17
|
helpers Labimotion::GenericHelpers
|
|
18
18
|
helpers Labimotion::ElementHelpers
|
|
19
19
|
helpers Labimotion::ParamHelpers
|
|
20
|
+
helpers Labimotion::ExportAuthorizationHelpers
|
|
20
21
|
|
|
21
22
|
resource :generic_elements do
|
|
22
23
|
# might be removed because the file is moved to public folder
|
|
@@ -129,14 +130,8 @@ module Labimotion
|
|
|
129
130
|
optional :export_format, type: String, desc: 'export format'
|
|
130
131
|
end
|
|
131
132
|
get do
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
element = Labimotion::Element.find(params[:id])
|
|
135
|
-
when 'Segment'
|
|
136
|
-
element = Labimotion::Segment.find(params[:id])
|
|
137
|
-
when 'Dataset'
|
|
138
|
-
element = Labimotion::Dataset.find(params[:id])
|
|
139
|
-
end
|
|
133
|
+
element = "Labimotion::#{params[:klass]}".constantize.find_by(id: params[:id])
|
|
134
|
+
authorize_export!(params[:klass], element)
|
|
140
135
|
export = Labimotion::ExportElement.new current_user, element, params[:export_format]
|
|
141
136
|
env['api.format'] = :binary
|
|
142
137
|
content_type 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
@@ -264,14 +259,10 @@ module Labimotion
|
|
|
264
259
|
desc 'upload generic files'
|
|
265
260
|
params do
|
|
266
261
|
requires :att_id, type: Integer, desc: 'Element Id'
|
|
267
|
-
requires :att_type, type: String, desc: 'Element Type'
|
|
262
|
+
requires :att_type, type: String, values: Labimotion::Prop::UPLOAD_ELEMENT_TYPES.keys, desc: 'Element Type'
|
|
268
263
|
end
|
|
269
264
|
after_validation do
|
|
270
|
-
|
|
271
|
-
el = "#{params[:att_type]}".constantize.find_by(id: params[:att_id])
|
|
272
|
-
else
|
|
273
|
-
el = "Labimotion::#{params[:att_type]}".constantize.find_by(id: params[:att_id])
|
|
274
|
-
end
|
|
265
|
+
el = Labimotion::Prop::UPLOAD_ELEMENT_TYPES[params[:att_type]].constantize.find_by(id: params[:att_id])
|
|
275
266
|
error!('401 Unauthorized', 401) if el.nil?
|
|
276
267
|
|
|
277
268
|
policy_updatable = ElementPolicy.new(current_user, el).update?
|
|
@@ -182,13 +182,18 @@ module Labimotion
|
|
|
182
182
|
|
|
183
183
|
def upload_generics_files(current_user, params)
|
|
184
184
|
attach_ary = []
|
|
185
|
+
element_type = Labimotion::Prop::UPLOAD_ELEMENT_TYPES.fetch(params[:att_type])
|
|
186
|
+
generic_element = element_type == Labimotion::Prop::L_ELEMENT
|
|
187
|
+
# Element properties and direct attachments only exist on generic elements; for any
|
|
188
|
+
# other att_type, att_id names a different table, so they are not touched.
|
|
185
189
|
att_ary = create_uploads(
|
|
186
190
|
Labimotion::Prop::ELEMENT,
|
|
187
191
|
params[:att_id],
|
|
188
192
|
params[:elfiles],
|
|
189
193
|
params[:elInfo],
|
|
190
194
|
current_user.id,
|
|
191
|
-
|
|
195
|
+
element_type
|
|
196
|
+
) if generic_element && params[:elfiles].present? && params[:elInfo].present?
|
|
192
197
|
|
|
193
198
|
(attach_ary << att_ary).flatten! unless att_ary&.empty?
|
|
194
199
|
|
|
@@ -197,16 +202,17 @@ module Labimotion
|
|
|
197
202
|
params[:att_id],
|
|
198
203
|
params[:sefiles],
|
|
199
204
|
params[:seInfo],
|
|
200
|
-
current_user.id
|
|
205
|
+
current_user.id,
|
|
206
|
+
element_type
|
|
201
207
|
) if params[:sefiles].present? && params[:seInfo].present?
|
|
202
208
|
|
|
203
209
|
(attach_ary << att_ary).flatten! unless att_ary&.empty?
|
|
204
210
|
|
|
205
|
-
if params[:attfiles].present? || params[:delfiles].present?
|
|
211
|
+
if generic_element && (params[:attfiles].present? || params[:delfiles].present?)
|
|
206
212
|
att_ary = create_attachments(
|
|
207
213
|
params[:attfiles],
|
|
208
214
|
params[:delfiles],
|
|
209
|
-
|
|
215
|
+
element_type,
|
|
210
216
|
params[:att_id],
|
|
211
217
|
params[:attfilesIdentifier],
|
|
212
218
|
current_user.id
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labimotion
|
|
4
|
+
# Gate shared by the routes that export an Element, Segment or Dataset to a file.
|
|
5
|
+
# A segment or dataset is readable when the element that holds it is; a dataset
|
|
6
|
+
# sits on an analysis container, so its element is that container's root element.
|
|
7
|
+
module ExportAuthorizationHelpers
|
|
8
|
+
# Answers 404 for a missing record and 401 unless the user passes the matrix
|
|
9
|
+
# check for the record's family and may read the element that holds it.
|
|
10
|
+
def authorize_export!(klass_name, record)
|
|
11
|
+
error!('404 Not Found', 404) if record.nil?
|
|
12
|
+
return if export_readable?(klass_name, record)
|
|
13
|
+
|
|
14
|
+
error!('401 Unauthorized', 401)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# The matrix right that shows each family in the UI.
|
|
18
|
+
EXPORT_MATRIX = { 'Element' => 'genericElement', 'Segment' => 'segment', 'Dataset' => 'genericDataset' }.freeze
|
|
19
|
+
|
|
20
|
+
def export_readable?(klass_name, record)
|
|
21
|
+
return false unless current_user.matrix_check_by_name(EXPORT_MATRIX.fetch(klass_name))
|
|
22
|
+
|
|
23
|
+
policy = ElementPolicy.new(current_user, export_parent_element(klass_name, record))
|
|
24
|
+
return policy.read? unless klass_name == 'Dataset'
|
|
25
|
+
|
|
26
|
+
# A dataset holds analysis data, which a share below the dataset detail
|
|
27
|
+
# level hides.
|
|
28
|
+
policy.read? && policy.read_dataset?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def export_parent_element(klass_name, record)
|
|
32
|
+
case klass_name
|
|
33
|
+
when 'Element' then record
|
|
34
|
+
when 'Segment' then record.element
|
|
35
|
+
when 'Dataset' then record.element&.root_element
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -142,16 +142,20 @@ module Labimotion
|
|
|
142
142
|
raise e
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
# element_type is the class name of the element that id names, so a segment
|
|
146
|
+
# lookup cannot reach another element type's segment with the same element_id.
|
|
147
|
+
def create_uploads(type, id, files, param_info, user_id, element_type)
|
|
146
148
|
return if files.nil? || param_info.nil? || files.empty? || param_info.empty?
|
|
147
149
|
|
|
148
150
|
attach_ary = []
|
|
149
151
|
map_info = JSON.parse(param_info)
|
|
152
|
+
# Derived here, not taken from param_info, so the request cannot pick the attachable_type
|
|
153
|
+
attachable_type = type == Labimotion::Prop::SEGMENT ? Labimotion::Prop::SEGMENTPROPS : Labimotion::Prop::ELEMENTPROPS
|
|
150
154
|
map_info&.keys&.each do |key|
|
|
151
155
|
next if map_info[key]['files'].empty?
|
|
152
156
|
|
|
153
157
|
if type == Labimotion::Prop::SEGMENT
|
|
154
|
-
element = Labimotion::Segment.find_by(element_id: id, segment_klass_id: key)
|
|
158
|
+
element = Labimotion::Segment.find_by(element_type: element_type, element_id: id, segment_klass_id: key)
|
|
155
159
|
elsif type == Labimotion::Prop::ELEMENT
|
|
156
160
|
element = Labimotion::Element.find_by(id: id)
|
|
157
161
|
end
|
|
@@ -172,7 +176,7 @@ module Labimotion
|
|
|
172
176
|
created_by: user_id,
|
|
173
177
|
created_for: user_id,
|
|
174
178
|
content_type: file[:type],
|
|
175
|
-
attachable_type:
|
|
179
|
+
attachable_type: attachable_type,
|
|
176
180
|
attachable_id: element.id,
|
|
177
181
|
)
|
|
178
182
|
begin
|
|
@@ -221,7 +225,8 @@ module Labimotion
|
|
|
221
225
|
end
|
|
222
226
|
end
|
|
223
227
|
unless (del_files || []).empty?
|
|
224
|
-
|
|
228
|
+
# Scoped to the element, so ids of another element's attachments are left alone
|
|
229
|
+
Attachment.where(id: del_files.map(&:to_i), attachable_type: type, attachable_id: id).update_all(attachable_id: nil)
|
|
225
230
|
end
|
|
226
231
|
attach_ary
|
|
227
232
|
rescue StandardError => e
|
|
@@ -8,9 +8,10 @@ require 'active_support/core_ext/string/inflections'
|
|
|
8
8
|
|
|
9
9
|
module Labimotion
|
|
10
10
|
## ReleaseMetadata
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
11
|
+
# Each klass's metadata as of its active release, for the `metadata_releases:` option the
|
|
12
|
+
# klass entities read and for records the gem builds itself. The klass row's own `metadata`
|
|
13
|
+
# follows every save, drafts included, so a record built from `properties_release` needs the
|
|
14
|
+
# copy kept on the revision.
|
|
14
15
|
# The active revision is the one whose uuid equals the klass's, which changes only on release.
|
|
15
16
|
class ReleaseMetadata
|
|
16
17
|
# A klass with no revision matching its uuid (never released, or imported without one)
|
|
@@ -21,6 +22,13 @@ module Labimotion
|
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
# The metadata a record built from the klass's `properties_release` stores: the active
|
|
26
|
+
# release's, or the klass's own when no revision matches its uuid. A failed lookup also
|
|
27
|
+
# falls back to the klass's own, so building the record never fails on it.
|
|
28
|
+
def self.for_klass(klass)
|
|
29
|
+
map_for([klass])[key_of(klass)] || klass.metadata || {}
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
# Family as well as id: a segment klass payload nests its element klass, and ids repeat
|
|
25
33
|
# across the klass tables.
|
|
26
34
|
def self.key_of(klass)
|
|
@@ -39,7 +47,7 @@ module Labimotion
|
|
|
39
47
|
end
|
|
40
48
|
rescue StandardError => e
|
|
41
49
|
# The release metadata is an addition to a list that must still render, and a failing
|
|
42
|
-
# family must not blank the families that resolved.
|
|
50
|
+
# family must not blank the families that resolved. A record builder falls back too.
|
|
43
51
|
Labimotion.log_exception(e)
|
|
44
52
|
{}
|
|
45
53
|
end
|
|
@@ -19,10 +19,17 @@ module Labimotion
|
|
|
19
19
|
SAMPLE = 'Sample'.freeze
|
|
20
20
|
MOLECULE = 'Molecule'.freeze
|
|
21
21
|
REACTION = 'Reaction'.freeze
|
|
22
|
+
RESEARCH_PLAN = 'ResearchPlan'.freeze
|
|
23
|
+
SCREEN = 'Screen'.freeze
|
|
22
24
|
CONTAINER = 'Container'.freeze
|
|
23
25
|
ELEMENTPROPS = 'ElementProps'.freeze
|
|
24
26
|
SEGMENTPROPS = 'SegmentProps'.freeze
|
|
25
27
|
DATASETPROPS = 'DatasetProps'.freeze
|
|
26
28
|
UPLOADPROPS = [ELEMENTPROPS, SEGMENTPROPS, DATASETPROPS].freeze
|
|
29
|
+
# att_type accepted by upload_generics_files => class name of the element it names
|
|
30
|
+
UPLOAD_ELEMENT_TYPES = {
|
|
31
|
+
ELEMENT => L_ELEMENT, SAMPLE => SAMPLE, REACTION => REACTION, RESEARCH_PLAN => RESEARCH_PLAN,
|
|
32
|
+
SCREEN => SCREEN
|
|
33
|
+
}.freeze
|
|
27
34
|
end
|
|
28
35
|
end
|
data/lib/labimotion/version.rb
CHANGED
data/lib/labimotion.rb
CHANGED
|
@@ -73,6 +73,7 @@ module Labimotion
|
|
|
73
73
|
autoload :ParamHelpers, 'labimotion/helpers/param_helpers'
|
|
74
74
|
autoload :ConverterHelpers, 'labimotion/helpers/converter_helpers'
|
|
75
75
|
autoload :ExporterHelpers, 'labimotion/helpers/exporter_helpers'
|
|
76
|
+
autoload :ExportAuthorizationHelpers, 'labimotion/helpers/export_authorization_helpers'
|
|
76
77
|
autoload :SampleAssociationHelpers, 'labimotion/helpers/sample_association_helpers'
|
|
77
78
|
autoload :RepositoryHelpers, 'labimotion/helpers/repository_helpers'
|
|
78
79
|
autoload :VocabularyHelpers, 'labimotion/helpers/vocabulary_helpers'
|
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.3.
|
|
4
|
+
version: 2.3.4
|
|
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-
|
|
12
|
+
date: 2026-11-03 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: caxlsx
|
|
@@ -114,6 +114,7 @@ files:
|
|
|
114
114
|
- lib/labimotion/helpers/converter_helpers.rb
|
|
115
115
|
- lib/labimotion/helpers/dataset_helpers.rb
|
|
116
116
|
- lib/labimotion/helpers/element_helpers.rb
|
|
117
|
+
- lib/labimotion/helpers/export_authorization_helpers.rb
|
|
117
118
|
- lib/labimotion/helpers/exporter_helpers.rb
|
|
118
119
|
- lib/labimotion/helpers/generic_helpers.rb
|
|
119
120
|
- lib/labimotion/helpers/mtt_helpers.rb
|