WIP...
This commit is contained in:
parent
e7d2f8f6c7
commit
57d7e7a3ce
17 changed files with 608 additions and 500 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,6 +10,7 @@ backend/file.db
|
||||||
conf.ron
|
conf.ron
|
||||||
|
|
||||||
*.wasm
|
*.wasm
|
||||||
|
*.asml.bak
|
||||||
node_modules
|
node_modules
|
||||||
pkg
|
pkg
|
||||||
package-lock.json
|
package-lock.json
|
||||||
1020
Cargo.lock
generated
1020
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
3
TODO.md
3
TODO.md
|
|
@ -4,8 +4,9 @@
|
||||||
* Describe the use cases.
|
* Describe the use cases.
|
||||||
* Define the UI (mockups).
|
* Define the UI (mockups).
|
||||||
* Two CSS: one for desktop and one for mobile
|
* Two CSS: one for desktop and one for mobile
|
||||||
|
* Use CSS flex/grid to define a good design/layout
|
||||||
* Define the logic behind each page and action.
|
* Define the logic behind each page and action.
|
||||||
* Add support to language into db model.
|
* Add support to translations into db model.
|
||||||
|
|
||||||
[ok] Change all id to i64
|
[ok] Change all id to i64
|
||||||
[ok] Check cookie lifetime -> Session by default
|
[ok] Check cookie lifetime -> Session by default
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ itertools = "0.10"
|
||||||
clap = {version = "4", features = ["derive"]}
|
clap = {version = "4", features = ["derive"]}
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.9"
|
env_logger = "0.10"
|
||||||
|
|
||||||
r2d2_sqlite = "0.21" # Connection pool with rusqlite (SQLite access).
|
r2d2_sqlite = "0.21" # Connection pool with rusqlite (SQLite access).
|
||||||
r2d2 = "0.8"
|
r2d2 = "0.8"
|
||||||
|
|
@ -27,10 +27,10 @@ rusqlite = {version = "0.28", features = ["bundled", "chrono"]}
|
||||||
|
|
||||||
futures = "0.3" # Needed by askam with the feature 'with-actix-web'.
|
futures = "0.3" # Needed by askam with the feature 'with-actix-web'.
|
||||||
|
|
||||||
askama = {version = "0.11", features = ["with-actix-web", "mime", "mime_guess", "markdown"]}
|
askama = {version = "0.12", features = ["with-actix-web", "mime", "mime_guess", "markdown"]}
|
||||||
askama_actix = "0.13"
|
askama_actix = "0.14"
|
||||||
|
|
||||||
argon2 = {version = "0.4", features = ["default", "std"]}
|
argon2 = {version = "0.5", features = ["default", "std"]}
|
||||||
rand_core = {version = "0.6", features = ["std"]}
|
rand_core = {version = "0.6", features = ["std"]}
|
||||||
|
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ impl Connection {
|
||||||
|
|
||||||
fn get(&self) -> Result<PooledConnection<SqliteConnectionManager>> {
|
fn get(&self) -> Result<PooledConnection<SqliteConnectionManager>> {
|
||||||
let con = self.pool.get()?;
|
let con = self.pool.get()?;
|
||||||
|
// ('foreign_keys' is ON by default).
|
||||||
con.pragma_update(None, "synchronous", "NORMAL")?;
|
con.pragma_update(None, "synchronous", "NORMAL")?;
|
||||||
Ok(con)
|
Ok(con)
|
||||||
}
|
}
|
||||||
|
|
@ -124,13 +125,12 @@ 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_db(&self) -> Result<()> {
|
fn create_or_update_db(&self) -> Result<()> {
|
||||||
// Check the Database version.
|
|
||||||
let mut con = self.get()?;
|
let mut con = self.get()?;
|
||||||
con.pragma_update(None, "journal_mode", "WAL")?;
|
con.pragma_update(None, "journal_mode", "WAL")?; // Note: use "WAL2" when available.
|
||||||
|
|
||||||
let tx = con.transaction()?;
|
let tx = con.transaction()?;
|
||||||
|
|
||||||
// Version 0 corresponds to an empty database.
|
// Check current database version. (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'",
|
||||||
|
|
@ -456,11 +456,14 @@ impl Connection {
|
||||||
match con
|
match con
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT [Recipe].[id] FROM [Recipe]
|
"SELECT [Recipe].[id] FROM [Recipe]
|
||||||
INNER JOIN [Image] ON [Image].[recipe_id] = [Recipe].[id]
|
LEFT JOIN [Image] ON [Image].[recipe_id] = [Recipe].[id]
|
||||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
LEFT JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||||
WHERE [Recipe].[user_id] = ?1
|
WHERE [Recipe].[user_id] = ?1
|
||||||
AND [Recipe].[estimate_time] = NULL
|
AND [Recipe].[title] = ''
|
||||||
AND [Recipe].[description] = NULL",
|
AND [Recipe].[estimate_time] IS NULL
|
||||||
|
AND [Recipe].[description] = ''
|
||||||
|
AND [Image].[id] IS NULL
|
||||||
|
AND [Group].[id] IS NULL",
|
||||||
[user_id],
|
[user_id],
|
||||||
|r| Ok(r.get::<&str, i64>("id")?),
|
|r| Ok(r.get::<&str, i64>("id")?),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ async fn main() -> std::io::Result<()> {
|
||||||
.service(services::sign_out)
|
.service(services::sign_out)
|
||||||
.service(services::view_recipe)
|
.service(services::view_recipe)
|
||||||
.service(services::edit_recipe)
|
.service(services::edit_recipe)
|
||||||
|
.service(services::new_recipe)
|
||||||
|
.service(services::webapi::set_recipe_title)
|
||||||
|
.service(services::webapi::set_recipe_description)
|
||||||
.service(fs::Files::new("/static", "static"))
|
.service(fs::Files::new("/static", "static"))
|
||||||
.default_service(web::to(services::not_found))
|
.default_service(web::to(services::not_found))
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
email, model, utils,
|
email, model, utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod api;
|
pub mod webapi;
|
||||||
|
|
||||||
///// UTILS /////
|
///// UTILS /////
|
||||||
|
|
||||||
|
|
@ -255,7 +255,6 @@ pub async fn edit_recipe(
|
||||||
#[get("/recipe/new")]
|
#[get("/recipe/new")]
|
||||||
pub async fn new_recipe(
|
pub async fn new_recipe(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<(i64,)>,
|
|
||||||
connection: web::Data<db::Connection>,
|
connection: web::Data<db::Connection>,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
let user = match get_current_user(&req, connection.clone()).await {
|
let user = match get_current_user(&req, connection.clone()).await {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% block body_container %}{% endblock %}
|
{% block body_container %}{% endblock %}
|
||||||
<div class="footer-container">gburri - 2022</div>
|
<footer class="footer-container">gburri - 2022</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -5,12 +5,14 @@
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% block main_container %}
|
{% block main_container %}
|
||||||
<div class="list">
|
<nav class="list">
|
||||||
<ul>
|
<ul>
|
||||||
{% for (id, title) in recipes %}
|
{% for (id, title) in recipes %}
|
||||||
<li>
|
<li>
|
||||||
{% match current_recipe_id %}
|
{% match current_recipe_id %}
|
||||||
{# Don't know how to avoid repetition: comparing (using '==' or .eq()) current_recipe_id.unwrap() and id doesn't work. Guards for match don't exist.
|
{# Don't know how to avoid
|
||||||
|
repetition: comparing (using '==' or .eq()) current_recipe_id.unwrap() and id doesn't work.
|
||||||
|
Guards for match don't exist.
|
||||||
See: https://github.com/djc/askama/issues/752 #}
|
See: https://github.com/djc/askama/issues/752 #}
|
||||||
{% when Some (current_id) %}
|
{% when Some (current_id) %}
|
||||||
{% if current_id == id %}
|
{% if current_id == id %}
|
||||||
|
|
@ -24,7 +26,7 @@
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</nav>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
{% extends "base_with_list.html" %}
|
{% extends "base_with_list.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<label for="title_field">Title</label>
|
<label for="title_field">Title</label>
|
||||||
<input
|
<input
|
||||||
id="title_field"
|
id="title_field"
|
||||||
|
|
@ -12,4 +11,13 @@
|
||||||
autocomplete="title"
|
autocomplete="title"
|
||||||
autofocus="autofocus" />
|
autofocus="autofocus" />
|
||||||
|
|
||||||
|
<label for="description_field">Description</label>
|
||||||
|
<input
|
||||||
|
id="title_field"
|
||||||
|
type="text"
|
||||||
|
name="title"
|
||||||
|
value="{{ current_recipe.description }}"
|
||||||
|
autocapitalize="none"
|
||||||
|
autocomplete="title"
|
||||||
|
autofocus="autofocus" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
13
doc/recipes.service
Normal file
13
doc/recipes.service
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Recipes
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=pi
|
||||||
|
WorkingDirectory=/home/pi/recipes
|
||||||
|
ExecStart=/home/pi/recipes/recipes
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -36,4 +36,4 @@ opt-level = "s"
|
||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.release]
|
[package.metadata.wasm-pack.profile.release]
|
||||||
wasm-opt = false
|
wasm-opt = false
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
wasm-pack build --target web
|
wasm-pack build --target web -- --features wee_alloc
|
||||||
cp pkg/frontend.js ../backend/static
|
cp pkg/frontend.js ../backend/static
|
||||||
cp pkg/frontend_bg.wasm ../backend/static
|
cp pkg/frontend_bg.wasm ../backend/static
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::Document;
|
use web_sys::Document;
|
||||||
|
|
||||||
pub fn edit_recipe(doc: &Document) {
|
pub fn edit_recipe(doc: &Document) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
mod utils;
|
|
||||||
mod handles;
|
mod handles;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::console;
|
use web_sys::console;
|
||||||
|
|
@ -11,7 +11,7 @@ use web_sys::console;
|
||||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern {
|
extern "C" {
|
||||||
fn alert(s: &str);
|
fn alert(s: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ pub fn main() -> Result<(), JsValue> {
|
||||||
handles::edit_recipe(&document);
|
handles::edit_recipe(&document);
|
||||||
|
|
||||||
let title_input = document.get_element_by_id("title_field").unwrap();
|
let title_input = document.get_element_by_id("title_field").unwrap();
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,4 +60,4 @@ pub fn main() -> Result<(), JsValue> {
|
||||||
// body.append_child(&val)?;
|
// body.append_child(&val)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ macro_rules! console_log {
|
||||||
// Note that this is using the `log` function imported above during
|
// Note that this is using the `log` function imported above during
|
||||||
// `bare_bones`
|
// `bare_bones`
|
||||||
($($t:tt)*) => (console::log_1(&format_args!($($t)*).to_string().into()))
|
($($t:tt)*) => (console::log_1(&format_args!($($t)*).to_string().into()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue