Add tables for shopping list and planner
This commit is contained in:
parent
0d3c63013e
commit
d9449de02b
8 changed files with 99 additions and 76 deletions
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||
common = { path = "../common" }
|
||||
|
||||
axum = { version = "0.8", features = ["macros"] }
|
||||
axum-extra = { version = "0.10", features = ["cookie"] }
|
||||
axum-extra = { version = "0.11", features = ["cookie"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tower = { version = "0.5", features = ["util"] }
|
||||
tower-http = { version = "0.6", features = ["fs", "trace"] }
|
||||
|
|
@ -27,8 +27,7 @@ clap = { version = "4", features = ["derive"] }
|
|||
|
||||
sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio", "chrono"] }
|
||||
|
||||
rinja = { version = "0.3", features = ["with-axum"] }
|
||||
rinja_axum = "0.3"
|
||||
rinja = { version = "0.3" }
|
||||
|
||||
argon2 = { version = "0.5", features = ["default", "std"] }
|
||||
rand_core = { version = "0.6", features = ["std"] }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
INSERT INTO [User] ([id], [email], [name], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||
INSERT INTO [User] ([id], [email], [name], [is_admin], [creation_datetime], [password], [validation_token_datetime], [validation_token])
|
||||
VALUES (
|
||||
1,
|
||||
'paul@atreides.com',
|
||||
'Paul',
|
||||
TRUE,
|
||||
'2025-01-07T10:41:05.697884837+00:00',
|
||||
'$argon2id$v=19$m=4096,t=4,p=2$l1fAMRc0VfkNzqpEfFEReg$/gsUsY2aML8EbKjPeCxucenxkxhiFSXDmizWZPLvNuo',
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -151,19 +151,72 @@ CREATE TABLE [Ingredient] (
|
|||
[step_id] INTEGER NOT NULL,
|
||||
|
||||
[name] TEXT NOT NULL DEFAULT '',
|
||||
[comment] TEXT NOT NULL DEFAULT '',
|
||||
[quantity_value] REAL,
|
||||
[quantity_unit] TEXT NOT NULL DEFAULT '',
|
||||
|
||||
[comment] TEXT NOT NULL DEFAULT '',
|
||||
|
||||
FOREIGN KEY([step_id]) REFERENCES [Step]([id]) ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE INDEX [Ingredient_order_index] ON [Ingredient]([order]);
|
||||
|
||||
-- Table not strict because [value] can story any type of data.
|
||||
CREATE TABLE [Settings] (
|
||||
[name] TEXT NOT NULL PRIMARY KEY,
|
||||
[value] TEXT NOT NULL
|
||||
CREATE TABLE [RecipeScheduled] (
|
||||
[id] INTEGER PRIMARY KEY,
|
||||
[user_id] INTEGER NOT NULL,
|
||||
[recipe_id] INTEGER NOT NULL,
|
||||
[date] TEXT NOT NULL,
|
||||
[servings] INTEGER, -- If NULL use [recipe].[servings].
|
||||
|
||||
FOREIGN KEY([user_id]) REFERENCES [User]([id]) ON DELETE CASCADE,
|
||||
FOREIGN KEY([recipe_id]) REFERENCES [Recipe]([id]) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO [Settings] ([name], [value]) VALUES ('new_user_registration_enabled', TRUE);
|
||||
CREATE TABLE [ShoppingEntry] (
|
||||
[id] INTEGER PRIMARY KEY,
|
||||
[user_id] INTEGER NOT NULL,
|
||||
-- The linkded ingredient can be deleted or a custom entry can be manually added.
|
||||
-- In both cases [name], [quantity_value] and [quantity_unit] are used to display
|
||||
-- the entry instead of [Ingredient] data.
|
||||
[ingredient_id] INTEGER,
|
||||
[is_checked] INTEGER NOT NULL DEFAULT FALSE,
|
||||
|
||||
[name] TEXT NOT NULL DEFAULT '',
|
||||
[quantity_value] REAL,
|
||||
[quantity_unit] TEXT NOT NULL DEFAULT '',
|
||||
[servings] INTEGER,
|
||||
|
||||
FOREIGN KEY([user_id]) REFERENCES [User]([id]) ON DELETE CASCADE,
|
||||
FOREIGN KEY([ingredient_id]) REFERENCES [Ingredient]([id]) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- When an ingredient is deleted, its values are copied to any shopping entry
|
||||
-- that referenced it.
|
||||
CREATE TRIGGER [Ingredient_trigger_delete]
|
||||
BEFORE DELETE
|
||||
ON [Ingredient]
|
||||
BEGIN
|
||||
UPDATE [ShoppingEntry]
|
||||
SET
|
||||
[name] = OLD.[name],
|
||||
[quantity_value] = OLD.[quantity_value],
|
||||
[quantity_unit] = OLD.[quantity_unit],
|
||||
[servings] = (
|
||||
SELECT [servings]
|
||||
FROM [Recipe]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
INNER JOIN [Step] ON [Step].[group_id] = [Group].[id]
|
||||
WHERE [Step].[id] = OLD.[step_id]
|
||||
)
|
||||
WHERE [ingredient_id] = OLD.[id];
|
||||
END;
|
||||
|
||||
CREATE TABLE [Settings] (
|
||||
[name] TEXT NOT NULL PRIMARY KEY,
|
||||
|
||||
-- Value can by anything that can be read from a text by
|
||||
-- implementing the trait 'std::str::FromStr'.
|
||||
[value] TEXT NOT NULL
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO [Settings] ([name], [value]) VALUES ('new_user_registration_enabled', 'true');
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ ORDER BY [title]
|
|||
r#"
|
||||
SELECT COUNT(*) = 1
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
WHERE [Recipe].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
WHERE [Recipe].[id] = $1 AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
)
|
||||
.bind(recipe_id)
|
||||
|
|
@ -80,9 +80,9 @@ WHERE [Recipe].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*) = 1
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
WHERE [Group].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Group].[id] = $1 AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
)
|
||||
.bind(group_id)
|
||||
|
|
@ -104,9 +104,9 @@ WHERE [Group].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
WHERE [Group].[id] IN ({}) AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Group].[id] IN ({}) AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
params
|
||||
);
|
||||
|
|
@ -123,10 +123,10 @@ WHERE [Group].[id] IN ({}) AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*) = 1
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
INNER JOIN [Step] ON [Step].[group_id] = [Group].[id]
|
||||
WHERE [Step].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Step].[id] = $1 AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
)
|
||||
.bind(step_id)
|
||||
|
|
@ -144,10 +144,10 @@ WHERE [Step].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
INNER JOIN [Step] ON [Step].[group_id] = [Group].[id]
|
||||
WHERE [Step].[id] IN ({}) AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Step].[id] IN ({}) AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
params
|
||||
);
|
||||
|
|
@ -168,11 +168,11 @@ WHERE [Step].[id] IN ({}) AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
INNER JOIN [Step] ON [Step].[group_id] = [Group].[id]
|
||||
INNER JOIN [Ingredient] ON [Ingredient].[step_id] = [Step].[id]
|
||||
WHERE [Ingredient].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Ingredient].[id] = $1 AND ([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
)
|
||||
.bind(ingredient_id)
|
||||
|
|
@ -194,11 +194,12 @@ WHERE [Ingredient].[id] = $1 AND ([is_admin] OR [user_id] = $2)
|
|||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM [Recipe]
|
||||
INNER JOIN [User] ON [User].id = [Recipe].user_id
|
||||
INNER JOIN [User] ON [User].[id] = [Recipe].[user_id]
|
||||
INNER JOIN [Group] ON [Group].[recipe_id] = [Recipe].[id]
|
||||
INNER JOIN [Step] ON [Step].[group_id] = [Group].[id]
|
||||
INNER JOIN [Ingredient] ON [Ingredient].[step_id] = [Step].[id]
|
||||
WHERE [Ingredient].[id] IN ({}) AND ([is_admin] OR [user_id] = $2)
|
||||
WHERE [Ingredient].[id] IN ({}) AND
|
||||
([user_id] = $2 OR (SELECT [is_admin] FROM [User] WHERE [id] = $2))
|
||||
"#,
|
||||
params
|
||||
);
|
||||
|
|
@ -681,6 +682,8 @@ VALUES ($1, $2)
|
|||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(db_result.last_insert_rowid())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rinja_axum::Template;
|
||||
use rinja::Template;
|
||||
|
||||
use crate::{
|
||||
data::model,
|
||||
|
|
|
|||
|
|
@ -522,7 +522,6 @@ pub async fn add_ingredient(
|
|||
) -> Result<impl IntoResponse> {
|
||||
check_user_rights_recipe_step(&connection, &user, ron.id).await?;
|
||||
let id = connection.add_recipe_ingredient(ron.id).await?;
|
||||
|
||||
Ok(ron_response(StatusCode::OK, common::ron_api::Id { id }))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@
|
|||
(RecipeDifficultyHard, "Difficile"),
|
||||
(RecipeTags, "Tags"),
|
||||
(RecipeLanguage, "Langue"),
|
||||
(RecipeIsPublished, "Est publié"),
|
||||
(RecipeIsPublished, "Est publiée"),
|
||||
(RecipeDelete, "Supprimer la recette"),
|
||||
(RecipeAddAGroup, "Ajouter un groupe"),
|
||||
(RecipeRemoveGroup, "Supprimer le groupe"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue