From 7b64134fe7c0790b802e312f51158bfe80593f95 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 12 May 2021 22:33:43 +0100 Subject: [PATCH] Refactor error handling for `confirm` handler. --- src/routes/subscriptions.rs | 2 +- src/routes/subscriptions_confirm.rs | 49 ++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/routes/subscriptions.rs b/src/routes/subscriptions.rs index aabe2fc..405d8cf 100644 --- a/src/routes/subscriptions.rs +++ b/src/routes/subscriptions.rs @@ -196,7 +196,7 @@ impl std::fmt::Display for StoreTokenError { } } -fn error_chain_fmt( +pub fn error_chain_fmt( e: &impl std::error::Error, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { diff --git a/src/routes/subscriptions_confirm.rs b/src/routes/subscriptions_confirm.rs index 2389006..1fb9a99 100644 --- a/src/routes/subscriptions_confirm.rs +++ b/src/routes/subscriptions_confirm.rs @@ -1,4 +1,7 @@ -use actix_web::{web, HttpResponse}; +use crate::routes::error_chain_fmt; +use actix_web::http::StatusCode; +use actix_web::{web, HttpResponse, ResponseError}; +use anyhow::Context; use sqlx::PgPool; use uuid::Uuid; @@ -7,24 +10,42 @@ pub struct Parameters { subscription_token: String, } +#[derive(thiserror::Error)] +pub enum ConfirmationError { + #[error(transparent)] + UnexpectedError(#[from] anyhow::Error), + #[error("There is no subscriber associated with the provided token.")] + UnknownToken, +} + +impl std::fmt::Debug for ConfirmationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + error_chain_fmt(self, f) + } +} + +impl ResponseError for ConfirmationError { + fn status_code(&self) -> StatusCode { + match self { + Self::UnknownToken => StatusCode::UNAUTHORIZED, + Self::UnexpectedError(_) => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + #[tracing::instrument(name = "Confirm a pending subscriber", skip(parameters, pool))] pub async fn confirm( parameters: web::Query, pool: web::Data, -) -> Result { - let id = get_subscriber_id_from_token(&pool, ¶meters.subscription_token) +) -> Result { + let subscriber_id = get_subscriber_id_from_token(&pool, ¶meters.subscription_token) .await - .map_err(|_| HttpResponse::InternalServerError().finish())?; - match id { - // Non-existing token! - None => Err(HttpResponse::Unauthorized().finish()), - Some(subscriber_id) => { - confirm_subscriber(&pool, subscriber_id) - .await - .map_err(|_| HttpResponse::InternalServerError().finish())?; - Ok(HttpResponse::Ok().finish()) - } - } + .context("Failed to retrieve the subscriber id associated with the provided token.")? + .ok_or(ConfirmationError::UnknownToken)?; + confirm_subscriber(&pool, subscriber_id) + .await + .context("Failed to update the subscriber status to `confirmed`.")?; + Ok(HttpResponse::Ok().finish()) } #[tracing::instrument(name = "Mark subscriber as confirmed", skip(subscriber_id, pool))]