db/models/
password_reset_token.rs1use sea_orm::entity::prelude::*;
2use sea_orm::ActiveValue::{Set, NotSet};
3use sea_orm::IntoActiveModel;
4use serde::{Deserialize, Serialize};
5use chrono::{DateTime, Utc, Duration};
6use rand::{thread_rng, Rng};
7use rand::distributions::Alphanumeric;
8
9#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
10#[sea_orm(table_name = "password_reset_tokens")]
11pub struct Model {
12 #[sea_orm(primary_key)]
13 pub id: i64,
14 pub user_id: i64,
15 pub token: String,
16 pub expires_at: DateTime<Utc>,
17 pub used: bool,
18 pub created_at: DateTime<Utc>,
19}
20
21#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
22pub enum Relation {
23 #[sea_orm(
24 belongs_to = "super::user::Entity",
25 from = "Column::UserId",
26 to = "super::user::Column::Id",
27 on_update = "NoAction",
28 on_delete = "Cascade"
29 )]
30 User,
31}
32
33impl Related<super::user::Entity> for Entity {
34 fn to() -> RelationDef {
35 Relation::User.def()
36 }
37}
38
39impl ActiveModelBehavior for ActiveModel {}
40
41impl Model {
42 pub fn new(user_id: i64, expiry_minutes: i64) -> Self {
43 let token = thread_rng()
44 .sample_iter(&Alphanumeric)
45 .take(32)
46 .map(char::from)
47 .collect::<String>();
48
49 Self {
50 id: 0,
51 user_id,
52 token,
53 expires_at: Utc::now() + Duration::minutes(expiry_minutes),
54 used: false,
55 created_at: Utc::now(),
56 }
57 }
58
59 pub async fn create(
60 db: &DatabaseConnection,
61 user_id: i64,
62 expiry_minutes: i64,
63 ) -> Result<Self, DbErr> {
64 let model = Self::new(user_id, expiry_minutes);
65 let mut active_model = model.into_active_model();
66 active_model.id = NotSet;
67 active_model.insert(db).await
68 }
69
70 pub async fn find_valid_token(
71 db: &DatabaseConnection,
72 token: &str,
73 ) -> Result<Option<Self>, DbErr> {
74 Entity::find()
75 .filter(Column::Token.eq(token))
76 .filter(Column::Used.eq(false))
77 .filter(Column::ExpiresAt.gt(Utc::now()))
78 .one(db)
79 .await
80 }
81
82 pub async fn mark_as_used(&self, db: &DatabaseConnection) -> Result<(), DbErr> {
83 let mut active_model: ActiveModel = self.clone().into();
84 active_model.used = Set(true);
85 active_model.update(db).await?;
86 Ok(())
87 }
88}