| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- use actix_web::{HttpResponse, HttpRequest, web, post};
- use stripe::{Event, EventType, EventObject, Webhook};
- use sqlx::PgPool;
- use crate::{
- http_error::HttpError,
- models::{
- purchase::{Purchase, Status},
- user::User
- },
- STRIPE_WEBHOOK_SECRET
- };
- #[post("/webhook/stripe")]
- pub async fn route(
- req: HttpRequest,
- db: web::Data<PgPool>,
- body: web::Bytes
- ) -> Result<HttpResponse, HttpError> {
- let payload = std::str::from_utf8(&body).unwrap();
- let signature = get_signature(&req)?;
- let secret = STRIPE_WEBHOOK_SECRET.get().unwrap();
- let event = Webhook::construct_event(payload, &signature, secret)
- .map_err(|_| HttpError::InvalidInput("Failed to verify webhook".into()))?;
- match event.type_ {
- EventType::PaymentIntentSucceeded => {handle_success(event, &db).await?},
- EventType::PaymentIntentPaymentFailed => {handle_failure(event, &db).await?},
- _ => ()
- };
- Ok(HttpResponse::Ok().finish())
- }
- fn get_signature(req: &HttpRequest) -> Result<String, HttpError> {
- let signature = req.headers()
- .get("stripe-signature")
- .and_then(|v| v.to_str().ok())
- .ok_or_else(|| HttpError::InvalidInput("No signature".into()))?
- .to_string();
- Ok(signature)
- }
- async fn handle_success(event: Event, db: &PgPool) -> Result<(), HttpError> {
- let id = match event.data.object {
- EventObject::PaymentIntent(pi) => pi.id.to_string(),
- _ => {return Err(HttpError::InvalidInput("No payment intent ID".into()))}
- };
- let p = Purchase::update_status(db, id, Status::Succeeded).await?;
- User::add_tokens(db, p.user_id, p.pack_count * p.tokens_per_pack).await?;
- Ok(())
- }
- async fn handle_failure(event: Event, db: &PgPool) -> Result<(), HttpError> {
- let id = match event.data.object {
- EventObject::PaymentIntent(pi) => pi.id.to_string(),
- _ => {return Err(HttpError::InvalidInput("No payment intent ID".into()))}
- };
- Purchase::update_status(db, id, Status::Succeeded).await?;
- Ok(())
- }
|