labimotion 2.2.0.rc8 → 2.2.0.rc9
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/dose_resp_request_api.rb +241 -0
- data/lib/labimotion/apis/element_variation_api.rb +45 -0
- data/lib/labimotion/apis/generic_element_api.rb +7 -3
- data/lib/labimotion/apis/labimotion_api.rb +3 -0
- data/lib/labimotion/apis/mtt_api.rb +238 -0
- data/lib/labimotion/entities/element_entity.rb +1 -0
- data/lib/labimotion/entities/element_variation_entity.rb +29 -0
- data/lib/labimotion/helpers/element_helpers.rb +22 -16
- data/lib/labimotion/helpers/generic_helpers.rb +1 -1
- data/lib/labimotion/helpers/mtt_helpers.rb +428 -0
- data/lib/labimotion/helpers/param_helpers.rb +6 -0
- data/lib/labimotion/libs/converter.rb +1 -2
- data/lib/labimotion/libs/export_element.rb +245 -19
- data/lib/labimotion/libs/nmr_mapper.rb +2 -2
- data/lib/labimotion/models/concerns/attachment_converter.rb +0 -1
- data/lib/labimotion/models/concerns/element_fetchable.rb +2 -2
- data/lib/labimotion/models/dose_resp_output.rb +27 -0
- data/lib/labimotion/models/dose_resp_request.rb +93 -0
- data/lib/labimotion/models/element.rb +8 -2
- data/lib/labimotion/models/element_variation.rb +21 -0
- data/lib/labimotion/utils/search.rb +2 -2
- data/lib/labimotion/version.rb +1 -1
- data/lib/labimotion.rb +8 -1
- metadata +10 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fde410e148abdf50036fd9146e2faea1ccd5078f7c93ec99dbd1c3fa6680ee96
|
|
4
|
+
data.tar.gz: 3a63d545e4b1c9da579e582f956ead5e2d204c4f9078f47803322a4831ce8b50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c2cd08a3c54a452994ab180b014e53545ade8ff6ebf65d19a06a23fe47770b7e27bb2c4e04e8c7c05d4a3ab45875240f5cdac29e3ae1e64f49281ea3d9a6bb3
|
|
7
|
+
data.tar.gz: 318fa9de8609f13f1074620e09aa24d62ad135d956e5415dfa582d262787897dbb70d119144a80227c4b567138fd69e871196dba072b6fb3e9eb5276ae0239f9
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'labimotion/version'
|
|
4
|
+
|
|
5
|
+
module Labimotion
|
|
6
|
+
# Dose Response Request API
|
|
7
|
+
class DoseRespRequestAPI < Grape::API
|
|
8
|
+
helpers Labimotion::ParamHelpers
|
|
9
|
+
|
|
10
|
+
resource :dose_resp_requests do
|
|
11
|
+
desc 'Get all dose response requests for current user'
|
|
12
|
+
params do
|
|
13
|
+
optional :element_id, type: Integer, desc: 'Filter by element ID'
|
|
14
|
+
optional :state, type: Integer, desc: 'Filter by state (-1, 0, 1, 2)'
|
|
15
|
+
optional :page, type: Integer, desc: 'Page number', default: 1
|
|
16
|
+
optional :per_page, type: Integer, desc: 'Items per page', default: 20
|
|
17
|
+
end
|
|
18
|
+
get do
|
|
19
|
+
requests = Labimotion::DoseRespRequest.where(created_by: current_user.id)
|
|
20
|
+
|
|
21
|
+
# Apply filters
|
|
22
|
+
requests = requests.where(element_id: params[:element_id]) if params[:element_id]
|
|
23
|
+
requests = requests.where(state: params[:state]) if params[:state]
|
|
24
|
+
|
|
25
|
+
# Pagination
|
|
26
|
+
page = params[:page] || 1
|
|
27
|
+
per_page = [params[:per_page] || 20, 100].min # Max 100 per page
|
|
28
|
+
|
|
29
|
+
total = requests.count
|
|
30
|
+
requests = requests.order(created_at: :desc)
|
|
31
|
+
.offset((page - 1) * per_page)
|
|
32
|
+
.limit(per_page)
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
requests: requests.map do |req|
|
|
36
|
+
{
|
|
37
|
+
id: req.id,
|
|
38
|
+
request_id: req.request_id,
|
|
39
|
+
element_id: req.element_id,
|
|
40
|
+
state: req.state,
|
|
41
|
+
state_label: state_label(req.state),
|
|
42
|
+
expires_at: req.expires_at,
|
|
43
|
+
created_at: req.created_at,
|
|
44
|
+
updated_at: req.updated_at,
|
|
45
|
+
first_accessed_at: req.first_accessed_at,
|
|
46
|
+
last_accessed_at: req.last_accessed_at,
|
|
47
|
+
access_count: req.access_count,
|
|
48
|
+
resp_message: req.resp_message,
|
|
49
|
+
active: req.active?
|
|
50
|
+
}
|
|
51
|
+
end,
|
|
52
|
+
pagination: {
|
|
53
|
+
page: page,
|
|
54
|
+
per_page: per_page,
|
|
55
|
+
total: total,
|
|
56
|
+
total_pages: (total.to_f / per_page).ceil
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
error!("Error: #{e.message}", 500)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc 'Get a dose response request by ID'
|
|
64
|
+
params do
|
|
65
|
+
requires :id, type: Integer, desc: 'Request ID'
|
|
66
|
+
end
|
|
67
|
+
get ':id' do
|
|
68
|
+
request = Labimotion::DoseRespRequest.find_by(id: params[:id])
|
|
69
|
+
error!('Request not found', 404) unless request
|
|
70
|
+
|
|
71
|
+
# Check authorization
|
|
72
|
+
error!('Unauthorized', 403) unless request.created_by == current_user.id
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
id: request.id,
|
|
76
|
+
request_id: request.request_id,
|
|
77
|
+
element_id: request.element_id,
|
|
78
|
+
state: request.state,
|
|
79
|
+
state_label: state_label(request.state),
|
|
80
|
+
wellplates_metadata: request.wellplates_metadata,
|
|
81
|
+
input_metadata: request.input_metadata,
|
|
82
|
+
expires_at: request.expires_at,
|
|
83
|
+
revoked_at: request.revoked_at,
|
|
84
|
+
created_at: request.created_at,
|
|
85
|
+
updated_at: request.updated_at,
|
|
86
|
+
first_accessed_at: request.first_accessed_at,
|
|
87
|
+
last_accessed_at: request.last_accessed_at,
|
|
88
|
+
access_count: request.access_count,
|
|
89
|
+
resp_message: request.resp_message,
|
|
90
|
+
active: request.active?,
|
|
91
|
+
expired: request.expired?,
|
|
92
|
+
revoked: request.revoked?
|
|
93
|
+
}
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
error!("Error: #{e.message}", 500)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
desc 'Update a dose response request'
|
|
99
|
+
params do
|
|
100
|
+
requires :id, type: Integer, desc: 'Request ID'
|
|
101
|
+
optional :state, type: Integer, desc: 'State', values: [-1, 0, 1, 2]
|
|
102
|
+
optional :resp_message, type: String, desc: 'Response message'
|
|
103
|
+
optional :wellplates_metadata, type: Hash, desc: 'Wellplates metadata'
|
|
104
|
+
end
|
|
105
|
+
put ':id' do
|
|
106
|
+
request = Labimotion::DoseRespRequest.find_by(id: params[:id])
|
|
107
|
+
error!('Request not found', 404) unless request
|
|
108
|
+
|
|
109
|
+
# Check authorization
|
|
110
|
+
error!('Unauthorized', 403) unless request.created_by == current_user.id
|
|
111
|
+
|
|
112
|
+
update_params = {}
|
|
113
|
+
update_params[:state] = params[:state] if params[:state]
|
|
114
|
+
update_params[:resp_message] = params[:resp_message] if params[:resp_message]
|
|
115
|
+
update_params[:wellplates_metadata] = params[:wellplates_metadata] if params[:wellplates_metadata]
|
|
116
|
+
|
|
117
|
+
request.update!(update_params)
|
|
118
|
+
|
|
119
|
+
{
|
|
120
|
+
success: true,
|
|
121
|
+
message: 'Request updated successfully',
|
|
122
|
+
request: {
|
|
123
|
+
id: request.id,
|
|
124
|
+
request_id: request.request_id,
|
|
125
|
+
state: request.state,
|
|
126
|
+
state_label: state_label(request.state),
|
|
127
|
+
resp_message: request.resp_message,
|
|
128
|
+
updated_at: request.updated_at
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
132
|
+
error!("Validation error: #{e.message}", 422)
|
|
133
|
+
rescue StandardError => e
|
|
134
|
+
error!("Error: #{e.message}", 500)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
desc 'Revoke a dose response request'
|
|
138
|
+
params do
|
|
139
|
+
requires :id, type: Integer, desc: 'Request ID'
|
|
140
|
+
end
|
|
141
|
+
post ':id/revoke' do
|
|
142
|
+
request = Labimotion::DoseRespRequest.find_by(id: params[:id])
|
|
143
|
+
error!('Request not found', 404) unless request
|
|
144
|
+
|
|
145
|
+
# Check authorization
|
|
146
|
+
error!('Unauthorized', 403) unless request.created_by == current_user.id
|
|
147
|
+
|
|
148
|
+
request.revoke!
|
|
149
|
+
|
|
150
|
+
{
|
|
151
|
+
success: true,
|
|
152
|
+
message: 'Request revoked successfully',
|
|
153
|
+
request: {
|
|
154
|
+
id: request.id,
|
|
155
|
+
request_id: request.request_id,
|
|
156
|
+
state: request.state,
|
|
157
|
+
revoked_at: request.revoked_at,
|
|
158
|
+
active: request.active?
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
rescue StandardError => e
|
|
162
|
+
error!("Error: #{e.message}", 500)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
desc 'Delete a dose response request'
|
|
166
|
+
params do
|
|
167
|
+
requires :id, type: Integer, desc: 'Request ID'
|
|
168
|
+
end
|
|
169
|
+
delete ':id' do
|
|
170
|
+
request = Labimotion::DoseRespRequest.find_by(id: params[:id])
|
|
171
|
+
error!('Request not found', 404) unless request
|
|
172
|
+
|
|
173
|
+
# Check authorization
|
|
174
|
+
error!('Unauthorized', 403) unless request.created_by == current_user.id
|
|
175
|
+
|
|
176
|
+
# Soft delete if acts_as_paranoid is enabled
|
|
177
|
+
request.destroy
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
success: true,
|
|
181
|
+
message: 'Request deleted successfully'
|
|
182
|
+
}
|
|
183
|
+
rescue StandardError => e
|
|
184
|
+
error!("Error: #{e.message}", 500)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
desc 'Get dose response requests by element ID'
|
|
188
|
+
params do
|
|
189
|
+
requires :element_id, type: Integer, desc: 'Element ID'
|
|
190
|
+
end
|
|
191
|
+
get 'by_element/:element_id' do
|
|
192
|
+
element = Labimotion::Element.find_by(id: params[:element_id])
|
|
193
|
+
error!('Element not found', 404) unless element
|
|
194
|
+
|
|
195
|
+
# Check if user has access to element
|
|
196
|
+
policy = ElementPolicy.new(current_user, element)
|
|
197
|
+
error!('Unauthorized', 403) unless policy.read?
|
|
198
|
+
|
|
199
|
+
requests = Labimotion::DoseRespRequest.where(element_id: params[:element_id])
|
|
200
|
+
.where(created_by: current_user.id)
|
|
201
|
+
.order(created_at: :desc)
|
|
202
|
+
|
|
203
|
+
{
|
|
204
|
+
element_id: element.id,
|
|
205
|
+
element_name: element.name,
|
|
206
|
+
requests: requests.map do |req|
|
|
207
|
+
{
|
|
208
|
+
id: req.id,
|
|
209
|
+
request_id: req.request_id,
|
|
210
|
+
state: req.state,
|
|
211
|
+
state_label: state_label(req.state),
|
|
212
|
+
expires_at: req.expires_at,
|
|
213
|
+
created_at: req.created_at,
|
|
214
|
+
access_count: req.access_count,
|
|
215
|
+
active: req.active?
|
|
216
|
+
}
|
|
217
|
+
end
|
|
218
|
+
}
|
|
219
|
+
rescue StandardError => e
|
|
220
|
+
error!("Error: #{e.message}", 500)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
helpers do
|
|
225
|
+
def state_label(state)
|
|
226
|
+
case state
|
|
227
|
+
when Labimotion::DoseRespRequest::STATE_ERROR
|
|
228
|
+
'error'
|
|
229
|
+
when Labimotion::DoseRespRequest::STATE_INITIAL
|
|
230
|
+
'initial'
|
|
231
|
+
when Labimotion::DoseRespRequest::STATE_PROCESSING
|
|
232
|
+
'processing'
|
|
233
|
+
when Labimotion::DoseRespRequest::STATE_COMPLETED
|
|
234
|
+
'completed'
|
|
235
|
+
else
|
|
236
|
+
'unknown'
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labimotion
|
|
4
|
+
class ElementVariationAPI < Grape::API
|
|
5
|
+
rescue_from ActiveRecord::RecordNotFound do
|
|
6
|
+
error!('404 Element not found', 404)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
resource :element_variations do
|
|
10
|
+
params do
|
|
11
|
+
requires :element_id, type: Integer, desc: 'Generic element id'
|
|
12
|
+
end
|
|
13
|
+
route_param :element_id do
|
|
14
|
+
before do
|
|
15
|
+
@element = Labimotion::Element.find(params[:element_id])
|
|
16
|
+
error!('401 Unauthorized', 401) unless ElementPolicy.new(current_user, @element).read?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc 'Return element variations for a generic element'
|
|
20
|
+
get do
|
|
21
|
+
record = Labimotion::ElementVariation.find_or_initialize_by(element_id: @element.id)
|
|
22
|
+
present record, with: Labimotion::ElementVariationEntity, root: 'element_variation'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc 'Upsert element variations for a generic element'
|
|
26
|
+
params do
|
|
27
|
+
requires :variations, type: Hash, desc: 'Variations keyed by row uuid'
|
|
28
|
+
optional :layout, type: Hash, desc: 'Column layout (selected/order/units/rowOrder)'
|
|
29
|
+
end
|
|
30
|
+
put do
|
|
31
|
+
error!('401 Unauthorized', 401) unless ElementPolicy.new(current_user, @element).update?
|
|
32
|
+
|
|
33
|
+
record = Labimotion::ElementVariation.find_or_initialize_by(element_id: @element.id)
|
|
34
|
+
record.variations = params[:variations] || {}
|
|
35
|
+
if params.key?(:layout) && record.class.column_names.include?('layout')
|
|
36
|
+
record.layout = params[:layout] || {}
|
|
37
|
+
end
|
|
38
|
+
record.save!
|
|
39
|
+
|
|
40
|
+
present record, with: Labimotion::ElementVariationEntity, root: 'element_variation'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -179,10 +179,11 @@ module Labimotion
|
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
namespace :klass_revisions do
|
|
182
|
-
desc 'list Generic
|
|
182
|
+
desc 'list Generic Klass Revisions'
|
|
183
183
|
params do
|
|
184
184
|
requires :id, type: Integer, desc: 'Generic Element Klass Id'
|
|
185
185
|
requires :klass, type: String, desc: 'Klass', values: %w[ElementKlass SegmentKlass DatasetKlass]
|
|
186
|
+
optional :limit, type: Integer, default: 10, desc: 'Max revisions returned'
|
|
186
187
|
end
|
|
187
188
|
get do
|
|
188
189
|
list = list_klass_revisions(params)
|
|
@@ -197,6 +198,7 @@ module Labimotion
|
|
|
197
198
|
desc 'list Generic Element Revisions'
|
|
198
199
|
params do
|
|
199
200
|
requires :id, type: Integer, desc: 'Generic Element Id'
|
|
201
|
+
optional :limit, type: Integer, default: 10, desc: 'Max revisions returned'
|
|
200
202
|
end
|
|
201
203
|
get do
|
|
202
204
|
list = element_revisions(params)
|
|
@@ -241,14 +243,15 @@ module Labimotion
|
|
|
241
243
|
end
|
|
242
244
|
|
|
243
245
|
namespace :segment_revisions do
|
|
244
|
-
desc 'list Generic
|
|
246
|
+
desc 'list Generic Segment Revisions'
|
|
245
247
|
params do
|
|
246
248
|
optional :id, type: Integer, desc: 'Generic Element Id'
|
|
249
|
+
optional :limit, type: Integer, default: 10, desc: 'Max revisions returned'
|
|
247
250
|
end
|
|
248
251
|
get do
|
|
249
252
|
klass = Labimotion::Segment.find(params[:id])
|
|
250
253
|
list = klass.segments_revisions unless klass.nil?
|
|
251
|
-
present list&.order(created_at: :desc)&.limit(
|
|
254
|
+
present list&.order(created_at: :desc)&.limit(params[:limit]), with: Labimotion::SegmentRevisionEntity, root: 'revisions'
|
|
252
255
|
rescue StandardError => e
|
|
253
256
|
Labimotion.log_exception(e, current_user)
|
|
254
257
|
[]
|
|
@@ -429,6 +432,7 @@ module Labimotion
|
|
|
429
432
|
desc 'Return serialized elements of current user'
|
|
430
433
|
params do
|
|
431
434
|
optional :collection_id, type: Integer, desc: 'Collection id'
|
|
435
|
+
optional :sync_collection_id, type: Integer, desc: 'SyncCollectionsUser id'
|
|
432
436
|
optional :el_type, type: String, desc: 'element klass name'
|
|
433
437
|
optional :from_date, type: Integer, desc: 'created_date from in ms'
|
|
434
438
|
optional :to_date, type: Integer, desc: 'created_date to in ms'
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'labimotion/version'
|
|
4
|
+
require 'labimotion/libs/export_element'
|
|
5
|
+
require 'labimotion/helpers/mtt_helpers'
|
|
6
|
+
require 'labimotion/models/dose_resp_output'
|
|
7
|
+
|
|
8
|
+
module Labimotion
|
|
9
|
+
# Generic Element API
|
|
10
|
+
class MttAPI < Grape::API
|
|
11
|
+
helpers Labimotion::ParamHelpers
|
|
12
|
+
helpers Labimotion::MttHelpers
|
|
13
|
+
|
|
14
|
+
namespace :public do
|
|
15
|
+
resource :mtt_apps do
|
|
16
|
+
route_param :token do
|
|
17
|
+
desc 'Download data from MTT app (GET endpoint)'
|
|
18
|
+
get do
|
|
19
|
+
download_json_to_external_app
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc 'Upload modified data from MTT app (POST endpoint)'
|
|
23
|
+
post do
|
|
24
|
+
upload_json_from_external_app
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
resource :mtt do
|
|
31
|
+
namespace :requests do
|
|
32
|
+
desc 'Get MTT requests for current user'
|
|
33
|
+
get do
|
|
34
|
+
# Get all requests created by current user
|
|
35
|
+
requests = Labimotion::DoseRespRequest
|
|
36
|
+
.includes(:dose_resp_outputs)
|
|
37
|
+
.where(created_by: current_user.id)
|
|
38
|
+
.order(created_at: :desc)
|
|
39
|
+
|
|
40
|
+
# Return formatted response
|
|
41
|
+
requests.map do |req|
|
|
42
|
+
{
|
|
43
|
+
id: req.id,
|
|
44
|
+
request_id: req.request_id,
|
|
45
|
+
element_id: req.element_id,
|
|
46
|
+
state: req.state,
|
|
47
|
+
state_name: case req.state
|
|
48
|
+
when Labimotion::DoseRespRequest::STATE_ERROR then 'error'
|
|
49
|
+
when Labimotion::DoseRespRequest::STATE_INITIAL then 'initial'
|
|
50
|
+
when Labimotion::DoseRespRequest::STATE_PROCESSING then 'processing'
|
|
51
|
+
when Labimotion::DoseRespRequest::STATE_COMPLETED then 'completed'
|
|
52
|
+
else 'unknown'
|
|
53
|
+
end,
|
|
54
|
+
created_at: req.created_at,
|
|
55
|
+
expires_at: req.expires_at,
|
|
56
|
+
expired: req.expired?,
|
|
57
|
+
revoked: req.revoked?,
|
|
58
|
+
active: req.active?,
|
|
59
|
+
resp_message: req.resp_message,
|
|
60
|
+
last_accessed_at: req.last_accessed_at,
|
|
61
|
+
access_count: req.access_count || 0,
|
|
62
|
+
outputs: req.dose_resp_outputs.map do |output|
|
|
63
|
+
{
|
|
64
|
+
id: output.id,
|
|
65
|
+
output_data: output.output_data,
|
|
66
|
+
notes: output.notes,
|
|
67
|
+
created_at: output.created_at
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
desc 'Delete one or multiple MTT requests'
|
|
75
|
+
params do
|
|
76
|
+
requires :ids, type: Array[Integer], desc: 'Array of request IDs to delete'
|
|
77
|
+
end
|
|
78
|
+
delete do
|
|
79
|
+
# Find requests belonging to current user
|
|
80
|
+
requests = Labimotion::DoseRespRequest.where(
|
|
81
|
+
id: params[:ids],
|
|
82
|
+
created_by: current_user.id
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if requests.empty?
|
|
86
|
+
error!('No requests found or unauthorized', 404)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
deleted_count = requests.count
|
|
90
|
+
requests.destroy_all
|
|
91
|
+
|
|
92
|
+
{
|
|
93
|
+
success: true,
|
|
94
|
+
message: "Successfully deleted #{deleted_count} request(s)",
|
|
95
|
+
deleted_count: deleted_count
|
|
96
|
+
}
|
|
97
|
+
rescue StandardError => e
|
|
98
|
+
error!("Error deleting requests: #{e.message}", 500)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
desc 'Update MTT request'
|
|
102
|
+
params do
|
|
103
|
+
requires :id, type: Integer, desc: 'Request ID'
|
|
104
|
+
optional :state, type: Integer, desc: 'State (-1: error, 0: initial, 1: processing, 2: completed)', values: [-1, 0, 1, 2]
|
|
105
|
+
optional :resp_message, type: String, desc: 'Response message'
|
|
106
|
+
optional :wellplates_metadata, type: Hash, desc: 'Wellplates metadata'
|
|
107
|
+
optional :input_metadata, type: Hash, desc: 'Input metadata'
|
|
108
|
+
optional :revoked, type: Boolean, desc: 'Revoke access token'
|
|
109
|
+
end
|
|
110
|
+
patch ':id' do
|
|
111
|
+
# Find request belonging to current user
|
|
112
|
+
request = Labimotion::DoseRespRequest.find_by(
|
|
113
|
+
id: params[:id],
|
|
114
|
+
created_by: current_user.id
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
error!('Request not found or unauthorized', 404) unless request
|
|
118
|
+
|
|
119
|
+
# Prepare update attributes
|
|
120
|
+
update_attrs = {}
|
|
121
|
+
update_attrs[:state] = params[:state] if params.key?(:state)
|
|
122
|
+
update_attrs[:resp_message] = params[:resp_message] if params.key?(:resp_message)
|
|
123
|
+
update_attrs[:wellplates_metadata] = params[:wellplates_metadata] if params.key?(:wellplates_metadata)
|
|
124
|
+
update_attrs[:input_metadata] = params[:input_metadata] if params.key?(:input_metadata)
|
|
125
|
+
update_attrs[:revoked_at] = params[:revoked] ? Time.current : nil if params.key?(:revoked)
|
|
126
|
+
|
|
127
|
+
if request.update(update_attrs)
|
|
128
|
+
{
|
|
129
|
+
success: true,
|
|
130
|
+
message: 'Request updated successfully',
|
|
131
|
+
request: {
|
|
132
|
+
id: request.id,
|
|
133
|
+
request_id: request.request_id,
|
|
134
|
+
state: request.state,
|
|
135
|
+
state_name: case request.state
|
|
136
|
+
when Labimotion::DoseRespRequest::STATE_ERROR then 'error'
|
|
137
|
+
when Labimotion::DoseRespRequest::STATE_INITIAL then 'initial'
|
|
138
|
+
when Labimotion::DoseRespRequest::STATE_PROCESSING then 'processing'
|
|
139
|
+
when Labimotion::DoseRespRequest::STATE_COMPLETED then 'completed'
|
|
140
|
+
else 'unknown'
|
|
141
|
+
end,
|
|
142
|
+
resp_message: request.resp_message,
|
|
143
|
+
revoked: request.revoked?,
|
|
144
|
+
updated_at: request.updated_at
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else
|
|
148
|
+
error!("Validation error: #{request.errors.full_messages.join(', ')}", 422)
|
|
149
|
+
end
|
|
150
|
+
rescue ActiveRecord::RecordNotFound
|
|
151
|
+
error!('Request not found', 404)
|
|
152
|
+
rescue StandardError => e
|
|
153
|
+
error!("Error updating request: #{e.message}", 500)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
namespace :outputs do
|
|
158
|
+
desc 'Delete one or multiple MTT outputs'
|
|
159
|
+
params do
|
|
160
|
+
requires :ids, type: Array[Integer], desc: 'Array of output IDs to delete'
|
|
161
|
+
end
|
|
162
|
+
delete do
|
|
163
|
+
# Find outputs where the parent request belongs to current user
|
|
164
|
+
outputs = Labimotion::DoseRespOutput
|
|
165
|
+
.joins(:dose_resp_request)
|
|
166
|
+
.where(
|
|
167
|
+
id: params[:ids],
|
|
168
|
+
dose_resp_requests: { created_by: current_user.id }
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if outputs.empty?
|
|
172
|
+
error!('No outputs found or unauthorized', 404)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
deleted_count = outputs.count
|
|
176
|
+
outputs.destroy_all
|
|
177
|
+
|
|
178
|
+
{
|
|
179
|
+
success: true,
|
|
180
|
+
message: "Successfully deleted #{deleted_count} output(s)",
|
|
181
|
+
deleted_count: deleted_count
|
|
182
|
+
}
|
|
183
|
+
rescue StandardError => e
|
|
184
|
+
error!("Error deleting outputs: #{e.message}", 500)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
namespace :create_mtt_request do
|
|
189
|
+
desc 'Create MTT assay request'
|
|
190
|
+
params do
|
|
191
|
+
use :create_mtt_request_params
|
|
192
|
+
end
|
|
193
|
+
post do
|
|
194
|
+
# Find element and wellplates
|
|
195
|
+
element = Labimotion::Element.find_by(id: params[:id])
|
|
196
|
+
error!('Element not found', 404) unless element
|
|
197
|
+
#byebug
|
|
198
|
+
# Verify user has update permission
|
|
199
|
+
error!('Unauthorized', 403) unless ElementPolicy.new(current_user, element).update?
|
|
200
|
+
|
|
201
|
+
wellplates = Wellplate.where(id: params[:wellplate_ids])
|
|
202
|
+
error!('No wellplates found', 404) if wellplates.empty?
|
|
203
|
+
|
|
204
|
+
# Generate wellplates metadata
|
|
205
|
+
wellplates_metadata = generate_wellplates_metadata(wellplates)
|
|
206
|
+
|
|
207
|
+
# Create DoseRespRequest record with token
|
|
208
|
+
dose_resp_request = Labimotion::DoseRespRequest.create!(
|
|
209
|
+
element_id: element.id,
|
|
210
|
+
wellplates_metadata: { wellplates: wellplates_metadata },
|
|
211
|
+
input_metadata: {
|
|
212
|
+
wellplate_ids: params[:wellplate_ids],
|
|
213
|
+
element_id: element.id,
|
|
214
|
+
element_name: element.name,
|
|
215
|
+
created_at: Time.current
|
|
216
|
+
},
|
|
217
|
+
state: Labimotion::DoseRespRequest::STATE_INITIAL,
|
|
218
|
+
created_by: current_user&.id,
|
|
219
|
+
expires_at: TPA_EXPIRATION.from_now
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Generate external app URL with token
|
|
223
|
+
token_uri = token_url(dose_resp_request)
|
|
224
|
+
external_app_url = get_external_app_url
|
|
225
|
+
|
|
226
|
+
# Format: "#{@app.url}?url=#{CGI.escape(token_uri)}&type=ThirdPartyApp"
|
|
227
|
+
"#{external_app_url}?method=DoseResponse&url=#{CGI.escape(token_uri)}"
|
|
228
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
229
|
+
error!("Validation error: #{e.message}", 422)
|
|
230
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
231
|
+
error!("Not found: #{e.message}", 404)
|
|
232
|
+
rescue StandardError => e
|
|
233
|
+
error!("Error: #{e.message}", 500)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'labimotion/entities/application_entity'
|
|
4
|
+
|
|
5
|
+
module Labimotion
|
|
6
|
+
class ElementVariationEntity < Labimotion::ApplicationEntity
|
|
7
|
+
expose :id
|
|
8
|
+
expose :element_id, as: :elementId
|
|
9
|
+
expose :variations
|
|
10
|
+
expose :layout
|
|
11
|
+
|
|
12
|
+
def variations
|
|
13
|
+
rows = object.variations_hash
|
|
14
|
+
rows.transform_values do |row|
|
|
15
|
+
next row unless row.is_a?(Hash)
|
|
16
|
+
|
|
17
|
+
row.symbolize_keys.slice(:uuid, :name, :properties, :metadata, :segments).tap do |slim|
|
|
18
|
+
slim[:properties] = (slim[:properties] || {})
|
|
19
|
+
slim[:metadata] = (slim[:metadata] || {}).slice('notes', 'analyses', 'group', :notes, :analyses, :group)
|
|
20
|
+
slim[:segments] = (slim[:segments] || {})
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def layout
|
|
26
|
+
object.layout_hash
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|