diff --git a/services/reports/src/http.rs b/services/reports/src/http.rs --- a/services/reports/src/http.rs +++ b/services/reports/src/http.rs @@ -4,8 +4,9 @@ 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; @@ -19,6 +20,7 @@ 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()) diff --git a/services/reports/src/main.rs b/services/reports/src/main.rs --- a/services/reports/src/main.rs +++ b/services/reports/src/main.rs @@ -3,8 +3,11 @@ 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<()> { @@ -25,9 +28,12 @@ #[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 --- /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)) + } +}