mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
Use v2 of the api in the app
This commit is contained in:
parent
1e4a1366af
commit
dfe5d668a4
@ -74,6 +74,7 @@ pub async fn handler(
|
|||||||
let cookie = Cookie::build(storage::AXUM_SESSION_COOKIE_NAME, cookie_value)
|
let cookie = Cookie::build(storage::AXUM_SESSION_COOKIE_NAME, cookie_value)
|
||||||
.same_site(SameSite::Strict)
|
.same_site(SameSite::Strict)
|
||||||
.secure(true)
|
.secure(true)
|
||||||
|
.path("/")
|
||||||
.finish();
|
.finish();
|
||||||
let parsed_cookie = match cookie.to_string().parse() {
|
let parsed_cookie = match cookie.to_string().parse() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
sig Recipe {
|
|
||||||
, desc: String
|
|
||||||
, title: String
|
|
||||||
, ingredients: set Ingredient
|
|
||||||
}
|
|
||||||
|
|
||||||
sig Cat {
|
|
||||||
, name: String
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract sig Unit { }
|
|
||||||
|
|
||||||
sig Tsp extends Unit {}
|
|
||||||
sig Tbsp extends Unit {}
|
|
||||||
sig Cup extends Unit {}
|
|
||||||
sig Pint extends Unit {}
|
|
||||||
sig Quart extends Unit {}
|
|
||||||
sig Gallon extends Unit {}
|
|
||||||
|
|
||||||
abstract sig Wgt extends Unit {
|
|
||||||
|
|
||||||
}
|
|
||||||
sig MilliGram extends Wgt {}
|
|
||||||
sig Gram extends Wgt {}
|
|
||||||
sig KiloGram extends Wgt {}
|
|
||||||
|
|
||||||
abstract sig Amt {}
|
|
||||||
sig Count extends Amt {
|
|
||||||
, value: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
sig Frac extends Amt {
|
|
||||||
, numerator: Int
|
|
||||||
, denominator: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
sig Ingredient {
|
|
||||||
, category: Cat
|
|
||||||
, name: String
|
|
||||||
, unit: Unit
|
|
||||||
, amt: Amt
|
|
||||||
}
|
|
@ -94,9 +94,18 @@ pub async fn init_page_state(store: &HttpStore, state: &app_state::State) -> Res
|
|||||||
}
|
}
|
||||||
info!("Synchronizing inventory data");
|
info!("Synchronizing inventory data");
|
||||||
match store.get_inventory_data().await {
|
match store.get_inventory_data().await {
|
||||||
Ok((filtered_ingredients, modified_amts)) => {
|
Ok((filtered_ingredients, modified_amts, mut extra_items)) => {
|
||||||
state.reset_modified_amts(modified_amts);
|
state.reset_modified_amts(modified_amts);
|
||||||
state.filtered_ingredients.set(filtered_ingredients);
|
state.filtered_ingredients.set(filtered_ingredients);
|
||||||
|
state.extras.set(
|
||||||
|
extra_items
|
||||||
|
.drain(0..)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, (amt, name))| {
|
||||||
|
(idx, (create_rc_signal(amt.clone()), create_rc_signal(name)))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{:?}", e);
|
error!("{:?}", e);
|
||||||
@ -160,10 +169,22 @@ pub struct HttpStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HttpStore {
|
impl HttpStore {
|
||||||
pub fn new(root: String) -> Self {
|
fn new(root: String) -> Self {
|
||||||
Self { root }
|
Self { root }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn v1_path(&self) -> String {
|
||||||
|
let mut path = self.root.clone();
|
||||||
|
path.push_str("/v1");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn v2_path(&self) -> String {
|
||||||
|
let mut path = self.root.clone();
|
||||||
|
path.push_str("/v2");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
pub fn provide_context<S: Into<String>>(cx: Scope, root: S) {
|
pub fn provide_context<S: Into<String>>(cx: Scope, root: S) {
|
||||||
provide_context(cx, std::rc::Rc::new(Self::new(root.into())));
|
provide_context(cx, std::rc::Rc::new(Self::new(root.into())));
|
||||||
}
|
}
|
||||||
@ -174,7 +195,7 @@ impl HttpStore {
|
|||||||
|
|
||||||
//#[instrument]
|
//#[instrument]
|
||||||
pub async fn get_categories(&self) -> Result<Option<String>, Error> {
|
pub async fn get_categories(&self) -> Result<Option<String>, Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/categories");
|
path.push_str("/categories");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
let resp = match reqwasm::http::Request::get(&path).send().await {
|
let resp = match reqwasm::http::Request::get(&path).send().await {
|
||||||
@ -203,7 +224,7 @@ impl HttpStore {
|
|||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub async fn get_recipes(&self) -> Result<Option<Vec<RecipeEntry>>, Error> {
|
pub async fn get_recipes(&self) -> Result<Option<Vec<RecipeEntry>>, Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/recipes");
|
path.push_str("/recipes");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
let resp = match reqwasm::http::Request::get(&path).send().await {
|
let resp = match reqwasm::http::Request::get(&path).send().await {
|
||||||
@ -247,7 +268,7 @@ impl HttpStore {
|
|||||||
&self,
|
&self,
|
||||||
id: S,
|
id: S,
|
||||||
) -> Result<Option<RecipeEntry>, Error> {
|
) -> Result<Option<RecipeEntry>, Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/recipe/");
|
path.push_str("/recipe/");
|
||||||
path.push_str(id.as_ref());
|
path.push_str(id.as_ref());
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
@ -282,7 +303,7 @@ impl HttpStore {
|
|||||||
|
|
||||||
#[instrument(skip(recipes), fields(count=recipes.len()))]
|
#[instrument(skip(recipes), fields(count=recipes.len()))]
|
||||||
pub async fn save_recipes(&self, recipes: Vec<RecipeEntry>) -> Result<(), Error> {
|
pub async fn save_recipes(&self, recipes: Vec<RecipeEntry>) -> Result<(), Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/recipes");
|
path.push_str("/recipes");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
for r in recipes.iter() {
|
for r in recipes.iter() {
|
||||||
@ -310,7 +331,7 @@ impl HttpStore {
|
|||||||
|
|
||||||
#[instrument(skip(categories))]
|
#[instrument(skip(categories))]
|
||||||
pub async fn save_categories(&self, categories: String) -> Result<(), Error> {
|
pub async fn save_categories(&self, categories: String) -> Result<(), Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/categories");
|
path.push_str("/categories");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
storage.set("categories", &categories)?;
|
storage.set("categories", &categories)?;
|
||||||
@ -327,21 +348,31 @@ impl HttpStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn save_state(&self, state: std::rc::Rc<app_state::State>) -> Result<(), Error> {
|
pub async fn save_state(&self, state: std::rc::Rc<app_state::State>) -> Result<(), Error> {
|
||||||
let mut plan = Vec::new();
|
let mut plan = Vec::new();
|
||||||
for (key, count) in state.recipe_counts.get_untracked().iter() {
|
for (key, count) in state.recipe_counts.get_untracked().iter() {
|
||||||
plan.push((key.clone(), *count.get_untracked() as i32));
|
plan.push((key.clone(), *count.get_untracked() as i32));
|
||||||
}
|
}
|
||||||
|
debug!("Saving plan data");
|
||||||
self.save_plan(plan).await?;
|
self.save_plan(plan).await?;
|
||||||
|
debug!("Saving inventory data");
|
||||||
self.save_inventory_data(
|
self.save_inventory_data(
|
||||||
state.filtered_ingredients.get_untracked().as_ref().clone(),
|
state.filtered_ingredients.get_untracked().as_ref().clone(),
|
||||||
state.get_current_modified_amts(),
|
state.get_current_modified_amts(),
|
||||||
|
state
|
||||||
|
.extras
|
||||||
|
.get()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.map(|t| (t.1 .0.get().as_ref().clone(), t.1 .1.get().as_ref().clone()))
|
||||||
|
.collect(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_plan(&self, plan: Vec<(String, i32)>) -> Result<(), Error> {
|
pub async fn save_plan(&self, plan: Vec<(String, i32)>) -> Result<(), Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/plan");
|
path.push_str("/plan");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
let serialized_plan = to_string(&plan).expect("Unable to encode plan as json");
|
let serialized_plan = to_string(&plan).expect("Unable to encode plan as json");
|
||||||
@ -360,7 +391,7 @@ impl HttpStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_plan(&self) -> Result<Option<Vec<(String, i32)>>, Error> {
|
pub async fn get_plan(&self) -> Result<Option<Vec<(String, i32)>>, Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v1_path();
|
||||||
path.push_str("/plan");
|
path.push_str("/plan");
|
||||||
let resp = reqwasm::http::Request::get(&path).send().await?;
|
let resp = reqwasm::http::Request::get(&path).send().await?;
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
@ -380,22 +411,47 @@ impl HttpStore {
|
|||||||
|
|
||||||
pub async fn get_inventory_data(
|
pub async fn get_inventory_data(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<(BTreeSet<IngredientKey>, BTreeMap<IngredientKey, String>), Error> {
|
) -> Result<
|
||||||
let mut path = self.root.clone();
|
(
|
||||||
|
BTreeSet<IngredientKey>,
|
||||||
|
BTreeMap<IngredientKey, String>,
|
||||||
|
Vec<(String, String)>,
|
||||||
|
),
|
||||||
|
Error,
|
||||||
|
> {
|
||||||
|
let mut path = self.v2_path();
|
||||||
path.push_str("/inventory");
|
path.push_str("/inventory");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
let resp = reqwasm::http::Request::get(&path).send().await?;
|
let resp = reqwasm::http::Request::get(&path).send().await?;
|
||||||
if resp.status() != 200 {
|
if resp.status() != 200 {
|
||||||
let err = Err(format!("Status: {}", resp.status()).into());
|
let err = Err(format!("Status: {}", resp.status()).into());
|
||||||
Ok(match storage.get("inventory") {
|
Ok(match storage.get("inventory") {
|
||||||
Ok(Some(val)) => from_str(&val).expect("Failed to deserialize cached val"),
|
Ok(Some(val)) => match from_str(&val) {
|
||||||
|
// TODO(jwall): Once we remove the v1 endpoint this is no longer needed.
|
||||||
|
Ok((filtered_ingredients, modified_amts)) => {
|
||||||
|
(filtered_ingredients, modified_amts, Vec::new())
|
||||||
|
}
|
||||||
|
Err(_) => match from_str(&val) {
|
||||||
|
Ok((filtered_ingredients, modified_amts, extra_items)) => {
|
||||||
|
(filtered_ingredients, modified_amts, extra_items)
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// Whatever is in storage is corrupted or invalid so we should delete it.
|
||||||
|
storage
|
||||||
|
.delete("inventory")
|
||||||
|
.expect("Unable to delete corrupt data in inventory cache");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
Ok(None) | Err(_) => return err,
|
Ok(None) | Err(_) => return err,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
debug!("We got a valid response back");
|
debug!("We got a valid response back");
|
||||||
let (filtered_ingredients, modified_amts): (
|
let (filtered_ingredients, modified_amts, extra_items): (
|
||||||
Vec<IngredientKey>,
|
Vec<IngredientKey>,
|
||||||
Vec<(IngredientKey, String)>,
|
Vec<(IngredientKey, String)>,
|
||||||
|
Vec<(String, String)>,
|
||||||
) = resp.json().await.map_err(|e| format!("{}", e))?;
|
) = resp.json().await.map_err(|e| format!("{}", e))?;
|
||||||
let _ = storage.set(
|
let _ = storage.set(
|
||||||
"inventory",
|
"inventory",
|
||||||
@ -405,29 +461,37 @@ impl HttpStore {
|
|||||||
Ok((
|
Ok((
|
||||||
filtered_ingredients.into_iter().collect(),
|
filtered_ingredients.into_iter().collect(),
|
||||||
modified_amts.into_iter().collect(),
|
modified_amts.into_iter().collect(),
|
||||||
|
extra_items,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn save_inventory_data(
|
pub async fn save_inventory_data(
|
||||||
&self,
|
&self,
|
||||||
filtered_ingredients: BTreeSet<IngredientKey>,
|
filtered_ingredients: BTreeSet<IngredientKey>,
|
||||||
modified_amts: BTreeMap<IngredientKey, String>,
|
modified_amts: BTreeMap<IngredientKey, String>,
|
||||||
|
extra_items: Vec<(String, String)>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut path = self.root.clone();
|
let mut path = self.v2_path();
|
||||||
|
path.push_str("/inventory");
|
||||||
let filtered_ingredients: Vec<IngredientKey> = filtered_ingredients.into_iter().collect();
|
let filtered_ingredients: Vec<IngredientKey> = filtered_ingredients.into_iter().collect();
|
||||||
let modified_amts: Vec<(IngredientKey, String)> = modified_amts.into_iter().collect();
|
let modified_amts: Vec<(IngredientKey, String)> = modified_amts.into_iter().collect();
|
||||||
let serialized_inventory = to_string(&(filtered_ingredients, modified_amts))
|
let serialized_inventory = to_string(&(filtered_ingredients, modified_amts, extra_items))
|
||||||
.expect("Unable to encode plan as json");
|
.expect("Unable to encode plan as json");
|
||||||
let storage = js_lib::get_storage();
|
let storage = js_lib::get_storage();
|
||||||
let _ = storage.set("inventory", &serialized_inventory);
|
debug!("Storing inventory data in cache");
|
||||||
path.push_str("/inventory");
|
storage
|
||||||
|
.set("inventory", &serialized_inventory)
|
||||||
|
.expect("Failed to cache inventory data");
|
||||||
|
debug!("Storing inventory data via API");
|
||||||
let resp = reqwasm::http::Request::post(&path)
|
let resp = reqwasm::http::Request::post(&path)
|
||||||
.body(&serialized_inventory)
|
.body(&serialized_inventory)
|
||||||
.header("content-type", "application/json")
|
.header("content-type", "application/json")
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
if resp.status() != 200 {
|
if resp.status() != 200 {
|
||||||
|
debug!("Invalid response back");
|
||||||
Err(format!("Status: {}", resp.status()).into())
|
Err(format!("Status: {}", resp.status()).into())
|
||||||
} else {
|
} else {
|
||||||
debug!("We got a valid response back!");
|
debug!("We got a valid response back!");
|
||||||
|
@ -21,7 +21,7 @@ use crate::{api, routing::Handler as RouteHandler};
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn UI<G: Html>(cx: Scope) -> View<G> {
|
pub fn UI<G: Html>(cx: Scope) -> View<G> {
|
||||||
crate::app_state::State::provide_context(cx);
|
crate::app_state::State::provide_context(cx);
|
||||||
api::HttpStore::provide_context(cx, "/api/v1".to_owned());
|
api::HttpStore::provide_context(cx, "/api".to_owned());
|
||||||
info!("Starting UI");
|
info!("Starting UI");
|
||||||
|
|
||||||
let view = create_signal(cx, View::empty());
|
let view = create_signal(cx, View::empty());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user