Calendar is now displayed on home page and recipes can be scheduled without being logged

This commit is contained in:
Greg Burri 2025-02-08 22:31:38 +01:00
parent ccb1248da3
commit 37721ac3ea
22 changed files with 538 additions and 166 deletions

View file

@ -1,7 +1,7 @@
use chrono::prelude::*;
use common::ron_api::Difficulty;
use itertools::Itertools;
use sqlx::Error;
use sqlx::{Error, Sqlite};
use super::{Connection, DBError, Result};
use crate::data::model;
@ -64,6 +64,37 @@ ORDER BY [title]
.map_err(DBError::from)
}
/// Returns titles associated to given ids in the same order.
/// Empty string for unknown id.
pub async fn get_recipe_titles(&self, ids: &[i64]) -> Result<Vec<String>> {
let mut query_builder: sqlx::QueryBuilder<Sqlite> =
sqlx::QueryBuilder::new("SELECT [id], [title] FROM [Recipe] WHERE [id] IN(");
let mut separated = query_builder.separated(", ");
for id in ids {
separated.push_bind(id);
}
separated.push_unseparated(")");
let query = query_builder.build_query_as::<(i64, String)>();
let titles = query.fetch_all(&self.pool).await?;
let mut result = vec![];
// Warning: O(n^2), OK for small number of ids.
for id in ids {
result.push(
titles
.iter()
.find_map(|(fetched_id, title)| {
if fetched_id == id {
Some(title.clone())
} else {
None
}
})
.unwrap_or_default(),
);
}
Ok(result)
}
pub async fn can_edit_recipe(&self, user_id: i64, recipe_id: i64) -> Result<bool> {
sqlx::query_scalar(
r#"

View file

@ -107,6 +107,7 @@ async fn main() {
// Disabled: update user profile is now made with a post data ('edit_user_post').
// .route("/user/update", put(services::ron::update_user))
.route("/set_lang", put(services::ron::set_lang))
.route("/recipe/get_titles", get(services::ron::get_titles))
.route("/recipe/set_title", put(services::ron::set_recipe_title))
.route(
"/recipe/set_description",

View file

@ -1,12 +1,14 @@
use axum::{
debug_handler,
extract::{Extension, Query, State},
extract::{Extension, State},
http::{HeaderMap, StatusCode},
response::{ErrorResponse, IntoResponse, Response, Result},
};
use axum_extra::extract::cookie::{Cookie, CookieJar};
use chrono::NaiveDate;
use serde::Deserialize;
use axum_extra::extract::{
cookie::{Cookie, CookieJar},
Query,
};
use serde::{Deserialize, Serialize};
// use tracing::{event, Level};
use crate::{
@ -20,11 +22,15 @@ use crate::{
const NOT_AUTHORIZED_MESSAGE: &str = "Action not authorized";
#[derive(Deserialize)]
pub struct RecipeId {
#[serde(rename = "recipe_id")]
pub struct Id {
id: i64,
}
#[derive(Deserialize, Serialize)]
pub struct Ids {
ids: Vec<i64>,
}
// #[allow(dead_code)]
// #[debug_handler]
// pub async fn update_user(
@ -67,6 +73,8 @@ pub async fn set_lang(
Ok((jar, StatusCode::OK))
}
/*** Rights ***/
async fn check_user_rights_recipe(
connection: &db::Connection,
user: &Option<model::User>,
@ -200,6 +208,20 @@ async fn check_user_rights_recipe_ingredients(
}
}
/*** Recipe ***/
/// Ask recipe titles associated with each given id. The returned titles are in the same order
/// as the given ids.
#[debug_handler]
pub async fn get_titles(
State(connection): State<db::Connection>,
recipe_ids: Query<Ids>,
) -> Result<impl IntoResponse> {
Ok(ron_response_ok(common::ron_api::Strings {
strs: connection.get_recipe_titles(&recipe_ids.ids).await?,
}))
}
#[debug_handler]
pub async fn set_recipe_title(
State(connection): State<db::Connection>,
@ -255,7 +277,7 @@ pub async fn set_estimated_time(
#[debug_handler]
pub async fn get_tags(
State(connection): State<db::Connection>,
recipe_id: Query<RecipeId>,
recipe_id: Query<Id>,
) -> Result<impl IntoResponse> {
Ok(ron_response_ok(common::ron_api::Tags {
recipe_id: recipe_id.id,
@ -395,7 +417,7 @@ impl From<model::Ingredient> for common::ron_api::Ingredient {
#[debug_handler]
pub async fn get_groups(
State(connection): State<db::Connection>,
recipe_id: Query<RecipeId>,
recipe_id: Query<Id>,
) -> Result<impl IntoResponse> {
// Here we don't check user rights on purpose.
Ok(ron_response_ok(
@ -598,17 +620,11 @@ pub async fn set_ingredients_order(
/// Calendar ///
#[derive(Deserialize)]
pub struct DateRange {
start_date: NaiveDate,
end_date: NaiveDate,
}
#[debug_handler]
pub async fn get_scheduled_recipes(
State(connection): State<db::Connection>,
Extension(user): Extension<Option<model::User>>,
date_range: Query<DateRange>,
date_range: Query<common::ron_api::DateRange>,
) -> Result<impl IntoResponse> {
if let Some(user) = user {
Ok(ron_response_ok(common::ron_api::ScheduledRecipes {

View file

@ -3,14 +3,14 @@ use std::{collections::HashMap, net::SocketAddr};
use axum::{
body::Body,
debug_handler,
extract::{ConnectInfo, Extension, Query, Request, State},
extract::{ConnectInfo, Extension, Request, State},
http::HeaderMap,
response::{Html, IntoResponse, Redirect, Response},
Form,
};
use axum_extra::extract::{
cookie::{Cookie, CookieJar},
Host,
Host, Query,
};
use chrono::Duration;
use lettre::Address;