slave 0.4.0

Laravel-inspired CLI for Rust MCP servers: scaffold apps whose business operations are MCP tools over Streamable HTTP, with built-in auth, users, roles and Turso migrations
use axum::extract::FromRef;
use slave_framework::database::Database;

use crate::base::error::{AppError, AppResult};
use crate::base::state::AppState;
use crate::modules::user::models::user::User;
use crate::modules::user::repositories::user_repository;

/// Business rules for managing user accounts.
#[derive(Debug, Clone)]
pub struct UserService {
    database: Database,
}

impl FromRef<AppState> for UserService {
    fn from_ref(state: &AppState) -> Self {
        Self {
            database: state.database.clone(),
        }
    }
}

impl UserService {
    pub async fn list(&self) -> AppResult<Vec<User>> {
        let conn = self.database.connect().await?;
        Ok(user_repository::all(&conn).await?)
    }

    pub async fn find(&self, id: i64) -> AppResult<User> {
        let conn = self.database.connect().await?;
        user_repository::find(&conn, id)
            .await?
            .ok_or_else(|| AppError::NotFound(format!("user {id}")))
    }

    /// Deletes `id` on behalf of `acting_user_id`, who may not delete themselves.
    pub async fn delete(&self, id: i64, acting_user_id: i64) -> AppResult<()> {
        if id == acting_user_id {
            return Err(AppError::Conflict(
                "you cannot delete your own account".into(),
            ));
        }
        let conn = self.database.connect().await?;
        if user_repository::delete(&conn, id).await? {
            Ok(())
        } else {
            Err(AppError::NotFound(format!("user {id}")))
        }
    }
}