diff --git a/app/src/main.rs b/app/src/main.rs index 18bb218..0213c0a 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -18,17 +18,26 @@ type SalesPersonService = service_impl::sales_person::SalesPersonServiceImpl< ClockService, UuidService, >; +type BookingService = service_impl::booking::BookingServiceImpl< + dao_impl::booking::BookingDaoImpl, + PermissionService, + ClockService, + UuidService, +>; #[derive(Clone)] pub struct RestStateImpl { permission_service: Arc, slot_service: Arc, sales_person_service: Arc, + booking_service: Arc, + } impl rest::RestStateDef for RestStateImpl { type PermissionService = PermissionService; type SlotService = SlotService; type SalesPersonService = SalesPersonService; + type BookingService = BookingService; fn permission_service(&self) -> Arc { self.permission_service.clone() @@ -39,12 +48,16 @@ impl rest::RestStateDef for RestStateImpl { fn sales_person_service(&self) -> Arc { self.sales_person_service.clone() } + fn booking_service(&self) -> Arc { + self.booking_service.clone() + } } impl RestStateImpl { pub fn new(pool: Arc>) -> Self { let permission_dao = dao_impl::PermissionDaoImpl::new(pool.clone()); let slot_dao = dao_impl::slot::SlotDaoImpl::new(pool.clone()); - let sales_person_dao = dao_impl::sales_person::SalesPersonDaoImpl::new(pool); + let sales_person_dao = dao_impl::sales_person::SalesPersonDaoImpl::new(pool.clone()); + let booking_dao = dao_impl::booking::BookingDaoImpl::new(pool); // Always authenticate with DEVUSER during development. // This is used to test the permission service locally without a login service. @@ -69,13 +82,20 @@ impl RestStateImpl { Arc::new(service_impl::sales_person::SalesPersonServiceImpl::new( sales_person_dao.into(), permission_service.clone(), - clock_service, - uuid_service, + clock_service.clone(), + uuid_service.clone(), )); + let booking_service = Arc::new(service_impl::booking::BookingServiceImpl::new( + booking_dao.into(), + permission_service.clone(), + clock_service, + uuid_service, + )); Self { permission_service, slot_service, sales_person_service, + booking_service, } } } diff --git a/rest/src/booking.rs b/rest/src/booking.rs new file mode 100644 index 0000000..3283ea4 --- /dev/null +++ b/rest/src/booking.rs @@ -0,0 +1,135 @@ +use std::sync::Arc; + +use axum::body::Body; +use axum::extract::Path; +use axum::routing::{delete, get, post}; +use axum::{extract::State, response::Response}; +use axum::{Json, Router}; +use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; +use uuid::Uuid; + +use crate::{error_handler, RestStateDef}; +use service::booking::{BookingService, Booking}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct BookingTO { + #[serde(default)] + pub id: Uuid, + pub sales_person_id: Uuid, + pub slot_id: Uuid, + pub calendar_week: i32, + pub year: u32, + #[serde(default)] + pub created: Option, + #[serde(default)] + pub deleted: Option, + #[serde(rename = "$version")] + #[serde(default)] + pub version: Uuid, +} +impl From<&Booking> for BookingTO { + fn from(booking: &Booking) -> Self { + Self { + id: booking.id, + sales_person_id: booking.sales_person_id, + slot_id: booking.slot_id, + calendar_week: booking.calendar_week, + year: booking.year, + created: booking.created, + deleted: booking.deleted, + version: booking.version, + } + } +} +impl From<&BookingTO> for Booking { + fn from(booking: &BookingTO) -> Self { + Self { + id: booking.id, + sales_person_id: booking.sales_person_id, + slot_id: booking.slot_id, + calendar_week: booking.calendar_week, + year: booking.year, + created: booking.created, + deleted: booking.deleted, + version: booking.version, + } + } +} + +pub fn generate_route() -> Router { + Router::new() + .route("/", get(get_all_bookings::)) + .route("/:id", get(get_booking::)) + .route("/", post(create_booking::)) + .route("/:id", delete(delete_booking::)) +} + +pub async fn get_all_bookings( + rest_state: State, +) -> Response { + error_handler( + (async { + let bookings: Arc<[BookingTO]> = rest_state + .booking_service() + .get_all(()) + .await? + .iter() + .map(BookingTO::from) + .collect(); + Ok(Response::builder() + .status(200) + .body(Body::new(serde_json::to_string(&bookings).unwrap())) + .unwrap()) + }) + .await, + ) +} + +pub async fn get_booking( + rest_state: State, + Path(booking_id): Path, +) -> Response { + error_handler( + (async { + let booking = rest_state.booking_service().get(booking_id, ()).await?; + Ok(Response::builder() + .status(200) + .body(Body::new(serde_json::to_string(&BookingTO::from(&booking)).unwrap())) + .unwrap()) + }) + .await, + ) +} + +pub async fn create_booking( + rest_state: State, + Json(booking): Json, +) -> Response { + error_handler( + (async { + let booking = rest_state.booking_service().create(&Booking::from(&booking), ()).await?; + Ok(Response::builder() + .status(200) + .body(Body::new(serde_json::to_string(&BookingTO::from(&booking)).unwrap())) + .unwrap()) + }) + .await, + ) +} + +pub async fn delete_booking( + rest_state: State, + Path(booking_id): Path, +) -> Response { + error_handler( + (async { + rest_state.booking_service().delete(booking_id, ()).await?; + Ok(Response::builder() + .status(200) + .body(Body::empty()) + .unwrap()) + }) + .await, + ) +} \ No newline at end of file diff --git a/rest/src/lib.rs b/rest/src/lib.rs index 375e9ed..9abafd9 100644 --- a/rest/src/lib.rs +++ b/rest/src/lib.rs @@ -1,5 +1,6 @@ use std::{convert::Infallible, sync::Arc}; +mod booking; mod permission; mod sales_person; mod slot; @@ -139,10 +140,12 @@ pub trait RestStateDef: Clone + Send + Sync + 'static { + Send + Sync + 'static; + type BookingService: service::booking::BookingService + Send + Sync + 'static; fn permission_service(&self) -> Arc; fn slot_service(&self) -> Arc; fn sales_person_service(&self) -> Arc; + fn booking_service(&self) -> Arc; } pub async fn start_server(rest_state: RestState) { @@ -150,6 +153,7 @@ pub async fn start_server(rest_state: RestState) { .nest("/permission", permission::generate_route()) .nest("/slot", slot::generate_route()) .nest("/sales-person", sales_person::generate_route()) + .nest("/booking", booking::generate_route()) .with_state(rest_state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") .await diff --git a/service_impl/src/booking.rs b/service_impl/src/booking.rs index e4decbd..53fa4c2 100644 --- a/service_impl/src/booking.rs +++ b/service_impl/src/booking.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use dao::booking; use service::{ booking::{Booking, BookingService}, ServiceError, ValidationFailureItem,