From 2a112855e54ea3a365fa032e8726196a7eec9a06 Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 16 Dec 2020 22:12:50 +0530 Subject: begin working on rating endpoints --- src/bin/server.rs | 11 +++++- src/handlers/product.rs | 23 +++++++++---- src/handlers/rating.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ src/models.rs | 25 ++++++++++++++ tests/requests.txt | 10 ++++-- 5 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 src/handlers/rating.rs diff --git a/src/bin/server.rs b/src/bin/server.rs index 601d514..5af3135 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -5,7 +5,7 @@ use actix_web::{web, App, HttpServer}; use diesel::r2d2::{ConnectionManager, Pool}; use diesel::MysqlConnection; use furby::handlers::smoke::manual_hello; -use furby::handlers::{cart_items, product, users}; +use furby::handlers::{cart_items, product, rating, users}; use rand::Rng; #[actix_web::main] @@ -45,6 +45,10 @@ async fn main() -> std::io::Result<()> { .route("/catalog", web::get().to(product::get_all_products)) .route("/new", web::post().to(product::new_product)) .route("/{id}", web::get().to(product::product_details)) + .route( + "/reviews/{id}", + web::get().to(product::get_product_reviews), + ) .route( "/update_product/{id}", web::post().to(product::update_product), @@ -62,6 +66,11 @@ async fn main() -> std::io::Result<()> { web::post().to(cart_items::remove_from_cart), ), ) + .service( + web::scope("/rating") + .route("/add", web::post().to(rating::add_rating)) + .route("/remove", web::post().to(rating::remove_rating)), + ) .route("/hey", web::get().to(manual_hello)) }) .bind("127.0.0.1:7878")? diff --git a/src/handlers/product.rs b/src/handlers/product.rs index 788efb3..21bdbc9 100644 --- a/src/handlers/product.rs +++ b/src/handlers/product.rs @@ -1,11 +1,11 @@ -use crate::models::{NewProduct, Product, UpdateProduct}; +use crate::models::{NewProduct, Product, Rating, UpdateProduct}; use crate::schema::product::dsl::*; +use crate::schema::rating::dsl as rating; use crate::TPool; use actix_web::{web, HttpResponse, Responder}; use diesel::prelude::*; use log::{error, info}; -use serde::Deserialize; pub async fn new_product( pool: web::Data, @@ -75,13 +75,24 @@ pub async fn get_all_products(pool: web::Data) -> impl Responder { let conn = pool.get().unwrap(); info!("Generating and returning catalog ..."); match product.load::(&conn) { - Ok(products) => { - return HttpResponse::Ok() - .body(serde_json::to_string(&products).unwrap()) - } + Ok(products) => return HttpResponse::Ok().json(&products), Err(_) => { return HttpResponse::InternalServerError() .body("Unable to fetch product catalog") } } } + +pub async fn get_product_reviews( + pool: web::Data, + product_id: web::Path, +) -> impl Responder { + let conn = pool.get().unwrap(); + info!("Fetching product reviews for {}", product_id); + let pid = product_id.into_inner(); + let rating_entries = rating::rating + .filter(rating::product_id.eq(pid)) + .load::(&conn) + .expect("Couldn't connect to DB"); + return HttpResponse::Ok().json(&rating_entries); +} diff --git a/src/handlers/rating.rs b/src/handlers/rating.rs new file mode 100644 index 0000000..309c2c6 --- /dev/null +++ b/src/handlers/rating.rs @@ -0,0 +1,90 @@ +use crate::models::{AddRating, Customer, Rating}; +use crate::schema::rating::dsl as rating; +use crate::schema::{customer::dsl::*, product::dsl::*}; +use crate::TPool; + +use actix_identity::Identity; +use actix_web::{web, HttpResponse, Responder}; +use diesel::prelude::*; +use log::{error, info}; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct AddRatingJson { + pub comment_text: Option, + pub stars: Option, + pub product_id: i32, +} + +pub async fn add_rating( + cookie: Identity, + rating_details: web::Json, + pool: web::Data, +) -> impl Responder { + info!("Add rating hit: {:?}", rating_details.product_id); + let conn = pool.get().unwrap(); + if let Some(uname) = cookie.identity() { + let selected_user = customer + .filter(username.eq(&uname)) + .limit(1) + .first::(&conn) + .expect("Couldn't connect to DB"); + let rating_details = rating_details.into_inner(); + let new_rating = AddRating { + comment_text: rating_details.comment_text, + stars: rating_details.stars, + product_id: rating_details.product_id, + customer_id: selected_user.id, + }; + diesel::insert_into(rating::rating) + .values(new_rating) + .execute(&conn) + .expect("Coundn't connect to DB"); + HttpResponse::Ok().body("Inserted rating successfully!") + } else { + error!("Unauthorized add rating action!"); + return HttpResponse::Unauthorized() + .body("Need to be logged in to add rating!"); + } +} + +#[derive(Deserialize, Debug)] +pub struct RemoveRating { + rating_id: i32, +} + +pub async fn remove_rating( + cookie: Identity, + rating_details: web::Json, + pool: web::Data, +) -> impl Responder { + info!("Remove rating hit: {:?}", rating_details.rating_id); + let conn = pool.get().unwrap(); + if let Some(uname) = cookie.identity() { + let selected_user = customer + .filter(username.eq(&uname)) + .limit(1) + .first::(&conn) + .expect("Couldn't connect to DB"); + + diesel::delete( + rating::rating + .filter(rating::customer_id.eq(selected_user.id)) + .filter(rating::id.eq(rating_details.rating_id)), + ) + .execute(&conn) + .expect("Coundn't connect to DB"); + HttpResponse::Ok().body("Removed successfully!") + } else { + error!("Unauthorized add to cart action!"); + return HttpResponse::Unauthorized() + .body("Need to be logged in to add to cart!"); + } +} + +// pub async fn get_product_reviews( +// product: web::Json, +// pool: web::Data, +// ) -> impl Responder { +// unimplemented!() +// } diff --git a/src/models.rs b/src/models.rs index acd67a6..a104209 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,6 @@ use super::schema::{cart_items, customer, product, rating, transaction}; +use chrono::naive::{NaiveDate, NaiveDateTime}; use diesel::{Insertable, Queryable}; use serde::{Deserialize, Serialize}; @@ -70,3 +71,27 @@ pub struct AddCartItem { pub cart_id: i32, pub product_id: i32, } + +/* Rating */ +#[derive(Queryable, Serialize)] +pub struct Rating { + pub id: i32, + pub comment_text: Option, + pub comment_date: Option, + pub product_id: Option, + pub customer_id: Option, + pub stars: Option, +} + +#[derive(Insertable, Deserialize)] +#[table_name = "rating"] +pub struct AddRating { + #[serde(skip_serializing_if = "Option::is_none")] + pub comment_text: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub stars: Option, + + pub product_id: i32, + pub customer_id: i32, +} diff --git a/tests/requests.txt b/tests/requests.txt index 7e38905..7e2ca5c 100644 --- a/tests/requests.txt +++ b/tests/requests.txt @@ -2,7 +2,7 @@ http POST :7878/user/login username=akshay password=password http POST :7878/user/login username=akshay password=nigga -http POST :7878/user/change_password Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== old_password=nigga new_password=nigga +http POST :7878/user/change_password Cookie: old_password=nigga new_password=nigga http :7878/user/change_password username=akshay password=password @@ -10,8 +10,12 @@ http :7878/product/catalog http :7878/product/1 -http POST :7878/cart/add Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== product_id:=1 +http POST :7878/cart/add Cookie: product_id:=1 -http :7878/cart/items Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== +http :7878/cart/items Cookie: http POST :7878/cart/remove Cookie: product_id:=1 + +http POST :7878/rating/add Cookie: product_id:=1 stars:=3 comment_text=Very good functional chair + +http :7878/product/reviews/1 -- cgit v1.2.3