From 0756da8b7b044d12c0a9d4b16ea9c1ca47d65758 Mon Sep 17 00:00:00 2001 From: Jani Pulkkinen Date: Thu, 29 May 2025 20:33:15 +0300 Subject: [PATCH] Lootaherra --- .../down.sql | 1 + .../up.sql | 7 + .../2025-04-10-074116_test_data/down.sql | 1 + migrations/2025-04-10-074116_test_data/up.sql | 1 + src/loota.rs | 143 +++++++++++++++++- src/main.rs | 5 +- src/models.rs | 48 +++++- src/schema.rs | 9 ++ 8 files changed, 207 insertions(+), 8 deletions(-) diff --git a/migrations/2025-04-10-064257_create_lootakalenteri/down.sql b/migrations/2025-04-10-064257_create_lootakalenteri/down.sql index 1a011d6..b7999cb 100644 --- a/migrations/2025-04-10-064257_create_lootakalenteri/down.sql +++ b/migrations/2025-04-10-064257_create_lootakalenteri/down.sql @@ -1,4 +1,5 @@ -- This file should undo anything in `up.sql` +drop table loota_admin; drop table loota_customer; drop table loota_order; drop table loota_box; \ No newline at end of file diff --git a/migrations/2025-04-10-064257_create_lootakalenteri/up.sql b/migrations/2025-04-10-064257_create_lootakalenteri/up.sql index a1a60ef..28755b7 100644 --- a/migrations/2025-04-10-064257_create_lootakalenteri/up.sql +++ b/migrations/2025-04-10-064257_create_lootakalenteri/up.sql @@ -1,4 +1,11 @@ -- Lootakalenteri migration tables +create table loota_admin +( + id uuid primary key not null default gen_random_uuid(), + identifier varchar not null, + created_time timestamp with time zone not null default now() +); + create table loota_customer ( id uuid primary key not null default gen_random_uuid(), diff --git a/migrations/2025-04-10-074116_test_data/down.sql b/migrations/2025-04-10-074116_test_data/down.sql index eedea31..9dbf0a1 100644 --- a/migrations/2025-04-10-074116_test_data/down.sql +++ b/migrations/2025-04-10-074116_test_data/down.sql @@ -1,2 +1,3 @@ -- This file should undo anything in `up.sql` +delete from loota_admin; delete from loota_customer; diff --git a/migrations/2025-04-10-074116_test_data/up.sql b/migrations/2025-04-10-074116_test_data/up.sql index c549b1c..d106845 100644 --- a/migrations/2025-04-10-074116_test_data/up.sql +++ b/migrations/2025-04-10-074116_test_data/up.sql @@ -1,4 +1,5 @@ -- Test data +insert into loota_admin (identifier) values ( 'admin1'); insert into loota_customer (identifier) values ( 'customer1'); insert into loota_customer (identifier) values ( 'customer2'); diff --git a/src/loota.rs b/src/loota.rs index f82b36d..a9aceb1 100644 --- a/src/loota.rs +++ b/src/loota.rs @@ -5,11 +5,13 @@ use diesel::result::Error; use uuid::Uuid; use crate::constants::APPLICATION_JSON; use crate::connection::establish_connection; -use crate::models::{Customer, Box, Order, LootaResponse, LootaBoxResponse, LootaRequest}; +use crate::models::{Customer, Box, Order, LootaResponse, LootaBoxResponse, LootaRequest, LootaOrderAdminResponse, LootaUserAdminResponse, LootaBoxAdminResponse, LootaBoxOrderAdminResponse}; +use crate::schema::loota_admin::dsl::loota_admin; use crate::schema::loota_box::dsl::loota_box; use crate::schema::loota_box::{delivery_date, id, pickup_date}; use crate::schema::loota_customer::dsl::loota_customer; use crate::schema::loota_customer::identifier; +use crate::schema::loota_order::dsl::loota_order; fn find_boxes(_identifier: String, _order: &Order, conn: &mut PgConnection) -> LootaResponse { let boxes = Box::belonging_to(_order) @@ -45,6 +47,66 @@ fn find_boxes(_identifier: String, _order: &Order, conn: &mut PgConnection) -> L } +fn find_admin_boxes(delivery_date_param: String, conn: &mut PgConnection) -> Result, Error> { + let parsed_date = chrono::NaiveDateTime::parse_from_str(&delivery_date_param, "%Y-%m-%dT%H:%M:%S") + .map_err(|_| Error::NotFound)?; + + + let boxes = loota_box + .filter(delivery_date.ge(Some(parsed_date))) + .inner_join(loota_order) + .select((Box::as_select(), Order::as_select())) + .load::<(Box, Order)>(conn)?; + + let response = boxes + .into_iter() + .map(|(box_data, order)| { + LootaBoxAdminResponse { + id: box_data.id.to_string(), + delivery_date: box_data.delivery_date, + pickup_date: box_data.pickup_date, + order: (LootaBoxOrderAdminResponse { + id: order.id.to_string(), + customer_id: order.customer_id.to_string(), + location: order.location, + created_time: order.created_time, + }) + } + }) + .collect(); + + Ok(response) + } + + +fn find_admin_orders(conn: &mut PgConnection) -> Result, Error> { + + let orders = loota_order + .inner_join(loota_customer) + .select((Order::as_select(), Customer::as_select())) + .load::<(Order, Customer)>(conn)?; + + let response = orders + .into_iter() + .map(|(order, customer)| { + LootaOrderAdminResponse { + id: order.id.to_string(), + location: order.location, + created_time: order.created_time, + user: (LootaUserAdminResponse { + id: customer.id.to_string(), + identifier: customer.identifier, + created_time: customer.created_time, + }) + } + }) + .collect(); + + Ok(response) +} + + + fn find_order(_customer: &Customer, conn: &mut PgConnection) -> Result { let _identifier = _customer.identifier.clone(); let order = Order::belonging_to(_customer) @@ -65,6 +127,17 @@ fn find_order(_customer: &Customer, conn: &mut PgConnection) -> Result bool { + let conn = &mut establish_connection(); + + let admin_exists = loota_admin + .filter(crate::schema::loota_admin::dsl::identifier.eq(&_identifier)) + .select(crate::schema::loota_admin::dsl::id) + .first::(conn); + + admin_exists.is_ok() +} + fn find_customer(_identifier: String) -> Result { let conn = &mut establish_connection(); @@ -119,10 +192,76 @@ fn parse_date(_date: String) -> Result { NaiveDateTime::parse_from_str(&_date, "%Y-%m-%dT%H:%M:%S") } +#[get("/lootaherra/{id}")] +async fn get_admin(path: web::Path) -> impl Responder { + let _identifier = path.into_inner(); + + let exists = web::block(move || find_admin(_identifier)).await.unwrap(); + + match exists { + true => { + HttpResponse::Ok() + }, + false => HttpResponse::NotFound() + } +} + +#[get("/lootaherra/orders")] +async fn get_admin_orders() -> impl Responder { + let orders = web::block(move || { + let conn = &mut establish_connection(); + find_admin_orders(conn) + }) + .await; + + match orders { + Ok(Ok(response)) => HttpResponse::Ok() + .content_type(APPLICATION_JSON) + .json(response), + + Ok(Err(diesel_error)) => { + println!("Diesel error: {:?}", diesel_error); + HttpResponse::InternalServerError() + .content_type(APPLICATION_JSON) + .body("Database query failed") + } + + Err(blocking_error) => { + println!("Blocking error: {:?}", blocking_error); + HttpResponse::InternalServerError() + .content_type(APPLICATION_JSON) + .body("Server thread blocking error") + } + } +} + +#[get("/lootaherra/box-list/{delivery_date}")] +async fn get_admin_boxes(path: web::Path) -> impl Responder { + let _delivery_date = path.into_inner(); + + + let boxes = web::block(move || { + let conn = &mut establish_connection(); + find_admin_boxes(_delivery_date, conn) + }) + .await; + + match boxes { + Ok(Ok(response)) => HttpResponse::Ok() + .content_type(APPLICATION_JSON) + .json(response), + _ => HttpResponse::NotFound() + .content_type(APPLICATION_JSON) + .await + .unwrap(), + } + +} + + #[get("/loota/{id}")] async fn get(path: web::Path) -> impl Responder { let identifer = path.into_inner(); - println!("id: {:?}", identifer); let response = web::block(move || find_customer(identifer)).await.unwrap(); diff --git a/src/main.rs b/src/main.rs index dac6bd4..df321bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,10 +23,11 @@ async fn main() -> io::Result<()> { HttpServer::new(|| { App::new() - // enable logger - always register actix-web Logger middleware last .wrap(middleware::Logger::default()) - // register HTTP requests handlers .service(loota::get) + .service(loota::get_admin_orders) + .service(loota::get_admin) + .service(loota::get_admin_boxes) .service(loota::update) }) .bind("0.0.0.0:9090")? diff --git a/src/models.rs b/src/models.rs index 71513d0..fff75a2 100644 --- a/src/models.rs +++ b/src/models.rs @@ -2,23 +2,33 @@ use uuid::Uuid; use diesel::prelude::*; use chrono::{NaiveDateTime}; use serde::{Serialize, Deserialize}; -use crate::schema::{loota_customer, loota_order, loota_box}; - +use crate::schema::{loota_customer, loota_admin, loota_order, loota_box}; #[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] #[diesel(table_name = loota_customer)] pub struct Customer { pub id: Uuid, - pub identifier: String + pub identifier: String, + pub created_time: NaiveDateTime } +#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] +#[diesel(table_name = loota_admin)] +pub struct Admin { + pub id: Uuid, + pub identifier: String, + pub created_time: NaiveDateTime +} + + #[derive(Queryable, Selectable, Identifiable, Associations, Debug, PartialEq)] -#[diesel(belongs_to(Customer))] +#[diesel(belongs_to(Customer, foreign_key = customer_id))] #[diesel(table_name = loota_order)] pub struct Order { pub id: Uuid, pub location: String, pub customer_id: Uuid, + pub created_time: NaiveDateTime } #[derive(Queryable, Selectable, Identifiable, Associations, Debug, PartialEq)] @@ -32,7 +42,37 @@ pub struct Box { pub order_id: Uuid } +#[derive(Debug, Serialize)] +pub struct LootaBoxAdminResponse { + pub id: String, + pub delivery_date: Option, + pub pickup_date: Option, + pub order: LootaBoxOrderAdminResponse +} +#[derive(Debug, Serialize)] +pub struct LootaBoxOrderAdminResponse { + pub id: String, + pub customer_id: String, + pub location: String, + pub created_time: NaiveDateTime +} + + +#[derive(Debug, Serialize)] +pub struct LootaOrderAdminResponse { + pub id: String, + pub location: String, + pub created_time: NaiveDateTime, + pub user: LootaUserAdminResponse +} + +#[derive(Debug, Serialize)] +pub struct LootaUserAdminResponse { + pub id: String, + pub identifier: String, + pub created_time: NaiveDateTime +} #[derive(Debug, Serialize)] pub struct LootaResponse { diff --git a/src/schema.rs b/src/schema.rs index faaee3d..57cfc80 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -1,5 +1,13 @@ // @generated automatically by Diesel CLI. +diesel::table! { + loota_admin (id) { + id -> Uuid, + identifier -> Varchar, + created_time -> Timestamp, + } +} + diesel::table! { loota_box (id) { id -> Uuid, @@ -31,6 +39,7 @@ diesel::joinable!(loota_box -> loota_order (order_id)); diesel::joinable!(loota_order -> loota_customer (customer_id)); diesel::allow_tables_to_appear_in_same_query!( + loota_admin, loota_box, loota_customer, loota_order,