From c1f61c458e0e97586796a3acdbd21aedf8b2e8ad Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Mon, 3 Oct 2022 20:24:38 +0200 Subject: Likes model and them to a model --- src/models/likes.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/models/mod.rs | 1 + src/routes/model.rs | 44 ++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 src/models/likes.rs (limited to 'src') diff --git a/src/models/likes.rs b/src/models/likes.rs new file mode 100644 index 0000000..56001d9 --- /dev/null +++ b/src/models/likes.rs @@ -0,0 +1,91 @@ +use crate::{db::get_client, errors::AppError}; +use chrono::{Local, NaiveDateTime}; +use serde::{Deserialize, Serialize}; +use sqlx::Row; + +/// Likes model +#[derive(Serialize, Deserialize, sqlx::FromRow)] +pub struct Like { + id: i32, + user_id: i32, + model_id: i32, + created: NaiveDateTime, +} + +impl Like { + /// Create a new like + pub fn new(user_id: i32, model_id: i32) -> Self { + let now = Local::now().naive_utc(); + Self { + id: 0, + user_id, + model_id, + created: now, + } + } + + /// Returns `true` if an user has already assigned a like to a model + pub async fn exists(&self) -> Result { + let pool = unsafe { get_client() }; + let cursor = sqlx::query( + r#" + SELECT COUNT(id) as count FROM likes WHERE user_id = $1 AND model_id = $2 + "#, + ) + .bind(self.user_id) + .bind(self.model_id) + .fetch_one(pool) + .await?; + + let count: i64 = cursor.try_get(0).unwrap(); + + Ok(count > 0) + } + + /// Save new like into db + pub async fn save(&self) -> Result { + let pool = unsafe { get_client() }; + + if self.exists().await? { + return Err(AppError::BadRequest( + "This user already likes this model".to_string(), + )); + } + + let rec: Like = sqlx::query_as( + r#" + INSERT INTO likes (user_id, model_id, created) + VALUES ($1, $2, $3) + RETURNING * + "#, + ) + .bind(self.user_id) + .bind(self.model_id) + .bind(self.created) + .fetch_one(pool) + .await?; + + Ok(rec) + } + + /// Remove a like + pub async fn remove(&self) -> Result<(), AppError> { + let pool = unsafe { get_client() }; + + if !self.exists().await? { + return Err(AppError::NotFound("Like not found".to_string())); + } + + sqlx::query( + r#" + DELETE FROM likes WHERE user_id = $1 AND model_id = $2 + "#, + ) + .bind(self.user_id) + .bind(self.model_id) + .execute(pool) + .await?; + + Ok(()) + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index 45a11f3..8062fe3 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,4 +1,5 @@ pub mod auth; +pub mod likes; pub mod model; pub mod user; pub mod warning; diff --git a/src/routes/model.rs b/src/routes/model.rs index 9242c31..d72d7af 100644 --- a/src/routes/model.rs +++ b/src/routes/model.rs @@ -3,6 +3,7 @@ use crate::{ files::{delete_upload, upload}, models::{ auth::Claims, + likes::Like, model::{Model, ModelCreate, ModelUpload, ModelUser}, user::User, }, @@ -21,6 +22,7 @@ pub fn create_route() -> Router { Router::new() .route("/", get(list_models).post(create_model)) .route("/:id", get(get_model).delete(delete_model).put(edit_model)) + .route("/:id/like", post(add_like).delete(delete_like)) .route("/:id/upload", post(upload_model_file)) .route("/:id/upload/:uid", delete(delete_model_file)) } @@ -207,3 +209,45 @@ async fn delete_model_file( Err(e) => Err(e), } } + +/// Assign a like to a model from the Authorization user +async fn add_like(claims: Claims, Path(model_id): Path) -> Result { + let model = match Model::find_by_id(model_id).await { + Ok(model) => model, + Err(_) => { + return Err(AppError::NotFound("Model not found".to_string())); + } + }; + + let user = User::find_by_id(claims.user_id).await?; + + let like = Like::new(user.id, model.id); + + match like.save().await { + Ok(_) => Ok(StatusCode::CREATED), + Err(e) => { + return Err(e); + } + } +} + +/// Remove a like from a model and an Authorization user +async fn delete_like(claims: Claims, Path(model_id): Path) -> Result { + let model = match Model::find_by_id(model_id).await { + Ok(model) => model, + Err(_) => { + return Err(AppError::NotFound("Model not found".to_string())); + } + }; + + let user = User::find_by_id(claims.user_id).await?; + + let like = Like::new(user.id, model.id); + + match like.remove().await { + Ok(_) => Ok(StatusCode::NO_CONTENT), + Err(e) => { + return Err(e); + } + } +} -- cgit v1.2.3-71-g8e6c