backbone_integrations/presentation/dto/
integration_account_dto.rs1use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "openapi")]
13#[cfg(feature = "openapi")]
14use utoipa::ToSchema;
15
16use crate::domain::entity::IntegrationAccount;
17use crate::domain::entity::AuditMetadata;
18use crate::domain::entity::IntegrationAccountStatus;
19use crate::domain::entity::OAuthProvider;
20
21#[derive(Debug, Clone, Deserialize)]
30#[cfg_attr(feature = "openapi", derive(ToSchema))]
31#[serde(rename_all = "camelCase")]
32pub struct CreateIntegrationAccountDto {
33 pub provider: OAuthProvider,
34 #[cfg_attr(feature = "openapi", schema(example = "example"))]
35 #[serde(alias = "account_ref")]
36 pub account_ref: String,
37 pub status: IntegrationAccountStatus,
38 #[cfg_attr(feature = "openapi", schema(example = "example"))]
39 pub scopes: String,
40 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pkce_verifier")]
41 pub pkce_verifier: Option<String>,
42 #[serde(default, skip_serializing_if = "Option::is_none", alias = "expires_at")]
43 pub expires_at: Option<DateTime<Utc>>,
44 #[serde(default, skip_serializing_if = "Option::is_none", alias = "last_refreshed_at")]
45 pub last_refreshed_at: Option<DateTime<Utc>>,
46}
47
48#[derive(Debug, Clone, Deserialize)]
57#[cfg_attr(feature = "openapi", derive(ToSchema))]
58#[serde(rename_all = "camelCase")]
59pub struct UpdateIntegrationAccountDto {
60 pub provider: OAuthProvider,
61 #[cfg_attr(feature = "openapi", schema(example = "example"))]
62 #[serde(alias = "account_ref")]
63 pub account_ref: String,
64 pub status: IntegrationAccountStatus,
65 #[cfg_attr(feature = "openapi", schema(example = "example"))]
66 pub scopes: String,
67 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pkce_verifier")]
68 pub pkce_verifier: Option<String>,
69 #[serde(default, skip_serializing_if = "Option::is_none", alias = "expires_at")]
70 pub expires_at: Option<DateTime<Utc>>,
71 #[serde(default, skip_serializing_if = "Option::is_none", alias = "last_refreshed_at")]
72 pub last_refreshed_at: Option<DateTime<Utc>>,
73}
74
75#[derive(Debug, Clone, Default, Deserialize)]
84#[cfg_attr(feature = "openapi", derive(ToSchema))]
85#[serde(rename_all = "camelCase")]
86pub struct PatchIntegrationAccountDto {
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub provider: Option<OAuthProvider>,
89 #[cfg_attr(feature = "openapi", schema(example = "example"))]
90 #[serde(skip_serializing_if = "Option::is_none", alias = "account_ref")]
91 pub account_ref: Option<String>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub status: Option<IntegrationAccountStatus>,
94 #[cfg_attr(feature = "openapi", schema(example = "example"))]
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub scopes: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none", alias = "pkce_verifier")]
98 pub pkce_verifier: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none", alias = "expires_at")]
100 pub expires_at: Option<DateTime<Utc>>,
101 #[serde(skip_serializing_if = "Option::is_none", alias = "last_refreshed_at")]
102 pub last_refreshed_at: Option<DateTime<Utc>>,
103}
104
105impl PatchIntegrationAccountDto {
106 pub fn has_changes(&self) -> bool {
108 self.provider.is_some() || self.account_ref.is_some() || self.status.is_some() || self.scopes.is_some() || self.pkce_verifier.is_some() || self.expires_at.is_some() || self.last_refreshed_at.is_some()
109 }
110}
111
112#[derive(Debug, Clone, Serialize)]
121#[cfg_attr(feature = "openapi", derive(ToSchema))]
122#[serde(rename_all = "camelCase")]
123pub struct IntegrationAccountResponseDto {
124 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
125 pub id: Uuid,
126 pub provider: OAuthProvider,
127 #[cfg_attr(feature = "openapi", schema(example = "example"))]
128 pub account_ref: String,
129 pub status: IntegrationAccountStatus,
130 #[cfg_attr(feature = "openapi", schema(example = "example"))]
131 pub scopes: String,
132 pub pkce_verifier: Option<String>,
133 pub expires_at: Option<DateTime<Utc>>,
134 pub last_refreshed_at: Option<DateTime<Utc>>,
135 pub metadata: AuditMetadata,
136}
137
138#[derive(Debug, Clone, Serialize)]
147#[cfg_attr(feature = "openapi", derive(ToSchema))]
148#[serde(rename_all = "camelCase")]
149pub struct IntegrationAccountListResponseDto {
150 pub items: Vec<IntegrationAccountResponseDto>,
152 pub total: u64,
154 pub page: u32,
156 pub per_page: u32,
158 pub total_pages: u32,
160 pub has_next: bool,
162 pub has_prev: bool,
164}
165
166impl IntegrationAccountListResponseDto {
167 pub fn new(items: Vec<IntegrationAccountResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
169 let total_pages = if per_page > 0 {
170 ((total as f64) / (per_page as f64)).ceil() as u32
171 } else {
172 0
173 };
174 Self {
175 items,
176 total,
177 page,
178 per_page,
179 total_pages,
180 has_next: page < total_pages,
181 has_prev: page > 1,
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize)]
188#[cfg_attr(feature = "openapi", derive(ToSchema))]
189#[serde(rename_all = "camelCase")]
190pub struct IntegrationAccountSummaryDto {
191 pub id: Uuid,
192 pub provider: OAuthProvider,
193 pub account_ref: String,
194 pub status: IntegrationAccountStatus,
195 pub created_at: Option<DateTime<Utc>>,
196}
197
198impl From<IntegrationAccount> for IntegrationAccountResponseDto {
203 fn from(entity: IntegrationAccount) -> Self {
204 Self {
205 id: entity.id,
206 provider: entity.provider,
207 account_ref: entity.account_ref,
208 status: entity.status,
209 scopes: entity.scopes,
210 pkce_verifier: entity.pkce_verifier,
211 expires_at: entity.expires_at,
212 last_refreshed_at: entity.last_refreshed_at,
213 metadata: entity.metadata,
214 }
215 }
216}
217
218impl From<IntegrationAccount> for IntegrationAccountSummaryDto {
219 fn from(entity: IntegrationAccount) -> Self {
220 let created_at = backbone_core::PersistentEntity::created_at(&entity);
221 Self {
222 id: entity.id,
223 provider: entity.provider,
224 account_ref: entity.account_ref,
225 status: entity.status,
226 created_at,
227 }
228 }
229}
230
231impl From<CreateIntegrationAccountDto> for IntegrationAccount {
232 fn from(dto: CreateIntegrationAccountDto) -> Self {
233 Self {
234 id: Uuid::new_v4(),
235 provider: dto.provider,
236 account_ref: dto.account_ref,
237 status: dto.status,
238 scopes: dto.scopes,
239 pkce_verifier: dto.pkce_verifier,
240 expires_at: dto.expires_at,
241 last_refreshed_at: dto.last_refreshed_at,
242 metadata: AuditMetadata::default(),
243 }
244 }
245}
246
247impl From<&IntegrationAccount> for IntegrationAccountResponseDto {
248 fn from(entity: &IntegrationAccount) -> Self {
249 Self {
250 id: entity.id.clone(),
251 provider: entity.provider.clone(),
252 account_ref: entity.account_ref.clone(),
253 status: entity.status.clone(),
254 scopes: entity.scopes.clone(),
255 pkce_verifier: entity.pkce_verifier.clone(),
256 expires_at: entity.expires_at.clone(),
257 last_refreshed_at: entity.last_refreshed_at.clone(),
258 metadata: entity.metadata.clone(),
259 }
260 }
261}
262
263impl backbone_core::FromCreateDto<CreateIntegrationAccountDto> for IntegrationAccount {
264 fn from_create_dto(dto: CreateIntegrationAccountDto) -> backbone_core::ServiceResult<Self> {
265 Ok(IntegrationAccount::from(dto))
266 }
267}
268
269impl backbone_core::ApplyUpdateDto<UpdateIntegrationAccountDto> for IntegrationAccount {
270 fn apply_update(mut self, dto: UpdateIntegrationAccountDto) -> backbone_core::ServiceResult<Self> {
271 self.provider = dto.provider;
272 self.account_ref = dto.account_ref;
273 self.status = dto.status;
274 self.scopes = dto.scopes;
275 self.pkce_verifier = dto.pkce_verifier;
276 self.expires_at = dto.expires_at;
277 self.last_refreshed_at = dto.last_refreshed_at;
278 Ok(self)
279 }
280}
281
282