email_dto.rs 248 lignes · 7823 octets
//! Email DTOs for request/response handling
//!
//! This module contains Data Transfer Objects for email-related endpoints:
//! - Password reset requests
//! - Email validation requests
//! - Email queue admin endpoints

use serde::{Deserialize, Serialize};
use uuid::Uuid;
use validator::Validate;

/// Tracking states for critical emails (SMTP traceability)
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EmailDeliveryState {
    /// Email has been queued but not yet sent.
    Queued,
    /// Email is currently being transmitted to the SMTP server.
    Sending,
    /// SMTP server accepted the message for delivery.
    Accepted,
    /// SMTP server rejected the message.
    Rejected,
    /// Email was not delivered before its expiry deadline.
    Expired,
    /// Final delivery confirmed (via DSN)
    Delivered,
    /// Bounce received (via DSN)
    Bounced,
}

impl EmailDeliveryState {
    /// Returns a static string representation of this delivery state.
    pub fn as_str(self) -> &'static str {
        match self {
            EmailDeliveryState::Queued => "queued",
            EmailDeliveryState::Sending => "sending",
            EmailDeliveryState::Accepted => "accepted",
            EmailDeliveryState::Rejected => "rejected",
            EmailDeliveryState::Expired => "expired",
            EmailDeliveryState::Delivered => "delivered",
            EmailDeliveryState::Bounced => "bounced",
        }
    }

    /// Parses a string slice into an `EmailDeliveryState`, defaulting to `Queued` for unknown values.
    pub fn parse(value: &str) -> Self {
        match value {
            "queued" => EmailDeliveryState::Queued,
            "sending" => EmailDeliveryState::Sending,
            "accepted" => EmailDeliveryState::Accepted,
            "rejected" => EmailDeliveryState::Rejected,
            "expired" => EmailDeliveryState::Expired,
            "delivered" => EmailDeliveryState::Delivered,
            "bounced" => EmailDeliveryState::Bounced,
            _ => EmailDeliveryState::Queued,
        }
    }
}

/// Request to initiate password reset
#[derive(Debug, Deserialize, Validate)]
pub struct ForgotPasswordRequest {
    /// User email address
    #[validate(email)]
    pub email: String,
}

/// Response for password reset request
#[derive(Debug, Serialize)]
pub struct ForgotPasswordResponse {
    /// Success message (always the same for security - don't reveal if email exists)
    pub message: String,
}

/// Request to reset password with token
#[derive(Debug, Deserialize, Validate)]
pub struct ResetPasswordRequest {
    /// Password reset token from email
    #[validate(length(min = 1))]
    pub token: String,
    /// New password (must meet password requirements)
    #[validate(length(min = 8))]
    pub new_password: String,
}

/// Response for password reset
#[derive(Debug, Serialize)]
pub struct ResetPasswordResponse {
    /// Success message
    pub message: String,
}

/// Request to resend email validation
#[derive(Debug, Deserialize, Validate)]
pub struct ResendVerificationRequest {
    /// User email address
    #[validate(email)]
    pub email: String,
}

/// Response for resend verification request
#[derive(Debug, Serialize)]
pub struct ResendVerificationResponse {
    /// Success message (always the same for security)
    pub message: String,
}

/// Response for email verification
#[derive(Debug, Serialize)]
pub struct VerifyEmailResponse {
    /// Success message
    pub message: String,
    /// Whether email was verified
    pub verified: bool,
}

/// Email queue entry response (for admin endpoints)
#[derive(Debug, Serialize)]
pub struct EmailQueueEntry {
    /// Email queue entry ID
    pub id: Uuid,
    /// Recipient email
    pub to_email: String,
    /// Recipient name
    pub to_name: Option<String>,
    /// Subject
    pub subject: String,
    /// Email type
    pub email_type: String,
    /// Status (pending, sent, failed)
    pub status: String,
    /// Number of attempts
    pub attempts: i32,
    /// Last SMTP code if available
    pub smtp_code: Option<String>,
    /// Last SMTP response if available
    pub smtp_response: Option<String>,
    /// Creation timestamp
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Sent timestamp
    pub sent_at: Option<chrono::DateTime<chrono::Utc>>,
}

/// Email queue list response (for admin endpoints)
#[derive(Debug, Serialize)]
pub struct EmailQueueListResponse {
    /// List of email queue entries
    pub emails: Vec<EmailQueueEntry>,
    /// Total number of emails matching filters
    pub total: u64,
    /// Limit used
    pub limit: usize,
    /// Offset used
    pub offset: usize,
}

/// Email queue detail response (for admin endpoints)
#[derive(Debug, Serialize)]
pub struct EmailQueueDetailResponse {
    /// Email queue entry ID
    pub id: Uuid,
    /// Recipient email
    pub to_email: String,
    /// Recipient name
    pub to_name: Option<String>,
    /// Sender email
    pub from_email: String,
    /// Sender name
    pub from_name: Option<String>,
    /// Subject
    pub subject: String,
    /// HTML body content
    pub body_html: String,
    /// Plain text body content
    pub body_text: String,
    /// Email type
    pub email_type: String,
    /// Status (pending, sent, failed)
    pub status: String,
    /// Number of attempts
    pub attempts: i32,
    /// Last attempt timestamp
    pub last_attempt_at: Option<chrono::DateTime<chrono::Utc>>,
    /// Sent timestamp
    pub sent_at: Option<chrono::DateTime<chrono::Utc>>,
    /// Error message if failed
    pub error_message: Option<String>,
    /// Last SMTP code if available
    pub smtp_code: Option<String>,
    /// Last SMTP response if available
    pub smtp_response: Option<String>,
    /// Creation timestamp
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Last update timestamp
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

/// Response for retry email request
#[derive(Debug, Serialize)]
pub struct RetryEmailResponse {
    /// Success message
    pub message: String,
    /// Email queue entry ID
    pub email_id: Uuid,
    /// Current status
    pub status: String,
}

/// Delivery status response for critical emails (admin)
#[derive(Debug, Serialize)]
pub struct EmailDeliveryStatusResponse {
    /// Unique identifier of the email queue entry.
    pub id: Uuid,
    /// Type of email (e.g. `password_reset`, `email_validation`).
    pub email_type: String,
    /// Recipient email address.
    pub recipient: String,
    /// Template name used to render the email.
    pub template: String,
    /// Current delivery state.
    pub state: EmailDeliveryState,
    /// SMTP response code from the last delivery attempt.
    pub smtp_code: Option<String>,
    /// Full SMTP response message from the last delivery attempt.
    pub smtp_response: Option<String>,
    /// Number of delivery attempts made so far.
    pub attempt_count: i32,
    /// Timestamp of the most recent delivery attempt.
    pub last_attempt_at: Option<chrono::DateTime<chrono::Utc>>,
    /// Timestamp of the last state change.
    pub last_state_at: chrono::DateTime<chrono::Utc>,
    /// Optional correlation ID linking to the originating request.
    pub correlation_id: Option<Uuid>,
    /// Timestamp when the queue entry was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Timestamp of the last update to this entry.
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

/// Paginated list of email delivery status entries.
#[derive(Debug, Serialize)]
pub struct EmailDeliveryStatusListResponse {
    /// Page of delivery status entries.
    pub items: Vec<EmailDeliveryStatusResponse>,
    /// Cursor for retrieving the next page, if any.
    pub next_cursor: Option<String>,
}