use chrono::{NaiveDateTime, TimeDelta}; use sqlx::{query_as, PgPool}; use super::Result; use crate::utils::token_generation::generate_token_and_expiration; pub trait Token { async fn delete(&self, pool: &PgPool) -> Result<()>; } #[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 { let (token, expires) = generate_token_and_expiration(64, 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> { let result = query_as!( PasswordReset, "SELECT * FROM passwordReset WHERE token = $1 AND expires > NOW();", token ) .fetch_optional(pool) .await?; Ok(result) } pub async fn delete(pool: &PgPool, token: &str) -> Result<()> { sqlx::query!("DELETE FROM passwordReset WHERE token = $1;", token) .execute(pool) .await?; Ok(()) } } impl Token for PasswordReset { async fn delete(&self, pool: &PgPool) -> Result<()> { PasswordReset::delete(pool, &self.token).await } }