//! Tests for platform admin routes. use crate::harness::TestHarness; use uuid::Uuid; #[sqlx::test] async fn non_admin_gets_404(_pool: sqlx::PgPool) { let mut h = TestHarness::new().await; let _user = h.login_as("regular").await; let resp = h.client.get("/_admin").await; assert_eq!(resp.status, axum::http::StatusCode::NOT_FOUND); } #[sqlx::test] async fn admin_can_see_dashboard(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; let _admin = h.login_as("admin").await; // Re-login with the correct admin_id since login_as generates a random UUID sqlx::query("UPDATE users SET mnw_account_id = $1 WHERE username = 'admin'") .bind(admin_id) .execute(&h.db) .await .unwrap(); // Re-establish session with correct user_id h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin", }); h.client.post_json("/_test/login", &body.to_string()).await; let resp = h.client.get("/_admin").await; assert_eq!(resp.status, axum::http::StatusCode::OK); assert!(resp.text.contains("Platform Admin")); } #[sqlx::test] async fn admin_can_suspend_community(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; // Set up admin session sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client.post_json("/_test/login", &body.to_string()).await; let community_id = h.create_community("Test Community", "test").await; let resp = h.client.post_form( &format!("/_admin/communities/{community_id}/suspend"), "reason=policy+violation", ).await; assert!(resp.status.is_redirection() || resp.status == axum::http::StatusCode::OK); // Verify community is now suspended (returns 403) // Verify the suspension stuck in the DB let suspended: bool = sqlx::query_scalar( "SELECT suspended_at IS NOT NULL FROM communities WHERE id = $1", ) .bind(community_id) .fetch_one(&h.db) .await .unwrap(); assert!(suspended); } #[sqlx::test] async fn admin_can_unsuspend_community(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client.post_json("/_test/login", &body.to_string()).await; let community_id = h.create_community("Test", "test").await; // Suspend it sqlx::query("UPDATE communities SET suspended_at = now(), suspension_reason = 'test' WHERE id = $1") .bind(community_id) .execute(&h.db) .await .unwrap(); let resp = h.client.post_form( &format!("/_admin/communities/{community_id}/unsuspend"), "", ).await; assert!(resp.status.is_redirection() || resp.status == axum::http::StatusCode::OK); let suspended: bool = sqlx::query_scalar( "SELECT suspended_at IS NOT NULL FROM communities WHERE id = $1", ) .bind(community_id) .fetch_one(&h.db) .await .unwrap(); assert!(!suspended); } #[sqlx::test] async fn admin_can_suspend_user(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client.post_json("/_test/login", &body.to_string()).await; // Create a user to suspend let target_id = Uuid::new_v4(); sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'baduser', 'Bad User')", ) .bind(target_id) .execute(&h.db) .await .unwrap(); let resp = h.client.post_form( &format!("/_admin/users/{target_id}/suspend"), "reason=abuse", ).await; assert!(resp.status.is_redirection() || resp.status == axum::http::StatusCode::OK); let suspended: bool = sqlx::query_scalar( "SELECT suspended_at IS NOT NULL FROM users WHERE mnw_account_id = $1", ) .bind(target_id) .fetch_one(&h.db) .await .unwrap(); assert!(suspended); } #[sqlx::test] async fn admin_can_unsuspend_user(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client.post_json("/_test/login", &body.to_string()).await; let target_id = Uuid::new_v4(); sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name, suspended_at, suspension_reason) VALUES ($1, 'baduser', 'Bad User', now(), 'abuse')", ) .bind(target_id) .execute(&h.db) .await .unwrap(); let resp = h.client.post_form( &format!("/_admin/users/{target_id}/unsuspend"), "", ).await; assert!(resp.status.is_redirection() || resp.status == axum::http::StatusCode::OK); let suspended: bool = sqlx::query_scalar( "SELECT suspended_at IS NOT NULL FROM users WHERE mnw_account_id = $1", ) .bind(target_id) .fetch_one(&h.db) .await .unwrap(); assert!(!suspended); } #[sqlx::test] async fn admin_search_finds_users(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client .post_json("/_test/login", &body.to_string()) .await; // Create a searchable user let target_id = Uuid::new_v4(); sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'findableuser', 'Findable User')", ) .bind(target_id) .execute(&h.db) .await .unwrap(); let resp = h.client.get("/_admin?q=findableuser").await; assert_eq!(resp.status, axum::http::StatusCode::OK); assert!( resp.text.contains("findableuser"), "Search results should include matching user" ); } #[sqlx::test] async fn admin_invalid_uuid_returns_400(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client .post_json("/_test/login", &body.to_string()) .await; let resp = h .client .post_form("/_admin/communities/not-a-uuid/suspend", "reason=test") .await; // parse_uuid returns 404 (hides admin routes from probing) assert_eq!(resp.status, axum::http::StatusCode::NOT_FOUND); } #[sqlx::test] async fn admin_suspend_creates_mod_log_entry(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; sqlx::query( "INSERT INTO users (mnw_account_id, username, display_name) VALUES ($1, 'admin', 'Admin') ON CONFLICT DO NOTHING", ) .bind(admin_id) .execute(&h.db) .await .unwrap(); h.client.get("/").await; let body = serde_json::json!({ "user_id": admin_id.to_string(), "username": "admin" }); h.client .post_json("/_test/login", &body.to_string()) .await; let community_id = h.create_community("Test", "test").await; h.client .post_form( &format!("/_admin/communities/{community_id}/suspend"), "reason=policy+violation", ) .await; // Verify mod_log entry exists let count: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM mod_log WHERE action = 'suspend_community' AND actor_id = $1", ) .bind(admin_id) .fetch_one(&h.db) .await .unwrap(); assert_eq!(count, 1, "Should have a mod_log entry for suspend_community"); } #[sqlx::test] async fn non_admin_post_to_suspend_returns_404(_pool: sqlx::PgPool) { let admin_id = Uuid::new_v4(); let mut h = TestHarness::new_with_admin(admin_id).await; let _user = h.login_as("regular").await; let community_id = h.create_community("Test", "test").await; let resp = h .client .post_form( &format!("/_admin/communities/{community_id}/suspend"), "reason=test", ) .await; assert_eq!(resp.status, axum::http::StatusCode::NOT_FOUND); }