backbone-bucket 0.3.0

Bucket Bounded Context: File Storage Module for Backbone Framework
Documentation
//! Commands for AccessLog aggregate
//!
//! Generated by backbone-schema. Do not edit manually.
//!
//! CQRS Commands represent intent to change state.

use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::domain::entity::AccessLog;
use crate::infrastructure::persistence::AccessLogRepository;
use super::CommandHandler;

// ============================================================================
// COMMAND TRAIT (DEPRECATED)
// ============================================================================

/// Command trait for AccessLog operations
///
/// **DEPRECATED**: Use the generic `CommandHandler<C>` trait from `mod.rs` instead.
/// This trait is kept for backwards compatibility.
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait AccessLogCommand: Send + Sync {
    type Output;
    async fn execute(&self) -> Result<Self::Output>;
}

// ============================================================================
// CREATE COMMAND
// ============================================================================

/// Command to create a new access_log
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateAccessLogCommand {
    pub file_id: Uuid,
    pub bucket_id: Option<Uuid>,
    pub action: AccessAction,
    pub user_id: Option<Uuid>,
    pub share_id: Option<Uuid>,
    pub is_owner: bool,
    pub is_shared: bool,
    pub is_public: bool,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub referer: Option<String>,
    pub country_code: Option<String>,
    pub city: Option<String>,
    pub bytes_transferred: Option<i64>,
    pub duration_ms: Option<i32>,
    pub success: bool,
    pub error_message: Option<String>,
    pub accessed_at: DateTime<Utc>,
    pub metadata: serde_json::Value,
}

/// Handler for CreateAccessLogCommand
pub struct CreateAccessLogHandler<R: AccessLogRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: AccessLogRepository> CreateAccessLogHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: AccessLogRepository + 'static> CommandHandler<CreateAccessLogCommand> for CreateAccessLogHandler<R> {
    type Output = AccessLog;

    async fn handle(&self, cmd: CreateAccessLogCommand) -> Result<Self::Output> {
        let entity = AccessLog::builder()
            .id(Uuid::new_v4().to_string())
            .file_id(cmd.file_id)
            .bucket_id(cmd.bucket_id)
            .action(cmd.action)
            .user_id(cmd.user_id)
            .share_id(cmd.share_id)
            .is_owner(cmd.is_owner)
            .is_shared(cmd.is_shared)
            .is_public(cmd.is_public)
            .ip_address(cmd.ip_address)
            .user_agent(cmd.user_agent)
            .referer(cmd.referer)
            .country_code(cmd.country_code)
            .city(cmd.city)
            .bytes_transferred(cmd.bytes_transferred)
            .duration_ms(cmd.duration_ms)
            .success(cmd.success)
            .error_message(cmd.error_message)
            .accessed_at(cmd.accessed_at)
            .metadata(cmd.metadata)
            .build()?;

        self.repository.save(&entity).await
    }
}

// ============================================================================
// UPDATE COMMAND
// ============================================================================

/// Command to update an existing access_log
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateAccessLogCommand {
    pub id: String,
    pub file_id: Option<Uuid>,
    pub bucket_id: Option<Uuid>,
    pub action: Option<AccessAction>,
    pub user_id: Option<Uuid>,
    pub share_id: Option<Uuid>,
    pub is_owner: Option<bool>,
    pub is_shared: Option<bool>,
    pub is_public: Option<bool>,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub referer: Option<String>,
    pub country_code: Option<String>,
    pub city: Option<String>,
    pub bytes_transferred: Option<i64>,
    pub duration_ms: Option<i32>,
    pub success: Option<bool>,
    pub error_message: Option<String>,
    pub accessed_at: Option<DateTime<Utc>>,
    pub metadata: Option<serde_json::Value>,
}

/// Handler for UpdateAccessLogCommand
pub struct UpdateAccessLogHandler<R: AccessLogRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: AccessLogRepository> UpdateAccessLogHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: AccessLogRepository + 'static> CommandHandler<UpdateAccessLogCommand> for UpdateAccessLogHandler<R> {
    type Output = Option<AccessLog>;

    async fn handle(&self, cmd: UpdateAccessLogCommand) -> Result<Self::Output> {
        let existing = self.repository.find_by_id(&cmd.id).await?;

        let Some(mut entity) = existing else {
            return Ok(None);
        };

        // Apply updates
        if let Some(value) = cmd.file_id {
            entity.file_id = value;
        }
        entity.bucket_id = cmd.bucket_id;
        if let Some(value) = cmd.action {
            entity.action = value;
        }
        entity.user_id = cmd.user_id;
        entity.share_id = cmd.share_id;
        if let Some(value) = cmd.is_owner {
            entity.is_owner = value;
        }
        if let Some(value) = cmd.is_shared {
            entity.is_shared = value;
        }
        if let Some(value) = cmd.is_public {
            entity.is_public = value;
        }
        entity.ip_address = cmd.ip_address;
        entity.user_agent = cmd.user_agent;
        entity.referer = cmd.referer;
        entity.country_code = cmd.country_code;
        entity.city = cmd.city;
        entity.bytes_transferred = cmd.bytes_transferred;
        entity.duration_ms = cmd.duration_ms;
        if let Some(value) = cmd.success {
            entity.success = value;
        }
        entity.error_message = cmd.error_message;
        if let Some(value) = cmd.accessed_at {
            entity.accessed_at = value;
        }
        if let Some(value) = cmd.metadata {
            entity.metadata = value;
        }

        self.repository.update(&cmd.id, &entity).await
    }
}

// ============================================================================
// DELETE COMMAND
// ============================================================================

/// Command to delete a access_log
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteAccessLogCommand {
    pub id: String,
    pub hard_delete: bool,
}

/// Handler for DeleteAccessLogCommand
pub struct DeleteAccessLogHandler<R: AccessLogRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: AccessLogRepository> DeleteAccessLogHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: AccessLogRepository + 'static> CommandHandler<DeleteAccessLogCommand> for DeleteAccessLogHandler<R> {
    type Output = bool;

    async fn handle(&self, cmd: DeleteAccessLogCommand) -> Result<Self::Output> {
        if cmd.hard_delete {
            self.repository.delete(&cmd.id).await
        } else {
            self.repository.soft_delete(&cmd.id).await
        }
    }
}

// ============================================================================
// CUSTOM COMMANDS
// ============================================================================
// <<< CUSTOM COMMANDS START >>>

// <<< CUSTOM COMMANDS START >>>
// Add your custom commands here
// Example:
//
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub struct ActivateAccessLogCommand {
//     pub id: String,
// }
// <<< CUSTOM COMMANDS END >>>