refactor(all): Remove unused code and update dependencies in multiple modules

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-03-08 21:51:28 -03:00
parent 3291266a42
commit 42fcd9398e
18 changed files with 192 additions and 324 deletions

121
Cargo.lock generated
View file

@ -74,6 +74,24 @@ dependencies = [
"syn 2.0.99",
]
[[package]]
name = "actix-multipart"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9edfb0e7663d7fe18c8d5b668c9c1bcf79176b1dcc9d4da9592503209a6bfb0"
dependencies = [
"actix-utils",
"actix-web",
"bytes",
"derive_more",
"futures-core",
"httparse",
"local-waker",
"log",
"mime",
"twoway",
]
[[package]]
name = "actix-router"
version = "0.5.3"
@ -2096,6 +2114,12 @@ dependencies = [
"zip",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dotenvy"
version = "0.15.7"
@ -2206,6 +2230,22 @@ dependencies = [
"zeroize",
]
[[package]]
name = "email-encoding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a87260449b06739ee78d6281c68d2a0ff3e3af64a78df63d3a1aeb3c06997c8a"
dependencies = [
"base64 0.22.1",
"memchr",
]
[[package]]
name = "email_address"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
[[package]]
name = "encoding_rs"
version = "0.8.35"
@ -2698,6 +2738,8 @@ dependencies = [
"async-trait",
"axum 0.7.9",
"chrono",
"jsonwebtoken",
"lettre",
"minio",
"mockall",
"rdkafka",
@ -2741,11 +2783,16 @@ dependencies = [
name = "gb-file"
version = "0.1.0"
dependencies = [
"actix-multipart",
"actix-web",
"async-trait",
"futures 0.3.31",
"gb-core",
"jsonwebtoken",
"lettre",
"minio",
"rstest",
"sanitize-filename",
"serde",
"serde_json",
"tempfile",
@ -2753,6 +2800,7 @@ dependencies = [
"tokio",
"tokio-test",
"tracing",
"uuid",
]
[[package]]
@ -2869,6 +2917,7 @@ dependencies = [
"async-trait",
"axum 0.7.9",
"chrono",
"dotenv",
"futures-util",
"gb-core",
"gb-file",
@ -3489,6 +3538,17 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "http"
version = "0.2.12"
@ -4182,6 +4242,29 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "lettre"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76bd09637ae3ec7bd605b8e135e757980b3968430ff2b1a4a94fb7769e50166d"
dependencies = [
"base64 0.21.7",
"email-encoding",
"email_address",
"fastrand 1.9.0",
"futures-util",
"hostname",
"httpdate",
"idna 0.3.0",
"mime",
"native-tls",
"nom 7.1.3",
"once_cell",
"quoted_printable",
"socket2 0.4.10",
"tokio",
]
[[package]]
name = "libc"
version = "0.2.170"
@ -4312,6 +4395,12 @@ dependencies = [
"weezl",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matchers"
version = "0.1.0"
@ -5986,6 +6075,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "quoted_printable"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3866219251662ec3b26fc217e3e05bf9c4f84325234dfb96bf0bf840889e49"
[[package]]
name = "rand"
version = "0.7.3"
@ -6696,6 +6791,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "sanitize-filename"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf18934a12018228c5b55a6dae9df5d0641e3566b3630cb46cc55564068e7c2f"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "schannel"
version = "0.1.27"
@ -8290,12 +8395,28 @@ dependencies = [
"webrtc-util",
]
[[package]]
name = "twoway"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47"
dependencies = [
"memchr",
"unchecked-index",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unchecked-index"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
[[package]]
name = "unicase"
version = "2.8.1"

View file

@ -46,6 +46,8 @@ tower-http = { version = "0.5", features = ["cors", "trace", "fs"] }
hyper = { version = "1.1", features = ["full"] }
hyper-util = { version = "0.1" }
tonic = { version = "0.10", features = ["tls", "transport"] }
actix-multipart = "0.4"
# Database and storage
sqlx = { version = "0.7", features = ["runtime-tokio-native-tls", "postgres", "mysql", "sqlite", "uuid", "time", "json"] }
@ -111,6 +113,9 @@ base64 = "0.21"
semver = "1.0"
walkdir = "2.4"
tempfile = "3.9"
dotenv = "0.15"
lettre = "0.10"
sanitize-filename = "0.3"
# Web assembly
wasm-bindgen = "0.2"

View file

@ -9,7 +9,7 @@ license = { workspace = true }
gb-core = { path = "../gb-core" }
# Authentication & Security
jsonwebtoken = "9.2"
jsonwebtoken = { workspace = true }
argon2 = "0.5"
rand = { version = "0.8", features = ["std"] }
oauth2 = "4.4"

View file

@ -24,6 +24,8 @@ rdkafka = { workspace = true }
tonic = { workspace = true }
actix-web ={ workspace = true }
anyhow = { workspace = true }
jsonwebtoken = { workspace = true }
lettre= { workspace = true }
[dev-dependencies]
mockall= { workspace = true }

View file

@ -7,7 +7,7 @@ pub struct AppConfig {
pub database: DatabaseConfig,
pub redis: RedisConfig,
pub kafka: KafkaConfig,
pub zitadel: ZitadelConfig,
// pub zitadel: ZitadelConfig,
pub minio: MinioConfig,
pub email: EmailConfig,
}
@ -39,6 +39,7 @@ pub struct ZitadelConfig {
pub domain: String,
pub client_id: String,
pub client_secret: String,
pub access_token: String,
}
#[derive(Clone, Debug, Deserialize)]
@ -82,12 +83,12 @@ impl AppConfig {
kafka: KafkaConfig {
brokers: env::var("KAFKA_BROKERS").expect("KAFKA_BROKERS must be set"),
},
zitadel: ZitadelConfig {
domain: env::var("ZITADEL_DOMAIN").expect("ZITADEL_DOMAIN must be set"),
client_id: env::var("ZITADEL_CLIENT_ID").expect("ZITADEL_CLIENT_ID must be set"),
client_secret: env::var("ZITADEL_CLIENT_SECRET")
.expect("ZITADEL_CLIENT_SECRET must be set"),
},
// zitadel: ZitadelConfig {
// domain: env::var("ZITADEL_DOMAIN").expect("ZITADEL_DOMAIN must be set"),
// client_id: env::var("ZITADEL_CLIENT_ID").expect("ZITADEL_CLIENT_ID must be set"),
// client_secret: env::var("ZITADEL_CLIENT_SECRET")
// .expect("ZITADEL_CLIENT_SECRET must be set"),
// },
minio: MinioConfig {
endpoint: env::var("MINIO_ENDPOINT").expect("MINIO_ENDPOINT must be set"),
access_key: env::var("MINIO_ACCESS_KEY").expect("MINIO_ACCESS_KEY must be set"),

View file

@ -1,29 +1,31 @@
use crate::config::AppConfig;
use anyhow::Result;
use rdkafka::ClientConfig;
use rdkafka::producer::FutureProducer;
use redis::aio::ConnectionManager as RedisConnectionManager;
use sqlx::postgres::{PgPoolOptions, PgPool};
use zitadel::api::clients::ClientBuilder;
use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
use minio::s3::client::{Client as MinioClient, ClientBuilder as MinioClientBuilder};
use minio::s3::creds::StaticProvider;
use minio::s3::http::BaseUrl;
use minio::s3::client::{Client as MinioClient, ClientBuilder as MinioClientBuilder};
use rdkafka::producer::FutureProducer;
use rdkafka::ClientConfig;
use redis::aio::ConnectionManager as RedisConnectionManager;
use sqlx::postgres::{PgPool, PgPoolOptions};
use std::str::FromStr;
use crate::config::AppConfig;
// use zitadel::api::clients::ClientBuilder;
// use zitadel::api::interceptors::AccessTokenInterceptor;
// use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
pub async fn init_postgres(config: &AppConfig) -> Result<PgPool> {
let pool = PgPoolOptions::new()
.max_connections(config.database.max_connections)
.connect(&config.database.url)
.await?;
.await
.map_err(|e| anyhow::anyhow!(e))?;
Ok(pool)
}
pub async fn init_redis(config: &AppConfig) -> Result<RedisConnectionManager> {
let client = redis::Client::open(config.redis.url.as_str())?;
let connection_manager = RedisConnectionManager::new(client).await?;
Ok(connection_manager)
}
@ -32,34 +34,29 @@ pub async fn init_kafka(config: &AppConfig) -> Result<FutureProducer> {
.set("bootstrap.servers", &config.kafka.brokers)
.set("message.timeout.ms", "5000")
.create()?;
Ok(producer)
}
pub async fn init_zitadel(config: &AppConfig) -> Result<AuthServiceClient<tonic::transport::Channel>> {
let mut client = ClientBuilder::new(&config.zitadel.domain)
.with_access_token(&"test")
.build_auth_client()
.await?;
Ok(client)
pub async fn init_zitadel(
config: &AppConfig,
) -> Result<
(),
Box<dyn std::error::Error>>
{
// TODO: https://github.com/smartive/zitadel-rust/blob/be389ca08c7f82d36fc1bcc36d2d9eb8666b22cd/examples/fetch_profile_with_service_account.rs#L18
Ok(())
}
pub async fn init_minio(config: &AppConfig) -> Result<MinioClient, Box<dyn std::error::Error + Send + Sync>> {
pub async fn init_minio(
config: &AppConfig,
) -> Result<MinioClient, Box<dyn std::error::Error + Send + Sync>> {
// Construct the base URL
let base_url = format!("https://{}", config.minio.endpoint);
let base_url = BaseUrl::from_str(&base_url)?;
// Create credentials provider
let credentials = StaticProvider::new(
&config.minio.access_key,
&config.minio.secret_key,
None,
);
let credentials = StaticProvider::new(&config.minio.access_key, &config.minio.secret_key, None);
// Build the MinIO client
let client = MinioClientBuilder::new(base_url.clone())
@ -69,23 +66,3 @@ pub async fn init_minio(config: &AppConfig) -> Result<MinioClient, Box<dyn std::
Ok(client)
}

View file

@ -3,5 +3,7 @@ pub mod errors;
pub mod models;
pub mod traits;
pub mod config;
pub mod utils;
pub use errors::{Error, ErrorKind, Result};
pub use utils::{create_response, extract_user_id};

View file

@ -5,7 +5,7 @@ use redis::aio::ConnectionManager as RedisConnectionManager;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use uuid::Uuid;
use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
//use zitadel::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
use serde_json::Value as JsonValue;
use std::str::FromStr;
@ -245,7 +245,7 @@ pub struct AppState {
pub db_pool: PgPool,
pub redis_pool: RedisConnectionManager,
pub kafka_producer: FutureProducer,
pub zitadel_client: AuthServiceClient<tonic::transport::Channel>,
// pub zitadel_client: AuthServiceClient<tonic::transport::Channel>,
pub minio_client: MinioClient,
}

View file

@ -1,75 +0,0 @@
//! Core traits defining the system interfaces
//! File: gb-core/src/traits.rs
use crate::models::*;
use std::future::Future;
use uuid::Uuid;
use async_trait::async_trait;
#[async_trait]
pub trait InstanceStore {
type Error;
fn create(&self, instance: &Instance) -> impl Future<Output = Result<Instance, Self::Error>> + Send;
fn get(&self, id: Uuid) -> impl Future<Output = Result<Instance, Self::Error>> + Send;
fn list_by_customer(&self, customer_id: Uuid) -> impl Future<Output = Result<Vec<Instance>, Self::Error>> + Send;
fn update(&self, instance: &Instance) -> impl Future<Output = Result<Instance, Self::Error>> + Send;
fn delete(&self, id: Uuid) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn list(&self, page: i32) -> impl Future<Output = Result<Vec<Instance>, Self::Error>> + Send;
}
#[async_trait]
pub trait RoomStore {
type Error;
fn create(&self, room: &Room) -> impl Future<Output = Result<Room, Self::Error>> + Send;
fn get(&self, id: Uuid) -> impl Future<Output = Result<Room, Self::Error>> + Send;
fn list_by_instance(&self, instance_id: Uuid) -> impl Future<Output = Result<Vec<Room>, Self::Error>> + Send;
fn update(&self, room: &Room) -> impl Future<Output = Result<Room, Self::Error>> + Send;
fn delete(&self, id: Uuid) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn list(&self, instance_id: Uuid) -> impl Future<Output = Result<Vec<Room>, Self::Error>> + Send;
}
#[async_trait]
pub trait TrackStore {
type Error;
fn create(&self, track: &Track) -> impl Future<Output = Result<Track, Self::Error>> + Send;
fn get(&self, id: Uuid) -> impl Future<Output = Result<Track, Self::Error>> + Send;
fn list_by_room(&self, room_id: Uuid) -> impl Future<Output = Result<Vec<Track>, Self::Error>> + Send;
fn update(&self, track: &Track) -> impl Future<Output = Result<Track, Self::Error>> + Send;
fn delete(&self, id: Uuid) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
#[async_trait]
pub trait UserStore {
type Error;
fn create(&self, user: &User) -> impl Future<Output = Result<User, Self::Error>> + Send;
fn get(&self, id: Uuid) -> impl Future<Output = Result<User, Self::Error>> + Send;
fn get_by_email(&self, email: &str) -> impl Future<Output = Result<User, Self::Error>> + Send;
fn list_by_instance(&self, instance_id: Uuid) -> impl Future<Output = Result<Vec<User>, Self::Error>> + Send;
fn update(&self, user: &User) -> impl Future<Output = Result<User, Self::Error>> + Send;
fn delete(&self, id: Uuid) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
#[async_trait]
pub trait MessageStore {
type Error;
fn send_message(&self, message: &Message) -> impl Future<Output = Result<MessageId, Self::Error>> + Send;
fn get_messages(&self, filter: &MessageFilter) -> impl Future<Output = Result<Vec<Message>, Self::Error>> + Send;
fn update_status(&self, message_id: Uuid, status: Status) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn delete_messages(&self, filter: &MessageFilter) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn search_messages(&self, query: &SearchQuery) -> impl Future<Output = Result<Vec<Message>, Self::Error>> + Send;
}
#[async_trait]
pub trait FileStore {
type Error;
fn upload_file(&self, upload: &FileUpload) -> impl Future<Output = Result<FileInfo, Self::Error>> + Send;
fn get_file(&self, file_id: Uuid) -> impl Future<Output = Result<FileContent, Self::Error>> + Send;
fn delete_file(&self, file_id: Uuid) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn list_files(&self, prefix: &str) -> impl Future<Output = Result<Vec<FileInfo>, Self::Error>> + Send;
}

View file

@ -40,7 +40,7 @@ pub fn generate_jwt(user: &User, secret: &str) -> Result<String, AppError> {
exp: expiration,
iat: issued_at,
email: user.email.clone(),
username: user.username.clone(),
username: user.email.clone(),
};
encode(

View file

@ -15,6 +15,13 @@ thiserror= { workspace = true }
tracing= { workspace = true }
minio = { workspace = true }
actix-web ={ workspace = true }
actix-multipart ={ workspace = true }
futures ={ workspace = true }
uuid = { workspace = true }
jsonwebtoken = { workspace = true }
lettre= { workspace = true }
sanitize-filename = { workspace = true }
[dev-dependencies]
rstest= { workspace = true }
tokio-test = "0.4"

View file

@ -1,11 +1,10 @@
use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse};
use futures::{StreamExt, TryStreamExt};
use gb_core::models::AppState;
use std::io::Write;
use uuid::Uuid;
use crate::models::AppError;
use crate::utils::{create_response, extract_user_id};
use gb_core::models::AppError;
use gb_core::utils::{create_response, extract_user_id};
#[actix_web::post("/files/upload")]
pub async fn upload_file(

View file

@ -0,0 +1 @@
pub mod handlers;

View file

@ -1,37 +0,0 @@
use actix_web::web;
use crate::router;
pub fn files_router_configure(cfg: &mut web::ServiceConfig) {
// File & Document Management
cfg.route("/files/upload", web::post().to(handlers::upload_file))
.route("/files/download", web::post().to(handlers::download))
.route("/files/delete", web::post().to(handlers::delete_file))
.route("/files/getContents", web::post().to(handlers::get_file_contents))
.route("/files/createFolder", web::post().to(handlers::create_folder))
.route("/files/dirFolder", web::post().to(handlers::dir_folder))
// Conversations & Real-time Communication
.route("/conversations/create", web::post().to(handlers::create_conversation))
.route("/conversations/join", web::post().to(handlers::join_conversation))
.route("/conversations/leave", web::post().to(handlers::leave_conversation))
.route("/conversations/members", web::get().to(handlers::get_conversation_members))
.route("/conversations/messages", web::get().to(handlers::get_messages))
.route("/conversations/messages/send", web::post().to(handlers::send_message))
// Communication Services
.route("/comm/email/send", web::post().to(handlers::send_email))
// User Management
.route("/users/profile", web::get().to(handlers::get_user_profile))
// Calendar & Task Management
.route("/calendar/events/create", web::post().to(handlers::create_event))
.route("/tasks/create", web::post().to(handlers::create_task))
.route("/tasks/list", web::get().to(handlers::get_tasks))
// Admin
.route("/admin/system/status", web::get().to(handlers::get_system_status))
.route("/admin/logs/view", web::get().to(handlers::view_logs));
}

View file

@ -28,6 +28,7 @@ hyper-util = { workspace = true }
tower = { workspace = true }
tower-http = { workspace = true, features = ["cors", "trace"] }
actix-web = { workspace = true }
dotenv = { workspace = true }
[dev-dependencies]
rstest = { workspace = true }

View file

@ -1,9 +1,10 @@
use actix_web::{middleware, web, App, HttpServer};
use gb_core::models;
use tracing_subscriber::fmt::format::FmtSpan;
use dotenv::dotenv;
use gb_core::config::AppConfig;
use gb_core::db::{init_kafka, init_minio, init_postgres, init_redis, init_zitadel};
use gb_core::db::{init_kafka, init_minio, init_postgres, init_redis};
use gb_file::handlers::upload_file;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
@ -21,7 +22,7 @@ async fn main() -> std::io::Result<()> {
let db_pool = init_postgres(&config).await.expect("Failed to connect to PostgreSQL");
let redis_pool = init_redis(&config).await.expect("Failed to connect to Redis");
let kafka_producer = init_kafka(&config).await.expect("Failed to initialize Kafka");
let zitadel_client = init_zitadel(&config).await.expect("Failed to initialize Zitadel");
// let zitadel_client = init_zitadel(&config).await.expect("Failed to initialize Zitadel");
let minio_client = init_minio(&config).await.expect("Failed to initialize Minio");
let app_state = web::Data::new(models::AppState {
@ -29,24 +30,23 @@ async fn main() -> std::io::Result<()> {
db_pool,
redis_pool,
kafka_producer,
zitadel_client,
minio_client,
});
// Start HTTP server
HttpServer::new(move || {
let cors = Cors::default()
.allow_any_origin()
.allow_any_method()
.allow_any_header()
.max_age(3600);
// let cors = Cors::default()
// .allow_any_origin()
// .allow_any_method()
// .allow_any_header()
// .max_age(3600);
App::new()
.wrap(middleware::Logger::default())
.wrap(middleware::Compress::default())
.wrap(cors)
// .wrap(cors)
.app_data(app_state.clone())
.configure(files_router_configure)
.service(upload_file)
})
.bind((config.server.host.clone(), config.server.port))?
.run()

View file

@ -1,103 +0,0 @@
use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse};
use futures::{StreamExt, TryStreamExt};
use std::io::Write;
use uuid::Uuid;
use crate::models::AppError;
use crate::utils::{create_response, extract_user_id};
#[actix_web::post("/files/upload")]
pub async fn upload_file(
req: HttpRequest,
mut payload: Multipart,
state: web::Data<AppState>,
) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?;
let folder_path = req.query_string(); // Assuming folder path is passed as query parameter
while let Ok(Some(mut field)) = payload.try_next().await {
let content_disposition = field.content_disposition();
let filename = content_disposition
.get_filename()
.ok_or_else(|| AppError::Validation("Filename not provided".to_string()))?
.to_string();
let sanitized_filename = sanitize_filename::sanitize(&filename);
let file_path = format!("{}/{}/{}", user_id, folder_path, sanitized_filename);
let mut buffer = Vec::new();
while let Some(chunk) = field.next().await {
let data = chunk.map_err(|e| AppError::Internal(format!("Error reading file: {}", e)))?;
buffer.write_all(&data).map_err(|e| AppError::Internal(format!("Error writing to buffer: {}", e)))?;
}
let content_type = field.content_type().map(|t| t.to_string()).unwrap_or_else(|| "application/octet-stream".to_string());
state.minio_client
.put_object(&state.config.minio.bucket, &file_path, &buffer, Some(content_type.as_str()), None)
.await
.map_err(|e| AppError::Minio(format!("Failed to upload file to Minio: {}", e)))?;
return Ok(create_response(
format!("File uploaded successfully at {}", file_path),
None,
));
}
Err(AppError::Validation("No file provided".to_string()))
}
#[actix_web::post("/files/download")]
pub async fn download(
req: HttpRequest,
state: web::Data<AppState>,
file_path: web::Json<String>,
) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?;
let file_content = state.minio_client
.get_object(&state.config.minio.bucket, &file_path)
.await
.map_err(|e| AppError::Minio(format!("Failed to retrieve file from Minio: {}", e)))?;
Ok(HttpResponse::Ok()
.content_type("application/octet-stream")
.append_header(("Content-Disposition", format!("attachment; filename=\"{}\"", file_path)))
.body(file_content))
}
#[actix_web::post("/files/delete")]
pub async fn delete_file(
req: HttpRequest,
state: web::Data<AppState>,
file_path: web::Json<String>,
) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?;
state.minio_client
.remove_object(&state.config.minio.bucket, &file_path)
.await
.map_err(|e| AppError::Minio(format!("Failed to delete file from Minio: {}", e)))?;
Ok(create_response(
true,
Some("File deleted successfully".to_string()),
))
}
#[actix_web::post("/files/list")]
pub async fn list_files(
req: HttpRequest,
state: web::Data<AppState>,
folder_path: web::Json<String>,
) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?;
let objects = state.minio_client
.list_objects(&state.config.minio.bucket, &folder_path, None, None)
.await
.map_err(|e| AppError::Minio(format!("Failed to list objects in Minio: {}", e)))?;
Ok(create_response(objects, None))
}

View file

@ -2,36 +2,3 @@ use actix_web::web;
use crate::router;
pub fn files_router_configure(cfg: &mut web::ServiceConfig) {
// File & Document Management
cfg.route("/files/upload", web::post().to(handlers::upload_file))
.route("/files/download", web::post().to(handlers::download))
.route("/files/delete", web::post().to(handlers::delete_file))
.route("/files/getContents", web::post().to(handlers::get_file_contents))
.route("/files/createFolder", web::post().to(handlers::create_folder))
.route("/files/dirFolder", web::post().to(handlers::dir_folder))
// Conversations & Real-time Communication
.route("/conversations/create", web::post().to(handlers::create_conversation))
.route("/conversations/join", web::post().to(handlers::join_conversation))
.route("/conversations/leave", web::post().to(handlers::leave_conversation))
.route("/conversations/members", web::get().to(handlers::get_conversation_members))
.route("/conversations/messages", web::get().to(handlers::get_messages))
.route("/conversations/messages/send", web::post().to(handlers::send_message))
// Communication Services
.route("/comm/email/send", web::post().to(handlers::send_email))
// User Management
.route("/users/profile", web::get().to(handlers::get_user_profile))
// Calendar & Task Management
.route("/calendar/events/create", web::post().to(handlers::create_event))
.route("/tasks/create", web::post().to(handlers::create_task))
.route("/tasks/list", web::get().to(handlers::get_tasks))
// Admin
.route("/admin/system/status", web::get().to(handlers::get_system_status))
.route("/admin/logs/view", web::get().to(handlers::view_logs));
}