Service for editing/creating recipe
[recipes.git] / backend / src / services.rs
index afa20a0..c283868 100644 (file)
@@ -11,13 +11,14 @@ use chrono::Duration;
 use log::{debug, error, info, log_enabled, Level};
 use serde::Deserialize;
 
-use crate::config::Config;
-use crate::consts;
-use crate::data::{asynchronous, db};
-use crate::email;
-use crate::model;
-use crate::user::User;
-use crate::utils;
+use crate::{
+    config::Config,
+    consts,
+    data::{asynchronous, db},
+    email,
+    model,
+    utils,
+};
 
 mod api;
 
@@ -45,7 +46,7 @@ fn get_ip_and_user_agent(req: &HttpRequest) -> (String, String) {
 async fn get_current_user(
     req: &HttpRequest,
     connection: web::Data<db::Connection>,
-) -> Option<User> {
+) -> Option<model::User> {
     let (client_ip, client_user_agent) = get_ip_and_user_agent(req);
 
     match req.cookie(consts::COOKIE_AUTH_TOKEN_NAME) {
@@ -149,7 +150,7 @@ impl actix_web::error::ResponseError for ServiceError {
 #[derive(Template)]
 #[template(path = "home.html")]
 struct HomeTemplate {
-    user: Option<User>,
+    user: Option<model::User>,
     recipes: Vec<(i64, String)>,
     current_recipe_id: Option<i64>,
 }
@@ -175,9 +176,10 @@ pub async fn home_page(
 #[derive(Template)]
 #[template(path = "view_recipe.html")]
 struct ViewRecipeTemplate {
-    user: Option<User>,
+    user: Option<model::User>,
     recipes: Vec<(i64, String)>,
     current_recipe_id: Option<i64>,
+
     current_recipe: model::Recipe,
 }
 
@@ -201,14 +203,15 @@ pub async fn view_recipe(
     .to_response())
 }
 
-///// EDIT RECIPE /////
+///// EDIT/NEW RECIPE /////
 
 #[derive(Template)]
 #[template(path = "edit_recipe.html")]
 struct EditRecipeTemplate {
-    user: Option<User>,
+    user: Option<model::User>,
     recipes: Vec<(i64, String)>,
     current_recipe_id: Option<i64>,
+
     current_recipe: model::Recipe,
 }
 
@@ -219,12 +222,28 @@ pub async fn edit_recipe(
     connection: web::Data<db::Connection>,
 ) -> Result<HttpResponse> {
     let (id,) = path.into_inner();
-    let user = get_current_user(&req, connection.clone()).await;
-    let recipes = connection.get_all_recipe_titles_async().await?;
+    let user = match get_current_user(&req, connection.clone()).await {
+        Some(u) => u,
+        None =>
+            return Ok(MessageTemplate {
+                user: None,
+                message: "Cannot edit a recipe without being logged in",
+            }.to_response())
+    };
+
     let recipe = connection.get_recipe_async(id).await?;
 
+    if recipe.user_id != user.id {
+        return Ok(MessageTemplate {
+            message: "Cannot edit a recipe you don't own",
+            user: Some(user)
+        }.to_response())
+    }
+
+    let recipes = connection.get_all_recipe_titles_async().await?;
+
     Ok(EditRecipeTemplate {
-        user,
+        user: Some(user),
         current_recipe_id: Some(recipe.id),
         recipes,
         current_recipe: recipe,
@@ -232,6 +251,34 @@ pub async fn edit_recipe(
     .to_response())
 }
 
+#[get("/recipe/new")]
+pub async fn new_recipe(
+    req: HttpRequest,
+    path: web::Path<(i64,)>,
+    connection: web::Data<db::Connection>,
+) -> Result<HttpResponse> {
+    let user = match get_current_user(&req, connection.clone()).await {
+        Some(u) => u,
+        None =>
+            return Ok(MessageTemplate {
+                message: "Cannot create a recipe without being logged in",
+                user: None
+            }.to_response())
+    };
+
+    let recipe_id = connection.create_recipe_async(user.id).await?;
+    let recipes = connection.get_all_recipe_titles_async().await?;
+    let user_id = user.id;
+
+    Ok(EditRecipeTemplate {
+        user: Some(user),
+        current_recipe_id: Some(recipe_id),
+        recipes,
+        current_recipe: model::Recipe::empty(recipe_id, user_id),
+    }
+    .to_response())
+}
+
 ///// MESSAGE /////
 
 #[derive(Template)]
@@ -243,7 +290,7 @@ struct MessageBaseTemplate<'a> {
 #[derive(Template)]
 #[template(path = "message.html")]
 struct MessageTemplate<'a> {
-    user: Option<User>,
+    user: Option<model::User>,
     message: &'a str,
 }
 
@@ -252,7 +299,7 @@ struct MessageTemplate<'a> {
 #[derive(Template)]
 #[template(path = "sign_up_form.html")]
 struct SignUpFormTemplate {
-    user: Option<User>,
+    user: Option<model::User>,
     email: String,
     message: String,
     message_email: String,
@@ -300,7 +347,7 @@ pub async fn sign_up_post(
     fn error_response(
         error: SignUpError,
         form: &web::Form<SignUpFormData>,
-        user: Option<User>,
+        user: Option<model::User>,
     ) -> Result<HttpResponse> {
         Ok(SignUpFormTemplate {
             user,
@@ -486,7 +533,7 @@ pub async fn sign_up_validation(
 #[derive(Template)]
 #[template(path = "sign_in_form.html")]
 struct SignInFormTemplate {
-    user: Option<User>,
+    user: Option<model::User>,
     email: String,
     message: String,
 }
@@ -524,7 +571,7 @@ pub async fn sign_in_post(
     fn error_response(
         error: SignInError,
         form: &web::Form<SignInFormData>,
-        user: Option<User>,
+        user: Option<model::User>,
     ) -> Result<HttpResponse> {
         Ok(SignInFormTemplate {
             user,