102 lines
2.6 KiB
Rust
102 lines
2.6 KiB
Rust
use anyhow::Result;
|
|
use chrono::NaiveDateTime;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::{FromRow, Pool, Postgres};
|
|
use uuid::Uuid;
|
|
|
|
use super::hash::hash;
|
|
|
|
#[derive(Deserialize, Serialize, FromRow)]
|
|
pub struct User {
|
|
/// User internal ID
|
|
pub id: Uuid,
|
|
|
|
/// User name (unique per instance, shows up in URLs)
|
|
pub name: String,
|
|
|
|
/// User email (for validation/login)
|
|
pub email: Option<String>,
|
|
|
|
/// Hashed password
|
|
pub password: Option<String>,
|
|
|
|
/// User's chosen displayed name
|
|
pub display_name: Option<String>,
|
|
|
|
/// Biography / User description
|
|
pub bio: Option<String>,
|
|
|
|
/// User roles (as role IDs)
|
|
pub roles: Vec<Uuid>,
|
|
|
|
/// Times
|
|
pub created_at: NaiveDateTime,
|
|
pub modified_at: Option<NaiveDateTime>,
|
|
pub deleted_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
impl Default for User {
|
|
fn default() -> Self {
|
|
Self {
|
|
id: Uuid::nil(),
|
|
name: Default::default(),
|
|
email: Default::default(),
|
|
password: Default::default(),
|
|
display_name: Default::default(),
|
|
bio: Default::default(),
|
|
roles: Default::default(),
|
|
created_at: Default::default(),
|
|
modified_at: Default::default(),
|
|
deleted_at: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl User {
|
|
pub async fn create(
|
|
pool: &Pool<Postgres>,
|
|
username: &str,
|
|
password: &str,
|
|
roles: &Vec<Uuid>,
|
|
) -> Result<Self> {
|
|
let result = sqlx::query!(
|
|
r#"INSERT INTO users ( name, password, roles ) VALUES ( $1,$2,$3 ) RETURNING id, created_at"#,
|
|
username,
|
|
hash(&password)?,
|
|
roles,
|
|
)
|
|
.fetch_one(pool)
|
|
.await?;
|
|
Ok(Self {
|
|
id: result.id,
|
|
name: username.to_owned(),
|
|
roles: roles.to_owned(),
|
|
created_at: result.created_at,
|
|
..Default::default()
|
|
})
|
|
}
|
|
|
|
pub async fn get_id(pool: &Pool<Postgres>, id: Uuid) -> Result<Option<Self>> {
|
|
Ok(sqlx::query_as("SELECT * FROM users WHERE id = $1")
|
|
.bind(id)
|
|
.fetch_optional(pool)
|
|
.await?)
|
|
}
|
|
|
|
pub async fn find(pool: &Pool<Postgres>, name: &str) -> Result<Option<Self>> {
|
|
Ok(sqlx::query_as("SELECT * FROM users WHERE name = $1")
|
|
.bind(name)
|
|
.fetch_optional(pool)
|
|
.await?)
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, FromRow)]
|
|
pub struct Role {
|
|
/// Role ID
|
|
pub id: Uuid,
|
|
|
|
/// Role scopes (permissions)
|
|
pub scopes: Vec<String>,
|
|
}
|