use std::sync::Arc; use axum::{ Json, http::StatusCode, extract::State, }; use axum_core::response::IntoResponse; use chrono::DateTime; use serde::Deserialize; use sqlx::{Error, PgPool}; use sqlx::postgres::PgQueryResult; use crate::api::db_vendo_navigator::get_railcar_identifier_by_journey; use crate::error::train_order_api_error::{CheckInError, ResolveTripNumberError}; use crate::model::app::AppState; use crate::model::database::User; use crate::model::travelynx::{CheckInReason, Train}; use crate::util::axum::UserBearerTokenExtractor; #[derive(Debug, Deserialize)] pub(crate) enum CheckIn { Traewelling(crate::model::traewelling::CheckIn), Travelynx(crate::model::travelynx::CheckIn), } #[axum::debug_handler] pub(crate) async fn receive_travelynx( State(app_state): State, UserBearerTokenExtractor(user): UserBearerTokenExtractor, Json(body): Json, ) -> impl IntoResponse { receive_travelynx_checkin(body, user, app_state.db).await.into_response() } async fn receive_travelynx_checkin( check_in: crate::model::travelynx::CheckIn, user: User, db: Arc ) -> impl IntoResponse { match check_in.reason { CheckInReason::CHECKIN => { let railcar_identifier = get_railcar_identifier_by_journey( check_in.status.train.train_type.unwrap(), check_in.status.train.number.to_owned().unwrap().parse().unwrap(), check_in.status.from_station.uic, check_in.status.from_station.scheduled_time.unwrap() ) .await .map_err(|e| CheckInError::from(e))?; let train_result = get_train_by_identifier(railcar_identifier as i32, db.clone()) .await; let train = train_result .map_err(|e| { match e { Error::RowNotFound => CheckInError::TrainNotFound, e => CheckInError::from(ResolveTripNumberError::from(e)) } })?; println!("Train: {:?}", train); let result = record_journey(user, train, check_in.status.from_station.scheduled_time.unwrap(), db) .await .map_err(|e| CheckInError::from(ResolveTripNumberError::from(e)))?; println!("Journey recorded: {:?}", result); let message = format!( "Successfully checked into {} {} ({}), departing from station {} at {}", check_in.status.train.train_type.unwrap(), check_in.status.train.number.unwrap(), railcar_identifier, check_in.status.from_station.uic, check_in.status.from_station.scheduled_time.unwrap() ); Ok::<_, CheckInError>(( StatusCode::CREATED, message ).into_response()) }, CheckInReason::UNDO => { Ok::<_, CheckInError>(( StatusCode::OK, "Checkin undone" ).into_response()) }, _ => Ok::<_, CheckInError>(( StatusCode::OK, "Nothing to do!" ).into_response()) } } async fn get_train_by_identifier(identifier: i32, db: Arc) -> sqlx::Result { sqlx::query_as!( crate::model::database::Train, "SELECT * FROM triebzug WHERE tz_id = $1", identifier ).fetch_one(db.as_ref()).await } async fn record_journey( user: User, train: crate::model::database::Train, timestamp: usize, db: Arc ) -> sqlx::Result { sqlx::query!( "INSERT INTO checkins VALUES (gen_random_uuid(), $1, $2, $3, NULL)", user.uuid, train.uuid, DateTime::from_timestamp(timestamp as i64, 0).unwrap().naive_utc() ).execute(db.as_ref()).await }