mirror of
https://github.com/Xevion/banner.git
synced 2026-01-31 14:23:36 -06:00
87 lines
2.5 KiB
Rust
87 lines
2.5 KiB
Rust
//! Database query functions for users.
|
|
|
|
use anyhow::Context;
|
|
use sqlx::PgPool;
|
|
|
|
use super::models::User;
|
|
use crate::error::Result;
|
|
|
|
/// Insert a new user or update username/avatar on conflict.
|
|
pub async fn upsert_user(
|
|
pool: &PgPool,
|
|
discord_id: i64,
|
|
username: &str,
|
|
avatar_hash: Option<&str>,
|
|
) -> Result<User> {
|
|
sqlx::query_as::<_, User>(
|
|
r#"
|
|
INSERT INTO users (discord_id, discord_username, discord_avatar_hash)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (discord_id) DO UPDATE
|
|
SET discord_username = EXCLUDED.discord_username,
|
|
discord_avatar_hash = EXCLUDED.discord_avatar_hash,
|
|
updated_at = now()
|
|
RETURNING *
|
|
"#,
|
|
)
|
|
.bind(discord_id)
|
|
.bind(username)
|
|
.bind(avatar_hash)
|
|
.fetch_one(pool)
|
|
.await
|
|
.context("failed to upsert user")
|
|
}
|
|
|
|
/// Fetch a user by Discord ID.
|
|
pub async fn get_user(pool: &PgPool, discord_id: i64) -> Result<Option<User>> {
|
|
sqlx::query_as::<_, User>("SELECT * FROM users WHERE discord_id = $1")
|
|
.bind(discord_id)
|
|
.fetch_optional(pool)
|
|
.await
|
|
.context("failed to get user")
|
|
}
|
|
|
|
/// List all users ordered by creation date (newest first).
|
|
pub async fn list_users(pool: &PgPool) -> Result<Vec<User>> {
|
|
sqlx::query_as::<_, User>("SELECT * FROM users ORDER BY created_at DESC")
|
|
.fetch_all(pool)
|
|
.await
|
|
.context("failed to list users")
|
|
}
|
|
|
|
/// Set the admin flag for a user, returning the updated user if found.
|
|
pub async fn set_admin(pool: &PgPool, discord_id: i64, is_admin: bool) -> Result<Option<User>> {
|
|
sqlx::query_as::<_, User>(
|
|
r#"
|
|
UPDATE users
|
|
SET is_admin = $2, updated_at = now()
|
|
WHERE discord_id = $1
|
|
RETURNING *
|
|
"#,
|
|
)
|
|
.bind(discord_id)
|
|
.bind(is_admin)
|
|
.fetch_optional(pool)
|
|
.await
|
|
.context("failed to set admin status")
|
|
}
|
|
|
|
/// Ensure a seed admin exists. Upserts with `is_admin = true` and a placeholder
|
|
/// username that will be replaced on first OAuth login.
|
|
pub async fn ensure_seed_admin(pool: &PgPool, discord_id: i64) -> Result<User> {
|
|
sqlx::query_as::<_, User>(
|
|
r#"
|
|
INSERT INTO users (discord_id, discord_username, is_admin)
|
|
VALUES ($1, 'seed-admin', true)
|
|
ON CONFLICT (discord_id) DO UPDATE
|
|
SET is_admin = true,
|
|
updated_at = now()
|
|
RETURNING *
|
|
"#,
|
|
)
|
|
.bind(discord_id)
|
|
.fetch_one(pool)
|
|
.await
|
|
.context("failed to ensure seed admin")
|
|
}
|