mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
refactor(workspace): decompose project into multiple crates
This commit is contained in:
Generated
+502
-457
File diff suppressed because it is too large
Load Diff
+15
-49
@@ -1,48 +1,20 @@
|
||||
[package]
|
||||
name = "bichon"
|
||||
[workspace]
|
||||
|
||||
members = ["crates/core", "crates/server", "crates/cli", "crates/admin"]
|
||||
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "bichon"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bichonctl"
|
||||
path = "src/bin/bichonctl.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bichon-admin"
|
||||
path = "src/bin/bichon_admin.rs"
|
||||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
vendored-openssl = ["openssl-sys"]
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
|
||||
[dependencies]
|
||||
[workspace.dependencies]
|
||||
chrono = "0.4.44"
|
||||
clap = { version = "4.6.1", features = ["derive", "env"] }
|
||||
mimalloc = "0.1.49"
|
||||
native_db = "0.8.2"
|
||||
itertools = "0.14.0"
|
||||
native_model = "0.4.20"
|
||||
poem = { version = "3.1.12", features = ["embed", "compression", "rustls"] }
|
||||
poem-derive = "3.1.12"
|
||||
poem-openapi = { version = "5.1.16", features = [
|
||||
"openapi-explorer",
|
||||
"rapidoc",
|
||||
"scalar",
|
||||
"redoc",
|
||||
"swagger-ui",
|
||||
"email",
|
||||
] }
|
||||
ring = { version = "0.17.14", features = ["std"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.149"
|
||||
@@ -74,7 +46,6 @@ tokio-rustls = { version = "0.26.4", default-features = false, features = [
|
||||
"tls12",
|
||||
] }
|
||||
timeago = "0.6.0"
|
||||
ahash = "0.8.12"
|
||||
oauth2 = { version = "5.0.0", features = ["reqwest-blocking"] }
|
||||
url = { version = "2.5.8", features = ["serde"] }
|
||||
sysinfo = "0.38.4"
|
||||
@@ -104,19 +75,12 @@ murmur3 = "0.5.2"
|
||||
autoconfig = "0.4.0"
|
||||
urlencoding = "2.1.3"
|
||||
dashmap = "6.1.0"
|
||||
# Statically links OpenSSL by compiling from source, avoiding system library dependencies
|
||||
openssl-sys = { version = "0.9.114", optional = true, features = ["vendored"] }
|
||||
gethostname = "1.1.0"
|
||||
itoa = "1.0.18"
|
||||
html2text = "0.17.1"
|
||||
bytes = "1.11.1"
|
||||
dialoguer = "0.12.0"
|
||||
console = "0.16.3"
|
||||
toml = "0.9.8"
|
||||
memmap2 = "0.9.10"
|
||||
outlook-pst = { git = "https://github.com/rustmailer/outlook-pst-rs.git", branch = "main" }
|
||||
compressed-rtf = "1.0.1"
|
||||
codepage-strings = "1.0.2"
|
||||
mail-send = "0.6.0"
|
||||
rcgen = "0.14.7"
|
||||
rustls-pemfile = "2.2.0"
|
||||
@@ -126,8 +90,10 @@ fjall = { version = "3.1.4", features = ["lz4", "metrics", "bytes_1"] }
|
||||
tantivy = { version = "0.26.0", features = ["zstd-compression"] }
|
||||
tracing-log = "0.2.0"
|
||||
tokio-util = "0.7.18"
|
||||
[dev-dependencies]
|
||||
#bincode = "1.3.3"
|
||||
#secret-lib = "1.0.0"
|
||||
tempfile = "3.27.0"
|
||||
lettre = "0.11.21"
|
||||
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "bichon-admin"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
[dependencies]
|
||||
bichon-core = { path = "../core" }
|
||||
tokio.workspace = true
|
||||
dialoguer.workspace = true
|
||||
console.workspace = true
|
||||
@@ -16,22 +16,19 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use bichon::modules::{
|
||||
cli::admin::meta::{find_admin, init_meta_database, update_admin_password},
|
||||
use bichon_core::{
|
||||
admin::meta::{find_admin, init_meta_database, update_admin_password},
|
||||
error::BichonError,
|
||||
utils::encrypt::internal_decrypt_string,
|
||||
};
|
||||
use console::{style, Emoji};
|
||||
use dialoguer::Confirm;
|
||||
use dialoguer::{theme::ColorfulTheme, Input, Password, Select};
|
||||
use native_db::Database;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -75,7 +72,7 @@ async fn main() {
|
||||
|
||||
let root_path = PathBuf::from(&root_dir_str);
|
||||
|
||||
let database: Rc<Database<'static>> = match init_meta_database(&root_path.join("meta.db")) {
|
||||
let database = match init_meta_database(&root_path.join("meta.db")) {
|
||||
Ok(database) => database,
|
||||
Err(e) => match e {
|
||||
BichonError::Generic {
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "bichon-cli"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
[dependencies]
|
||||
bichon-core = { path = "../core" }
|
||||
tokio.workspace = true
|
||||
serde.workspace = true
|
||||
clap.workspace = true
|
||||
dialoguer.workspace = true
|
||||
console.workspace = true
|
||||
mail-parser.workspace = true
|
||||
reqwest.workspace = true
|
||||
toml = "0.9.8"
|
||||
memmap2 = "0.9.10"
|
||||
outlook-pst = { git = "https://github.com/rustmailer/outlook-pst-rs.git", branch = "main" }
|
||||
compressed-rtf = "1.0.1"
|
||||
chrono.workspace = true
|
||||
mail-send.workspace = true
|
||||
base64.workspace = true
|
||||
codepage-strings = "1.0.2"
|
||||
hex = "0.4.3"
|
||||
@@ -16,19 +16,19 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::process;
|
||||
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use reqwest::Client;
|
||||
|
||||
use crate::modules::{
|
||||
use bichon_core::{
|
||||
account::payload::MinimalAccount,
|
||||
cli::BichonCtlConfig,
|
||||
users::{permissions::Permission, view::UserView},
|
||||
};
|
||||
|
||||
use crate::BichonCtlConfig;
|
||||
|
||||
pub async fn verify_user_and_get_account(config: &BichonCtlConfig, theme: &ColorfulTheme) -> u64 {
|
||||
let client = Client::new();
|
||||
let url = format!("{}/api/v1/current-user", config.base_url);
|
||||
@@ -16,7 +16,6 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
@@ -28,10 +27,9 @@ use dialoguer::{theme::ColorfulTheme, Input};
|
||||
use mail_parser::MessageParser;
|
||||
use reqwest::Client;
|
||||
|
||||
use crate::{
|
||||
base64_encode_url_safe,
|
||||
modules::cli::{sender::send_batch_request, BichonCtlConfig},
|
||||
};
|
||||
use bichon_core::base64_encode_url_safe;
|
||||
|
||||
use crate::{sender::send_batch_request, BichonCtlConfig};
|
||||
|
||||
pub async fn handle_eml_directory_import(
|
||||
config: &BichonCtlConfig,
|
||||
@@ -16,17 +16,51 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use bichon::modules::cli::{
|
||||
auth::verify_user_and_get_account, eml::handle_eml_directory_import,
|
||||
mbox::handle_mbox_single_file_import, pst::handle_pst_import,
|
||||
thunderbird::handle_thunderbird_import, BichonCli, BichonCtlConfig,
|
||||
};
|
||||
use bichon_core::bichon_version;
|
||||
use clap::Parser;
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
|
||||
use crate::{
|
||||
auth::verify_user_and_get_account, eml::handle_eml_directory_import,
|
||||
mbox::handle_mbox_single_file_import, pst::handle_pst_import,
|
||||
thunderbird::handle_thunderbird_import,
|
||||
};
|
||||
|
||||
pub mod auth;
|
||||
pub mod eml;
|
||||
pub mod mbox;
|
||||
pub mod pst;
|
||||
pub mod sender;
|
||||
pub mod thunderbird;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
name = "bichonctl",
|
||||
author = "rustmailer",
|
||||
version = bichon_version!(),
|
||||
about = "A CLI tool to import email data into Bichon service"
|
||||
)]
|
||||
pub struct BichonCli {
|
||||
/// Path to the configuration file
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
default_value = "config.toml",
|
||||
value_name = "FILE",
|
||||
help = "Sets a custom config file"
|
||||
)]
|
||||
pub config: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BichonCtlConfig {
|
||||
pub base_url: String,
|
||||
pub api_token: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli = BichonCli::parse();
|
||||
@@ -19,11 +19,11 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::base64_encode_url_safe;
|
||||
use crate::modules::cli::mbox::gmail::determine_folder;
|
||||
use crate::modules::cli::mbox::reader::MboxFile;
|
||||
use crate::modules::cli::sender::send_batch_request;
|
||||
use crate::modules::cli::BichonCtlConfig;
|
||||
use crate::mbox::gmail::determine_folder;
|
||||
use crate::mbox::reader::MboxFile;
|
||||
use crate::sender::send_batch_request;
|
||||
use crate::BichonCtlConfig;
|
||||
use bichon_core::base64_encode_url_safe;
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Input};
|
||||
use dialoguer::{Confirm, Select};
|
||||
@@ -16,7 +16,6 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use memmap2::Mmap;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
@@ -130,7 +129,7 @@ impl<'a> Iterator for MboxReader<'a> {
|
||||
mod tests {
|
||||
use mail_parser::MessageParser;
|
||||
|
||||
use crate::modules::cli::mbox::gmail::determine_folder;
|
||||
use crate::mbox::gmail::determine_folder;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -221,7 +220,6 @@ mod tests {
|
||||
labels,
|
||||
determine_folder(labels)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use dialoguer::theme::ColorfulTheme;
|
||||
use dialoguer::Input;
|
||||
@@ -24,10 +23,10 @@ use mail_send::mail_builder::headers::text::Text;
|
||||
use mail_send::mail_builder::MessageBuilder;
|
||||
use outlook_pst::ltp::prop_context::PropertyValue;
|
||||
|
||||
use crate::base64_encode_url_safe;
|
||||
use crate::modules::cli::pst::encoding::decode_subject;
|
||||
use crate::modules::cli::sender::send_batch_request;
|
||||
use crate::modules::cli::BichonCtlConfig;
|
||||
use crate::BichonCtlConfig;
|
||||
use crate::pst::encoding::decode_subject;
|
||||
use crate::sender::send_batch_request;
|
||||
use bichon_core::base64_encode_url_safe;
|
||||
use dialoguer::Confirm;
|
||||
use outlook_pst::messaging::attachment::AttachmentProperties;
|
||||
use outlook_pst::messaging::folder::Folder;
|
||||
@@ -16,11 +16,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use console::style;
|
||||
use reqwest::Client;
|
||||
|
||||
use crate::modules::{cli::BichonCtlConfig, import::BatchEmlRequest};
|
||||
use bichon_core::import::BatchEmlRequest;
|
||||
|
||||
use crate::BichonCtlConfig;
|
||||
|
||||
pub async fn send_batch_request(
|
||||
client: &Client,
|
||||
@@ -16,10 +16,9 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::modules::cli::{mbox::run_import, BichonCtlConfig};
|
||||
use crate::{mbox::run_import, BichonCtlConfig};
|
||||
use console::style;
|
||||
use dialoguer::{theme::ColorfulTheme, Confirm, Input};
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
[package]
|
||||
name = "bichon-core"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
[features]
|
||||
default = ["web-api"]
|
||||
web-api = ["dep:poem-openapi"]
|
||||
|
||||
[dependencies]
|
||||
poem-openapi = { version = "5.1.16", features = [
|
||||
"openapi-explorer",
|
||||
"rapidoc",
|
||||
"scalar",
|
||||
"redoc",
|
||||
"swagger-ui",
|
||||
"email",
|
||||
], optional = true }
|
||||
chrono.workspace = true
|
||||
clap.workspace = true
|
||||
native_db.workspace = true
|
||||
itertools.workspace = true
|
||||
native_model.workspace = true
|
||||
ring.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-appender.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
base64.workspace = true
|
||||
snafu.workspace = true
|
||||
reqwest.workspace = true
|
||||
tokio-socks.workspace = true
|
||||
regex.workspace = true
|
||||
email_address.workspace = true
|
||||
futures.workspace = true
|
||||
utf7-imap.workspace = true
|
||||
mail-parser.workspace = true
|
||||
tokio-rustls.workspace = true
|
||||
oauth2.workspace = true
|
||||
sysinfo.workspace = true
|
||||
num_cpus.workspace = true
|
||||
rand.workspace = true
|
||||
encoding_rs.workspace = true
|
||||
async-imap.workspace = true
|
||||
webpki-roots.workspace = true
|
||||
rustls.workspace = true
|
||||
rustls-pki-types.workspace = true
|
||||
tokio-io-timeout.workspace = true
|
||||
governor.workspace = true
|
||||
lru.workspace = true
|
||||
time.workspace = true
|
||||
murmur3.workspace = true
|
||||
autoconfig.workspace = true
|
||||
dashmap.workspace = true
|
||||
itoa.workspace = true
|
||||
html2text.workspace = true
|
||||
bytes.workspace = true
|
||||
mail-send.workspace = true
|
||||
blake3.workspace = true
|
||||
uuid.workspace = true
|
||||
fjall.workspace = true
|
||||
tantivy.workspace = true
|
||||
tracing-log.workspace = true
|
||||
tokio-util.workspace = true
|
||||
@@ -16,19 +16,19 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{encrypt, error::BichonResult};
|
||||
|
||||
use crate::{encrypt, modules::error::BichonResult};
|
||||
|
||||
use poem_openapi::{Enum, Object};
|
||||
//use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct ImapConfig {
|
||||
/// IMAP server hostname or IP address
|
||||
#[oai(validator(max_length = 253, pattern = r"^[a-zA-Z0-9\-\.]+$"))]
|
||||
//#[oai(validator(max_length = 253, pattern = r"^[a-zA-Z0-9\-\.]+$"))]
|
||||
pub host: String,
|
||||
/// IMAP server port number
|
||||
#[oai(validator(minimum(value = "1"), maximum(value = "65535")))]
|
||||
//#[oai(validator(minimum(value = "1"), maximum(value = "65535")))]
|
||||
pub port: u16,
|
||||
/// Connection encryption method
|
||||
pub encryption: Encryption,
|
||||
@@ -52,8 +52,8 @@ impl ImapConfig {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Enum, Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum AuthType {
|
||||
/// Standard password authentication (PLAIN/LOGIN)
|
||||
#[default]
|
||||
@@ -62,7 +62,8 @@ pub enum AuthType {
|
||||
OAuth2,
|
||||
}
|
||||
|
||||
#[derive(Object, Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AuthConfig {
|
||||
///Authentication method to use
|
||||
pub auth_type: AuthType,
|
||||
@@ -70,7 +71,7 @@ pub struct AuthConfig {
|
||||
///
|
||||
/// Users should provide a plaintext password (1 to 256 characters).
|
||||
/// The server will encrypt the password using AES-256-GCM and securely store it.
|
||||
#[oai(validator(max_length = 256, min_length = 1))]
|
||||
//#[oai(validator(max_length = 256, min_length = 1))]
|
||||
pub password: Option<String>,
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ impl AuthConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Enum)]
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum Encryption {
|
||||
/// SSL/TLS encrypted connection
|
||||
#[default]
|
||||
@@ -16,11 +16,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
raise_error, utc_now,
|
||||
{
|
||||
account::migration::AccountModel,
|
||||
common::auth::ClientContext,
|
||||
database::{manager::DB_MANAGER, with_transaction},
|
||||
@@ -31,10 +32,10 @@ use crate::{
|
||||
UserModel,
|
||||
},
|
||||
},
|
||||
raise_error, utc_now,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct BatchAccountRoleRequest {
|
||||
pub account_ids: Vec<u64>,
|
||||
pub user_ids: Vec<u64>,
|
||||
@@ -18,56 +18,54 @@
|
||||
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
|
||||
use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
encrypt,
|
||||
modules::{
|
||||
account::{
|
||||
entity::ImapConfig,
|
||||
since::{DateSince, RelativeDate},
|
||||
state::DownloadState,
|
||||
},
|
||||
cache::imap::mailbox::MailBox,
|
||||
database::{list_all_impl, secondary_find_impl, with_transaction},
|
||||
error::BichonResult,
|
||||
store::tantivy::{attachment::ATTACHMENT_MANAGER, envelope::ENVELOPE_MANAGER},
|
||||
users::{role::DEFAULT_ACCOUNT_MANAGER_ROLE_ID, UserModel, DEFAULT_ADMIN_USER_ID},
|
||||
account::{
|
||||
entity::ImapConfig,
|
||||
since::{DateSince, RelativeDate},
|
||||
state::DownloadState,
|
||||
},
|
||||
cache::imap::mailbox::MailBox,
|
||||
common::paginated::DataPage,
|
||||
database::{list_all_impl, secondary_find_impl, with_transaction},
|
||||
encrypt,
|
||||
error::BichonResult,
|
||||
store::tantivy::{attachment::ATTACHMENT_MANAGER, envelope::ENVELOPE_MANAGER},
|
||||
users::{role::DEFAULT_ACCOUNT_MANAGER_ROLE_ID, UserModel, DEFAULT_ADMIN_USER_ID},
|
||||
utc_now,
|
||||
};
|
||||
|
||||
use crate::id;
|
||||
use crate::modules::account::payload::AccountCreateRequest;
|
||||
use crate::modules::account::payload::AccountUpdateRequest;
|
||||
use crate::modules::account::payload::MinimalAccount;
|
||||
use crate::modules::cache::imap::task::SYNC_TASKS;
|
||||
use crate::modules::context::controller::DOWNLOAD_CONTROLLER;
|
||||
use crate::modules::database::count_by_unique_secondary_key_impl;
|
||||
use crate::modules::database::delete_impl;
|
||||
use crate::modules::database::manager::DB_MANAGER;
|
||||
use crate::modules::database::{
|
||||
use crate::account::payload::AccountCreateRequest;
|
||||
use crate::account::payload::AccountUpdateRequest;
|
||||
use crate::account::payload::MinimalAccount;
|
||||
use crate::cache::imap::task::SYNC_TASKS;
|
||||
use crate::context::controller::DOWNLOAD_CONTROLLER;
|
||||
use crate::database::count_by_unique_secondary_key_impl;
|
||||
use crate::database::delete_impl;
|
||||
use crate::database::manager::DB_MANAGER;
|
||||
use crate::database::{
|
||||
async_secondary_find_impl, paginate_query_primary_scan_all_impl, update_impl,
|
||||
};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::oauth2::token::OAuth2AccessToken;
|
||||
use crate::modules::rest::response::DataPage;
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::id;
|
||||
use crate::oauth2::token::OAuth2AccessToken;
|
||||
use crate::raise_error;
|
||||
|
||||
pub type AccountModel = AccountV4;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum AccountType {
|
||||
#[default]
|
||||
IMAP,
|
||||
NoSync,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum QuotaWindow {
|
||||
Hourly,
|
||||
#[default]
|
||||
@@ -76,7 +74,7 @@ pub enum QuotaWindow {
|
||||
Monthly,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[native_model(id = 4, version = 1)]
|
||||
#[native_db(primary_key(pk -> String))]
|
||||
pub struct AccountV1 {
|
||||
@@ -84,7 +82,7 @@ pub struct AccountV1 {
|
||||
pub id: u64,
|
||||
pub imap: Option<ImapConfig>,
|
||||
pub enabled: bool,
|
||||
#[oai(validator(custom = "crate::modules::common::validator::EmailValidator"))]
|
||||
//#[oai(validator(custom = "crate::common::validator::EmailValidator"))]
|
||||
pub email: String,
|
||||
pub name: Option<String>,
|
||||
pub capabilities: Option<Vec<String>>,
|
||||
@@ -104,7 +102,7 @@ impl AccountV1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[native_model(id = 4, version = 2, from = AccountV1)]
|
||||
#[native_db(primary_key(pk -> String))]
|
||||
pub struct AccountV2 {
|
||||
@@ -112,7 +110,7 @@ pub struct AccountV2 {
|
||||
pub id: u64,
|
||||
pub imap: Option<ImapConfig>,
|
||||
pub enabled: bool,
|
||||
#[oai(validator(custom = "crate::modules::common::validator::EmailValidator"))]
|
||||
//#[oai(validator(custom = "crate::common::validator::EmailValidator"))]
|
||||
pub email: String,
|
||||
pub name: Option<String>,
|
||||
pub capabilities: Option<Vec<String>>,
|
||||
@@ -135,7 +133,7 @@ impl AccountV2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[native_model(id = 4, version = 3, from = AccountV2)]
|
||||
#[native_db(primary_key(pk -> String))]
|
||||
pub struct AccountV3 {
|
||||
@@ -143,7 +141,7 @@ pub struct AccountV3 {
|
||||
pub id: u64,
|
||||
pub imap: Option<ImapConfig>,
|
||||
pub enabled: bool,
|
||||
#[oai(validator(custom = "crate::modules::common::validator::EmailValidator"))]
|
||||
//#[oai(validator(custom = "crate::common::validator::EmailValidator"))]
|
||||
pub email: String,
|
||||
pub name: Option<String>,
|
||||
pub capabilities: Option<Vec<String>>,
|
||||
@@ -169,7 +167,8 @@ impl AccountV3 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 4, version = 4, from = AccountV3)]
|
||||
#[native_db(primary_key(pk -> String))]
|
||||
pub struct AccountV4 {
|
||||
@@ -177,7 +176,7 @@ pub struct AccountV4 {
|
||||
pub id: u64,
|
||||
pub imap: Option<ImapConfig>,
|
||||
pub enabled: bool,
|
||||
#[oai(validator(custom = "crate::modules::common::validator::EmailValidator"))]
|
||||
//#[oai(validator(custom = "crate::common::validator::EmailValidator"))]
|
||||
pub email: String,
|
||||
pub account_name: Option<String>,
|
||||
pub login_name: Option<String>,
|
||||
@@ -16,26 +16,18 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// use crate::{
|
||||
// modules::{
|
||||
// database::{async_find_impl, delete_impl, manager::DB_MANAGER, update_impl, upsert_impl},
|
||||
// error::{code::ErrorCode, BichonResult},
|
||||
// },
|
||||
// raise_error, utc_now,
|
||||
// };
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct MailboxBatchProgress {
|
||||
pub total_batches: u32,
|
||||
pub current_batch: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[native_model(id = 2, version = 1)]
|
||||
#[native_db]
|
||||
pub struct AccountRunningState {
|
||||
@@ -51,7 +43,7 @@ pub struct AccountRunningState {
|
||||
pub initial_sync_failed_time: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct AccountError {
|
||||
pub error: String,
|
||||
pub at: i64,
|
||||
@@ -16,18 +16,18 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::entity::ImapConfig;
|
||||
use crate::modules::account::migration::{AccountModel, AccountType, QuotaWindow};
|
||||
use crate::modules::account::since::{DateSince, RelativeDate};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::account::entity::ImapConfig;
|
||||
use crate::account::migration::{AccountModel, AccountType, QuotaWindow};
|
||||
use crate::account::since::{DateSince, RelativeDate};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::{raise_error, validate_email};
|
||||
use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AccountCreateRequest {
|
||||
#[oai(validator(custom = "crate::modules::common::validator::EmailValidator"))]
|
||||
//#[oai(validator(custom = "crate::common::validator::EmailValidator"))]
|
||||
pub email: String,
|
||||
pub login_name: Option<String>,
|
||||
pub account_name: Option<String>,
|
||||
@@ -36,11 +36,11 @@ pub struct AccountCreateRequest {
|
||||
pub date_since: Option<DateSince>,
|
||||
pub date_before: Option<RelativeDate>,
|
||||
pub account_type: AccountType,
|
||||
#[oai(validator(minimum(value = "100")))]
|
||||
//#[oai(validator(minimum(value = "100")))]
|
||||
pub folder_limit: Option<u32>,
|
||||
#[oai(validator(minimum(value = "10")))]
|
||||
//#[oai(validator(minimum(value = "10")))]
|
||||
pub download_interval_min: Option<i64>,
|
||||
#[oai(validator(minimum(value = "10"), maximum(value = "200")))]
|
||||
//#[oai(validator(minimum(value = "10"), maximum(value = "200")))]
|
||||
pub download_batch_size: Option<u32>,
|
||||
pub use_proxy: Option<u64>,
|
||||
pub use_dangerous: bool,
|
||||
@@ -107,7 +107,8 @@ impl AccountCreateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AccountUpdateRequest {
|
||||
pub email: Option<String>,
|
||||
/// Represents the account activation status.
|
||||
@@ -135,7 +136,7 @@ pub struct AccountUpdateRequest {
|
||||
/// Max emails to sync for this folder.
|
||||
/// If not set, sync all emails.
|
||||
/// otherwise sync up to `n` most recent emails (min 10).
|
||||
#[oai(validator(minimum(value = "100")))]
|
||||
//#[oai(validator(minimum(value = "100")))]
|
||||
pub folder_limit: Option<u32>,
|
||||
pub clear_folder_limit: Option<bool>,
|
||||
/// Configuration for selective folder (mailbox/label) synchronization
|
||||
@@ -153,9 +154,9 @@ pub struct AccountUpdateRequest {
|
||||
/// Modified folders will be automatically synced on the next update.
|
||||
pub sync_folders: Option<Vec<String>>,
|
||||
/// Incremental sync interval (seconds)
|
||||
#[oai(validator(minimum(value = "10")))]
|
||||
//#[oai(validator(minimum(value = "10")))]
|
||||
pub download_interval_min: Option<i64>,
|
||||
#[oai(validator(minimum(value = "10"), maximum(value = "200")))]
|
||||
//#[oai(validator(minimum(value = "10"), maximum(value = "200")))]
|
||||
pub download_batch_size: Option<u32>,
|
||||
/// Optional proxy ID for establishing the connection to external APIs (e.g., Gmail, Outlook).
|
||||
/// - If `None` or not provided, the client will connect directly to the API server.
|
||||
@@ -225,7 +226,8 @@ impl AccountUpdateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
|
||||
pub struct MinimalAccount {
|
||||
pub id: u64,
|
||||
@@ -17,14 +17,14 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::error::{code::ErrorCode, BichonResult},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
raise_error,
|
||||
};
|
||||
use chrono::{Datelike, Days, Local, Months, NaiveDate, Utc};
|
||||
use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct DateSince {
|
||||
/// Absolute date boundary in ISO 8601 format (YYYY-MM-DD)
|
||||
///
|
||||
@@ -38,7 +38,7 @@ pub struct DateSince {
|
||||
/// "fixed": "2025-05-01"
|
||||
/// }
|
||||
/// ```
|
||||
#[oai(validator(pattern = r"^\d{4}-\d{2}-\d{2}$"))]
|
||||
//#[oai(validator(pattern = r"^\d{4}-\d{2}-\d{2}$"))]
|
||||
pub fixed: Option<String>,
|
||||
/// Relative time period from current date
|
||||
///
|
||||
@@ -58,7 +58,8 @@ pub struct DateSince {
|
||||
pub relative: Option<RelativeDate>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum Unit {
|
||||
#[default]
|
||||
Days,
|
||||
@@ -66,12 +67,13 @@ pub enum Unit {
|
||||
Years,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct RelativeDate {
|
||||
/// The time unit to use for the offset (days, months, or years)
|
||||
pub unit: Unit,
|
||||
/// The quantity of time units to offset (must be a positive integer)
|
||||
#[oai(validator(minimum(value = "1")))]
|
||||
//#[oai(validator(minimum(value = "1")))]
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
@@ -255,7 +257,7 @@ impl DateSince {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::modules::account::since::{DateSince, RelativeDate, Unit};
|
||||
use crate::account::since::{DateSince, RelativeDate, Unit};
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
database::{async_find_impl, delete_impl, manager::DB_MANAGER, update_impl, upsert_impl},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
},
|
||||
@@ -25,11 +25,11 @@ use crate::{
|
||||
};
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum DownloadStatus {
|
||||
Running,
|
||||
Success,
|
||||
@@ -38,14 +38,16 @@ pub enum DownloadStatus {
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum TriggerType {
|
||||
Manual,
|
||||
#[default]
|
||||
Scheduled,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum FolderStatus {
|
||||
#[default]
|
||||
Pending,
|
||||
@@ -55,7 +57,8 @@ pub enum FolderStatus {
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct FolderProgress {
|
||||
pub folder_name: String,
|
||||
pub planned: u64,
|
||||
@@ -64,7 +67,8 @@ pub struct FolderProgress {
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct DownloadSession {
|
||||
pub start_time: i64,
|
||||
pub end_time: Option<i64>,
|
||||
@@ -76,7 +80,8 @@ pub struct DownloadSession {
|
||||
pub errors: Vec<AccountError>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 3, version = 1)]
|
||||
#[native_db]
|
||||
pub struct DownloadState {
|
||||
@@ -89,7 +94,8 @@ pub struct DownloadState {
|
||||
pub global_errors: Vec<AccountError>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AccountError {
|
||||
pub error: String,
|
||||
pub at: i64,
|
||||
@@ -17,11 +17,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
account::{
|
||||
entity::ImapConfig,
|
||||
migration::{AccountModel, AccountType, QuotaWindow},
|
||||
@@ -30,7 +28,8 @@ use crate::modules::{
|
||||
users::UserModel,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AccountResp {
|
||||
pub id: u64,
|
||||
pub imap: Option<ImapConfig>,
|
||||
@@ -23,7 +23,7 @@ use std::{path::Path, rc::Rc};
|
||||
use native_db::{Builder, Database};
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
database::META_MODELS,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
token::{AccessTokenModel, AccessTokenModelKey, TokenType},
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
|
||||
use autoconfig::config::OAuth2Config as XOAuth2Config;
|
||||
use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::modules::account::entity::Encryption;
|
||||
use crate::account::entity::Encryption;
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct ServerConfig {
|
||||
/// server hostname or IP address
|
||||
pub host: String,
|
||||
@@ -43,7 +43,8 @@ impl ServerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct OAuth2Config {
|
||||
/// The authorization server's issuer identifier URL
|
||||
pub issuer: String,
|
||||
@@ -66,7 +67,8 @@ impl From<&XOAuth2Config> for OAuth2Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct MailServerConfig {
|
||||
/// IMAP server configuration
|
||||
pub imap: ServerConfig,
|
||||
@@ -17,10 +17,10 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use crate::modules::autoconfig::entity::{MailServerConfig, ServerConfig};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::autoconfig::entity::{MailServerConfig, ServerConfig};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
account::entity::Encryption, autoconfig::CachedMailSettings, error::BichonResult,
|
||||
},
|
||||
raise_error,
|
||||
@@ -17,12 +17,12 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use crate::modules::database::manager::DB_MANAGER;
|
||||
use crate::modules::database::{delete_impl, async_find_impl, upsert_impl};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::database::manager::DB_MANAGER;
|
||||
use crate::database::{delete_impl, async_find_impl, upsert_impl};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::raise_error;
|
||||
use crate::{
|
||||
modules::autoconfig::entity::MailServerConfig, modules::error::BichonResult, utc_now,
|
||||
autoconfig::entity::MailServerConfig, error::BichonResult, utc_now,
|
||||
};
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
+1
-1
@@ -20,7 +20,7 @@ use std::collections::BTreeSet;
|
||||
|
||||
use crate::{
|
||||
decode_mailbox_name,
|
||||
modules::{
|
||||
{
|
||||
account::migration::{AccountModel, AccountType},
|
||||
cache::imap::mailbox::{AttributeEnum, MailBox},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
account::{
|
||||
migration::AccountModel,
|
||||
state::{DownloadState, TriggerType},
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
account::{
|
||||
migration::AccountModel,
|
||||
state::{DownloadState, DownloadStatus, FolderStatus},
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
account::{
|
||||
migration::{AccountModel, AccountType},
|
||||
state::{DownloadState, DownloadStatus},
|
||||
Vendored
+1
-1
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
account::{
|
||||
migration::AccountModel,
|
||||
state::{DownloadState, DownloadStatus, FolderStatus},
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use crate::{
|
||||
decode_mailbox_name, encode_mailbox_name,
|
||||
modules::{
|
||||
{
|
||||
database::{
|
||||
async_filter_by_secondary_key_impl, async_find_impl, batch_delete_impl,
|
||||
batch_insert_impl, batch_upsert_impl, delete_impl, filter_by_secondary_key_impl,
|
||||
@@ -32,10 +32,10 @@ use async_imap::types::{Name, NameAttribute};
|
||||
use itertools::Itertools;
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 1, version = 1)]
|
||||
#[native_db]
|
||||
pub struct MailBox {
|
||||
@@ -145,7 +145,8 @@ impl MailBox {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct Attribute {
|
||||
pub attr: AttributeEnum,
|
||||
pub extension: Option<String>,
|
||||
@@ -157,7 +158,8 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Enum)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum AttributeEnum {
|
||||
NoInferiors,
|
||||
NoSelect,
|
||||
@@ -16,18 +16,20 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::LazyLock;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use crate::modules::{
|
||||
account::{state::DownloadState, old_state::AccountRunningState},
|
||||
use crate::{
|
||||
account::{old_state::AccountRunningState, state::DownloadState},
|
||||
database::ModelsAdapter,
|
||||
};
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use mailbox::MailBox;
|
||||
use native_db::Models;
|
||||
|
||||
pub mod mailbox;
|
||||
pub mod download;
|
||||
pub mod mailbox;
|
||||
pub mod task;
|
||||
|
||||
pub static MAILBOX_MODELS: LazyLock<Models> = LazyLock::new(|| {
|
||||
@@ -42,7 +44,7 @@ pub fn find_missing_mailboxes(
|
||||
local_mailboxes: &[MailBox],
|
||||
server_mailboxes: &[MailBox],
|
||||
) -> Vec<MailBox> {
|
||||
let local_names: AHashSet<_> = local_mailboxes.iter().map(|m| &m.name).collect();
|
||||
let local_names: HashSet<_> = local_mailboxes.iter().map(|m| &m.name).collect();
|
||||
server_mailboxes
|
||||
.iter()
|
||||
.filter(|m| !local_names.contains(&m.name))
|
||||
@@ -54,7 +56,7 @@ pub fn find_intersecting_mailboxes(
|
||||
local_mailboxes: &[MailBox],
|
||||
remote_mailboxes: &[MailBox],
|
||||
) -> Vec<(MailBox, MailBox)> {
|
||||
let local_map: AHashMap<_, _> = local_mailboxes
|
||||
let local_map: HashMap<_, _> = local_mailboxes
|
||||
.iter()
|
||||
.map(|m| (m.name.clone(), m.clone()))
|
||||
.collect();
|
||||
@@ -16,12 +16,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::entity::AuthType;
|
||||
use crate::modules::account::state::DownloadState;
|
||||
use crate::modules::cache::imap::download::process_imap_download;
|
||||
use crate::modules::common::periodic::{PeriodicTask, TaskHandle};
|
||||
use crate::modules::oauth2::token::OAuth2AccessToken;
|
||||
use crate::modules::{account::migration::AccountModel, error::BichonResult};
|
||||
use crate::account::entity::AuthType;
|
||||
use crate::account::state::DownloadState;
|
||||
use crate::cache::imap::download::process_imap_download;
|
||||
use crate::common::periodic::{PeriodicTask, TaskHandle};
|
||||
use crate::oauth2::token::OAuth2AccessToken;
|
||||
use crate::{account::migration::AccountModel, error::BichonResult};
|
||||
use crate::utc_now;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use crate::modules::settings::cli::SETTINGS;
|
||||
use crate::settings::cli::SETTINGS;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
use std::{
|
||||
collections::{BTreeSet, HashSet},
|
||||
net::IpAddr,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
raise_error,
|
||||
users::{permissions::Permission, role::UserRole, UserModel},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClientContext {
|
||||
pub ip_addr: Option<IpAddr>,
|
||||
pub user: UserModel,
|
||||
}
|
||||
|
||||
impl ClientContext {
|
||||
pub async fn require_any_permission(
|
||||
&self,
|
||||
requirements: Vec<(Option<u64>, &str)>,
|
||||
) -> BichonResult<()> {
|
||||
for (account_id, permission) in requirements {
|
||||
if self.has_permission(account_id, permission).await {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(raise_error!(
|
||||
"Access denied: Insufficient permissions to perform this action.".into(),
|
||||
ErrorCode::Forbidden
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn check_has_permission(
|
||||
user: &UserModel,
|
||||
account_id: Option<u64>,
|
||||
permission: &str,
|
||||
) -> bool {
|
||||
if user.is_admin().await {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut global_perms = HashSet::new();
|
||||
for rid in &user.global_roles {
|
||||
if let Some(role) = UserRole::find(*rid).await.ok().flatten() {
|
||||
global_perms.extend(role.permissions);
|
||||
}
|
||||
}
|
||||
|
||||
if Self::check_global_logic(&global_perms, permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(aid) = account_id {
|
||||
if let Some(role_id) = user.account_access_map.get(&aid) {
|
||||
if let Some(role) = UserRole::find(*role_id).await.ok().flatten() {
|
||||
if role.permissions.contains(&permission.to_string())
|
||||
|| Self::check_account_logic(&role.permissions, permission)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn has_permission(&self, account_id: Option<u64>, permission: &str) -> bool {
|
||||
if self.user.is_admin().await {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut global_perms = HashSet::new();
|
||||
for rid in &self.user.global_roles {
|
||||
if let Some(role) = UserRole::find(*rid).await.ok().flatten() {
|
||||
global_perms.extend(role.permissions);
|
||||
}
|
||||
}
|
||||
|
||||
if Self::check_global_logic(&global_perms, permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(aid) = account_id {
|
||||
if let Some(role_id) = self.user.account_access_map.get(&aid) {
|
||||
if let Some(role) = UserRole::find(*role_id).await.ok().flatten() {
|
||||
if role.permissions.contains(&permission.to_string())
|
||||
|| Self::check_account_logic(&role.permissions, permission)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn check_global_logic(global: &HashSet<String>, perm: &str) -> bool {
|
||||
if global.contains(perm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match perm {
|
||||
Permission::DATA_READ => global.contains(Permission::DATA_READ_ALL),
|
||||
Permission::DATA_DELETE => global.contains(Permission::DATA_DELETE_ALL),
|
||||
Permission::DATA_RAW_DOWNLOAD => global.contains(Permission::DATA_RAW_DOWNLOAD_ALL),
|
||||
Permission::DATA_EXPORT_BATCH => global.contains(Permission::DATA_EXPORT_BATCH_ALL),
|
||||
Permission::ACCOUNT_MANAGE | Permission::ACCOUNT_READ_DETAILS => {
|
||||
global.contains(Permission::ACCOUNT_MANAGE_ALL)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_account_logic(scoped_perms: &BTreeSet<String>, perm: &str) -> bool {
|
||||
if scoped_perms.contains(perm) {
|
||||
return true;
|
||||
}
|
||||
match perm {
|
||||
Permission::DATA_READ | Permission::ACCOUNT_READ_DETAILS => {
|
||||
scoped_perms.contains(Permission::ACCOUNT_MANAGE)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn require_permission(
|
||||
&self,
|
||||
account_id: Option<u64>,
|
||||
permission: &str,
|
||||
) -> BichonResult<()> {
|
||||
if self.has_permission(account_id, permission).await {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(raise_error!(
|
||||
format!("Access Denied: Missing permission '{}'", permission),
|
||||
ErrorCode::Forbidden
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,29 +16,17 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::error::code::ErrorCode;
|
||||
use super::error::BichonError;
|
||||
use mail_parser::{Addr as ImapAddr, Address as ImapAddress};
|
||||
use poem::error::ResponseError;
|
||||
use poem::Body;
|
||||
use poem::{http::StatusCode, Error, Response};
|
||||
use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Deref;
|
||||
use tracing::error;
|
||||
|
||||
use mail_parser::{Addr as ImapAddr, Address as ImapAddress};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub mod auth;
|
||||
pub mod error;
|
||||
pub mod log;
|
||||
pub mod paginated;
|
||||
pub mod periodic;
|
||||
pub mod rustls;
|
||||
pub mod signal;
|
||||
pub mod timeout;
|
||||
pub mod tls;
|
||||
pub mod validator;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
pub struct Addr {
|
||||
/// The optional display name associated with the email address (e.g., "John Doe").
|
||||
/// If `None`, no display name is specified.
|
||||
@@ -91,57 +79,3 @@ impl<'x> From<&ImapAddress<'x>> for AddrVec {
|
||||
AddrVec(vec)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn create_rust_mailer_error(message: &str, code: ErrorCode) -> BichonError {
|
||||
BichonError::Generic {
|
||||
message: message.into(),
|
||||
location: snafu::location!(),
|
||||
code,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create_api_error_response(message: &str, code: ErrorCode) -> Error {
|
||||
let rust_mailer_error = create_rust_mailer_error(message, code);
|
||||
rust_mailer_error.into()
|
||||
}
|
||||
|
||||
impl ResponseError for BichonError {
|
||||
fn status(&self) -> StatusCode {
|
||||
match self {
|
||||
BichonError::Generic {
|
||||
message: _,
|
||||
location: _,
|
||||
code,
|
||||
} => code.status(),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_response(&self) -> Response
|
||||
where
|
||||
Self: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
match self {
|
||||
BichonError::Generic {
|
||||
message,
|
||||
location,
|
||||
code,
|
||||
} => {
|
||||
error!(
|
||||
error_code = *code as u32,
|
||||
error_message = %message,
|
||||
error_location = ?location
|
||||
);
|
||||
|
||||
let body = Body::from_json(serde_json::json!({
|
||||
"code": *code as u32,
|
||||
"message": message.to_string(),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
Response::builder().status(self.status()).body(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
raise_error,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::min;
|
||||
|
||||
pub fn paginate_vec<T: Clone>(
|
||||
items: &Vec<T>,
|
||||
page: Option<u64>,
|
||||
page_size: Option<u64>,
|
||||
) -> BichonResult<Paginated<T>> {
|
||||
let total_items = items.len() as u64;
|
||||
|
||||
let (offset, total_pages) = match (page, page_size) {
|
||||
(Some(p), Some(s)) if p > 0 && s > 0 => {
|
||||
let offset = (p - 1) * s;
|
||||
let total_pages = if total_items > 0 {
|
||||
(total_items + s - 1) / s
|
||||
} else {
|
||||
0
|
||||
};
|
||||
(Some(offset), Some(total_pages))
|
||||
}
|
||||
(Some(0), _) | (_, Some(0)) => {
|
||||
return Err(raise_error!(
|
||||
"'page' and 'page_size' must be greater than 0.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
let data = match offset {
|
||||
Some(offset) if offset >= total_items => vec![],
|
||||
Some(offset) => {
|
||||
let end = min(offset + page_size.unwrap_or(total_items), total_items) as usize;
|
||||
items[offset as usize..end].to_vec()
|
||||
}
|
||||
None => items.clone(),
|
||||
};
|
||||
|
||||
Ok(Paginated::new(
|
||||
page,
|
||||
page_size,
|
||||
total_items,
|
||||
total_pages,
|
||||
data,
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(feature = "web-api"))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct DataPage<S>
|
||||
where
|
||||
S: Serialize + std::fmt::Debug + std::marker::Unpin + Send + Sync,
|
||||
{
|
||||
/// The current page number (starting from 1).
|
||||
pub current_page: Option<u64>,
|
||||
/// The number of items per page.
|
||||
pub page_size: Option<u64>,
|
||||
/// The total number of items across all pages.
|
||||
pub total_items: u64,
|
||||
/// The list of items returned on the current page.
|
||||
pub items: Vec<S>,
|
||||
/// The total number of pages. This is optional and may not be set if not calculated.
|
||||
pub total_pages: Option<u64>,
|
||||
}
|
||||
#[cfg(not(feature = "web-api"))]
|
||||
impl<S: Serialize + std::fmt::Debug + std::marker::Unpin + Send + Sync> From<Paginated<S>>
|
||||
for DataPage<S>
|
||||
{
|
||||
fn from(paginated: Paginated<S>) -> Self {
|
||||
DataPage {
|
||||
current_page: paginated.page,
|
||||
page_size: paginated.page_size,
|
||||
total_items: paginated.total_items,
|
||||
total_pages: paginated.total_pages,
|
||||
items: paginated.items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(feature = "web-api")]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, poem_openapi::Object)]
|
||||
pub struct DataPage<S>
|
||||
where
|
||||
S: Serialize
|
||||
+ std::fmt::Debug
|
||||
+ std::marker::Unpin
|
||||
+ Send
|
||||
+ Sync
|
||||
+ poem_openapi::types::Type
|
||||
+ poem_openapi::types::ParseFromJSON
|
||||
+ poem_openapi::types::ToJSON,
|
||||
{
|
||||
/// The current page number (starting from 1).
|
||||
pub current_page: Option<u64>,
|
||||
/// The number of items per page.
|
||||
pub page_size: Option<u64>,
|
||||
/// The total number of items across all pages.
|
||||
pub total_items: u64,
|
||||
/// The list of items returned on the current page.
|
||||
pub items: Vec<S>,
|
||||
/// The total number of pages. This is optional and may not be set if not calculated.
|
||||
pub total_pages: Option<u64>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "web-api")]
|
||||
impl<
|
||||
S: Serialize
|
||||
+ std::fmt::Debug
|
||||
+ std::marker::Unpin
|
||||
+ Send
|
||||
+ Sync
|
||||
+ poem_openapi::types::Type
|
||||
+ poem_openapi::types::ParseFromJSON
|
||||
+ poem_openapi::types::ToJSON,
|
||||
> From<Paginated<S>> for DataPage<S>
|
||||
{
|
||||
fn from(paginated: Paginated<S>) -> Self {
|
||||
DataPage {
|
||||
current_page: paginated.page,
|
||||
page_size: paginated.page_size,
|
||||
total_items: paginated.total_items,
|
||||
total_pages: paginated.total_pages,
|
||||
items: paginated.items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Paginated<T> {
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
pub total_items: u64,
|
||||
pub total_pages: Option<u64>,
|
||||
pub items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Paginated<T> {
|
||||
pub fn new(
|
||||
page: Option<u64>,
|
||||
page_size: Option<u64>,
|
||||
total_items: u64,
|
||||
total_pages: Option<u64>,
|
||||
items: Vec<T>,
|
||||
) -> Self {
|
||||
Paginated {
|
||||
page,
|
||||
page_size,
|
||||
total_items,
|
||||
total_pages,
|
||||
items,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{common::signal::SIGNAL_MANAGER, error::BichonResult};
|
||||
use crate::{common::signal::SIGNAL_MANAGER, error::BichonResult};
|
||||
use std::{future::Future, time::Duration};
|
||||
use tokio::{sync::oneshot, task::JoinHandle, time::MissedTickBehavior};
|
||||
use tracing::{info, warn};
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
context::Initialize,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::modules::{context::Initialize, error::BichonResult, utils::shutdown::shutdown_signal};
|
||||
use crate::{context::Initialize, error::BichonResult, utils::shutdown::shutdown_signal};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
pub static SIGNAL_MANAGER: LazyLock<SignalManager> = LazyLock::new(SignalManager::new);
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{cache::imap::task::SYNC_TASKS, error::BichonResult};
|
||||
use crate::{cache::imap::task::SYNC_TASKS, error::BichonResult};
|
||||
use std::{sync::LazyLock, time::Duration};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::{error, info};
|
||||
@@ -16,10 +16,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::migration::AccountType;
|
||||
use crate::modules::context::Initialize;
|
||||
use crate::account::migration::AccountType;
|
||||
use crate::context::Initialize;
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
account::migration::AccountModel, context::controller::DOWNLOAD_CONTROLLER, error::BichonResult,
|
||||
},
|
||||
utc_now,
|
||||
@@ -16,11 +16,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{common::periodic::TaskHandle, error::BichonResult};
|
||||
use crate::{common::periodic::TaskHandle, error::BichonResult};
|
||||
|
||||
pub mod controller;
|
||||
pub mod executors;
|
||||
pub mod status;
|
||||
|
||||
#[allow(async_fn_in_trait)]
|
||||
pub trait Initialize {
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
store::tantivy::{
|
||||
attachment::ATTACHMENT_MANAGER,
|
||||
envelope::ENVELOPE_MANAGER,
|
||||
@@ -25,24 +25,24 @@ use crate::modules::{
|
||||
},
|
||||
users::permissions::Permission,
|
||||
};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use tantivy::{schema::Value, TantivyDocument};
|
||||
|
||||
use crate::{
|
||||
bichon_version,
|
||||
modules::{
|
||||
bichon_version, raise_error,
|
||||
{
|
||||
account::migration::AccountModel,
|
||||
common::auth::ClientContext,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
settings::dir::DATA_DIR_MANAGER,
|
||||
utils::get_total_size,
|
||||
},
|
||||
raise_error,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct DashboardStats {
|
||||
pub account_count: usize, // Number of accounts
|
||||
pub email_count: u64, // Total number of emails
|
||||
@@ -57,7 +57,6 @@ pub struct DashboardStats {
|
||||
pub top_largest_emails: Vec<LargestEmail>, // Top 10 largest emails
|
||||
pub top_largest_attachments: Vec<LargestAttachment>, // Top 10 largest attachments
|
||||
pub system_version: String, // The semantic version string of the currently running backend service
|
||||
pub commit_hash: String, // Git commit hash used to build this system version
|
||||
}
|
||||
|
||||
impl DashboardStats {
|
||||
@@ -103,25 +102,27 @@ impl DashboardStats {
|
||||
}
|
||||
|
||||
stat.system_version = bichon_version!().to_string();
|
||||
stat.commit_hash = env!("GIT_HASH").to_string();
|
||||
|
||||
Ok(stat)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct TimeBucket {
|
||||
pub timestamp_ms: i64, // Timestamp in milliseconds
|
||||
pub count: u64, // Number of emails in this time bucket
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct Group {
|
||||
pub key: String,
|
||||
pub count: u64, // Number of emails from this sender
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct LargestEmail {
|
||||
pub subject: String, // Email subject
|
||||
pub size_bytes: u64, // Email size in bytes
|
||||
@@ -173,7 +174,8 @@ impl LargestEmail {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct LargestAttachment {
|
||||
pub name: String, // Attachment name
|
||||
pub size_bytes: u64, // Attachment size in bytes
|
||||
@@ -16,13 +16,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::migration::AccountModel;
|
||||
use crate::modules::cache::imap::MAILBOX_MODELS;
|
||||
use crate::modules::error::{code::ErrorCode, BichonError};
|
||||
use crate::modules::settings::cli::SETTINGS;
|
||||
use crate::modules::settings::dir::DATA_DIR_MANAGER;
|
||||
use crate::modules::users::UserModel;
|
||||
use crate::modules::{database::META_MODELS, error::BichonResult};
|
||||
use crate::account::migration::AccountModel;
|
||||
use crate::cache::imap::MAILBOX_MODELS;
|
||||
use crate::error::{code::ErrorCode, BichonError};
|
||||
use crate::settings::cli::SETTINGS;
|
||||
use crate::settings::dir::DATA_DIR_MANAGER;
|
||||
use crate::users::UserModel;
|
||||
use crate::{database::META_MODELS, error::BichonResult};
|
||||
use crate::raise_error;
|
||||
use native_db::{Builder, Database};
|
||||
use std::sync::{Arc, LazyLock};
|
||||
@@ -16,18 +16,19 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::migration::{AccountV1, AccountV2, AccountV3, AccountV4};
|
||||
use crate::modules::autoconfig::CachedMailSettings;
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::oauth2::entity::OAuth2;
|
||||
use crate::modules::oauth2::pending::OAuth2PendingEntity;
|
||||
use crate::modules::oauth2::token::OAuth2AccessToken;
|
||||
use crate::modules::settings::proxy::Proxy;
|
||||
use crate::modules::settings::system::SystemSetting;
|
||||
use crate::modules::token::AccessTokenModel;
|
||||
use crate::modules::users::role::UserRole;
|
||||
use crate::modules::users::{BichonUser, BichonUserV2};
|
||||
use crate::account::migration::{AccountV1, AccountV2, AccountV3, AccountV4};
|
||||
use crate::autoconfig::CachedMailSettings;
|
||||
use crate::common::paginated::Paginated;
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::oauth2::entity::OAuth2;
|
||||
use crate::oauth2::pending::OAuth2PendingEntity;
|
||||
use crate::oauth2::token::OAuth2AccessToken;
|
||||
use crate::settings::proxy::Proxy;
|
||||
use crate::settings::system::SystemSetting;
|
||||
use crate::token::AccessTokenModel;
|
||||
use crate::users::role::UserRole;
|
||||
use crate::users::{BichonUser, BichonUserV2};
|
||||
use crate::raise_error;
|
||||
use db_type::{KeyOptions, ToKeyDefinition};
|
||||
use itertools::Itertools;
|
||||
@@ -503,30 +504,3 @@ pub fn secondary_find_impl<T: ToInput + Clone + Send + 'static>(
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
Ok(entities)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Paginated<T> {
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
pub total_items: u64,
|
||||
pub total_pages: Option<u64>,
|
||||
pub items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Paginated<T> {
|
||||
pub fn new(
|
||||
page: Option<u64>,
|
||||
page_size: Option<u64>,
|
||||
total_items: u64,
|
||||
total_pages: Option<u64>,
|
||||
items: Vec<T>,
|
||||
) -> Self {
|
||||
Paginated {
|
||||
page,
|
||||
page_size,
|
||||
total_items,
|
||||
total_pages,
|
||||
items,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,18 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::common::AddrVec;
|
||||
use crate::modules::envelope::utils::normalize_subject;
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::message::content::AttachmentInfo;
|
||||
use crate::modules::store::storage::{DetachedEmail, BLOB_MANAGER};
|
||||
use crate::modules::store::tantivy::attachment::ATTACHMENT_MANAGER;
|
||||
use crate::modules::store::tantivy::envelope::ENVELOPE_MANAGER;
|
||||
use crate::modules::store::tantivy::model::{AttachmentModel, EnvelopeWithAttachments};
|
||||
use crate::modules::utils::html::extract_text;
|
||||
use crate::modules::utils::{compute_content_hash, hex_hash};
|
||||
use crate::{id, modules::store::envelope::Envelope};
|
||||
use crate::common::AddrVec;
|
||||
use crate::envelope::utils::normalize_subject;
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::message::content::AttachmentInfo;
|
||||
use crate::store::storage::{DetachedEmail, BLOB_MANAGER};
|
||||
use crate::store::tantivy::attachment::ATTACHMENT_MANAGER;
|
||||
use crate::store::tantivy::envelope::ENVELOPE_MANAGER;
|
||||
use crate::store::tantivy::model::{AttachmentModel, EnvelopeWithAttachments};
|
||||
use crate::utils::html::extract_text;
|
||||
use crate::utils::{compute_content_hash, hex_hash};
|
||||
use crate::{id, store::envelope::Envelope};
|
||||
use crate::{raise_error, utc_now};
|
||||
use async_imap::types::Fetch;
|
||||
use bytes::Bytes;
|
||||
@@ -90,7 +90,7 @@ pub fn normalize_subject(raw_subject: Option<&str>) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::modules::envelope::utils::merge_contiguous_encoded_words;
|
||||
use crate::envelope::utils::merge_contiguous_encoded_words;
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
@@ -0,0 +1,44 @@
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(u32)]
|
||||
pub enum ErrorCode {
|
||||
// Client-side errors (10000–10999)
|
||||
InvalidParameter = 10000,
|
||||
MissingConfiguration = 10020,
|
||||
Incompatible = 10030,
|
||||
PayloadTooLarge = 10070,
|
||||
RequestTimeout = 10080,
|
||||
MethodNotAllowed = 10090,
|
||||
|
||||
// Authentication and authorization errors (20000–20999)
|
||||
PermissionDenied = 20000,
|
||||
AccountDisabled = 20010,
|
||||
Forbidden = 20020,
|
||||
OAuth2ItemDisabled = 20050,
|
||||
MissingRefreshToken = 20060,
|
||||
|
||||
// Resource errors (30000–30999)
|
||||
ResourceNotFound = 30000,
|
||||
TooManyRequest = 30020,
|
||||
AlreadyExists = 30030,
|
||||
|
||||
// Network connection errors (40000–40999)
|
||||
NetworkError = 40000,
|
||||
ConnectionTimeout = 40010,
|
||||
ConnectionPoolTimeout = 40020,
|
||||
HttpResponseError = 40030,
|
||||
|
||||
// Mail service errors (50000–50999)
|
||||
ImapCommandFailed = 50000,
|
||||
ImapAuthenticationFailed = 50010,
|
||||
ImapUnexpectedResult = 50020,
|
||||
AutoconfigFetchFailed = 50060,
|
||||
// Internal system errors (70000–70999)
|
||||
InternalError = 70000,
|
||||
UnhandledPoemError = 70010,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
pub fn to_u32(&self) -> u32 {
|
||||
*self as u32
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use snafu::{Location, Snafu};
|
||||
|
||||
use crate::error::code::ErrorCode;
|
||||
|
||||
pub mod code;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
pub enum BichonError {
|
||||
#[snafu(display("{message}"))]
|
||||
Generic {
|
||||
message: String,
|
||||
#[snafu(implicit)]
|
||||
location: Location,
|
||||
code: ErrorCode,
|
||||
},
|
||||
}
|
||||
|
||||
pub type BichonResult<T, E = BichonError> = std::result::Result<T, E>;
|
||||
@@ -16,9 +16,9 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::{modules::error::BichonResult, raise_error};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::imap::session::SessionStream;
|
||||
use crate::{error::BichonResult, raise_error};
|
||||
use async_imap::types::Capability;
|
||||
use async_imap::{types::Capabilities, Session};
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::entity::Encryption;
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::modules::imap::stats::StatsWrapper;
|
||||
use crate::modules::utils::net::establish_tcp_connection_with_timeout;
|
||||
use crate::modules::utils::net::establish_tls_connection;
|
||||
use crate::modules::utils::tls::establish_tls_stream;
|
||||
use crate::account::entity::Encryption;
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::imap::session::SessionStream;
|
||||
use crate::imap::stats::StatsWrapper;
|
||||
use crate::utils::net::establish_tcp_connection_with_timeout;
|
||||
use crate::utils::net::establish_tls_connection;
|
||||
use crate::utils::tls::establish_tls_stream;
|
||||
use crate::raise_error;
|
||||
use async_imap::Client as ImapClient;
|
||||
use async_imap::Session as ImapSession;
|
||||
@@ -16,14 +16,14 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::migration::AccountModel;
|
||||
use crate::modules::account::state::{DownloadState, FolderStatus};
|
||||
use crate::modules::cache::imap::mailbox::MailBox;
|
||||
use crate::modules::cache::imap::download::flow::{generate_uid_sequence_hashset, DEFAULT_BATCH_SIZE};
|
||||
use crate::modules::envelope::extractor::extract_envelope_and_store_it;
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::modules::{error::BichonResult, imap::manager::ImapConnectionManager};
|
||||
use crate::account::migration::AccountModel;
|
||||
use crate::account::state::{DownloadState, FolderStatus};
|
||||
use crate::cache::imap::mailbox::MailBox;
|
||||
use crate::cache::imap::download::flow::{generate_uid_sequence_hashset, DEFAULT_BATCH_SIZE};
|
||||
use crate::envelope::extractor::extract_envelope_and_store_it;
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::imap::session::SessionStream;
|
||||
use crate::{error::BichonResult, imap::manager::ImapConnectionManager};
|
||||
use crate::raise_error;
|
||||
use async_imap::types::Name;
|
||||
use async_imap::Session;
|
||||
@@ -16,17 +16,17 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::entity::AuthType;
|
||||
use crate::modules::account::migration::{AccountModel, AccountType};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::imap::capabilities::{
|
||||
use crate::account::entity::AuthType;
|
||||
use crate::account::migration::{AccountModel, AccountType};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::imap::capabilities::{
|
||||
capability_to_string, check_capabilities, fetch_capabilities,
|
||||
};
|
||||
use crate::modules::imap::client::Client;
|
||||
use crate::modules::imap::oauth2::OAuth2;
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::modules::oauth2::token::OAuth2AccessToken;
|
||||
use crate::imap::client::Client;
|
||||
use crate::imap::oauth2::OAuth2;
|
||||
use crate::imap::session::SessionStream;
|
||||
use crate::oauth2::token::OAuth2AccessToken;
|
||||
use crate::{bichon_version, decrypt, raise_error};
|
||||
use async_imap::Session;
|
||||
use tracing::{error, warn};
|
||||
@@ -23,7 +23,7 @@ use std::task::{Context, Poll};
|
||||
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::imap::session::SessionStream;
|
||||
|
||||
pub struct StatsWrapper<T> {
|
||||
inner: T,
|
||||
@@ -20,7 +20,7 @@ use mail_parser::{parsers::MessageStream, MessageParser, MimeHeaders};
|
||||
|
||||
use crate::{
|
||||
base64_encode_url_safe,
|
||||
modules::{account::entity::Encryption, imap::client::Client},
|
||||
{account::entity::Encryption, imap::client::Client},
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -17,12 +17,12 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
base64_decode_url_safe,
|
||||
modules::{
|
||||
{
|
||||
account::migration::{AccountModel, AccountType},
|
||||
cache::imap::mailbox::{Attribute, AttributeEnum, MailBox},
|
||||
envelope::extractor::extract_envelope_from_eml,
|
||||
@@ -32,7 +32,8 @@ use crate::{
|
||||
raise_error,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct BatchEmlRequest {
|
||||
pub account_id: u64,
|
||||
pub mail_folder: String,
|
||||
@@ -40,7 +41,8 @@ pub struct BatchEmlRequest {
|
||||
pub emls: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct FailedEmlDetail {
|
||||
/// The 0-based index of the failed EML in the request list
|
||||
pub index: usize,
|
||||
@@ -48,7 +50,8 @@ pub struct FailedEmlDetail {
|
||||
pub error_message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct BatchEmlResult {
|
||||
/// Total number of emails processed
|
||||
pub total: usize,
|
||||
@@ -0,0 +1,23 @@
|
||||
pub mod account;
|
||||
pub mod admin;
|
||||
pub mod autoconfig;
|
||||
pub mod cache;
|
||||
pub mod common;
|
||||
pub mod context;
|
||||
pub mod dashboard;
|
||||
pub mod database;
|
||||
pub mod envelope;
|
||||
pub mod error;
|
||||
pub mod imap;
|
||||
pub mod import;
|
||||
pub mod logger;
|
||||
pub mod mailbox;
|
||||
pub mod message;
|
||||
pub mod oauth2;
|
||||
pub mod settings;
|
||||
pub mod store;
|
||||
pub mod tasks;
|
||||
pub mod token;
|
||||
pub mod users;
|
||||
pub mod utils;
|
||||
pub mod version;
|
||||
@@ -16,9 +16,9 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::logger::LocalTimer;
|
||||
use crate::modules::settings::cli::SETTINGS;
|
||||
use crate::modules::settings::dir::DATA_DIR_MANAGER;
|
||||
use crate::logger::LocalTimer;
|
||||
use crate::settings::cli::SETTINGS;
|
||||
use crate::settings::dir::DATA_DIR_MANAGER;
|
||||
use std::sync::OnceLock;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing::Level;
|
||||
@@ -16,8 +16,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::logger::file::setup_file_logger;
|
||||
use crate::modules::settings::cli::SETTINGS;
|
||||
use crate::logger::file::setup_file_logger;
|
||||
use crate::settings::cli::SETTINGS;
|
||||
use chrono::Local;
|
||||
use std::process;
|
||||
use tracing::Level;
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
cache::imap::mailbox::MailBox,
|
||||
error::BichonResult,
|
||||
store::tantivy::{attachment::ATTACHMENT_MANAGER, envelope::ENVELOPE_MANAGER},
|
||||
@@ -16,13 +16,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::account::migration::{AccountModel, AccountType};
|
||||
use crate::modules::cache::imap::mailbox::{Attribute, AttributeEnum, MailBox};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::imap::executor::ImapExecutor;
|
||||
use crate::modules::imap::session::SessionStream;
|
||||
use crate::modules::utils::create_hash;
|
||||
use crate::account::migration::{AccountModel, AccountType};
|
||||
use crate::cache::imap::mailbox::{Attribute, AttributeEnum, MailBox};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::imap::executor::ImapExecutor;
|
||||
use crate::imap::session::SessionStream;
|
||||
use crate::utils::create_hash;
|
||||
use crate::raise_error;
|
||||
use async_imap::types::Name;
|
||||
use async_imap::Session;
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
encode_mailbox_name,
|
||||
modules::{
|
||||
{
|
||||
account::migration::{AccountModel, AccountType},
|
||||
envelope::extractor::reattach_eml_content,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
@@ -8,12 +8,13 @@ use crate::{
|
||||
},
|
||||
raise_error,
|
||||
};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const MAX_RESTORE_COUNT: usize = 100;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct RestoreMessagesRequest {
|
||||
/// envelope IDs to restore (max 100)
|
||||
pub envelope_ids: Vec<String>,
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
dashboard::Group,
|
||||
envelope::extractor::reattach_eml_content,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
@@ -11,10 +11,11 @@ use crate::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use mail_parser::MessageParser;
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AttachmentMetadata {
|
||||
/// Statistics of attachment file extensions (key + count).
|
||||
/// Each item represents a file extension and its occurrence count.
|
||||
@@ -1,7 +1,7 @@
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct Contact {
|
||||
pub email: String,
|
||||
pub name: Option<String>,
|
||||
@@ -17,23 +17,24 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::base64_encode;
|
||||
use crate::modules::account::migration::AccountModel;
|
||||
use crate::modules::envelope::extractor::{
|
||||
use crate::account::migration::AccountModel;
|
||||
use crate::envelope::extractor::{
|
||||
extract_envelope_from_nested_message, reattach_eml_content,
|
||||
};
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::store::envelope::Envelope;
|
||||
use crate::modules::utils::compute_content_hash;
|
||||
use crate::{modules::error::BichonResult, raise_error};
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::store::envelope::Envelope;
|
||||
use crate::utils::compute_content_hash;
|
||||
use crate::{error::BichonResult, raise_error};
|
||||
use mail_parser::{MessageParser, MimeHeaders};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
/// Represents metadata of an attachment in a Gmail message.
|
||||
///
|
||||
/// This struct stores information required to identify, download,
|
||||
/// and render an attachment, including inline images embedded
|
||||
/// in HTML emails.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AttachmentInfo {
|
||||
/// MIME content type of the attachment (e.g., `image/png`, `application/pdf`).
|
||||
pub file_type: String,
|
||||
@@ -134,7 +135,8 @@ impl AttachmentInfo {
|
||||
///
|
||||
/// - `plain`: The plain text version of the message, if available.
|
||||
/// - `html`: The HTML version of the message, if available.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct FullMessageContent {
|
||||
/// Optional plain text version of the message.
|
||||
pub text: Option<String>,
|
||||
@@ -144,7 +146,8 @@ pub struct FullMessageContent {
|
||||
pub attachments: Option<Vec<AttachmentInfo>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct FullNestedMessageContent {
|
||||
/// Optional plain text version of the message.
|
||||
pub text: Option<String>,
|
||||
@@ -16,9 +16,9 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::store::tantivy::attachment::ATTACHMENT_MANAGER;
|
||||
use crate::modules::store::tantivy::envelope::ENVELOPE_MANAGER;
|
||||
use crate::error::BichonResult;
|
||||
use crate::store::tantivy::attachment::ATTACHMENT_MANAGER;
|
||||
use crate::store::tantivy::envelope::ENVELOPE_MANAGER;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub async fn delete_messages_impl(request: HashMap<u64, Vec<String>>) -> BichonResult<()> {
|
||||
@@ -16,11 +16,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
account::migration::AccountModel,
|
||||
error::BichonResult,
|
||||
rest::response::DataPage,
|
||||
store::{envelope::Envelope, tantivy::envelope::ENVELOPE_MANAGER},
|
||||
use crate::{
|
||||
account::migration::AccountModel, common::paginated::DataPage, error::BichonResult, store::{envelope::Envelope, tantivy::envelope::ENVELOPE_MANAGER}
|
||||
};
|
||||
|
||||
pub async fn get_thread_messages(
|
||||
@@ -16,25 +16,21 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use poem_openapi::{Enum, Object};
|
||||
//use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
rest::response::DataPage,
|
||||
store::{
|
||||
common::paginated::DataPage, error::{BichonResult, code::ErrorCode}, raise_error, store::{
|
||||
envelope::Envelope,
|
||||
tantivy::{
|
||||
attachment::ATTACHMENT_MANAGER, envelope::ENVELOPE_MANAGER, model::AttachmentModel,
|
||||
},
|
||||
},
|
||||
},
|
||||
raise_error,
|
||||
}
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct EmailSearchFilter {
|
||||
pub text: Option<String>,
|
||||
pub subject: Option<String>,
|
||||
@@ -59,14 +55,16 @@ pub struct EmailSearchFilter {
|
||||
pub attachment_content_type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Enum)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum SortBy {
|
||||
#[default]
|
||||
DATE,
|
||||
SIZE,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct EmailSearchRequest {
|
||||
filter: EmailSearchFilter,
|
||||
page: u64,
|
||||
@@ -110,7 +108,8 @@ pub async fn search_messages_impl(
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AttachmentSearchFilter {
|
||||
pub id: Option<String>,
|
||||
pub text: Option<String>,
|
||||
@@ -139,7 +138,8 @@ pub struct AttachmentSearchFilter {
|
||||
pub max_page_count: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AttachmentSearchRequest {
|
||||
filter: AttachmentSearchFilter,
|
||||
page: u64,
|
||||
@@ -18,23 +18,26 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use poem_openapi::{Enum, Object};
|
||||
//use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct TagsRequest {
|
||||
pub updates: HashMap<u64, Vec<String>>,
|
||||
pub tags: Vec<String>,
|
||||
pub action: TagAction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct TagCount {
|
||||
pub tag: String,
|
||||
pub count: u64,
|
||||
}
|
||||
|
||||
#[derive(Enum, Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Enum))]
|
||||
pub enum TagAction {
|
||||
Add,
|
||||
Remove,
|
||||
@@ -17,25 +17,24 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
encrypt, id,
|
||||
modules::{
|
||||
database::{
|
||||
async_secondary_find_impl, delete_impl, insert_impl, manager::DB_MANAGER,
|
||||
paginate_query_primary_scan_all_impl, update_impl,
|
||||
},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
rest::response::DataPage,
|
||||
common::paginated::DataPage,
|
||||
database::{
|
||||
async_secondary_find_impl, delete_impl, insert_impl, manager::DB_MANAGER,
|
||||
paginate_query_primary_scan_all_impl, update_impl,
|
||||
},
|
||||
raise_error, utc_now,
|
||||
encrypt,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
id, raise_error, utc_now,
|
||||
};
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Represents the OAuth2 configuration for a client, including initialization and runtime values.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 5, version = 1)]
|
||||
#[native_db(primary_key(pk -> String))]
|
||||
pub struct OAuth2 {
|
||||
@@ -175,7 +174,8 @@ impl OAuth2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct OAuth2CreateRequest {
|
||||
/// A description of what this configuration is used for.
|
||||
pub description: Option<String>,
|
||||
@@ -225,7 +225,8 @@ impl OAuth2CreateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct OAuth2UpdateRequest {
|
||||
/// A description of what this configuration is used for.
|
||||
pub description: Option<String>,
|
||||
@@ -17,18 +17,18 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::error::BichonResult;
|
||||
use crate::modules::oauth2::{
|
||||
use crate::error::code::ErrorCode;
|
||||
use crate::error::BichonResult;
|
||||
use crate::oauth2::{
|
||||
entity::OAuth2, pending::OAuth2PendingEntity, token::OAuth2AccessToken,
|
||||
};
|
||||
use crate::modules::settings::proxy::Proxy;
|
||||
use crate::settings::proxy::Proxy;
|
||||
use crate::{decrypt, encrypt, raise_error};
|
||||
use oauth2::{
|
||||
basic::BasicClient, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken,
|
||||
PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenResponse, TokenUrl,
|
||||
};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type OAuth2Client = oauth2::Client<
|
||||
@@ -47,7 +47,8 @@ pub type OAuth2Client = oauth2::Client<
|
||||
oauth2::EndpointSet,
|
||||
>;
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct AuthorizeUrlRequest {
|
||||
/// The ID of the account for which the authorization URL is generated.
|
||||
pub account_id: u64,
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
{
|
||||
database::{
|
||||
batch_delete_impl, delete_impl, async_find_impl, insert_impl, manager::DB_MANAGER,
|
||||
},
|
||||
@@ -16,10 +16,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::common::periodic::{PeriodicTask, TaskHandle};
|
||||
use crate::modules::context::BichonTask;
|
||||
use crate::modules::oauth2::token::EXTERNAL_OAUTH_APP_ID;
|
||||
use crate::modules::oauth2::{flow::OAuth2Flow, token::OAuth2AccessToken};
|
||||
use crate::common::periodic::{PeriodicTask, TaskHandle};
|
||||
use crate::context::BichonTask;
|
||||
use crate::oauth2::token::EXTERNAL_OAUTH_APP_ID;
|
||||
use crate::oauth2::{flow::OAuth2Flow, token::OAuth2AccessToken};
|
||||
use crate::utc_now;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, error, info};
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
common::periodic::{PeriodicTask, TaskHandle},
|
||||
context::BichonTask,
|
||||
oauth2::pending::OAuth2PendingEntity,
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
use crate::{
|
||||
decrypt, encrypt,
|
||||
modules::{
|
||||
{
|
||||
database::{
|
||||
async_find_impl, delete_impl, insert_impl, list_all_impl, manager::DB_MANAGER,
|
||||
update_impl, upsert_impl,
|
||||
@@ -31,12 +31,13 @@ use crate::{
|
||||
};
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const EXTERNAL_OAUTH_APP_ID: u64 = 0;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 7, version = 1)]
|
||||
#[native_db]
|
||||
pub struct OAuth2AccessToken {
|
||||
@@ -195,7 +196,8 @@ impl OAuth2AccessToken {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct ExternalOAuth2Request {
|
||||
/// The id of the OAuth2 configuration associated with this access token.
|
||||
pub oauth2_id: Option<u64>,
|
||||
@@ -245,7 +247,7 @@ impl ExternalOAuth2Request {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::modules::oauth2::token::OAuth2AccessToken;
|
||||
use crate::oauth2::token::OAuth2AccessToken;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test1() {
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::settings::io::check_dir_read_write;
|
||||
use crate::settings::io::check_dir_read_write;
|
||||
use clap::{builder::ValueParser, Parser, ValueEnum};
|
||||
use std::{collections::HashSet, env, fmt, path::PathBuf, sync::LazyLock};
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::context::Initialize;
|
||||
use crate::modules::settings::cli::SETTINGS;
|
||||
use crate::context::Initialize;
|
||||
use crate::settings::cli::SETTINGS;
|
||||
use crate::{
|
||||
modules::error::{code::ErrorCode, BichonResult},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
raise_error,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
@@ -16,8 +16,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::settings::cli::Settings;
|
||||
use poem_openapi::Object;
|
||||
use crate::settings::cli::Settings;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod cli;
|
||||
@@ -25,7 +25,8 @@ pub mod dir;
|
||||
pub mod io;
|
||||
pub mod proxy;
|
||||
pub mod system;
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct SystemConfigurations {
|
||||
pub bichon_log_level: String,
|
||||
pub bichon_http_port: i32,
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
id,
|
||||
modules::{
|
||||
{
|
||||
database::{
|
||||
async_find_impl, delete_impl, insert_impl, list_all_impl, manager::DB_MANAGER,
|
||||
update_impl,
|
||||
@@ -34,7 +34,8 @@ use crate::{
|
||||
raise_error, utc_now,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
#[native_model(id = 8, version = 1)]
|
||||
#[native_db]
|
||||
pub struct Proxy {
|
||||
@@ -16,11 +16,6 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
// use crate::modules::database::manager::DB_MANAGER;
|
||||
// use crate::modules::database::{find_impl, upsert_impl};
|
||||
// use crate::modules::error::BichonResult;
|
||||
// use crate::utc_now;
|
||||
use native_db::*;
|
||||
use native_model::{native_model, Model};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -16,11 +16,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use poem_openapi::Object;
|
||||
//use poem_openapi::Object;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tantivy::doc;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
|
||||
pub struct Envelope {
|
||||
pub id: String,
|
||||
pub message_id: String,
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::modules::{
|
||||
use crate::{
|
||||
common::signal::SIGNAL_MANAGER,
|
||||
envelope::extractor::reattach_eml_content,
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
+4
-13
@@ -25,28 +25,19 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
common::signal::SIGNAL_MANAGER,
|
||||
dashboard::{Group, LargestAttachment},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
message::{
|
||||
common::{paginated::DataPage, signal::SIGNAL_MANAGER}, dashboard::{Group, LargestAttachment}, error::{BichonResult, code::ErrorCode}, message::{
|
||||
attachment::AttachmentMetadata,
|
||||
search::{AttachmentSearchFilter, SortBy},
|
||||
tags::{TagAction, TagCount, TagsRequest},
|
||||
},
|
||||
rest::response::DataPage,
|
||||
settings::dir::DATA_DIR_MANAGER,
|
||||
store::tantivy::{
|
||||
}, raise_error, settings::dir::DATA_DIR_MANAGER, store::tantivy::{
|
||||
fatal_commit,
|
||||
fields::{
|
||||
F_ATTACHMENT_CATEGORY, F_ATTACHMENT_CONTENT_TYPE, F_ATTACHMENT_EXT, F_DATE, F_SIZE,
|
||||
F_TAGS,
|
||||
},
|
||||
model::{extract_senders, AttachmentModel},
|
||||
model::{AttachmentModel, extract_senders},
|
||||
schema::SchemaTools,
|
||||
},
|
||||
},
|
||||
raise_error,
|
||||
}
|
||||
};
|
||||
|
||||
use serde_json::json;
|
||||
@@ -25,18 +25,10 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
modules::{
|
||||
account::migration::AccountModel,
|
||||
common::signal::SIGNAL_MANAGER,
|
||||
dashboard::{DashboardStats, Group, LargestEmail, TimeBucket},
|
||||
error::{code::ErrorCode, BichonResult},
|
||||
message::{
|
||||
account::migration::AccountModel, common::{paginated::DataPage, signal::SIGNAL_MANAGER}, dashboard::{DashboardStats, Group, LargestEmail, TimeBucket}, error::{BichonResult, code::ErrorCode}, message::{
|
||||
search::{EmailSearchFilter, SortBy},
|
||||
tags::{TagAction, TagCount, TagsRequest},
|
||||
},
|
||||
rest::response::DataPage,
|
||||
settings::dir::DATA_DIR_MANAGER,
|
||||
store::{
|
||||
}, raise_error, settings::dir::DATA_DIR_MANAGER, store::{
|
||||
envelope::Envelope,
|
||||
storage::BLOB_MANAGER,
|
||||
tantivy::{
|
||||
@@ -45,12 +37,10 @@ use crate::{
|
||||
F_ACCOUNT_ID, F_DATE, F_FROM, F_REGULAR_ATTACHMENT_COUNT, F_SIZE, F_TAGS,
|
||||
F_THREAD_ID, F_UID,
|
||||
},
|
||||
model::{extract_contacts, EnvelopeWithAttachments},
|
||||
model::{EnvelopeWithAttachments, extract_contacts},
|
||||
schema::SchemaTools,
|
||||
},
|
||||
},
|
||||
},
|
||||
raise_error, utc_now,
|
||||
}, utc_now
|
||||
};
|
||||
|
||||
use chrono::Utc;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user