diff --git a/services/reports/src/http.rs b/services/reports/src/http.rs index 0ff29f995..abc87eab7 100644 --- a/services/reports/src/http.rs +++ b/services/reports/src/http.rs @@ -1,34 +1,36 @@ use actix_web::{web, App, HttpResponse, HttpServer}; use anyhow::Result; use tracing::info; use crate::config::CONFIG; use crate::constants::REQUEST_BODY_JSON_SIZE_LIMIT; +use crate::service::ReportsService; -pub async fn run_http_server() -> Result<()> { +pub async fn run_http_server(service: ReportsService) -> Result<()> { use actix_web::middleware::{Logger, NormalizePath}; use comm_services_lib::http::cors_config; use tracing_actix_web::TracingLogger; info!( "Starting HTTP server listening at port {}", CONFIG.http_port ); HttpServer::new(move || { let json_cfg = web::JsonConfig::default().limit(REQUEST_BODY_JSON_SIZE_LIMIT); App::new() .app_data(json_cfg) + .app_data(service.to_owned()) .wrap(Logger::default()) .wrap(TracingLogger::default()) .wrap(NormalizePath::trim()) .wrap(cors_config(CONFIG.is_dev())) // Health endpoint for load balancers checks .route("/health", web::get().to(HttpResponse::Ok)) }) .bind(("0.0.0.0", CONFIG.http_port))? .run() .await?; Ok(()) } diff --git a/services/reports/src/main.rs b/services/reports/src/main.rs index 98a951d9f..93cf02405 100644 --- a/services/reports/src/main.rs +++ b/services/reports/src/main.rs @@ -1,33 +1,39 @@ pub mod config; pub mod constants; pub mod database; pub mod http; pub mod report_types; +pub mod service; use anyhow::Result; +use comm_services_lib::blob::client::BlobServiceClient; +use service::ReportsService; use tracing_subscriber::filter::{EnvFilter, LevelFilter}; fn configure_logging() -> Result<()> { let filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) .with_env_var(EnvFilter::DEFAULT_ENV) .from_env_lossy(); // init HTTP logger - it relies on 'log' instead of 'tracing' // so we have to initialize a polyfill tracing_log::LogTracer::init()?; let subscriber = tracing_subscriber::fmt().with_env_filter(filter).finish(); tracing::subscriber::set_global_default(subscriber)?; Ok(()) } #[tokio::main] async fn main() -> Result<()> { configure_logging()?; - config::parse_cmdline_args()?; + let cfg = config::parse_cmdline_args()?; + let aws_config = config::load_aws_config().await; - let _aws_config = config::load_aws_config().await; + let db = database::client::DatabaseClient::new(&aws_config); + let blob_client = BlobServiceClient::new(cfg.blob_service_url.clone()); + let service = ReportsService::new(db, blob_client); - crate::http::run_http_server().await + crate::http::run_http_server(service).await } diff --git a/services/reports/src/service.rs b/services/reports/src/service.rs new file mode 100644 index 000000000..87231784b --- /dev/null +++ b/services/reports/src/service.rs @@ -0,0 +1,64 @@ +use actix_web::FromRequest; +use comm_services_lib::{auth::UserIdentity, blob::client::BlobServiceClient}; +use std::future::{ready, Ready}; + +use crate::database::client::DatabaseClient; +#[derive(Clone)] +pub struct ReportsService { + db: DatabaseClient, + blob_client: BlobServiceClient, + requesting_user_id: Option, +} + +impl ReportsService { + pub fn new(db: DatabaseClient, blob_client: BlobServiceClient) -> Self { + Self { + db, + blob_client, + requesting_user_id: None, + } + } + + pub fn authenticated(&self, user: UserIdentity) -> Self { + let user_id = user.user_id.to_string(); + Self { + db: self.db.clone(), + blob_client: self.blob_client.with_user_identity(user), + requesting_user_id: Some(user_id), + } + } +} + +impl FromRequest for ReportsService { + type Error = actix_web::Error; + type Future = Ready>; + + #[inline] + fn from_request( + req: &actix_web::HttpRequest, + _payload: &mut actix_web::dev::Payload, + ) -> Self::Future { + use actix_web::HttpMessage; + + let Some(service) = req.app_data::() else { + tracing::error!( + "FATAL! Failed to extract ReportsService from actix app_data. \ + Check HTTP server configuration" + ); + return ready(Err(actix_web::error::ErrorInternalServerError("Internal server error"))); + }; + + let auth_service = + if let Some(user_identity) = req.extensions().get::() { + tracing::trace!("Found user identity. Creating authenticated service"); + service.authenticated(user_identity.clone()) + } else { + tracing::trace!( + "No user identity found. Leaving unauthenticated service" + ); + service.clone() + }; + + ready(Ok(auth_service)) + } +}