commit
a1b8f5a1a1
@ -0,0 +1,4 @@ |
|||||||
|
/target |
||||||
|
**/*.rs.bk |
||||||
|
.idea/ |
||||||
|
inventory.json |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="NodePackageJsonFileManager"> |
||||||
|
<packageJsonPaths /> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,2 @@ |
|||||||
|
# Default ignored files |
||||||
|
/workspace.xml |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@ |
|||||||
|
[package] |
||||||
|
name = "rocket-inv" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
rocket-download-response = "0.4.9" |
||||||
|
#rocket-include-tera = "0.4.5" |
||||||
|
|
||||||
|
serde = { version = "1.0", features = ["derive"] } |
||||||
|
serde_json = "1.0" |
||||||
|
json_dotpath = "0.1.2" |
||||||
|
|
||||||
|
parking_lot = "0.10.0" |
||||||
|
|
||||||
|
[dependencies.rocket] |
||||||
|
version = "0.4.2" |
||||||
|
default-features = false |
||||||
|
|
||||||
|
[dependencies.rocket_contrib] |
||||||
|
version = "0.4.2" |
||||||
|
default-features = false |
||||||
|
features = ["json", "serve", "tera_templates"] |
@ -0,0 +1,2 @@ |
|||||||
|
[global] |
||||||
|
port = 8123 |
@ -0,0 +1,39 @@ |
|||||||
|
#![feature(proc_macro_hygiene, decl_macro)] |
||||||
|
|
||||||
|
#[macro_use] extern crate rocket; |
||||||
|
#[macro_use] extern crate serde; |
||||||
|
|
||||||
|
//use rocket::request::FromSegments;
|
||||||
|
//use rocket::http::uri::Segments;
|
||||||
|
//use rocket_contrib::serve::StaticFiles;
|
||||||
|
use rocket_contrib::templates::Template; |
||||||
|
|
||||||
|
mod store; |
||||||
|
use crate::store::Store; |
||||||
|
use rocket::State; |
||||||
|
use parking_lot::RwLock; |
||||||
|
use rocket::response::Redirect; |
||||||
|
use rocket::http::Status; |
||||||
|
use rocket::request::Form; |
||||||
|
use std::collections::HashMap; |
||||||
|
|
||||||
|
#[get("/")] |
||||||
|
fn index(store : State<RwLock<Store>>) -> Template { |
||||||
|
let mut context = HashMap::new(); |
||||||
|
let rg = store.read(); |
||||||
|
context.insert("records", &rg.parts); |
||||||
|
Template::render("index", context) |
||||||
|
} |
||||||
|
|
||||||
|
#[post("/add", data="<record>")] |
||||||
|
fn add_part(store : State<RwLock<Store>>, record : Form<store::Part>) -> Redirect { |
||||||
|
store.write().add(record.into_inner()); |
||||||
|
Redirect::to(uri!(index)) |
||||||
|
} |
||||||
|
|
||||||
|
fn main() { |
||||||
|
rocket::ignite() |
||||||
|
.attach(Template::fairing()) |
||||||
|
.manage(RwLock::new(Store::new())) |
||||||
|
.mount("/", routes![index, add_part]).launch(); |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
use std::fs::{File, OpenOptions}; |
||||||
|
use std::io::{Read, Write, Error}; |
||||||
|
use std::path::Path; |
||||||
|
use rocket::request::FromForm; |
||||||
|
|
||||||
|
#[derive(Serialize,Deserialize)] |
||||||
|
pub struct Store { |
||||||
|
pub parts : Vec<Part> |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Serialize,Deserialize,FromForm)] |
||||||
|
pub struct Part { |
||||||
|
name : String, |
||||||
|
quantity : usize, |
||||||
|
location : String, |
||||||
|
} |
||||||
|
|
||||||
|
fn load_file_or(file : impl AsRef<Path>, def : String) -> String { |
||||||
|
let mut file = match File::open(file) { |
||||||
|
Ok(file) => file, |
||||||
|
Err(_) => return def |
||||||
|
}; |
||||||
|
|
||||||
|
let mut buf = String::new(); |
||||||
|
if file.read_to_string(&mut buf).is_err() { |
||||||
|
return def; |
||||||
|
} |
||||||
|
|
||||||
|
buf |
||||||
|
} |
||||||
|
|
||||||
|
impl Store { |
||||||
|
pub fn new() -> Self { |
||||||
|
let mut file = load_file_or("inventory.json", "[]".to_string()); |
||||||
|
|
||||||
|
Store { |
||||||
|
parts: serde_json::from_str(&file).unwrap(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add(&mut self, part : Part) { |
||||||
|
self.parts.push(part); |
||||||
|
|
||||||
|
self.persist() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn persist(&self) { |
||||||
|
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open("inventory.json").unwrap(); |
||||||
|
|
||||||
|
file.write(serde_json::to_string(&self.parts).unwrap().as_bytes()).unwrap(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
|
||||||
|
<form action="/add" method="POST"> |
||||||
|
Name: <input type="text" name="name"><br> |
||||||
|
Qty: <input type="number" step="1" min="0" name="quantity"><br> |
||||||
|
Location: <input type="text" name="location"><br> |
||||||
|
<button type="submit">Add</button> |
||||||
|
</form> |
||||||
|
|
||||||
|
<ul> |
||||||
|
{% for record in records %} |
||||||
|
<li> |
||||||
|
{{ record.name }} x {{ record.quantity }} in {{ record.location }} |
||||||
|
</li> |
||||||
|
{% endfor %} |
||||||
|
</ul> |
Loading…
Reference in new issue