remove common suffix from AppError enum members
This commit is contained in:
parent
1f08b5a590
commit
2c15cdfd11
7 changed files with 31 additions and 36 deletions
|
@ -8,18 +8,16 @@ use validator::ValidationErrors;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AppError {
|
pub enum AppError {
|
||||||
InternalServerError(anyhow::Error),
|
InternalServerError(anyhow::Error),
|
||||||
ForbiddenError(String),
|
Forbidden(String),
|
||||||
NotFoundError(String),
|
NotFound(String),
|
||||||
BadRequestError(String),
|
BadRequest(String),
|
||||||
TooManyRequestsError(String),
|
TooManyRequests(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppError {
|
impl AppError {
|
||||||
pub fn from_validation_errors(errs: ValidationErrors) -> Self {
|
pub fn from_validation_errors(errs: ValidationErrors) -> Self {
|
||||||
// TODO: customize validation errors formatting
|
// TODO: customize validation errors formatting
|
||||||
Self::BadRequestError(
|
Self::BadRequest(serde_json::to_string(&errs).unwrap_or("validation error".to_string()))
|
||||||
serde_json::to_string(&errs).unwrap_or("validation error".to_string()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,21 +28,21 @@ impl IntoResponse for AppError {
|
||||||
tracing::error!("Application error: {:?}", err);
|
tracing::error!("Application error: {:?}", err);
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response()
|
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response()
|
||||||
}
|
}
|
||||||
Self::ForbiddenError(client_message) => {
|
Self::Forbidden(client_message) => {
|
||||||
tracing::info!("Forbidden: {}", client_message);
|
tracing::info!("Forbidden: {}", client_message);
|
||||||
(StatusCode::FORBIDDEN, client_message).into_response()
|
(StatusCode::FORBIDDEN, client_message).into_response()
|
||||||
}
|
}
|
||||||
Self::NotFoundError(client_message) => {
|
Self::NotFound(client_message) => {
|
||||||
tracing::info!("Not found: {}", client_message);
|
tracing::info!("Not found: {}", client_message);
|
||||||
(StatusCode::NOT_FOUND, client_message).into_response()
|
(StatusCode::NOT_FOUND, client_message).into_response()
|
||||||
}
|
}
|
||||||
Self::TooManyRequestsError(client_message) => {
|
Self::TooManyRequests(client_message) => {
|
||||||
// Debug level so that if this is from a runaway loop, it won't
|
// Debug level so that if this is from a runaway loop, it won't
|
||||||
// overwhelm server logs
|
// overwhelm server logs
|
||||||
tracing::debug!("Too many requests: {}", client_message);
|
tracing::debug!("Too many requests: {}", client_message);
|
||||||
(StatusCode::TOO_MANY_REQUESTS, client_message).into_response()
|
(StatusCode::TOO_MANY_REQUESTS, client_message).into_response()
|
||||||
}
|
}
|
||||||
Self::BadRequestError(client_message) => {
|
Self::BadRequest(client_message) => {
|
||||||
tracing::info!("Bad user input: {}", client_message);
|
tracing::info!("Bad user input: {}", client_message);
|
||||||
(StatusCode::BAD_REQUEST, client_message).into_response()
|
(StatusCode::BAD_REQUEST, client_message).into_response()
|
||||||
}
|
}
|
||||||
|
@ -66,16 +64,16 @@ impl Display for AppError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AppError::InternalServerError(inner) => inner.fmt(f),
|
AppError::InternalServerError(inner) => inner.fmt(f),
|
||||||
AppError::ForbiddenError(client_message) => {
|
AppError::Forbidden(client_message) => {
|
||||||
write!(f, "ForbiddenError: {}", client_message)
|
write!(f, "ForbiddenError: {}", client_message)
|
||||||
}
|
}
|
||||||
AppError::NotFoundError(client_message) => {
|
AppError::NotFound(client_message) => {
|
||||||
write!(f, "NotFoundError: {}", client_message)
|
write!(f, "NotFoundError: {}", client_message)
|
||||||
}
|
}
|
||||||
AppError::BadRequestError(client_message) => {
|
AppError::BadRequest(client_message) => {
|
||||||
write!(f, "BadRequestError: {}", client_message)
|
write!(f, "BadRequestError: {}", client_message)
|
||||||
}
|
}
|
||||||
AppError::TooManyRequestsError(client_message) => {
|
AppError::TooManyRequests(client_message) => {
|
||||||
write!(f, "TooManyRequestsError: {}", client_message)
|
write!(f, "TooManyRequestsError: {}", client_message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ async fn callback(
|
||||||
})?;
|
})?;
|
||||||
if session_csrf_token != query.state {
|
if session_csrf_token != query.state {
|
||||||
tracing::debug!("oauth csrf tokens did not match");
|
tracing::debug!("oauth csrf tokens did not match");
|
||||||
return Err(AppError::ForbiddenError(
|
return Err(AppError::Forbidden(
|
||||||
"OAuth CSRF tokens do not match.".to_string(),
|
"OAuth CSRF tokens do not match.".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn get_channel_by_params<'a>(
|
||||||
.filter(Channel::with_team(team_id))
|
.filter(Channel::with_team(team_id))
|
||||||
.first(conn)
|
.first(conn)
|
||||||
{
|
{
|
||||||
diesel::QueryResult::Err(diesel::result::Error::NotFound) => Err(AppError::NotFoundError(
|
diesel::QueryResult::Err(diesel::result::Error::NotFound) => Err(AppError::NotFound(
|
||||||
"Channel with that team and ID not found.".to_string(),
|
"Channel with that team and ID not found.".to_string(),
|
||||||
)),
|
)),
|
||||||
diesel::QueryResult::Err(err) => Err(err.into()),
|
diesel::QueryResult::Err(err) => Err(err.into()),
|
||||||
|
@ -153,7 +153,7 @@ async fn post_new_channel(
|
||||||
.await
|
.await
|
||||||
.unwrap()?,
|
.unwrap()?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(AppError::BadRequestError(
|
return Err(AppError::BadRequest(
|
||||||
"Channel type not recognized.".to_string(),
|
"Channel type not recognized.".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ async fn channel_page(
|
||||||
.unwrap()?
|
.unwrap()?
|
||||||
{
|
{
|
||||||
None => {
|
None => {
|
||||||
return Err(AppError::NotFoundError(
|
return Err(AppError::NotFound(
|
||||||
"Channel with that team and ID not found".to_string(),
|
"Channel with that team and ID not found".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ async fn update_channel(
|
||||||
.context("Failed to load Channel while updating.")?
|
.context("Failed to load Channel while updating.")?
|
||||||
};
|
};
|
||||||
if updated_rows != 1 {
|
if updated_rows != 1 {
|
||||||
return Err(AppError::NotFoundError(
|
return Err(AppError::NotFound(
|
||||||
"Channel with that team and ID not found".to_string(),
|
"Channel with that team and ID not found".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ async fn update_channel_email_recipient(
|
||||||
guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
||||||
|
|
||||||
if !is_permissible_email(&form_body.recipient) {
|
if !is_permissible_email(&form_body.recipient) {
|
||||||
return Err(AppError::BadRequestError(
|
return Err(AppError::BadRequest(
|
||||||
"Unable to validate email address format.".to_string(),
|
"Unable to validate email address format.".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ async fn verify_email(
|
||||||
guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
guards::require_team_membership(¤t_user, &team_id, &db_conn).await?;
|
||||||
|
|
||||||
if form_body.code.len() != VERIFICATION_CODE_LEN {
|
if form_body.code.len() != VERIFICATION_CODE_LEN {
|
||||||
return Err(AppError::BadRequestError(format!(
|
return Err(AppError::BadRequest(format!(
|
||||||
"Verification code must be {} characters long.",
|
"Verification code must be {} characters long.",
|
||||||
VERIFICATION_CODE_LEN
|
VERIFICATION_CODE_LEN
|
||||||
)));
|
)));
|
||||||
|
@ -414,15 +414,13 @@ async fn verify_email(
|
||||||
let channel = get_channel_by_params(conn, &team_id, &channel_id)?;
|
let channel = get_channel_by_params(conn, &team_id, &channel_id)?;
|
||||||
let config: EmailBackendConfig = channel.backend_config.try_into()?;
|
let config: EmailBackendConfig = channel.backend_config.try_into()?;
|
||||||
if config.verified {
|
if config.verified {
|
||||||
return Err(AppError::BadRequestError(
|
return Err(AppError::BadRequest(
|
||||||
"Channel's email address is already verified.".to_string(),
|
"Channel's email address is already verified.".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
const MAX_VERIFICATION_GUESSES: u32 = 100;
|
const MAX_VERIFICATION_GUESSES: u32 = 100;
|
||||||
if config.verification_code_guesses > MAX_VERIFICATION_GUESSES {
|
if config.verification_code_guesses > MAX_VERIFICATION_GUESSES {
|
||||||
return Err(AppError::BadRequestError(
|
return Err(AppError::BadRequest("Verification expired.".to_string()));
|
||||||
"Verification expired.".to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let new_config = if config.verification_code == verification_code {
|
let new_config = if config.verification_code == verification_code {
|
||||||
EmailBackendConfig {
|
EmailBackendConfig {
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub async fn require_team_membership(
|
||||||
};
|
};
|
||||||
match maybe_team {
|
match maybe_team {
|
||||||
Some((team, _)) => Ok(team),
|
Some((team, _)) => Ok(team),
|
||||||
None => Err(AppError::ForbiddenError(
|
None => Err(AppError::Forbidden(
|
||||||
"not a member of requested team".to_string(),
|
"not a member of requested team".to_string(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,6 @@ pub async fn require_valid_csrf_token(
|
||||||
if validate_csrf_token(db_conn, csrf_token, Some(current_user.id)).await? {
|
if validate_csrf_token(db_conn, csrf_token, Some(current_user.id)).await? {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(AppError::ForbiddenError("invalid CSRF token".to_string()))
|
Err(AppError::Forbidden("invalid CSRF token".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ async fn project_page(
|
||||||
.filter(Project::with_team(&team_id))
|
.filter(Project::with_team(&team_id))
|
||||||
.first(conn)
|
.first(conn)
|
||||||
{
|
{
|
||||||
diesel::QueryResult::Err(diesel::NotFound) => Err(AppError::NotFoundError(
|
diesel::QueryResult::Err(diesel::NotFound) => Err(AppError::NotFound(
|
||||||
"Project with that team and ID not found.".to_string(),
|
"Project with that team and ID not found.".to_string(),
|
||||||
)),
|
)),
|
||||||
other => other
|
other => other
|
||||||
|
@ -213,7 +213,7 @@ async fn update_enabled_channels(
|
||||||
.filter(Project::with_team(&team_id))
|
.filter(Project::with_team(&team_id))
|
||||||
.first(conn)
|
.first(conn)
|
||||||
{
|
{
|
||||||
diesel::QueryResult::Err(diesel::NotFound) => Err(AppError::NotFoundError(
|
diesel::QueryResult::Err(diesel::NotFound) => Err(AppError::NotFound(
|
||||||
"Project with that team and ID not found.".to_string(),
|
"Project with that team and ID not found.".to_string(),
|
||||||
)),
|
)),
|
||||||
other => other
|
other => other
|
||||||
|
|
|
@ -139,7 +139,7 @@ async fn remove_api_key(
|
||||||
"there should never be more than 1 API key with the same ID"
|
"there should never be more than 1 API key with the same ID"
|
||||||
);
|
);
|
||||||
if n_deleted == 0 {
|
if n_deleted == 0 {
|
||||||
Err(AppError::NotFoundError(
|
Err(AppError::NotFound(
|
||||||
"no API key with that ID and team found".to_owned(),
|
"no API key with that ID and team found".to_owned(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -67,9 +67,8 @@ async fn say_get(
|
||||||
query.validate().map_err(AppError::from_validation_errors)?;
|
query.validate().map_err(AppError::from_validation_errors)?;
|
||||||
|
|
||||||
let api_key = {
|
let api_key = {
|
||||||
let query_key = try_parse_as_uuid(&query.key).or(Err(AppError::ForbiddenError(
|
let query_key = try_parse_as_uuid(&query.key)
|
||||||
"key not accepted".to_string(),
|
.or(Err(AppError::Forbidden("key not accepted".to_string())))?;
|
||||||
)))?;
|
|
||||||
db_conn
|
db_conn
|
||||||
.interact::<_, Result<ApiKey, AppError>>(move |conn| {
|
.interact::<_, Result<ApiKey, AppError>>(move |conn| {
|
||||||
update(api_keys::table.filter(ApiKey::with_id(&query_key)))
|
update(api_keys::table.filter(ApiKey::with_id(&query_key)))
|
||||||
|
@ -78,7 +77,7 @@ async fn say_get(
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.optional()
|
.optional()
|
||||||
.context("failed to get API key")?
|
.context("failed to get API key")?
|
||||||
.ok_or(AppError::ForbiddenError("key not accepted.".to_string()))
|
.ok_or(AppError::Forbidden("key not accepted.".to_string()))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()?
|
.unwrap()?
|
||||||
|
@ -146,7 +145,7 @@ async fn say_get(
|
||||||
.unwrap()?
|
.unwrap()?
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
return Err(AppError::TooManyRequestsError(
|
return Err(AppError::TooManyRequests(
|
||||||
"team rate limit exceeded".to_string(),
|
"team rate limit exceeded".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue