docs + locations

This commit is contained in:
JMARyA 2024-09-02 18:40:02 +02:00
parent e1618b40ef
commit 48f00d8f6f
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
17 changed files with 390 additions and 33 deletions

44
src/json_store.rs Normal file
View file

@ -0,0 +1,44 @@
use std::{collections::HashMap, ops::Deref};
use serde::Deserialize;
pub struct JSONStore<T> {
documents: HashMap<String, T>,
}
impl<T: for<'a> Deserialize<'a>> JSONStore<T> {
pub fn new(dir: &str) -> Self {
let mut documents = HashMap::new();
for e in walkdir::WalkDir::new(dir)
.into_iter()
.filter_map(std::result::Result::ok)
{
if e.path().is_dir() {
continue;
}
if e.path().extension().is_none() {
continue;
}
if e.path().extension().unwrap().to_str().unwrap() == "json" {
let path = e.path().to_str().unwrap().to_owned();
let file_name = e.path().file_stem().unwrap().to_str().unwrap().to_string();
let content = std::fs::read_to_string(path).unwrap();
let json = serde_json::from_str(&content).unwrap();
documents.insert(file_name, json);
}
}
Self { documents }
}
}
impl<T> Deref for JSONStore<T> {
type Target = HashMap<String, T>;
fn deref(&self) -> &Self::Target {
&self.documents
}
}

70
src/location.rs Normal file
View file

@ -0,0 +1,70 @@
use mongod::{
derive::{Model, Referencable},
Model, ToAPI, Validate,
};
use mongodb::bson::doc;
use serde::{Deserialize, Serialize};
use serde_json::json;
/// A Storage Location
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
pub struct Location {
/// UUID
pub _id: String,
/// Name
pub name: String,
/// Parent
pub parent: Option<String>,
/// Storage Conditions
pub conditions: Option<StorageConditions>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct StorageConditions {
/// Median temperature
pub temperature: i64,
}
impl Validate for Location {
async fn validate(&self) -> Result<(), String> {
Ok(())
}
}
impl ToAPI for Location {
async fn api(&self) -> serde_json::Value {
json!({
"id": self._id,
"name": self.name,
"parent": self.parent,
"conditions": self.conditions
})
}
}
impl Location {
pub async fn add(id: &str, o: serde_json::Value) {
let l = Location {
_id: id.to_string(),
name: o
.as_object()
.unwrap()
.get("name")
.unwrap()
.as_str()
.unwrap()
.to_string(),
parent: o
.as_object()
.unwrap()
.get("parent")
.map(|x| x.as_str().unwrap().to_string()),
conditions: serde_json::from_value(
o.as_object().unwrap().get("conditions").unwrap().clone(),
)
.unwrap(),
};
l.insert_overwrite().await.unwrap();
}
}

View file

@ -1,8 +1,15 @@
use std::ops::Deref;
use json_store::JSONStore;
use location::Location;
use mongod::Model;
use rocket::routes as route;
use rocket::{http::Method, launch};
mod db;
mod item;
mod json_store;
mod location;
mod process;
mod routes;
mod transaction;
@ -41,6 +48,11 @@ async fn rocket() -> _ {
.expect("error creating CORS options");
let itemdb = db::ItemDB::new("./itemdb").await;
let locations: JSONStore<Location> = JSONStore::new("./locations");
for location in locations.deref() {
location.1.insert_overwrite().await.unwrap();
}
rocket::build()
.mount(
@ -60,5 +72,6 @@ async fn rocket() -> _ {
],
)
.manage(itemdb)
.manage(locations)
.attach(cors)
}

View file

@ -0,0 +1,26 @@
use mongod::ToAPI;
use rocket::{get, State};
use crate::{
json_store::JSONStore,
location::Location,
routes::{api_error, FallibleApiResponse},
};
#[get("/location/<id>")]
pub async fn location_info(
id: &str,
locations: &State<JSONStore<Location>>,
) -> FallibleApiResponse {
let loc = locations
.get(id)
.ok_or_else(|| api_error("No location with that ID"))?;
Ok(loc.api().await)
}
#[get("/locations")]
pub async fn locations_info(locations: &State<JSONStore<Location>>) -> FallibleApiResponse {
// todo : recursive location map
unimplemented!()
}

View file

@ -1,9 +1,11 @@
mod demand;
mod error;
mod location;
mod supply;
pub use demand::*;
pub use error::*;
pub use location::*;
use mongod::Model;
use mongod::ToAPI;
pub use supply::*;

View file

@ -16,6 +16,7 @@ pub struct SupplyForm {
variant: String,
price: String,
origin: Option<String>,
location: Option<String>,
}
/// Route for supply action. Creates a new Transaction for the specified Item Variant.
@ -35,6 +36,7 @@ pub async fn supply_route(form: Json<SupplyForm>, itemdb: &State<ItemDB>) -> Fal
.try_into()
.map_err(|()| api_error("Price malformed"))?,
form.origin.as_deref(),
form.location.as_deref(),
)
.await;

View file

@ -1,12 +1,13 @@
use mongod::{
assert_reference_of,
derive::{Model, Referencable},
Model, Validate,
reference_of, Model, Referencable, Reference, Validate,
};
use mongodb::bson::doc;
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::item::Item;
use crate::{item::Item, location::Location};
/// A Transaction of an Item Variant
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
@ -21,6 +22,8 @@ pub struct Transaction {
pub price: Price,
/// Origin of the Item
pub origin: Option<String>,
/// The location of the Item
pub location: Option<Reference>,
/// Info on consumption of the Item
pub consumed: Option<Consumed>,
/// Timestamp of the Transaction
@ -29,6 +32,10 @@ pub struct Transaction {
impl Validate for Transaction {
async fn validate(&self) -> Result<(), String> {
if let Some(location) = &self.location {
assert_reference_of!(location, Location);
}
Ok(())
}
}
@ -45,7 +52,13 @@ pub struct Consumed {
}
impl Transaction {
pub fn new(item: &str, variant: &str, price: Price, origin: Option<&str>) -> Self {
pub async fn new(
item: &str,
variant: &str,
price: Price,
origin: Option<&str>,
location: Option<&str>,
) -> Self {
Self {
_id: uuid::Uuid::new_v4().to_string(),
item: item.to_string(),
@ -53,6 +66,11 @@ impl Transaction {
price,
consumed: None,
origin: origin.map(std::string::ToString::to_string),
location: if let Some(location) = location {
reference_of!(Location, location)
} else {
None
},
timestamp: chrono::Utc::now().timestamp(),
}
}

View file

@ -142,8 +142,13 @@ impl Variant {
/// # Returns
///
/// Returns a UUID string representing the transaction.
pub async fn supply(&self, price: Price, origin: Option<&str>) -> String {
let t = Transaction::new(&self.item, &self.variant, price, origin);
pub async fn supply(
&self,
price: Price,
origin: Option<&str>,
location: Option<&str>,
) -> String {
let t = Transaction::new(&self.item, &self.variant, price, origin, location).await;
t.insert().await.unwrap();