simplify handling of ical-related errors

This commit is contained in:
Lennart K
2026-01-16 14:16:22 +01:00
parent 2c67890343
commit 63373ad525
7 changed files with 22 additions and 62 deletions

View File

@@ -26,10 +26,7 @@ pub async fn route_import<C: CalendarStore, S: SubscriptionStore>(
} }
let parser = ical::IcalParser::from_slice(body.as_bytes()); let parser = ical::IcalParser::from_slice(body.as_bytes());
let mut cal = parser let mut cal = parser.expect_one()?.mutable();
.expect_one()
.map_err(rustical_ical::Error::ParserError)?
.mutable();
// Extract calendar metadata // Extract calendar metadata
let displayname = cal let displayname = cal
@@ -70,12 +67,7 @@ pub async fn route_import<C: CalendarStore, S: SubscriptionStore>(
cal_components.push(CalendarObjectType::Todo); cal_components.push(CalendarObjectType::Todo);
} }
let objects = cal let objects = cal.into_objects()?.into_iter().map(Into::into).collect();
.into_objects()
.map_err(rustical_ical::Error::ParserError)?
.into_iter()
.map(Into::into)
.collect();
let new_cal = Calendar { let new_cal = Calendar {
principal, principal,
id: cal_id, id: cal_id,

View File

@@ -75,7 +75,8 @@ impl Error {
Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST,
Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR,
Self::NotFound => StatusCode::NOT_FOUND, Self::NotFound => StatusCode::NOT_FOUND,
Self::IcalError(err) => err.status_code(), // TODO: Can also be Bad Request, if it's used input
Self::IcalError(_err) => StatusCode::INTERNAL_SERVER_ERROR,
Self::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED, Self::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED,
} }
} }

View File

@@ -43,7 +43,8 @@ impl Error {
Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST,
Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR,
Self::NotFound => StatusCode::NOT_FOUND, Self::NotFound => StatusCode::NOT_FOUND,
Self::IcalError(err) => err.status_code(), // TODO: Can also be Bad Request, if it's used input
Self::IcalError(_err) => StatusCode::INTERNAL_SERVER_ERROR,
} }
} }
} }

View File

@@ -1,34 +0,0 @@
use axum::{http::StatusCode, response::IntoResponse};
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum Error {
#[error("Invalid ics/vcf input: {0}")]
InvalidData(String),
#[error("Missing calendar")]
MissingCalendar,
#[error("Missing contact")]
MissingContact,
#[error(transparent)]
ParserError(#[from] ical::parser::ParserError),
}
impl Error {
#[must_use]
pub const fn status_code(&self) -> StatusCode {
match self {
Self::InvalidData(_) | Self::MissingCalendar | Self::MissingContact => {
StatusCode::BAD_REQUEST
}
Self::ParserError(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
impl IntoResponse for Error {
fn into_response(self) -> axum::response::Response {
(self.status_code(), self.to_string()).into_response()
}
}

View File

@@ -1,13 +1,13 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery)] #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
mod timestamp; mod timestamp;
use ical::parser::ParserError;
pub use timestamp::*; pub use timestamp::*;
mod calendar_object; mod calendar_object;
pub use calendar_object::*; pub use calendar_object::*;
mod error;
pub use error::Error;
mod address_object; mod address_object;
pub use address_object::AddressObject; pub use address_object::AddressObject;
pub type Error = ParserError;

View File

@@ -26,7 +26,7 @@ pub enum Error {
Other(#[from] anyhow::Error), Other(#[from] anyhow::Error),
#[error(transparent)] #[error(transparent)]
IcalError(#[from] rustical_ical::Error), IcalError(#[from] ical::parser::ParserError),
} }
impl Error { impl Error {
@@ -36,7 +36,8 @@ impl Error {
Self::NotFound => StatusCode::NOT_FOUND, Self::NotFound => StatusCode::NOT_FOUND,
Self::AlreadyExists => StatusCode::CONFLICT, Self::AlreadyExists => StatusCode::CONFLICT,
Self::ReadOnly => StatusCode::FORBIDDEN, Self::ReadOnly => StatusCode::FORBIDDEN,
Self::IcalError(err) => err.status_code(), // TODO: Can also be Bad Request, depending on when this is raised
Self::IcalError(_err) => StatusCode::INTERNAL_SERVER_ERROR,
Self::InvalidPrincipalType(_) => StatusCode::BAD_REQUEST, Self::InvalidPrincipalType(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR,
} }

View File

@@ -25,18 +25,17 @@ struct CalendarObjectRow {
impl TryFrom<CalendarObjectRow> for (String, CalendarObject) { impl TryFrom<CalendarObjectRow> for (String, CalendarObject) {
type Error = rustical_store::Error; type Error = rustical_store::Error;
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> { fn try_from(row: CalendarObjectRow) -> Result<Self, Self::Error> {
let object = CalendarObject::from_ics(value.ics)?; let object = CalendarObject::from_ics(row.ics)?;
if object.get_uid() != value.uid { if object.get_uid() != row.uid {
return Err(rustical_store::Error::IcalError( warn!(
rustical_ical::Error::InvalidData(format!( "Calendar object {}.ics: UID={} and row uid={} do not match",
"uid={} and UID={} don't match", row.id,
value.uid, object.get_uid(),
object.get_uid() row.uid
)), );
));
} }
Ok((value.id, object)) Ok((row.id, object))
} }
} }