Skip to main content

backbone_integrations/presentation/dto/
integration_account_dto.rs

1//! IntegrationAccount DTOs (Data Transfer Objects)
2//!
3//! Generated by metaphor-schema. Do not edit manually.
4//!
5//! DTOs provide a clean separation between domain entities and API
6//! representations, with OpenAPI documentation support.
7
8use 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// =============================================================================
22// Create DTO
23// =============================================================================
24
25/// Request DTO for creating a new IntegrationAccount
26///
27/// Used in POST requests to create new entities.
28/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
29#[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// =============================================================================
49// Update DTO
50// =============================================================================
51
52/// Request DTO for full update of a IntegrationAccount
53///
54/// Used in PUT requests for full entity replacement.
55/// All fields are required (except auto-generated ones).
56#[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// =============================================================================
76// Patch DTO
77// =============================================================================
78
79/// Request DTO for partial update of a IntegrationAccount
80///
81/// Used in PATCH requests for partial updates.
82/// All fields are optional - only provided fields will be updated.
83#[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    /// Check if any field is set
107    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// =============================================================================
113// Response DTO
114// =============================================================================
115
116/// Response DTO for IntegrationAccount entity
117///
118/// Used in API responses for single entity.
119/// Includes all fields including metadata.
120#[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// =============================================================================
139// List Response DTO
140// =============================================================================
141
142/// Paginated list response for IntegrationAccount entities
143///
144/// Used in API responses for list endpoints.
145/// Includes pagination metadata.
146#[derive(Debug, Clone, Serialize)]
147#[cfg_attr(feature = "openapi", derive(ToSchema))]
148#[serde(rename_all = "camelCase")]
149pub struct IntegrationAccountListResponseDto {
150    /// List of items
151    pub items: Vec<IntegrationAccountResponseDto>,
152    /// Total number of items (across all pages)
153    pub total: u64,
154    /// Current page number (1-indexed)
155    pub page: u32,
156    /// Number of items per page
157    pub per_page: u32,
158    /// Total number of pages
159    pub total_pages: u32,
160    /// Whether there is a next page
161    pub has_next: bool,
162    /// Whether there is a previous page
163    pub has_prev: bool,
164}
165
166impl IntegrationAccountListResponseDto {
167    /// Create a new list response from items and pagination info
168    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/// Summary DTO for list views (compact version)
187#[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
198// =============================================================================
199// Conversions
200// =============================================================================
201
202impl 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// =============================================================================
283// Custom DTOs
284// =============================================================================
285
286// Add custom DTOs specific to IntegrationAccount here.
287// This section will be preserved during regeneration.
288// >>> END CUSTOM DTOs
289