brass/src/models/password_reset.rs

56 lines
1.5 KiB
Rust

use anyhow::Result;
use chrono::{NaiveDateTime, TimeDelta, Utc};
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng as _};
use sqlx::{query_as, PgPool};
#[derive(Debug)]
pub struct PasswordReset {
pub id: i32,
pub token: String,
pub userid: i32,
pub expires: NaiveDateTime
}
impl PasswordReset {
pub async fn insert_new_for_user(pool: &PgPool, user_id: i32) -> Result<PasswordReset>{
let value = std::iter::repeat(())
.map(|()| OsRng.sample(Alphanumeric))
.take(64)
.collect::<Vec<_>>();
let token = String::from_utf8(value).unwrap().try_into().unwrap();
let expires = Utc::now().naive_utc() + TimeDelta::hours(24);
let inserted = query_as!(
PasswordReset,
"INSERT INTO passwordReset (token, userId, expires) VALUES ($1, $2, $3) RETURNING *;",
token,
user_id,
expires
)
.fetch_one(pool)
.await?;
Ok(inserted)
}
pub async fn does_token_exist(pool: &PgPool, token: &str) -> Result<PasswordReset> {
let result = query_as!(PasswordReset,
"SELECT * FROM passwordReset WHERE token = $1 AND expires > NOW();", token
)
.fetch_one(pool)
.await?;
Ok(result)
}
pub async fn delete(pool: &PgPool, token: &str) -> anyhow::Result<()> {
sqlx::query!("DELETE FROM passwordReset WHERE token = $1;", token)
.execute(pool)
.await?;
Ok(())
}
}