slave 0.13.1

CLI for slave, a Laravel-inspired Rust framework for MCP-first apps: scaffold an MCP backend with auth, roles, teams and SurrealDB migrations, add server-rendered web apps, and route them by domain or path
use axum::extract::FromRef;
use slave_framework::database::Db;

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

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

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

impl UserService {
    pub async fn list(&self) -> AppResult<Vec<User>> {
        let users: Vec<User> = self
            .db
            .query(format!("SELECT {} FROM user ORDER BY id", User::FIELDS))
            .await?
            .take(0)?;
        Ok(users)
    }

    pub async fn find(&self, id: i64) -> AppResult<User> {
        let user: Option<User> = self
            .db
            .query(format!(
                "SELECT {} FROM type::record('user', $id)",
                User::FIELDS
            ))
            .bind(("id", id))
            .await?
            .take(0)?;
        user.ok_or_else(|| AppError::NotFound(format!("user {id}")))
    }

    /// Deletes `id` on behalf of `acting_user_id`, who may not delete
    /// themselves. Their roles and memberships are deleted with them.
    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(),
            ));
        }
        self.find(id).await?;
        self.db
            .query("DELETE type::record('user', $id)")
            .bind(("id", id))
            .await?
            .check()?;
        Ok(())
    }
}