Initial model + some various changes
This commit is contained in:
parent
a080d19cb9
commit
108476e355
17 changed files with 1070 additions and 1286 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -6,3 +6,4 @@ backend/data/recipes.sqlite-journal
|
||||||
style.css.map
|
style.css.map
|
||||||
backend/static/style.css
|
backend/static/style.css
|
||||||
backend/file.db
|
backend/file.db
|
||||||
|
*.sqlite
|
||||||
2014
Cargo.lock
generated
2014
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,6 +6,8 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
strip = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
lto = true
|
lto = true
|
||||||
# opt-level = 'z' # Optimize for size.
|
# Tell `rustc` to optimize for small code size.
|
||||||
|
# opt-level = "s"
|
||||||
|
|
|
||||||
27
README.md
27
README.md
|
|
@ -1,9 +1,30 @@
|
||||||
== Autoreload
|
# Use cases
|
||||||
|
|
||||||
https://actix.rs/docs/autoreload/
|
## Create a recipe
|
||||||
|
(A group is automatically created)
|
||||||
|
|
||||||
|
## Create a groupe
|
||||||
|
|
||||||
== Documentation
|
## Move a group
|
||||||
|
|
||||||
|
## Delete a group
|
||||||
|
|
||||||
|
## Create a step
|
||||||
|
|
||||||
|
## Move a step
|
||||||
|
|
||||||
|
## Delete a step
|
||||||
|
|
||||||
|
# Technical
|
||||||
|
|
||||||
|
## Useful URLs
|
||||||
|
|
||||||
* Rust patterns : https://github.com/rust-unofficial/patterns/tree/master/patterns
|
* Rust patterns : https://github.com/rust-unofficial/patterns/tree/master/patterns
|
||||||
* Rusqlite (SQLite) : https://docs.rs/rusqlite/0.20.0/rusqlite/
|
* Rusqlite (SQLite) : https://docs.rs/rusqlite/0.20.0/rusqlite/
|
||||||
|
|
||||||
|
## How to develop
|
||||||
|
|
||||||
|
Autoreload: https://actix.rs/docs/autoreload/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
3
TODO.md
3
TODO.md
|
|
@ -1,5 +1,6 @@
|
||||||
* (WIP) Enable Logging to file.
|
* (WIP) Enable Logging to file.
|
||||||
* Define the recipes model (UML).
|
* Describe the use cases.
|
||||||
|
* Define the recipes model (SYSML).
|
||||||
* Implement the model as relational with SQLite.
|
* Implement the model as relational with SQLite.
|
||||||
* Create and update functions.
|
* Create and update functions.
|
||||||
* Define the UI (mockups).
|
* Define the UI (mockups).
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,26 @@
|
||||||
name = "recipes"
|
name = "recipes"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
authors = ["Grégory Burri <greg.burri@gmail.com>"]
|
authors = ["Grégory Burri <greg.burri@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "2"
|
actix-web = "4"
|
||||||
actix-rt = "1"
|
actix-files = "0.6"
|
||||||
actix-files = "0.2"
|
serde = { version = "1.0", features = [ "derive" ] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
listenfd = "0.3" # To watch file modifications and automatically launch a build process (only used in dev/debug).
|
|
||||||
ron = "0.6" # Rust object notation, to load configuration files.
|
|
||||||
itertools = "0.9"
|
|
||||||
|
|
||||||
r2d2_sqlite = "0.16" # Connection pool with rusqlite (SQLite access).
|
ron = "0.8" # Rust object notation, to load configuration files.
|
||||||
|
itertools = "0.10"
|
||||||
|
|
||||||
|
env_logger = "0.9"
|
||||||
|
|
||||||
|
r2d2_sqlite = "0.21" # Connection pool with rusqlite (SQLite access).
|
||||||
r2d2 = "0.8"
|
r2d2 = "0.8"
|
||||||
|
|
||||||
futures = "0.3" # Needed by askam with the feature 'with-actix-web'.
|
futures = "0.3" # Needed by askam with the feature 'with-actix-web'.
|
||||||
|
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
|
|
||||||
[dependencies.rusqlite]
|
askama = { version = "0.11", features = ["with-actix-web", "mime", "mime_guess"] }
|
||||||
version = "0.23"
|
askama_actix = "0.13"
|
||||||
features = ["bundled"]
|
|
||||||
|
|
||||||
# Template system.
|
rusqlite = { version = "0.28", features = ["bundled"] }
|
||||||
[dependencies.askama]
|
|
||||||
version = "0.9"
|
|
||||||
features = ["with-actix-web"]
|
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,37 @@ What is build here:
|
||||||
- Compile the SASS file to CSS file.
|
- Compile the SASS file to CSS file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::process::Command;
|
use std::{ env, process::{ Command, Output }, path::Path };
|
||||||
|
|
||||||
|
fn exists_in_path<P>(filename: P) -> bool
|
||||||
|
where P: AsRef<Path> {
|
||||||
|
for path in env::split_paths(&env::var_os("PATH").unwrap()) {
|
||||||
|
if path.join(&filename).is_file() { return true; }
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=style.scss");
|
println!("cargo:rerun-if-changed=style.scss");
|
||||||
|
|
||||||
let output =
|
fn run_sass(command: &mut Command) -> Output {
|
||||||
Command::new("sass")
|
command
|
||||||
.arg("./style.scss")
|
.arg("style.scss")
|
||||||
.arg("./static/style.css")
|
.arg("static/style.css")
|
||||||
.output()
|
.output()
|
||||||
.expect("Unable to compile SASS file, install SASS, see https://sass-lang.com/");
|
.expect("Unable to compile SASS file, install SASS, see https://sass-lang.com/")
|
||||||
|
}
|
||||||
|
|
||||||
|
let output =
|
||||||
|
if exists_in_path("sass.bat") {
|
||||||
|
run_sass(Command::new("cmd").args(&["/C", "sass.bat"]))
|
||||||
|
} else {
|
||||||
|
run_sass(&mut Command::new("sass"))
|
||||||
|
};
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
//panic!("Unable to compile SASS file, install SASS, see https://sass-lang.com/")
|
// SASS will put the error in the file.
|
||||||
let error = std::fs::read_to_string("./static/style.css").expect("unable to read style.css");
|
let error = std::fs::read_to_string("./static/style.css").expect("unable to read style.css");
|
||||||
panic!(error);
|
panic!("{}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
# To launch RUP and watching source. See https://actix.rs/docs/autoreload/.
|
# To launch RUP and watching source. See https://actix.rs/docs/autoreload/.
|
||||||
systemfd --no-pid -s http::8082 -- cargo watch -x run
|
cargo watch -x run
|
||||||
64
backend/sql/version_1.sql
Normal file
64
backend/sql/version_1.sql
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
-- Version 1 is the initial structure.
|
||||||
|
CREATE TABLE Version (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
version INTEGER NOT NULL UNIQUE,
|
||||||
|
datetime DATETIME
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE User (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
email TEXT NOT NULL,
|
||||||
|
password TEXT NOT NULL, -- Hashed and salted.
|
||||||
|
name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Recipe (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
estimate_time INTEGER,
|
||||||
|
description DATETIME,
|
||||||
|
|
||||||
|
FOREIGN KEY(user_id) REFERENCES User(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Quantity (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
value REAL,
|
||||||
|
unit TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Ingredient (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
quantity_id INTEGER,
|
||||||
|
input_step_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(quantity_id) REFERENCES Quantity(id),
|
||||||
|
FOREIGN KEY(input_step_id) REFERENCES Step(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE [Group] (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Step (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
action TEXT NOT NULL,
|
||||||
|
group_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(group_id) REFERENCES [Group](id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IntermediateSubstance (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
quantity_id INTEGER,
|
||||||
|
output_step_id INTEGER NOT NULL,
|
||||||
|
input_step_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(quantity_id) REFERENCES Quantity(id),
|
||||||
|
FOREIGN KEY(output_step_id) REFERENCES Step(id),
|
||||||
|
FOREIGN KEY(input_step_id) REFERENCES Step(id)
|
||||||
|
);
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
pub static FILE_CONF: &str = "conf.ron";
|
pub const FILE_CONF: &str = "conf.ron";
|
||||||
pub static DB_DIRECTORY: &str = "data";
|
pub const DB_DIRECTORY: &str = "data";
|
||||||
pub static DB_FILENAME: &str = "recipes.sqlite";
|
pub const DB_FILENAME: &str = "data/recipes.sqlite";
|
||||||
|
pub const SQL_FILENAME: &str = "sql/version_{VERSION}.sql";
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
use std::path::Path;
|
use crate::consts::SQL_FILENAME;
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
//use rusqlite::types::ToSql;
|
|
||||||
//use rusqlite::{Connection, Result, NO_PARAMS};
|
|
||||||
|
|
||||||
//extern crate r2d2;
|
|
||||||
//extern crate r2d2_sqlite;
|
|
||||||
//extern crate rusqlite;
|
|
||||||
|
|
||||||
use r2d2_sqlite::SqliteConnectionManager;
|
|
||||||
use r2d2::Pool;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum DbError {
|
|
||||||
SqliteError(rusqlite::Error),
|
|
||||||
R2d2Error(r2d2::Error),
|
|
||||||
UnsupportedVersion(i32),
|
|
||||||
}
|
|
||||||
|
|
||||||
use super::consts;
|
use super::consts;
|
||||||
|
|
||||||
|
use std::{fs::{self, File}, path::Path, io::Read};
|
||||||
|
|
||||||
|
//use rusqlite::types::ToSql;
|
||||||
|
//use rusqlite::{Connection, Result, NO_PARAMS};
|
||||||
|
use r2d2::Pool;
|
||||||
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
|
||||||
const CURRENT_DB_VERSION: u32 = 1;
|
const CURRENT_DB_VERSION: u32 = 1;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DBError {
|
||||||
|
SqliteError(rusqlite::Error),
|
||||||
|
R2d2Error(r2d2::Error),
|
||||||
|
UnsupportedVersion(u32),
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
//con: rusqlite::Connection
|
//con: rusqlite::Connection
|
||||||
pool: Pool<SqliteConnectionManager>
|
pool: Pool<SqliteConnectionManager>
|
||||||
|
|
@ -32,20 +29,20 @@ pub struct Recipe {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<rusqlite::Error> for DbError {
|
impl std::convert::From<rusqlite::Error> for DBError {
|
||||||
fn from(error: rusqlite::Error) -> Self {
|
fn from(error: rusqlite::Error) -> Self {
|
||||||
DbError::SqliteError(error)
|
DBError::SqliteError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<r2d2::Error> for DbError {
|
impl std::convert::From<r2d2::Error> for DBError {
|
||||||
fn from(error: r2d2::Error) -> Self {
|
fn from(error: r2d2::Error) -> Self {
|
||||||
DbError::R2d2Error(error)
|
DBError::R2d2Error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
pub fn new() -> Result<Connection, DbError> {
|
pub fn new() -> Result<Connection, DBError> {
|
||||||
|
|
||||||
let data_dir = Path::new(consts::DB_DIRECTORY);
|
let data_dir = Path::new(consts::DB_DIRECTORY);
|
||||||
|
|
||||||
|
|
@ -53,7 +50,7 @@ impl Connection {
|
||||||
fs::DirBuilder::new().create(data_dir).unwrap();
|
fs::DirBuilder::new().create(data_dir).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let manager = SqliteConnectionManager::file("file.db");
|
let manager = SqliteConnectionManager::file(consts::DB_FILENAME);
|
||||||
let pool = r2d2::Pool::new(manager).unwrap();
|
let pool = r2d2::Pool::new(manager).unwrap();
|
||||||
|
|
||||||
let connection = Connection { pool };
|
let connection = Connection { pool };
|
||||||
|
|
@ -65,7 +62,7 @@ impl Connection {
|
||||||
* Called after the connection has been established for creating or updating the database.
|
* Called after the connection has been established for creating or updating the database.
|
||||||
* The 'Version' table tracks the current state of the database.
|
* The 'Version' table tracks the current state of the database.
|
||||||
*/
|
*/
|
||||||
fn create_or_update(self: &Self) -> Result<(), DbError> {
|
fn create_or_update(self: &Self) -> Result<(), DBError> {
|
||||||
// let connection = Connection::new();
|
// let connection = Connection::new();
|
||||||
// let mut stmt = connection.sqlite_con.prepare("SELECT * FROM versions ORDER BY date").unwrap();
|
// let mut stmt = connection.sqlite_con.prepare("SELECT * FROM versions ORDER BY date").unwrap();
|
||||||
// let mut stmt = connection.sqlite_con.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='versions'").unwrap();
|
// let mut stmt = connection.sqlite_con.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='versions'").unwrap();
|
||||||
|
|
@ -74,13 +71,14 @@ impl Connection {
|
||||||
let mut con = self.pool.get()?;
|
let mut con = self.pool.get()?;
|
||||||
let tx = con.transaction()?;
|
let tx = con.transaction()?;
|
||||||
|
|
||||||
|
// Version 0 corresponds to an empty database.
|
||||||
let mut version = {
|
let mut version = {
|
||||||
match tx.query_row(
|
match tx.query_row(
|
||||||
"SELECT [name] FROM [sqlite_master] WHERE [type] = 'table' AND [name] = 'Version'",
|
"SELECT [name] FROM [sqlite_master] WHERE [type] = 'table' AND [name] = 'Version'",
|
||||||
rusqlite::NO_PARAMS,
|
[],
|
||||||
|row| row.get::<usize, String>(0)
|
|row| row.get::<usize, String>(0)
|
||||||
) {
|
) {
|
||||||
Ok(_) => tx.query_row("SELECT [version] FROM [Version]", rusqlite::NO_PARAMS, |row| row.get(0)).unwrap_or_default(),
|
Ok(_) => tx.query_row("SELECT [version] FROM [Version]", [], |row| row.get(0)).unwrap_or_default(),
|
||||||
Err(_) => 0
|
Err(_) => 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -94,45 +92,33 @@ impl Connection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_to_next_version(version: i32, tx: &rusqlite::Transaction) -> Result<bool, DbError> {
|
fn update_to_next_version(current_version: u32, tx: &rusqlite::Transaction) -> Result<bool, DBError> {
|
||||||
match version {
|
let next_version = current_version + 1;
|
||||||
0 => {
|
|
||||||
println!("Update to version 1...");
|
|
||||||
|
|
||||||
// Initial structure.
|
if next_version <= CURRENT_DB_VERSION {
|
||||||
tx.execute_batch(
|
println!("Update to version {}...", next_version);
|
||||||
"
|
}
|
||||||
CREATE TABLE [Version] (
|
|
||||||
[id] INTEGER PRIMARY KEY,
|
|
||||||
[version] INTEGER NOT NULL UNIQUE,
|
|
||||||
[datetime] INTEGER DATETIME
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE [Recipe] (
|
fn ok(updated: bool) -> Result<bool, DBError> {
|
||||||
[id] INTEGER PRIMARY KEY,
|
if updated {
|
||||||
[title] INTEGER NOT NULL,
|
println!("Version updated");
|
||||||
[description] INTEGER DATETIME
|
}
|
||||||
);
|
Ok(updated)
|
||||||
"
|
}
|
||||||
)?;
|
|
||||||
|
|
||||||
/*
|
match next_version {
|
||||||
tx.execute(
|
1 => {
|
||||||
"
|
tx.execute_batch(&load_sql_file(next_version)?)?;
|
||||||
INSERT INTO Version
|
|
||||||
",
|
|
||||||
rusqlite::NO_PARAMS
|
|
||||||
);*/
|
|
||||||
|
|
||||||
Ok(true)
|
ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current version.
|
// Version 1 doesn't exist yet.
|
||||||
1 =>
|
2 =>
|
||||||
Ok(false),
|
ok(false),
|
||||||
|
|
||||||
v =>
|
v =>
|
||||||
Err(DbError::UnsupportedVersion(v)),
|
Err(DBError::UnsupportedVersion(v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,3 +126,11 @@ impl Connection {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_sql_file(version: u32) -> Result<String, DBError> {
|
||||||
|
let sql_file = SQL_FILENAME.replace("{VERSION}", &version.to_string());
|
||||||
|
let mut file = File::open(&sql_file).map_err(|err| DBError::Other(format!("Cannot open SQL file ({}): {}", &sql_file, err.to_string())))?;
|
||||||
|
let mut sql = String::new();
|
||||||
|
file.read_to_string(&mut sql).map_err(|err| DBError::Other(format!("Cannot read SQL file ({}) : {}", &sql_file, err.to_string())))?;
|
||||||
|
Ok(sql)
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,14 @@ use std::{fs::File, env::args};
|
||||||
use actix_files as fs;
|
use actix_files as fs;
|
||||||
use actix_web::{get, web, Responder, middleware, App, HttpServer, HttpResponse, HttpRequest, web::Query};
|
use actix_web::{get, web, Responder, middleware, App, HttpServer, HttpResponse, HttpRequest, web::Query};
|
||||||
|
|
||||||
use askama::Template;
|
use askama_actix::Template;
|
||||||
use listenfd::ListenFd;
|
|
||||||
use ron::de::from_reader;
|
use ron::de::from_reader;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
|
mod model;
|
||||||
mod db;
|
mod db;
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
|
|
@ -53,10 +53,13 @@ fn get_exe_name() -> String {
|
||||||
first_arg[first_arg.rfind(sep).unwrap()+1..].to_string()
|
first_arg[first_arg.rfind(sep).unwrap()+1..].to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
if process_args() { return Ok(()) }
|
if process_args() { return Ok(()) }
|
||||||
|
|
||||||
|
std::env::set_var("RUST_LOG", "actix_web=debug");
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
println!("Starting Recipes as web server...");
|
println!("Starting Recipes as web server...");
|
||||||
|
|
||||||
let config: Config = {
|
let config: Config = {
|
||||||
|
|
@ -73,11 +76,11 @@ async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
std::env::set_var("RUST_LOG", "actix_web=info");
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||||
|
|
||||||
let mut listenfd = ListenFd::from_env();
|
|
||||||
let mut server =
|
let mut server =
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
|| {
|
|| {
|
||||||
App::new()
|
App::new()
|
||||||
|
.wrap(middleware::Logger::default())
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.service(home_page)
|
.service(home_page)
|
||||||
.service(view_page)
|
.service(view_page)
|
||||||
|
|
@ -85,12 +88,7 @@ async fn main() -> std::io::Result<()> {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
server =
|
server = server.bind(&format!("0.0.0.0:{}", config.port)).unwrap();
|
||||||
if let Some(l) = listenfd.take_tcp_listener(0).unwrap() {
|
|
||||||
server.listen(l).unwrap()
|
|
||||||
} else {
|
|
||||||
server.bind(&format!("0.0.0.0:{}", config.port)).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
server.run().await
|
server.run().await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
struct Recipe {
|
struct Recipe {
|
||||||
ingredients: Vec<Ingredient>,
|
title: String,
|
||||||
process: Vec<Group>,
|
estimate_time: Option<i32>, // [min].
|
||||||
|
difficulty: Option<Difficulty>,
|
||||||
|
|
||||||
|
//ingredients: Vec<Ingredient>, // For four people.
|
||||||
|
process: Vec<Group>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Ingredient {
|
struct Ingredient {
|
||||||
quantity: Quantity,
|
quantity: Option<Quantity>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12,15 +16,16 @@ struct Quantity {
|
||||||
value: f32,
|
value: f32,
|
||||||
unit: String,
|
unit: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Group {
|
struct Group {
|
||||||
name: String,
|
name: Option<String>,
|
||||||
steps: Vec<Step>,
|
steps: Vec<Step>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Step {
|
struct Step {
|
||||||
action: String,
|
action: String,
|
||||||
input: Vec<StepInput>,
|
input: Vec<StepInput>,
|
||||||
output: Vec<IntermediateSubstance>,
|
output: Vec<IntermediateSubstance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IntermediateSubstance {
|
struct IntermediateSubstance {
|
||||||
|
|
@ -30,5 +35,12 @@ struct IntermediateSubstance {
|
||||||
|
|
||||||
enum StepInput {
|
enum StepInput {
|
||||||
Ingredient(Ingredient),
|
Ingredient(Ingredient),
|
||||||
IntermediateSubstance,
|
IntermediateSubstance(IntermediateSubstance),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Difficulty {
|
||||||
|
Unknown,
|
||||||
|
Easy,
|
||||||
|
Medium,
|
||||||
|
Hard,
|
||||||
}
|
}
|
||||||
|
|
@ -8,10 +8,10 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="header-container"><h1><a href="/">RECIPES</a></h1></div>
|
<div class="header-container"><h1><a href="/">~ RECIPES ~</a></h1></div>
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
{% block main_container %}{% endblock %}
|
{% block main_container %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-container">gburri - 2020</div>
|
<div class="footer-container">gburri - 2022</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{% extends "base_with_list.html" %}
|
{% extends "base_with_list.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
HOME
|
|
||||||
|
*** HOME - PUT SOMETHING HERE ***
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Grégory Burri <greg.burri@gmail.com>"]
|
authors = ["Grégory Burri <greg.burri@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,9 @@ Copy-SSH -source "./target/arm-unknown-linux-gnueabihf/release/recipes" -destina
|
||||||
Invoke-SSH "rm -rf recipes/static"
|
Invoke-SSH "rm -rf recipes/static"
|
||||||
Copy-SSH -source "./backend/static/" -destination "~/recipes/"
|
Copy-SSH -source "./backend/static/" -destination "~/recipes/"
|
||||||
|
|
||||||
|
Copy-SSH -source "./backend/sql/" -destination "~/recipes/"
|
||||||
|
|
||||||
Invoke-SSH "chmod u+x recipes/recipes"
|
Invoke-SSH "chmod u+x recipes/recipes"
|
||||||
Invoke-SSH "strip recipes/recipes"
|
|
||||||
Invoke-SSH "sudo systemctl start recipes"
|
Invoke-SSH "sudo systemctl start recipes"
|
||||||
|
|
||||||
Write-Output "Deployment finished"
|
Write-Output "Deployment finished"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue