labimotion 2.2.0.rc4 → 2.2.0.rc5

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: 7cc7c70f57932c158e55ee04ec5abe32ea9991468bc6efcd82a8409ed19cedb2
4
- data.tar.gz: 12afc9b342dab9003162ca09a4fb50211b5dea1a978f1390761233d299ec09f7
3
+ metadata.gz: 5aa32269487161d9b1e5647154e1d55ec3fae34dc50082e538adae80679afdf9
4
+ data.tar.gz: 5df8ec5d405a7c64ee0840cfffe1dd8a60537997447c898d2f1d8870b3910830
5
5
  SHA512:
6
- metadata.gz: 31c66a67385d571938cc3b343b89336c38d724f58c71230884e6fa134ee9da8693b83985dc1f8633a7b2a8054e02fff70d537da9476e2e50a486bcb7c98ff483
7
- data.tar.gz: c155b3eebba77d5899bd25f84656008c263fefdf351a2e5857a7d019e331252b18a6c5a377a9a47f2b1fdeca7795e1df3e3440ff07bd34f0d3fab1594f2ae879
6
+ metadata.gz: 68ebbb1d5ebbe512808bcab3f34b3452c9ee0dbeceebbed183db20904e433b0aa06cd533f66a0896e7d3824e615307d25edd669cb1de5c0f0415213c2f349e1f
7
+ data.tar.gz: 14a545856a83b9d5778910eefd06c2cb4b865e696036c8e7e1901c18e2688726c6447aca3af8a65703e788d2fc95357acfe1fd5e6177706a3f0dc62b712e885d
@@ -12,7 +12,5 @@ module Labimotion
12
12
  mount Labimotion::LabimotionHubAPI
13
13
  mount Labimotion::StandardLayerAPI
14
14
  mount Labimotion::VocabularyAPI
15
- mount Labimotion::MttAPI
16
- mount Labimotion::DoseRespRequestAPI
17
15
  end
18
16
  end
@@ -87,12 +87,13 @@ module Labimotion
87
87
  }
88
88
  element = Labimotion::Element.new(attributes)
89
89
 
90
- if params[:collection_id]
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
91
94
  collection = current_user.collections.find(params[:collection_id])
92
95
  element.collections << collection
93
96
  end
94
- all_coll = Collection.get_all_collection_for_user(current_user.id)
95
- element.collections << all_coll
96
97
  element.save!
97
98
  element.properties = update_sample_association(params[:properties], current_user, element)
98
99
  # element.properties = update_vocabularies(_properties, current_user, element)
@@ -246,27 +247,21 @@ module Labimotion
246
247
  end
247
248
 
248
249
  def list_serialized_elements(params, current_user)
249
- collection_id =
250
- if params[:collection_id]
251
- Collection
252
- .belongs_to_or_shared_by(current_user.id, current_user.group_ids)
253
- .find_by(id: params[:collection_id])&.id
254
- elsif params[:sync_collection_id]
255
- current_user
256
- .all_sync_in_collections_users
257
- .find_by(id: params[:sync_collection_id])&.collection&.id
258
- end
250
+ scope = Labimotion::Element.none
259
251
 
260
- scope =
261
- if collection_id
262
- Labimotion::Element
263
- .joins(:element_klass, :collections_elements)
264
- .where(
265
- element_klasses: { name: params[:el_type] },
266
- collections_elements: { collection_id: collection_id },
267
- ).includes(:tag, collections: :sync_collections_users)
252
+ if params[:collection_id]
253
+ begin
254
+ collection = Collection.accessible_for(current_user).find(params[:collection_id])
255
+ scope = collection.elements
256
+ .joins(:element_klass)
257
+ .where(element_klasses: { name: params[:el_type] })
258
+ .includes(:tag)
259
+ rescue ActiveRecord::RecordNotFound
260
+ Labimotion::Element.none
261
+ end
268
262
  else
269
- Labimotion::Element.none
263
+ # All collection of current_user
264
+ scope = Labimotion::Element.for_user(current_user.id)
270
265
  end
271
266
 
272
267
  ## TO DO: refactor labimotion
@@ -146,11 +146,5 @@ module Labimotion
146
146
  requires :layer_id, type: String, desc: 'layer identifier'
147
147
  requires :field_id, type: String, desc: 'field identifier'
148
148
  end
149
-
150
-
151
- params :create_mtt_request_params do
152
- requires :id, type: Integer, desc: 'Element ID'
153
- requires :wellplate_ids, type: Array, desc: 'Selected Wellplates'
154
- end
155
149
  end
156
150
  end
@@ -12,7 +12,7 @@ module Labimotion
12
12
  end
13
13
 
14
14
  def self.elements_search(params, current_user, c_id, dl)
15
- collection = Collection.belongs_to_or_shared_by(current_user.id, current_user.group_ids).find(c_id)
15
+ collection = Collection.accessible_for(current_user).find(c_id)
16
16
  element_scope = Labimotion::Element.joins(:collections_elements).where('collections_elements.collection_id = ?', collection.id).joins(:element_klass).where('element_klasses.id = elements.element_klass_id AND element_klasses.name = ?', params[:selection][:genericElName])
17
17
  element_scope = element_scope.where('elements.name like (?)', "%#{params[:selection][:searchName]}%") if params[:selection][:searchName].present?
18
18
  element_scope = element_scope.where('elements.short_label like (?)', "%#{params[:selection][:searchShowLabel]}%") if params[:selection][:searchShowLabel].present?
@@ -97,7 +97,7 @@ module Labimotion
97
97
  def self.samples_search(c_id = @c_id)
98
98
  sqls = []
99
99
  sps = params[:selection][:searchProperties]
100
- collection = Collection.belongs_to_or_shared_by(current_user.id, current_user.group_ids).find(c_id)
100
+ collection = Collection.accessible_for(current_user).find(c_id)
101
101
  element_scope = Sample.joins(:collections_samples).where('collections_samples.collection_id = ?', collection.id)
102
102
  return element_scope if sps.empty?
103
103
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  ## Labimotion Version
4
4
  module Labimotion
5
- VERSION = '2.2.0.rc4'
5
+ VERSION = '2.2.0.rc5'
6
6
  end
data/lib/labimotion.rb CHANGED
@@ -27,8 +27,6 @@ module Labimotion
27
27
  autoload :ExporterAPI, 'labimotion/apis/exporter_api'
28
28
  autoload :StandardLayerAPI, 'labimotion/apis/standard_layer_api'
29
29
  autoload :VocabularyAPI, 'labimotion/apis/vocabulary_api'
30
- autoload :MttAPI, 'labimotion/apis/mtt_api'
31
- autoload :DoseRespRequestAPI, 'labimotion/apis/dose_resp_request_api'
32
30
 
33
31
  ######## Entities
34
32
  autoload :PropertiesEntity, 'labimotion/entities/properties_entity'
@@ -116,8 +114,6 @@ module Labimotion
116
114
  autoload :StdLayersRevision, 'labimotion/models/std_layers_revision'
117
115
 
118
116
  autoload :DeviceDescription, 'labimotion/models/device_description'
119
- autoload :DoseRespRequest, 'labimotion/models/dose_resp_request'
120
- autoload :DoseRespOutput, 'labimotion/models/dose_resp_output'
121
117
  autoload :Reaction, 'labimotion/models/reaction'
122
118
  autoload :ResearchPlan, 'labimotion/models/research_plan'
123
119
  autoload :Sample, 'labimotion/models/sample'
@@ -130,6 +126,6 @@ module Labimotion
130
126
  autoload :ElementFetchable, 'labimotion/models/concerns/element_fetchable'
131
127
  autoload :Segmentable, 'labimotion/models/concerns/segmentable'
132
128
  autoload :Datasetable, 'labimotion/models/concerns/datasetable'
133
- autoload :AttachmentConverter, 'labimotion/models/concerns/attachment_converter'
129
+ autoload :AttachmentConverter, 'labimotion/models/concerns/attachment_converter.rb'
134
130
  autoload :LinkedProperties, 'labimotion/models/concerns/linked_properties'
135
131
  end
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.2.0.rc4
4
+ version: 2.2.0.rc5
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-01-29 00:00:00.000000000 Z
12
+ date: 2026-03-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: caxlsx
@@ -55,14 +55,12 @@ extra_rdoc_files: []
55
55
  files:
56
56
  - lib/labimotion.rb
57
57
  - lib/labimotion/apis/converter_api.rb
58
- - lib/labimotion/apis/dose_resp_request_api.rb
59
58
  - lib/labimotion/apis/exporter_api.rb
60
59
  - lib/labimotion/apis/generic_dataset_api.rb
61
60
  - lib/labimotion/apis/generic_element_api.rb
62
61
  - lib/labimotion/apis/generic_klass_api.rb
63
62
  - lib/labimotion/apis/labimotion_api.rb
64
63
  - lib/labimotion/apis/labimotion_hub_api.rb
65
- - lib/labimotion/apis/mtt_api.rb
66
64
  - lib/labimotion/apis/segment_api.rb
67
65
  - lib/labimotion/apis/standard_api.rb
68
66
  - lib/labimotion/apis/standard_layer_api.rb
@@ -92,7 +90,6 @@ files:
92
90
  - lib/labimotion/helpers/element_helpers.rb
93
91
  - lib/labimotion/helpers/exporter_helpers.rb
94
92
  - lib/labimotion/helpers/generic_helpers.rb
95
- - lib/labimotion/helpers/mtt_helpers.rb
96
93
  - lib/labimotion/helpers/param_helpers.rb
97
94
  - lib/labimotion/helpers/repository_helpers.rb
98
95
  - lib/labimotion/helpers/sample_association_helpers.rb
@@ -101,7 +98,6 @@ files:
101
98
  - lib/labimotion/helpers/vocabulary_helpers.rb
102
99
  - lib/labimotion/libs/attachment_handler.rb
103
100
  - lib/labimotion/libs/converter.rb
104
- - lib/labimotion/libs/data/layer/StdDataset.json
105
101
  - lib/labimotion/libs/data/mapper/Chemwiki.json
106
102
  - lib/labimotion/libs/data/mapper/Source.json
107
103
  - lib/labimotion/libs/data/vocab/Standard.json
@@ -133,8 +129,6 @@ files:
133
129
  - lib/labimotion/models/dataset_klasses_revision.rb
134
130
  - lib/labimotion/models/datasets_revision.rb
135
131
  - lib/labimotion/models/device_description.rb
136
- - lib/labimotion/models/dose_resp_output.rb
137
- - lib/labimotion/models/dose_resp_request.rb
138
132
  - lib/labimotion/models/element.rb
139
133
  - lib/labimotion/models/element_klass.rb
140
134
  - lib/labimotion/models/element_klasses_revision.rb
@@ -1,241 +0,0 @@
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
@@ -1,238 +0,0 @@
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