use std::sync::Arc; use async_trait::async_trait; use sea_orm::{ActiveValue, prelude::*}; use serde::{Deserialize, Serialize}; use crate::{ app::AppContextTrait, crypto::UserPassCredential, errors::{RecorderError, RecorderResult}, }; #[derive( Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, DeriveDisplay, Serialize, Deserialize, )] #[sea_orm( rs_type = "String", db_type = "Enum", enum_name = "credential_3rd_type" )] pub enum Credential3rdType { #[sea_orm(string_value = "mikan")] Mikan, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)] #[sea_orm(table_name = "credential3rd")] pub struct Model { #[sea_orm(default_expr = "Expr::current_timestamp()")] pub created_at: DateTimeUtc, #[sea_orm(default_expr = "Expr::current_timestamp()")] pub updated_at: DateTimeUtc, #[sea_orm(primary_key)] pub id: i32, pub subscriber_id: i32, pub credential_type: Credential3rdType, pub cookies: Option, pub username: Option, pub password: Option, pub user_agent: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::subscribers::Entity", from = "Column::SubscriberId", to = "super::subscribers::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] Subscriber, #[sea_orm(has_many = "super::subscriptions::Entity")] Subscription, } impl Related for Entity { fn to() -> RelationDef { Relation::Subscriber.def() } } impl Related for Entity { fn to() -> RelationDef { Relation::Subscription.def() } } #[async_trait] impl ActiveModelBehavior for ActiveModel {} impl ActiveModel { pub async fn try_encrypt(mut self, ctx: Arc) -> RecorderResult { let crypto = ctx.crypto(); if let ActiveValue::Set(Some(username)) = self.username { let username_enc = crypto.encrypt_credentials(&username)?; self.username = ActiveValue::Set(Some(username_enc)); } if let ActiveValue::Set(Some(password)) = self.password { let password_enc = crypto.encrypt_credentials(&password)?; self.password = ActiveValue::Set(Some(password_enc)); } if let ActiveValue::Set(Some(cookies)) = self.cookies { let cookies_enc = crypto.encrypt_credentials(&cookies)?; self.cookies = ActiveValue::Set(Some(cookies_enc)); } Ok(self) } } impl Model { pub async fn find_by_id( ctx: Arc, id: i32, ) -> RecorderResult> { let db = ctx.db(); let credential = Entity::find_by_id(id).one(db).await?; Ok(credential) } pub fn try_into_userpass_credential( self, ctx: Arc, ) -> RecorderResult { let crypto = ctx.crypto(); let username_enc = self .username .ok_or_else(|| RecorderError::Credential3rdError { message: "UserPassCredential username is required".to_string(), source: None.into(), })?; let username: String = crypto.decrypt_credentials(&username_enc)?; let password_enc = self .password .ok_or_else(|| RecorderError::Credential3rdError { message: "UserPassCredential password is required".to_string(), source: None.into(), })?; let password: String = crypto.decrypt_credentials(&password_enc)?; let cookies: Option = if let Some(cookies_enc) = self.cookies { let cookies = crypto.decrypt_credentials(&cookies_enc)?; Some(cookies) } else { None }; Ok(UserPassCredential { username, password, cookies, user_agent: self.user_agent, }) } }