aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/server.rs11
-rw-r--r--src/handlers/product.rs23
-rw-r--r--src/handlers/rating.rs90
-rw-r--r--src/models.rs25
-rw-r--r--tests/requests.txt10
5 files changed, 149 insertions, 10 deletions
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};
5use diesel::r2d2::{ConnectionManager, Pool}; 5use diesel::r2d2::{ConnectionManager, Pool};
6use diesel::MysqlConnection; 6use diesel::MysqlConnection;
7use furby::handlers::smoke::manual_hello; 7use furby::handlers::smoke::manual_hello;
8use furby::handlers::{cart_items, product, users}; 8use furby::handlers::{cart_items, product, rating, users};
9use rand::Rng; 9use rand::Rng;
10 10
11#[actix_web::main] 11#[actix_web::main]
@@ -46,6 +46,10 @@ async fn main() -> std::io::Result<()> {
46 .route("/new", web::post().to(product::new_product)) 46 .route("/new", web::post().to(product::new_product))
47 .route("/{id}", web::get().to(product::product_details)) 47 .route("/{id}", web::get().to(product::product_details))
48 .route( 48 .route(
49 "/reviews/{id}",
50 web::get().to(product::get_product_reviews),
51 )
52 .route(
49 "/update_product/{id}", 53 "/update_product/{id}",
50 web::post().to(product::update_product), 54 web::post().to(product::update_product),
51 ), 55 ),
@@ -62,6 +66,11 @@ async fn main() -> std::io::Result<()> {
62 web::post().to(cart_items::remove_from_cart), 66 web::post().to(cart_items::remove_from_cart),
63 ), 67 ),
64 ) 68 )
69 .service(
70 web::scope("/rating")
71 .route("/add", web::post().to(rating::add_rating))
72 .route("/remove", web::post().to(rating::remove_rating)),
73 )
65 .route("/hey", web::get().to(manual_hello)) 74 .route("/hey", web::get().to(manual_hello))
66 }) 75 })
67 .bind("127.0.0.1:7878")? 76 .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 @@
1use crate::models::{NewProduct, Product, UpdateProduct}; 1use crate::models::{NewProduct, Product, Rating, UpdateProduct};
2use crate::schema::product::dsl::*; 2use crate::schema::product::dsl::*;
3use crate::schema::rating::dsl as rating;
3use crate::TPool; 4use crate::TPool;
4 5
5use actix_web::{web, HttpResponse, Responder}; 6use actix_web::{web, HttpResponse, Responder};
6use diesel::prelude::*; 7use diesel::prelude::*;
7use log::{error, info}; 8use log::{error, info};
8use serde::Deserialize;
9 9
10pub async fn new_product( 10pub async fn new_product(
11 pool: web::Data<TPool>, 11 pool: web::Data<TPool>,
@@ -75,13 +75,24 @@ pub async fn get_all_products(pool: web::Data<TPool>) -> impl Responder {
75 let conn = pool.get().unwrap(); 75 let conn = pool.get().unwrap();
76 info!("Generating and returning catalog ..."); 76 info!("Generating and returning catalog ...");
77 match product.load::<Product>(&conn) { 77 match product.load::<Product>(&conn) {
78 Ok(products) => { 78 Ok(products) => return HttpResponse::Ok().json(&products),
79 return HttpResponse::Ok()
80 .body(serde_json::to_string(&products).unwrap())
81 }
82 Err(_) => { 79 Err(_) => {
83 return HttpResponse::InternalServerError() 80 return HttpResponse::InternalServerError()
84 .body("Unable to fetch product catalog") 81 .body("Unable to fetch product catalog")
85 } 82 }
86 } 83 }
87} 84}
85
86pub async fn get_product_reviews(
87 pool: web::Data<TPool>,
88 product_id: web::Path<i32>,
89) -> impl Responder {
90 let conn = pool.get().unwrap();
91 info!("Fetching product reviews for {}", product_id);
92 let pid = product_id.into_inner();
93 let rating_entries = rating::rating
94 .filter(rating::product_id.eq(pid))
95 .load::<Rating>(&conn)
96 .expect("Couldn't connect to DB");
97 return HttpResponse::Ok().json(&rating_entries);
98}
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 @@
1use crate::models::{AddRating, Customer, Rating};
2use crate::schema::rating::dsl as rating;
3use crate::schema::{customer::dsl::*, product::dsl::*};
4use crate::TPool;
5
6use actix_identity::Identity;
7use actix_web::{web, HttpResponse, Responder};
8use diesel::prelude::*;
9use log::{error, info};
10use serde::Deserialize;
11
12#[derive(Deserialize, Debug)]
13pub struct AddRatingJson {
14 pub comment_text: Option<String>,
15 pub stars: Option<i32>,
16 pub product_id: i32,
17}
18
19pub async fn add_rating(
20 cookie: Identity,
21 rating_details: web::Json<AddRatingJson>,
22 pool: web::Data<TPool>,
23) -> impl Responder {
24 info!("Add rating hit: {:?}", rating_details.product_id);
25 let conn = pool.get().unwrap();
26 if let Some(uname) = cookie.identity() {
27 let selected_user = customer
28 .filter(username.eq(&uname))
29 .limit(1)
30 .first::<Customer>(&conn)
31 .expect("Couldn't connect to DB");
32 let rating_details = rating_details.into_inner();
33 let new_rating = AddRating {
34 comment_text: rating_details.comment_text,
35 stars: rating_details.stars,
36 product_id: rating_details.product_id,
37 customer_id: selected_user.id,
38 };
39 diesel::insert_into(rating::rating)
40 .values(new_rating)
41 .execute(&conn)
42 .expect("Coundn't connect to DB");
43 HttpResponse::Ok().body("Inserted rating successfully!")
44 } else {
45 error!("Unauthorized add rating action!");
46 return HttpResponse::Unauthorized()
47 .body("Need to be logged in to add rating!");
48 }
49}
50
51#[derive(Deserialize, Debug)]
52pub struct RemoveRating {
53 rating_id: i32,
54}
55
56pub async fn remove_rating(
57 cookie: Identity,
58 rating_details: web::Json<RemoveRating>,
59 pool: web::Data<TPool>,
60) -> impl Responder {
61 info!("Remove rating hit: {:?}", rating_details.rating_id);
62 let conn = pool.get().unwrap();
63 if let Some(uname) = cookie.identity() {
64 let selected_user = customer
65 .filter(username.eq(&uname))
66 .limit(1)
67 .first::<Customer>(&conn)
68 .expect("Couldn't connect to DB");
69
70 diesel::delete(
71 rating::rating
72 .filter(rating::customer_id.eq(selected_user.id))
73 .filter(rating::id.eq(rating_details.rating_id)),
74 )
75 .execute(&conn)
76 .expect("Coundn't connect to DB");
77 HttpResponse::Ok().body("Removed successfully!")
78 } else {
79 error!("Unauthorized add to cart action!");
80 return HttpResponse::Unauthorized()
81 .body("Need to be logged in to add to cart!");
82 }
83}
84
85// pub async fn get_product_reviews(
86// product: web::Json<GetProductReviews>,
87// pool: web::Data<TPool>,
88// ) -> impl Responder {
89// unimplemented!()
90// }
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 @@
1use super::schema::{cart_items, customer, product, rating, transaction}; 1use super::schema::{cart_items, customer, product, rating, transaction};
2 2
3use chrono::naive::{NaiveDate, NaiveDateTime};
3use diesel::{Insertable, Queryable}; 4use diesel::{Insertable, Queryable};
4use serde::{Deserialize, Serialize}; 5use serde::{Deserialize, Serialize};
5 6
@@ -70,3 +71,27 @@ pub struct AddCartItem {
70 pub cart_id: i32, 71 pub cart_id: i32,
71 pub product_id: i32, 72 pub product_id: i32,
72} 73}
74
75/* Rating */
76#[derive(Queryable, Serialize)]
77pub struct Rating {
78 pub id: i32,
79 pub comment_text: Option<String>,
80 pub comment_date: Option<NaiveDate>,
81 pub product_id: Option<i32>,
82 pub customer_id: Option<i32>,
83 pub stars: Option<i32>,
84}
85
86#[derive(Insertable, Deserialize)]
87#[table_name = "rating"]
88pub struct AddRating {
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub comment_text: Option<String>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub stars: Option<i32>,
94
95 pub product_id: i32,
96 pub customer_id: i32,
97}
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
2 2
3http POST :7878/user/login username=akshay password=nigga 3http POST :7878/user/login username=akshay password=nigga
4 4
5http POST :7878/user/change_password Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== old_password=nigga new_password=nigga 5http POST :7878/user/change_password Cookie: old_password=nigga new_password=nigga
6 6
7http :7878/user/change_password username=akshay password=password 7http :7878/user/change_password username=akshay password=password
8 8
@@ -10,8 +10,12 @@ http :7878/product/catalog
10 10
11http :7878/product/1 11http :7878/product/1
12 12
13http POST :7878/cart/add Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== product_id:=1 13http POST :7878/cart/add Cookie: product_id:=1
14 14
15http :7878/cart/items Cookie:user-login=mKT3PRPSKJp/AdsfPCXg3GICmQW2wViUwUKPpsXKp+70ug== 15http :7878/cart/items Cookie:
16 16
17http POST :7878/cart/remove Cookie: product_id:=1 17http POST :7878/cart/remove Cookie: product_id:=1
18
19http POST :7878/rating/add Cookie: product_id:=1 stars:=3 comment_text=Very good functional chair
20
21http :7878/product/reviews/1