Skip to content

Commit

Permalink
improving error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
FayCarsons committed Feb 23, 2024
1 parent 3f94c1c commit 02442a6
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 49 deletions.
69 changes: 36 additions & 33 deletions backend/src/api/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::model::{
order::{JsonOrder, NewOrder, Order, OrderFilter},
};
use actix_web::{
delete, post,
delete,
error::{self, ErrorInternalServerError},
post,
web::{self, Path},
HttpResponse,
HttpResponse, Result,
};
use diesel::{prelude::*, r2d2::ConnectionManager};
use r2d2::PooledConnection;
Expand All @@ -17,51 +19,48 @@ use crate::{error::ShopResult, DbPool};
pub async fn get_orders(
pool: web::Data<DbPool>,
filter: Path<OrderFilter>,
) -> ShopResult<HttpResponse> {
) -> Result<HttpResponse> {
use crate::schema::orders;
let filter = filter.into_inner();

let orders = web::block(move || -> ShopResult<Vec<Order>> {
let mut conn = pool.get()?;
let orders = web::block(move || {
let mut conn = pool.get().map_err(|_| "Cannot get DB connection")?;

let res = match filter {
match filter {
OrderFilter::All => orders::table
.select(Order::as_select())
.get_results(&mut conn)?,
.get_results(&mut conn),
OrderFilter::Fulfilled => orders::table
.select(Order::as_select())
.filter(orders::fulfilled.eq(true))
.get_results(&mut conn)?,
.get_results(&mut conn),
OrderFilter::Unfulfilled => orders::table
.select(Order::as_select())
.filter(orders::fulfilled.eq(false))
.get_results(&mut conn)?,
};
Ok(res)
.get_results(&mut conn),
}
.map_err(|_| "Cannot fetch orders from DB")
})
.await??;
.await?
.map_err(error::ErrorInternalServerError)?;

let json = serde_json::to_string(&orders)?;
Ok(HttpResponse::Ok().content_type("text/json").body(json))
}

#[delete("/orders/{id}")]
pub async fn delete_order(pool: web::Data<DbPool>, id: Path<i32>) -> ShopResult<HttpResponse> {
pub async fn delete_order(pool: web::Data<DbPool>, id: Path<i32>) -> Result<HttpResponse> {
use crate::schema::orders;
let id = id.into_inner();
let mut conn = pool.get()?;

web::block(move || -> ShopResult<()> {
match diesel::delete(orders::table.filter(orders::id.eq(id))).execute(&mut conn) {
Ok(_) => (),
Err(e) => {
eprintln!("DATABASE ERROR: {e}");
panic!()
}
}
Ok(())

web::block(move || {
let mut conn = pool.get().map_err(|_| "Cannot connect to DB")?;
diesel::delete(orders::table.filter(orders::id.eq(id)))
.execute(&mut conn)
.map_err(|_| "Cannot delete order")
})
.await??;
.await?
.map_err(error::ErrorInternalServerError)?;

Ok(HttpResponse::Ok().finish())
}
Expand All @@ -75,7 +74,7 @@ pub struct OrderId {
pub async fn post_order(
pool: web::Data<DbPool>,
body: web::Json<JsonOrder>,
) -> ShopResult<HttpResponse> {
) -> Result<HttpResponse> {
let JsonOrder {
name,
street,
Expand All @@ -88,7 +87,9 @@ pub async fn post_order(
.into_iter()
.map(<(i32, i32)>::from)
.collect::<Vec<(i32, i32)>>();
let conn = pool.get()?;
let conn = pool
.get()
.map_err(|e| ErrorInternalServerError(e.to_string()))?;
let id = insert_order(conn, cart, name, street, zipcode).await?;
let id = OrderId { id };

Expand All @@ -101,8 +102,8 @@ pub async fn insert_order(
name: String,
street: String,
zipcode: String,
) -> ShopResult<i32> {
web::block(move || -> ShopResult<i32> {
) -> Result<i32> {
web::block(move || -> std::result::Result<i32, &str> {
use crate::schema::{carts, orders};

let order = NewOrder {
Expand All @@ -115,7 +116,8 @@ pub async fn insert_order(
let inserted_id = diesel::insert_into(orders::table)
.values(&order)
.returning(orders::dsl::id)
.get_result::<i32>(&mut conn)?;
.get_result::<i32>(&mut conn)
.map_err(|_| "Cannot insert order into DB")?;

let new_carts = cart
.into_iter()
Expand All @@ -128,9 +130,10 @@ pub async fn insert_order(

diesel::insert_into(carts::table)
.values(&new_carts)
.execute(&mut conn)?;
.execute(&mut conn)
.map_err(|_| "Cannot insert carts into DB")?;
Ok(inserted_id)
})
.await
.expect("Failure while inserting order into DB")
.await?
.map_err(ErrorInternalServerError)
}
30 changes: 14 additions & 16 deletions backend/src/stripe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::model::{item::Item, ItemId, Quantity};
use actix_web::{
post,
web::{self, Json},
HttpRequest, HttpResponse,
HttpRequest, HttpResponse, Result,
};

use stripe::{
Expand Down Expand Up @@ -144,31 +144,33 @@ pub async fn webhook_handler(
req: HttpRequest,
payload: web::Bytes,
pool: web::Data<DbPool>,
) -> HttpResponse {
) -> Result<HttpResponse> {
println!("INSERTING INTO DATABASE VIA STRIPE WEBHOOKS");

match parse_webhook(req, payload, pool).await {
Ok(()) => HttpResponse::Ok().finish(),
Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
}
parse_webhook(req, payload, pool)
.await
.map(|_| HttpResponse::Ok().finish())
}

/// Determines whether webhook is correct type, IE is a completed checkout session
/// Determines whether webhook is correct type: is a completed checkout session
pub async fn parse_webhook(
req: HttpRequest,
payload: web::Bytes,
pool: web::Data<DbPool>,
) -> ShopResult<()> {
) -> Result<()> {
print_red("", "CURRENTLY IN 'handle_webhook'");

let secret = "whsec_c9335e3acc0d0d41902e80bcd43289d05f6f7542e4f5688fbdfa150eb1642722";
#[cfg(not(release))]
let secret = std::env::var("STRIPE_SECRET").map_err(|_| {
actix_web::error::ErrorInternalServerError("Stripe secret not present in env")
})?;

let payload_str = std::str::from_utf8(payload.borrow())
.map_err(|e| BackendError::PaymentError(e.to_string()))?;

let stripe_sig = get_header_value(&req, "Stripe-Signature").unwrap_or_default();

if let Ok(event) = Webhook::construct_event(payload_str, stripe_sig, secret) {
if let Ok(event) = Webhook::construct_event(payload_str, stripe_sig, &secret) {
if let EventType::CheckoutSessionCompleted = event.type_ {
if let EventObject::CheckoutSession(session) = event.data.object {
handle_checkout(session, pool).await?;
Expand All @@ -185,11 +187,7 @@ pub async fn parse_webhook(
}

/// Takes data from completed checkout session, stores it in DB and updates stock
/// PLEASE BREAK INTO SMALLER FNs
async fn handle_checkout(
session: stripe::CheckoutSession,
pool: web::Data<DbPool>,
) -> ShopResult<()> {
async fn handle_checkout(session: stripe::CheckoutSession, pool: web::Data<DbPool>) -> Result<()> {
let shipping_info = session.shipping_details.unwrap();
let Shipping { address, name, .. } = shipping_info;

Expand All @@ -212,7 +210,7 @@ async fn handle_checkout(
Ok((id, qty))
})
.collect::<Result<Vec<(i32, i32)>, ParseIntError>>()
.map_err(|e| BackendError::PaymentError(e.to_string()))?;
.map_err(|_| actix_web::error::ErrorInternalServerError("Cannot parse user cart"))?;

let cart_conn = pool.get().unwrap();
let stock_conn = pool.get().unwrap();
Expand Down

0 comments on commit 02442a6

Please sign in to comment.