authx-plugins 0.1.2

Auth plugin collection for authx-rs: email/password, TOTP, magic link, OAuth, API keys, organizations, and more
Documentation
mod service;

pub use service::{AdminService, BanStatus};

#[cfg(test)]
mod tests {
    use super::service::{AdminService, BanStatus};
    use authx_core::{events::EventBus, models::CreateUser};
    use authx_storage::{memory::MemoryStore, ports::UserRepository};
    use uuid::Uuid;

    fn setup() -> (MemoryStore, EventBus) {
        (MemoryStore::new(), EventBus::new())
    }

    async fn make_user(store: &MemoryStore, email: &str) -> Uuid {
        UserRepository::create(
            store,
            CreateUser {
                email: email.into(),
                username: None,
                metadata: None,
            },
        )
        .await
        .unwrap()
        .id
    }

    #[tokio::test]
    async fn ban_and_check_status() {
        let (store, events) = setup();
        let admin_id = make_user(&store, "admin@x.com").await;
        let user_id = make_user(&store, "user@x.com").await;
        let svc = AdminService::new(store.clone(), events, 3600);
        svc.ban_user(admin_id, user_id, "test ban").await.unwrap();
        assert_eq!(svc.ban_status(user_id).await.unwrap(), BanStatus::Banned);
    }

    #[tokio::test]
    async fn unban_restores_active_status() {
        let (store, events) = setup();
        let admin_id = make_user(&store, "admin@x.com").await;
        let user_id = make_user(&store, "user@x.com").await;
        let svc = AdminService::new(store.clone(), events, 3600);
        svc.ban_user(admin_id, user_id, "temp ban").await.unwrap();
        svc.unban_user(admin_id, user_id).await.unwrap();
        assert_eq!(svc.ban_status(user_id).await.unwrap(), BanStatus::Active);
    }

    #[tokio::test]
    async fn ban_revokes_all_sessions() {
        use authx_core::models::CreateSession;
        use authx_storage::ports::SessionRepository;
        use chrono::Utc;

        let (store, events) = setup();
        let admin_id = make_user(&store, "admin@x.com").await;
        let user_id = make_user(&store, "user@x.com").await;

        SessionRepository::create(
            &store,
            CreateSession {
                user_id,
                token_hash: "abc123".into(),
                device_info: serde_json::Value::Null,
                ip_address: "127.0.0.1".into(),
                org_id: None,
                expires_at: Utc::now() + chrono::Duration::hours(1),
            },
        )
        .await
        .unwrap();

        let svc = AdminService::new(store.clone(), events, 3600);
        svc.ban_user(admin_id, user_id, "session test")
            .await
            .unwrap();
        let sessions = SessionRepository::find_by_user(&store, user_id)
            .await
            .unwrap();
        assert!(sessions.is_empty());
    }

    #[tokio::test]
    async fn impersonate_creates_tagged_session() {
        let (store, events) = setup();
        let admin_id = make_user(&store, "admin@x.com").await;
        let target_id = make_user(&store, "target@x.com").await;
        let svc = AdminService::new(store.clone(), events, 3600);
        let (session, token) = svc
            .impersonate(admin_id, target_id, "10.0.0.1")
            .await
            .unwrap();
        assert_eq!(session.user_id, target_id);
        assert!(session.ip_address.contains("impersonation"));
        assert_eq!(token.len(), 64);
    }

    #[tokio::test]
    async fn get_user_returns_user() {
        let (store, events) = setup();
        let user_id = make_user(&store, "getme@x.com").await;
        let svc = AdminService::new(store.clone(), events, 3600);
        let user = svc.get_user(user_id).await.unwrap();
        assert_eq!(user.email, "getme@x.com");
    }

    #[tokio::test]
    async fn get_user_fails_for_unknown() {
        let (store, events) = setup();
        let svc = AdminService::new(store, events, 3600);
        assert!(svc.get_user(Uuid::new_v4()).await.is_err());
    }

    #[tokio::test]
    async fn list_users_paginated() {
        let (store, events) = setup();
        for i in 0..5 {
            make_user(&store, &format!("u{}@x.com", i)).await;
        }
        let svc = AdminService::new(store.clone(), events, 3600);
        let page = svc.list_users(2, 2).await.unwrap();
        assert_eq!(page.len(), 2);
    }

    #[tokio::test]
    async fn create_user_admin() {
        let (store, events) = setup();
        let admin_id = make_user(&store, "admin@x.com").await;
        let svc = AdminService::new(store.clone(), events, 3600);
        let user = svc.create_user(admin_id, "new@x.com".into()).await.unwrap();
        assert_eq!(user.email, "new@x.com");
    }
}