use actix_cors::Cors; use actix_multipart::form::tempfile::TempFileConfig; use actix_remote_ip::RemoteIPConfig; use actix_session::SessionMiddleware; use actix_session::config::SessionLifecycle; use actix_session::storage::RedisSessionStore; use actix_web::cookie::Key; use actix_web::middleware::Logger; use actix_web::{App, HttpServer, web}; use moneymgr_backend::app_config::AppConfig; use moneymgr_backend::connections::{db_connection, s3_connection}; use moneymgr_backend::controllers::*; use moneymgr_backend::services::users_service; use moneymgr_backend::{constants, routines}; #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); log::info!( "Money manager server, start to listen on {}", AppConfig::get().listen_address ); // Initialize bucket log::info!("Initialize S3 bucket"); s3_connection::create_bucket_if_required() .await .expect("Failed to initialize S3 bucket!"); // Connect to Redis let cookie_secret_key = Key::from(AppConfig::get().secret().as_bytes()); let redis_store = RedisSessionStore::new(AppConfig::get().redis_connection_string()) .await .expect("Failed to connect to Redis!"); // Initialize database connection db_connection::initialize_conn().expect("Failed to connect to PostgresSQL database!"); // Auto create default account, if requested if let Some(mail) = &AppConfig::get().unsecure_auto_login_email { users_service::create_or_update_user(mail, "Anonymous") .await .expect("Failed to create default account!"); } // Automatically execute routines tokio::spawn(routines::main_routine()); HttpServer::new(move || { let session_mw = SessionMiddleware::builder(redis_store.clone(), cookie_secret_key.clone()) .cookie_name("moneymgr-session".to_string()) .session_lifecycle(SessionLifecycle::BrowserSession(Default::default())) .build(); let cors = Cors::default() .allowed_origin(&AppConfig::get().website_origin) .allowed_methods(vec!["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) .allowed_header(constants::API_TOKEN_HEADER) .allow_any_header() .supports_credentials() .max_age(3600); App::new() .wrap(Logger::default()) .wrap(session_mw) .wrap(cors) .app_data(web::Data::new(RemoteIPConfig { proxy: AppConfig::get().proxy_ip.clone(), })) // Uploaded files .app_data(TempFileConfig::default().directory(&AppConfig::get().temp_dir)) // Server controller .route("/robots.txt", web::get().to(server_controller::robots_txt)) .route( "/api/server/config", web::get().to(server_controller::config), ) // Auth controller .route( "/api/auth/start_oidc", web::get().to(auth_controller::start_oidc), ) .route( "/api/auth/finish_oidc", web::post().to(auth_controller::finish_oidc), ) .route("/api/auth/info", web::get().to(auth_controller::auth_info)) .route( "/api/auth/sign_out", web::get().to(auth_controller::sign_out), ) // Tokens controller .route("/api/token", web::post().to(tokens_controller::create)) .route("/api/tokens", web::get().to(tokens_controller::get_list)) .route( "/api/token/{id}", web::delete().to(tokens_controller::delete), ) // Accounts controller .route("/api/account", web::post().to(accounts_controller::create)) .route( "/api/accounts", web::get().to(accounts_controller::get_list), ) .route( "/api/account/{account_id}", web::get().to(accounts_controller::get_single), ) .route( "/api/account/{account_id}", web::put().to(accounts_controller::update), ) .route( "/api/account/{account_id}/default", web::put().to(accounts_controller::set_default), ) .route( "/api/account/{account_id}", web::delete().to(accounts_controller::delete), ) // Files controller .route("/api/file", web::post().to(files_controller::upload)) .route( "/api/file/{file_id}", web::get().to(files_controller::get_info), ) .route( "/api/file/{file_id}/download", web::get().to(files_controller::download), ) .route( "/api/file/{file_id}", web::delete().to(files_controller::delete), ) // Movement controller .route("/api/movement", web::post().to(movement_controller::create)) .route( "/api/accounts/balances", web::get().to(movement_controller::get_accounts_balances), ) .route( "/api/account/{account_id}/movements", web::get().to(movement_controller::get_list_of_account), ) .route( "/api/movement/{movement_id}", web::get().to(movement_controller::get_single), ) .route( "/api/movement/{movement_id}", web::put().to(movement_controller::update), ) .route( "/api/movement/{movement_id}", web::delete().to(movement_controller::delete), ) // Inbox controller .route("/api/inbox", web::post().to(inbox_controller::create)) .route("/api/inbox", web::get().to(inbox_controller::get_list)) .route( "/api/inbox/count", web::get().to(inbox_controller::count_entries), ) .route( "/api/inbox/{inbox_id}", web::get().to(inbox_controller::get_single), ) .route( "/api/inbox/{inbox_id}", web::put().to(inbox_controller::update), ) .route( "/api/inbox/{inbox_id}", web::delete().to(inbox_controller::delete), ) // Statistics controller .route("/api/stats/global", web::get().to(stats_controller::global)) .route( "/api/stats/balance_variation", web::get().to(stats_controller::balance_variation), ) // Backup controller .route( "/api/backup/finances_manager/import", web::post().to(backup_controller::finances_manager_import), ) .route( "/api/backup/finances_manager/export", web::get().to(backup_controller::finances_manager_export), ) .route( "/api/backup/zip/export", web::get().to(backup_controller::zip_export), ) .route( "/api/backup/zip/import", web::post().to(backup_controller::zip_import), ) .route( "/api/backup/xslx/export", web::get().to(backup_controller::xslx_export), ) // Static assets .route("/", web::get().to(static_controller::root_index)) .route( "/{tail:.*}", web::get().to(static_controller::serve_static_content), ) }) .bind(AppConfig::get().listen_address.as_str())? .run() .await }