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