//
// 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::collections::HashMap;
use crate::database::manager::DB_MANAGER;
use crate::database::{
MemDbModel, delete_impl, filter_impl, find_impl, insert_impl, list_all_impl, update_impl, with_transaction
};
use crate::error::code::ErrorCode;
use crate::raise_error;
use crate::settings::cli::SETTINGS;
use crate::token::view::AccessTokenResp;
use crate::users::UserModel;
use crate::{
error::BichonResult, generate_token, token::payload::AccessTokenCreateRequest, utc_now,
};
//use poem_openapi::{Enum, Object};
use serde::{Deserialize, Serialize};
pub mod payload;
pub mod view;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
pub enum TokenType {
WebUI,
Api,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
pub struct AccessTokenModel {
/// The ID of the user who owns this token
pub user_id: u64,
/// The unique token string used for authentication
pub token: String,
/// An optional name of the token.
pub name: Option,
/// Token type: WebUI or API
pub token_type: TokenType,
/// The timestamp (in milliseconds since epoch) when the token was created.
pub created_at: i64,
/// The timestamp (in milliseconds since epoch) when the token was last updated.
pub updated_at: i64,
/// The timestamp (in milliseconds since epoch) when the token expires.
/// None means the token does not expire (this applies only to API tokens).
pub expire_at: Option,
/// The timestamp (in milliseconds since epoch) when the token was last used.
pub last_access_at: i64,
}
impl MemDbModel for AccessTokenModel {
fn collection() -> &'static str {
"tokens"
}
fn key(&self) -> String {
self.token.clone()
}
}
impl AccessTokenModel {
pub fn new_api_token(
token: String,
user_id: u64,
name: Option,
expire_at: Option,
) -> Self {
Self {
token,
created_at: utc_now!(),
updated_at: utc_now!(),
last_access_at: Default::default(),
name,
user_id,
token_type: TokenType::Api,
expire_at,
}
}
pub fn new_webui_token(user_id: u64) -> AccessTokenModel {
let now = utc_now!();
AccessTokenModel {
token: generate_token!(128),
created_at: now,
updated_at: now,
last_access_at: Default::default(),
name: None,
user_id,
token_type: TokenType::WebUI,
expire_at: None,
}
}
pub fn reset_webui_token(user_id: u64) -> BichonResult {
let old_token = Self::get_user_webui_token(user_id)?;
let new_token = Self::new_webui_token(user_id);
let new_token_str = new_token.token.clone();
match old_token {
Some(old) => {
with_transaction(DB_MANAGER.db(), move |txn| {
let txn = txn.delete(AccessTokenModel::collection(), old.token.clone());
txn.insert(AccessTokenModel::collection(), new_token.key(), &new_token)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))
})?;
}
None => {
insert_impl(DB_MANAGER.db(), new_token)?;
}
}
Ok(new_token_str)
}
pub fn get_user_webui_token(user_id: u64) -> BichonResult