// // Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com) // // This file is part of the Bichon Email Archiving Project // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use std::{path::Path, rc::Rc}; use native_db::{Builder, Database}; use crate::{ account::migration::AccountV3, database::META_MODELS, error::{code::ErrorCode, BichonResult}, raise_error, token::{AccessTokenModel, AccessTokenModelKey, TokenType}, users::{UserModel, DEFAULT_ADMIN_USER_ID}, utils::encrypt::internal_encrypt_string, }; use itertools::Itertools; pub fn init_meta_database(path: impl AsRef) -> BichonResult>> { let database = Builder::new() .set_cache_size(134217728) .create(&META_MODELS, path) .map_err(|e| { raise_error!( format!("Failed to open database: {:?}", e), ErrorCode::InternalError ) })?; Ok(Rc::new(database)) } pub fn list_all_accounts(database: &Rc>) -> BichonResult> { let r_transaction = database .r_transaction() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; let entities: Vec = r_transaction .scan() .primary() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? .all() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? .try_collect() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; Ok(entities) } pub fn find_admin(database: &Rc>) -> BichonResult> { let r_transaction = database .r_transaction() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; let entity: Option = r_transaction .get() .primary(DEFAULT_ADMIN_USER_ID) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; return Ok(entity); } pub fn update_admin_password( database: &Rc>, password: String, encrypt_key: &str, ) -> BichonResult<()> { let rw_transaction = database .rw_transaction() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; let entity: UserModel = rw_transaction .get() .primary(DEFAULT_ADMIN_USER_ID) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? .ok_or_else(|| raise_error!("admin is not found".into(), ErrorCode::InternalError))?; let mut updated = entity.clone(); updated.password = Some( internal_encrypt_string(encrypt_key, &password) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?, ); rw_transaction .update(entity, updated) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; rw_transaction .commit() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; return Ok(()); } pub fn reset_webui_token(database: &Rc>) -> BichonResult<()> { let rw_transaction = database .rw_transaction() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; let tokens: Vec = rw_transaction .scan() .secondary(AccessTokenModelKey::user_id) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? .start_with(DEFAULT_ADMIN_USER_ID) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? .try_collect() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; let webui_token = tokens .into_iter() .find(|t| t.token_type == TokenType::WebUI); let new_token = AccessTokenModel::new_webui_token(DEFAULT_ADMIN_USER_ID); match webui_token { Some(current) => { rw_transaction .remove(current) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; rw_transaction .insert(new_token) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; } None => { rw_transaction .insert(new_token) .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; } } rw_transaction .commit() .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; Ok(()) }