1use std::sync::Arc;
4
5use openapp_sdk_common::NameMatch;
6use reqwest::Method;
7
8use super::JsonValue;
9use crate::{
10 error::SdkError,
11 resolve::{
12 fetch_all_paginated, items_from_list_response, resolve_unique_sdk, use_server_q_prefilter,
13 },
14 transport::{RequestSpec, Transport},
15};
16
17#[derive(Debug, Clone, Default)]
19pub struct ListIntegrationsParams {
20 pub provider_type: Option<String>,
21 pub q: Option<String>,
22 pub limit: Option<u32>,
23 pub offset: Option<u32>,
24}
25
26#[derive(Debug, Clone)]
27pub struct IntegrationsClient {
28 transport: Arc<Transport>,
29}
30
31impl IntegrationsClient {
32 pub(crate) fn new(transport: Arc<Transport>) -> Self {
33 Self { transport }
34 }
35
36 pub async fn list(&self) -> Result<JsonValue, SdkError> {
37 self.list_with(ListIntegrationsParams::default()).await
38 }
39
40 pub async fn list_with(&self, params: ListIntegrationsParams) -> Result<JsonValue, SdkError> {
41 let query = build_list_query(¶ms);
42 self.transport
43 .request_json::<(), JsonValue>(RequestSpec {
44 method: Method::GET,
45 path: "/integrations",
46 query: &query,
47 ..Default::default()
48 })
49 .await
50 }
51
52 pub async fn get_by_name(
54 &self,
55 name: &str,
56 mode: NameMatch,
57 provider_type: Option<&str>,
58 ) -> Result<JsonValue, SdkError> {
59 let q = use_server_q_prefilter(mode, name).then(|| name.to_owned());
60 let provider = provider_type.map(str::to_owned);
61 let client = self.clone();
62 let items = fetch_all_paginated(move |limit, offset| {
63 let client = client.clone();
64 let params = ListIntegrationsParams {
65 provider_type: provider.clone(),
66 q: q.clone(),
67 limit: Some(limit),
68 offset: Some(offset),
69 };
70 async move { client.list_with(params).await }
71 })
72 .await?;
73 resolve_unique_sdk(&items, "integration", "name", name, mode)
74 }
75
76 pub async fn get_access_portal_by_name(
78 &self,
79 integration_id: &str,
80 name: &str,
81 mode: NameMatch,
82 ) -> Result<JsonValue, SdkError> {
83 let path = format!("/integrations/{integration_id}/access-portals");
84 let response = self
85 .transport
86 .request_json::<(), JsonValue>(RequestSpec {
87 method: Method::GET,
88 path: &path,
89 ..Default::default()
90 })
91 .await?;
92 let items = items_from_list_response(&response, Some("portals"));
93 resolve_unique_sdk(&items, "portal", "name", name, mode)
94 }
95
96 pub async fn create(&self, body: &JsonValue) -> Result<JsonValue, SdkError> {
97 self.transport
98 .request_json::<JsonValue, JsonValue>(RequestSpec {
99 method: Method::POST,
100 path: "/integrations",
101 body: Some(body),
102 ..Default::default()
103 })
104 .await
105 }
106
107 pub async fn provider_types(&self) -> Result<Vec<JsonValue>, SdkError> {
108 self.transport
109 .request_json::<(), Vec<JsonValue>>(RequestSpec {
110 method: Method::GET,
111 path: "/integrations/provider-types",
112 ..Default::default()
113 })
114 .await
115 }
116
117 pub async fn provider_definition(&self, provider_type: &str) -> Result<JsonValue, SdkError> {
118 let path = format!("/integrations/provider-types/{provider_type}/definition");
119 self.transport
120 .request_json::<(), JsonValue>(RequestSpec {
121 method: Method::GET,
122 path: &path,
123 ..Default::default()
124 })
125 .await
126 }
127
128 pub async fn get(&self, id: &str) -> Result<JsonValue, SdkError> {
129 let path = format!("/integrations/{id}");
130 self.transport
131 .request_json::<(), JsonValue>(RequestSpec {
132 method: Method::GET,
133 path: &path,
134 ..Default::default()
135 })
136 .await
137 }
138
139 pub async fn update(&self, id: &str, body: &JsonValue) -> Result<JsonValue, SdkError> {
140 let path = format!("/integrations/{id}");
141 self.transport
142 .request_json::<JsonValue, JsonValue>(RequestSpec {
143 method: Method::PUT,
144 path: &path,
145 body: Some(body),
146 ..Default::default()
147 })
148 .await
149 }
150
151 pub async fn purge(&self, id: &str) -> Result<(), SdkError> {
152 let path = format!("/integrations/{id}/purge");
153 self.transport
154 .request_json::<(), ()>(RequestSpec {
155 method: Method::DELETE,
156 path: &path,
157 ..Default::default()
158 })
159 .await
160 }
161
162 pub async fn restore(&self, id: &str) -> Result<JsonValue, SdkError> {
163 let path = format!("/integrations/{id}/restore");
164 self.transport
165 .request_json::<(), JsonValue>(RequestSpec {
166 method: Method::POST,
167 path: &path,
168 ..Default::default()
169 })
170 .await
171 }
172
173 pub async fn device_metadata_schema(&self, id: &str) -> Result<JsonValue, SdkError> {
174 let path = format!("/integrations/{id}/device-metadata-schema");
175 self.transport
176 .request_json::<(), JsonValue>(RequestSpec {
177 method: Method::GET,
178 path: &path,
179 ..Default::default()
180 })
181 .await
182 }
183
184 pub async fn discovered_devices(&self, id: &str) -> Result<Vec<JsonValue>, SdkError> {
185 let path = format!("/integrations/{id}/discovered-devices");
186 self.transport
187 .request_json::<(), Vec<JsonValue>>(RequestSpec {
188 method: Method::GET,
189 path: &path,
190 ..Default::default()
191 })
192 .await
193 }
194
195 pub async fn entities(&self, id: &str) -> Result<Vec<JsonValue>, SdkError> {
196 let path = format!("/integrations/{id}/entities");
197 self.transport
198 .request_json::<(), Vec<JsonValue>>(RequestSpec {
199 method: Method::GET,
200 path: &path,
201 ..Default::default()
202 })
203 .await
204 }
205
206 pub async fn ops(&self, id: &str) -> Result<Vec<JsonValue>, SdkError> {
207 let path = format!("/integrations/{id}/ops");
208 self.transport
209 .request_json::<(), Vec<JsonValue>>(RequestSpec {
210 method: Method::GET,
211 path: &path,
212 ..Default::default()
213 })
214 .await
215 }
216
217 pub async fn run_op(
218 &self,
219 id: &str,
220 op_id: &str,
221 body: &JsonValue,
222 ) -> Result<JsonValue, SdkError> {
223 let path = format!("/integrations/{id}/ops/{op_id}");
224 self.transport
225 .request_json::<JsonValue, JsonValue>(RequestSpec {
226 method: Method::POST,
227 path: &path,
228 body: Some(body),
229 ..Default::default()
230 })
231 .await
232 }
233
234 pub async fn list_access_portals(&self, id: &str) -> Result<JsonValue, SdkError> {
237 let path = format!("/integrations/{id}/access-portals");
238 self.transport
239 .request_json::<(), JsonValue>(RequestSpec {
240 method: Method::GET,
241 path: &path,
242 ..Default::default()
243 })
244 .await
245 }
246
247 pub async fn create_access_portal(
248 &self,
249 id: &str,
250 body: &JsonValue,
251 ) -> Result<JsonValue, SdkError> {
252 let path = format!("/integrations/{id}/access-portals");
253 self.transport
254 .request_json::<JsonValue, JsonValue>(RequestSpec {
255 method: Method::POST,
256 path: &path,
257 body: Some(body),
258 ..Default::default()
259 })
260 .await
261 }
262
263 pub async fn get_access_portal(&self, portal_id: &str) -> Result<JsonValue, SdkError> {
264 let path = format!("/integrations/access-portals/{portal_id}");
265 self.transport
266 .request_json::<(), JsonValue>(RequestSpec {
267 method: Method::GET,
268 path: &path,
269 ..Default::default()
270 })
271 .await
272 }
273
274 pub async fn update_access_portal(
275 &self,
276 id: &str,
277 portal_id: &str,
278 body: &JsonValue,
279 ) -> Result<JsonValue, SdkError> {
280 let path = format!("/integrations/{id}/access-portals/{portal_id}");
281 self.transport
282 .request_json::<JsonValue, JsonValue>(RequestSpec {
283 method: Method::PUT,
284 path: &path,
285 body: Some(body),
286 ..Default::default()
287 })
288 .await
289 }
290
291 pub async fn delete_access_portal(&self, id: &str, portal_id: &str) -> Result<(), SdkError> {
292 let path = format!("/integrations/{id}/access-portals/{portal_id}");
293 self.transport
294 .request_json::<(), ()>(RequestSpec {
295 method: Method::DELETE,
296 path: &path,
297 ..Default::default()
298 })
299 .await
300 }
301
302 pub async fn create_access_invite(
303 &self,
304 id: &str,
305 body: &JsonValue,
306 ) -> Result<JsonValue, SdkError> {
307 let path = format!("/integrations/{id}/access-invites");
308 self.transport
309 .request_json::<JsonValue, JsonValue>(RequestSpec {
310 method: Method::POST,
311 path: &path,
312 body: Some(body),
313 ..Default::default()
314 })
315 .await
316 }
317
318 pub async fn update_access_invite(
319 &self,
320 id: &str,
321 invite_link_id: &str,
322 body: &JsonValue,
323 ) -> Result<JsonValue, SdkError> {
324 let path = format!("/integrations/{id}/access-invites/{invite_link_id}");
325 self.transport
326 .request_json::<JsonValue, JsonValue>(RequestSpec {
327 method: Method::PUT,
328 path: &path,
329 body: Some(body),
330 ..Default::default()
331 })
332 .await
333 }
334
335 pub async fn delete_access_invite(
336 &self,
337 id: &str,
338 invite_link_id: &str,
339 ) -> Result<(), SdkError> {
340 let path = format!("/integrations/{id}/access-invites/{invite_link_id}");
341 self.transport
342 .request_json::<(), ()>(RequestSpec {
343 method: Method::DELETE,
344 path: &path,
345 ..Default::default()
346 })
347 .await
348 }
349
350 pub async fn restore_access_invite(
351 &self,
352 id: &str,
353 invite_link_id: &str,
354 ) -> Result<JsonValue, SdkError> {
355 let path = format!("/integrations/{id}/access-invites/{invite_link_id}/restore");
356 self.transport
357 .request_json::<(), JsonValue>(RequestSpec {
358 method: Method::POST,
359 path: &path,
360 ..Default::default()
361 })
362 .await
363 }
364}
365
366fn build_list_query(params: &ListIntegrationsParams) -> Vec<(&str, Option<String>)> {
367 vec![
368 (
369 "provider_type",
370 params
371 .provider_type
372 .as_ref()
373 .map(std::borrow::ToOwned::to_owned),
374 ),
375 ("q", params.q.as_ref().map(std::borrow::ToOwned::to_owned)),
376 ("limit", params.limit.map(|n| n.to_string())),
377 ("offset", params.offset.map(|n| n.to_string())),
378 ]
379}