// // Copyright (c) 2025 rustmailer.com (https://rustmailer.com) // // This file is part of the Bichon Email Archiving Project // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use crate::modules::common::auth::ClientContext; use crate::modules::dashboard::DashboardStats; use crate::modules::error::code::ErrorCode; use crate::modules::rest::api::ApiTags; use crate::modules::rest::ApiResult; use crate::modules::settings::cli::SETTINGS; use crate::modules::settings::proxy::Proxy; use crate::modules::settings::SystemConfigurations; use crate::modules::users::permissions::Permission; use crate::modules::version::{fetch_notifications, Notifications}; use crate::raise_error; use poem_openapi::param::Path; use poem_openapi::payload::{Json, PlainText}; use poem_openapi::OpenApi; pub struct SystemApi; #[OpenApi(prefix_path = "/api/v1", tag = "ApiTags::System")] impl SystemApi { /// Retrieves important system notifications for the RustMail service. /// /// This endpoint returns a consolidated view of all critical system notifications including: /// - Available version updates /// - License expiration warnings #[oai( method = "get", path = "/notifications", operation_id = "get_notifications" )] async fn get_notifications(&self) -> ApiResult> { let notification = fetch_notifications() .await .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; Ok(Json(notification)) } /// Get overall dashboard statistics. /// /// Returns various aggregated metrics about the mail system, such as /// total email count, total storage size, index usage, top senders, /// recent activity histogram, and more. #[oai( method = "get", path = "/dashboard-stats", operation_id = "get_dashboard_stats" )] async fn get_dashboard_stats(&self, context: ClientContext) -> ApiResult> { let stats = DashboardStats::get(context).await?; Ok(Json(stats)) } /// Get the full list of SOCKS5 proxy configurations. #[oai(method = "get", path = "/list-proxy", operation_id = "list_proxy")] async fn list_proxy(&self, context: ClientContext) -> ApiResult>> { context .require_any_permission(vec![ (None, Permission::ACCOUNT_CREATE), (None, Permission::ROOT), ]) .await?; let proxies = Proxy::list_all() .await .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; Ok(Json(proxies)) } /// Delete a specific proxy configuration by ID. Requires root permission. #[oai(path = "/proxy/:id", method = "delete", operation_id = "remove_proxy")] async fn remove_proxy( &self, /// The ID of the proxy configuration to delete. id: Path, context: ClientContext, ) -> ApiResult<()> { context .require_permission(None, Permission::ROOT) .await?; Ok(Proxy::delete(id.0).await?) } /// Retrieve a specific proxy configuration by ID. Requires root permission. #[oai(path = "/proxy/:id", method = "get", operation_id = "get_proxy")] async fn get_proxy( &self, /// The ID of the proxy configuration to retrieve. id: Path, context: ClientContext, ) -> ApiResult> { context .require_permission(None, Permission::ROOT) .await?; Ok(Json(Proxy::get(id.0).await?)) } /// Create a new proxy configuration. Requires root permission. #[oai(path = "/proxy", method = "post", operation_id = "create_proxy")] async fn create_proxy(&self, url: PlainText, context: ClientContext) -> ApiResult<()> { context .require_permission(None, Permission::ROOT) .await?; let entity = Proxy::new(url.0); Ok(entity.save().await?) } /// Update the URL of a specific proxy by ID. Requires root permission. #[oai(path = "/proxy/:id", method = "post", operation_id = "update_proxy")] async fn update_proxy( &self, id: Path, url: PlainText, context: ClientContext, ) -> ApiResult<()> { context .require_permission(None, Permission::ROOT) .await?; Ok(Proxy::update(id.0, url.0).await?) } /// Get system configurations. /// /// Returns a read-only snapshot of the server configuration /// resolved at startup. Sensitive values are not exposed. #[oai( method = "get", path = "/system-configurations", operation_id = "get_system_configurations" )] async fn get_system_configurations( &self, context: ClientContext, ) -> ApiResult> { context .require_permission(None, Permission::ROOT) .await?; let config: SystemConfigurations = SystemConfigurations::from(&*SETTINGS); Ok(Json(config)) } }