use std::collections::BTreeMap; // Copyright 2022 Jeremy Wall (Jeremy@marzhilsltudios.com) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #[cfg(feature = "server")] use axum::{ self, http::StatusCode, response::{IntoResponse, Response as AxumResponse}, }; use serde::{Deserialize, Serialize}; use recipes::{IngredientKey, RecipeEntry}; #[derive(Serialize, Deserialize, Debug)] pub enum Response { Success(T), Err { status: u16, message: String }, NotFound, Unauthorized, } impl Response { pub fn error>(code: u16, msg: S) -> Self { Self::Err { status: code, message: msg.into(), } } pub fn success(payload: T) -> Self { Self::Success(payload) } #[cfg(feature = "browser")] pub fn as_success(self) -> Option { if let Self::Success(val) = self { Some(val) } else { None } } } #[cfg(feature = "server")] impl IntoResponse for Response where T: Serialize, { fn into_response(self) -> AxumResponse { match &self { Self::Success(_) => (StatusCode::OK, axum::Json::from(self)).into_response(), Self::Err { status, message: _ } => { let code = match StatusCode::from_u16(*status) { Ok(c) => c, Err(_) => StatusCode::INTERNAL_SERVER_ERROR, }; (code, axum::Json::from(self)).into_response() } // TODO(jwall): Perhaps this can show a more useful json payload? Self::NotFound => (StatusCode::NOT_FOUND, axum::Json::from(self)).into_response(), Self::Unauthorized => { (StatusCode::UNAUTHORIZED, axum::Json::from(self)).into_response() } } } } impl From> for Response { fn from(val: Result) -> Self { match val { Ok(val) => Response::Success(val), Err(e) => Response::error(500, e), } } } impl From, String>> for Response where T: Default, { fn from(val: Result, String>) -> Self { match val { Ok(Some(val)) => Response::Success(val), Ok(None) => Response::Success(T::default()), Err(e) => Response::error(500, e), } } } pub type CategoryResponse = Response; pub type EmptyResponse = Response<()>; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct UserData { pub user_id: String, } pub type AccountResponse = Response; impl From for AccountResponse { fn from(user_data: UserData) -> Self { Response::Success(user_data) } } pub type RecipeEntryResponse = Response>; impl From> for RecipeEntryResponse { fn from(entries: Vec) -> Self { Response::Success(entries) } } pub type PlanDataResponse = Response>; impl From> for PlanDataResponse { fn from(plan: Vec<(String, i32)>) -> Self { Response::Success(plan) } } impl From>> for PlanDataResponse { fn from(plan: Option>) -> Self { match plan { Some(plan) => Response::Success(plan), None => Response::Success(Vec::new()), } } } pub type PlanHistoryResponse = Response>>; #[derive(Serialize, Deserialize)] pub struct InventoryData { pub filtered_ingredients: Vec, pub modified_amts: Vec<(IngredientKey, String)>, pub extra_items: Vec<(String, String)>, } pub type InventoryResponse = Response; impl From<( Vec, Vec<(IngredientKey, String)>, Vec<(String, String)>, )> for InventoryData { fn from( (filtered_ingredients, modified_amts, extra_items): ( Vec, Vec<(IngredientKey, String)>, Vec<(String, String)>, ), ) -> Self { InventoryData { filtered_ingredients, modified_amts, extra_items, } } } impl From for InventoryResponse { fn from(inventory_data: InventoryData) -> Self { Response::Success(inventory_data) } } pub type CategoryMappingResponse = Response>; impl From> for CategoryMappingResponse { fn from(mappings: Vec<(String, String)>) -> Self { Response::Success(mappings) } }