Move ical-related stuff to rustical_ical crate

This commit is contained in:
Lennart
2025-06-03 18:15:26 +02:00
parent 5a6ffd3c19
commit 7f3ce01c2b
35 changed files with 121 additions and 68 deletions

4
Cargo.lock generated
View File

@@ -3114,6 +3114,7 @@ dependencies = [
"quick-xml", "quick-xml",
"rustical_dav", "rustical_dav",
"rustical_dav_push", "rustical_dav_push",
"rustical_ical",
"rustical_store", "rustical_store",
"rustical_xml", "rustical_xml",
"serde", "serde",
@@ -3198,6 +3199,7 @@ dependencies = [
name = "rustical_ical" name = "rustical_ical"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix-web",
"chrono", "chrono",
"chrono-tz", "chrono-tz",
"derive_more 2.0.1", "derive_more 2.0.1",
@@ -3206,6 +3208,8 @@ dependencies = [
"regex", "regex",
"rrule", "rrule",
"rustical_xml", "rustical_xml",
"serde",
"sha2",
"strum", "strum",
"strum_macros", "strum_macros",
"thiserror 2.0.12", "thiserror 2.0.12",

View File

@@ -103,7 +103,7 @@ rustical_carddav = { path = "./crates/carddav/" }
rustical_frontend = { path = "./crates/frontend/" } rustical_frontend = { path = "./crates/frontend/" }
rustical_xml = { path = "./crates/xml/" } rustical_xml = { path = "./crates/xml/" }
rustical_oidc = { path = "./crates/oidc/" } rustical_oidc = { path = "./crates/oidc/" }
rustical_ical = { path = "./crates/ical/" } rustical_ical = { path = "./crates/ical/", features = ["actix"] }
chrono-tz = "0.10" chrono-tz = "0.10"
chrono-humanize = "0.2" chrono-humanize = "0.2"
rand = "0.8" rand = "0.8"

View File

@@ -2,8 +2,8 @@ use crate::Error;
use crate::calendar::prop::SupportedCalendarComponentSet; use crate::calendar::prop::SupportedCalendarComponentSet;
use actix_web::HttpResponse; use actix_web::HttpResponse;
use actix_web::web::{Data, Path}; use actix_web::web::{Data, Path};
use rustical_ical::CalendarObjectType;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::calendar::CalendarObjectType;
use rustical_store::{Calendar, CalendarStore}; use rustical_store::{Calendar, CalendarStore};
use rustical_xml::{Unparsed, XmlDeserialize, XmlDocument, XmlRootTag}; use rustical_xml::{Unparsed, XmlDeserialize, XmlDocument, XmlRootTag};
use tracing::instrument; use tracing::instrument;

View File

@@ -11,7 +11,8 @@ use rustical_dav::{
resource::{PrincipalUri, Resource}, resource::{PrincipalUri, Resource},
xml::{MultistatusElement, PropfindType, multistatus::ResponseElement}, xml::{MultistatusElement, PropfindType, multistatus::ResponseElement},
}; };
use rustical_store::{CalendarObject, CalendarStore, auth::User}; use rustical_ical::CalendarObject;
use rustical_store::{CalendarStore, auth::User};
use rustical_xml::XmlDeserialize; use rustical_xml::XmlDeserialize;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]

View File

@@ -2,8 +2,8 @@ use rustical_dav::{
resource::{PrincipalUri, Resource}, resource::{PrincipalUri, Resource},
xml::{MultistatusElement, PropfindType}, xml::{MultistatusElement, PropfindType},
}; };
use rustical_ical::UtcDateTime; use rustical_ical::{CalendarObject, UtcDateTime};
use rustical_store::{CalendarObject, CalendarStore, auth::User, calendar_store::CalendarQuery}; use rustical_store::{CalendarStore, auth::User, calendar_store::CalendarQuery};
use rustical_xml::XmlDeserialize; use rustical_xml::XmlDeserialize;
use std::ops::Deref; use std::ops::Deref;

View File

@@ -1,5 +1,5 @@
use derive_more::derive::{From, Into}; use derive_more::derive::{From, Into};
use rustical_store::calendar::CalendarObjectType; use rustical_ical::CalendarObjectType;
use rustical_xml::{XmlDeserialize, XmlSerialize}; use rustical_xml::{XmlDeserialize, XmlSerialize};
#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq, From, Into)] #[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq, From, Into)]

View File

@@ -4,8 +4,9 @@ use actix_web::HttpResponse;
use actix_web::http::header; use actix_web::http::header;
use actix_web::http::header::HeaderValue; use actix_web::http::header::HeaderValue;
use actix_web::web::{Data, Path}; use actix_web::web::{Data, Path};
use rustical_ical::CalendarObject;
use rustical_store::CalendarStore;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::{CalendarObject, CalendarStore};
use tracing::instrument; use tracing::instrument;
use tracing_actix_web::RootSpan; use tracing_actix_web::RootSpan;

View File

@@ -9,7 +9,8 @@ use rustical_dav::{
resource::{PrincipalUri, Resource, ResourceService}, resource::{PrincipalUri, Resource, ResourceService},
xml::Resourcetype, xml::Resourcetype,
}; };
use rustical_store::{CalendarObject, CalendarStore, auth::User}; use rustical_ical::CalendarObject;
use rustical_store::{CalendarStore, auth::User};
use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize};
use serde::Deserialize; use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;

View File

@@ -23,6 +23,9 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
XmlDecodeError(#[from] rustical_xml::XmlError), XmlDecodeError(#[from] rustical_xml::XmlError),
#[error(transparent)]
IcalError(#[from] rustical_ical::Error),
} }
impl actix_web::ResponseError for Error { impl actix_web::ResponseError for Error {
@@ -30,9 +33,7 @@ impl actix_web::ResponseError for Error {
match self { match self {
Error::StoreError(err) => match err { Error::StoreError(err) => match err {
rustical_store::Error::NotFound => StatusCode::NOT_FOUND, rustical_store::Error::NotFound => StatusCode::NOT_FOUND,
rustical_store::Error::InvalidData(_) => StatusCode::BAD_REQUEST,
rustical_store::Error::AlreadyExists => StatusCode::CONFLICT, rustical_store::Error::AlreadyExists => StatusCode::CONFLICT,
rustical_store::Error::ParserError(_) => StatusCode::BAD_REQUEST,
rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN,
_ => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR,
}, },
@@ -42,12 +43,14 @@ impl actix_web::ResponseError for Error {
Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST, Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST,
Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR,
Error::NotFound => StatusCode::NOT_FOUND, Error::NotFound => StatusCode::NOT_FOUND,
Error::IcalError(err) => err.status_code(),
} }
} }
fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> { fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
error!("Error: {self}"); error!("Error: {self}");
match self { match self {
Error::DavError(err) => err.error_response(), Error::DavError(err) => err.error_response(),
Error::IcalError(err) => err.error_response(),
_ => HttpResponse::build(self.status_code()).body(self.to_string()), _ => HttpResponse::build(self.status_code()).body(self.to_string()),
} }
} }

View File

@@ -26,3 +26,4 @@ chrono = { workspace = true }
rustical_xml.workspace = true rustical_xml.workspace = true
uuid.workspace = true uuid.workspace = true
rustical_dav_push.workspace = true rustical_dav_push.workspace = true
rustical_ical.workspace = true

View File

@@ -8,8 +8,9 @@ use actix_web::http::header::HeaderValue;
use actix_web::web::{Data, Path}; use actix_web::web::{Data, Path};
use rustical_dav::privileges::UserPrivilege; use rustical_dav::privileges::UserPrivilege;
use rustical_dav::resource::Resource; use rustical_dav::resource::Resource;
use rustical_ical::AddressObject;
use rustical_store::AddressbookStore;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::{AddressObject, AddressbookStore};
use tracing::instrument; use tracing::instrument;
use tracing_actix_web::RootSpan; use tracing_actix_web::RootSpan;

View File

@@ -8,7 +8,8 @@ use rustical_dav::{
resource::{PrincipalUri, Resource, ResourceService}, resource::{PrincipalUri, Resource, ResourceService},
xml::Resourcetype, xml::Resourcetype,
}; };
use rustical_store::{AddressObject, AddressbookStore, auth::User}; use rustical_ical::AddressObject;
use rustical_store::{AddressbookStore, auth::User};
use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize};
use serde::Deserialize; use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;

View File

@@ -10,7 +10,8 @@ use rustical_dav::{
resource::{PrincipalUri, Resource}, resource::{PrincipalUri, Resource},
xml::{MultistatusElement, PropfindType, multistatus::ResponseElement}, xml::{MultistatusElement, PropfindType, multistatus::ResponseElement},
}; };
use rustical_store::{AddressObject, AddressbookStore, auth::User}; use rustical_ical::AddressObject;
use rustical_store::{AddressbookStore, auth::User};
use rustical_xml::XmlDeserialize; use rustical_xml::XmlDeserialize;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]

View File

@@ -23,6 +23,9 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
XmlDecodeError(#[from] rustical_xml::XmlError), XmlDecodeError(#[from] rustical_xml::XmlError),
#[error(transparent)]
IcalError(#[from] rustical_ical::Error),
} }
impl actix_web::ResponseError for Error { impl actix_web::ResponseError for Error {
@@ -30,9 +33,7 @@ impl actix_web::ResponseError for Error {
match self { match self {
Error::StoreError(err) => match err { Error::StoreError(err) => match err {
rustical_store::Error::NotFound => StatusCode::NOT_FOUND, rustical_store::Error::NotFound => StatusCode::NOT_FOUND,
rustical_store::Error::InvalidData(_) => StatusCode::BAD_REQUEST,
rustical_store::Error::AlreadyExists => StatusCode::CONFLICT, rustical_store::Error::AlreadyExists => StatusCode::CONFLICT,
rustical_store::Error::ParserError(_) => StatusCode::BAD_REQUEST,
rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN,
_ => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR,
}, },
@@ -42,12 +43,14 @@ impl actix_web::ResponseError for Error {
Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST, Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST,
Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR,
Error::NotFound => StatusCode::NOT_FOUND, Error::NotFound => StatusCode::NOT_FOUND,
Self::IcalError(err) => err.status_code(),
} }
} }
fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> { fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
error!("Error: {self}"); error!("Error: {self}");
match self { match self {
Error::DavError(err) => err.error_response(), Error::DavError(err) => err.error_response(),
Error::IcalError(err) => err.error_response(),
_ => HttpResponse::build(self.status_code()).body(self.to_string()), _ => HttpResponse::build(self.status_code()).body(self.to_string()),
} }
} }

View File

@@ -5,6 +5,9 @@ edition.workspace = true
description.workspace = true description.workspace = true
repository.workspace = true repository.workspace = true
[features]
actix = ["dep:actix-web"]
[dependencies] [dependencies]
chrono.workspace = true chrono.workspace = true
chrono-tz.workspace = true chrono-tz.workspace = true
@@ -17,3 +20,6 @@ regex.workspace = true
strum.workspace = true strum.workspace = true
strum_macros.workspace = true strum_macros.workspace = true
rrule = "0.14" rrule = "0.14"
serde.workspace = true
sha2.workspace = true
actix-web = { workspace = true, optional = true }

View File

@@ -1,10 +1,10 @@
use crate::{CalDateTime, LOCAL_DATE};
use crate::{CalendarObject, Error}; use crate::{CalendarObject, Error};
use chrono::Datelike; use chrono::Datelike;
use ical::parser::{ use ical::parser::{
Component, Component,
vcard::{self, component::VcardContact}, vcard::{self, component::VcardContact},
}; };
use rustical_ical::{CalDateTime, LOCAL_DATE};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{collections::HashMap, io::BufReader}; use std::{collections::HashMap, io::BufReader};
@@ -18,7 +18,7 @@ pub struct AddressObject {
impl AddressObject { impl AddressObject {
pub fn from_vcf(object_id: String, vcf: String) -> Result<Self, Error> { pub fn from_vcf(object_id: String, vcf: String) -> Result<Self, Error> {
let mut parser = vcard::VcardParser::new(BufReader::new(vcf.as_bytes())); let mut parser = vcard::VcardParser::new(BufReader::new(vcf.as_bytes()));
let vcard = parser.next().ok_or(Error::NotFound)??; let vcard = parser.next().ok_or(Error::MissingContact)??;
if parser.next().is_some() { if parser.next().is_some() {
return Err(Error::InvalidData( return Err(Error::InvalidData(
"multiple vcards, only one allowed".to_owned(), "multiple vcards, only one allowed".to_owned(),

35
crates/ical/src/error.rs Normal file
View File

@@ -0,0 +1,35 @@
use crate::CalDateTimeError;
#[derive(Debug, thiserror::Error)]
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),
#[error(transparent)]
CalDateTimeError(#[from] CalDateTimeError),
#[error(transparent)]
RRuleError(#[from] rrule::RRuleError),
}
#[cfg(feature = "actix")]
impl actix_web::ResponseError for Error {
fn status_code(&self) -> actix_web::http::StatusCode {
match self {
Self::InvalidData(_) => actix_web::http::StatusCode::BAD_REQUEST,
Self::MissingCalendar | Self::MissingContact => {
actix_web::http::StatusCode::BAD_REQUEST
}
_ => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
}
}
}

View File

@@ -1,4 +1,5 @@
use crate::Error; use crate::Error;
use crate::{CalDateTime, ComponentMut, parse_duration};
use chrono::{DateTime, Duration}; use chrono::{DateTime, Duration};
use ical::{ use ical::{
generator::IcalEvent, generator::IcalEvent,
@@ -6,7 +7,6 @@ use ical::{
property::Property, property::Property,
}; };
use rrule::{RRule, RRuleSet}; use rrule::{RRule, RRuleSet};
use rustical_ical::{CalDateTime, ComponentMut, parse_duration};
use std::{collections::HashMap, str::FromStr}; use std::{collections::HashMap, str::FromStr};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@@ -1,10 +1,8 @@
mod calendar;
mod event; mod event;
mod journal; mod journal;
mod object; mod object;
mod todo; mod todo;
pub use calendar::*;
pub use event::*; pub use event::*;
pub use journal::*; pub use journal::*;
pub use object::*; pub use object::*;

View File

@@ -1,10 +1,10 @@
use super::{EventObject, JournalObject, TodoObject}; use super::{EventObject, JournalObject, TodoObject};
use crate::CalDateTime;
use crate::Error; use crate::Error;
use ical::{ use ical::{
generator::{Emitter, IcalCalendar}, generator::{Emitter, IcalCalendar},
parser::{Component, ical::component::IcalTimeZone}, parser::{Component, ical::component::IcalTimeZone},
}; };
use rustical_ical::CalDateTime;
use serde::Serialize; use serde::Serialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{collections::HashMap, io::BufReader}; use std::{collections::HashMap, io::BufReader};
@@ -66,7 +66,7 @@ pub struct CalendarObject {
impl CalendarObject { impl CalendarObject {
pub fn from_ics(object_id: String, ics: String) -> Result<Self, Error> { pub fn from_ics(object_id: String, ics: String) -> Result<Self, Error> {
let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes())); let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes()));
let cal = parser.next().ok_or(Error::NotFound)??; let cal = parser.next().ok_or(Error::MissingCalendar)??;
if parser.next().is_some() { if parser.next().is_some() {
return Err(Error::InvalidData( return Err(Error::InvalidData(
"multiple calendars, only one allowed".to_owned(), "multiple calendars, only one allowed".to_owned(),

View File

@@ -8,3 +8,12 @@ pub use timezone::*;
mod duration; mod duration;
pub use duration::parse_duration; pub use duration::parse_duration;
mod icalendar;
pub use icalendar::*;
mod error;
pub use error::Error;
mod address_object;
pub use address_object::AddressObject;

View File

@@ -1,5 +0,0 @@
pub mod address_object;
pub mod addressbook;
pub use address_object::*;
pub use addressbook::*;

View File

@@ -1,8 +1,6 @@
use crate::{ use crate::{Error, addressbook::Addressbook};
Error,
addressbook::{AddressObject, Addressbook},
};
use async_trait::async_trait; use async_trait::async_trait;
use rustical_ical::AddressObject;
#[async_trait] #[async_trait]
pub trait AddressbookStore: Send + Sync + 'static { pub trait AddressbookStore: Send + Sync + 'static {

View File

@@ -38,7 +38,7 @@ impl TryFrom<&str> for PrincipalType {
"ROOM" => Self::Room, "ROOM" => Self::Room,
"UNKNOWN" => Self::Unknown, "UNKNOWN" => Self::Unknown,
_ => { _ => {
return Err(crate::Error::InvalidData( return Err(crate::Error::InvalidPrincipalType(
"Invalid principal type".to_owned(), "Invalid principal type".to_owned(),
)); ));
} }

View File

@@ -1,6 +1,6 @@
use super::CalendarObjectType;
use crate::synctoken::format_synctoken; use crate::synctoken::format_synctoken;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use rustical_ical::CalendarObjectType;
use serde::Serialize; use serde::Serialize;
#[derive(Debug, Default, Clone, Serialize)] #[derive(Debug, Default, Clone, Serialize)]

View File

@@ -1,7 +1,7 @@
use crate::calendar::{Calendar, CalendarObject}; use crate::{Calendar, error::Error};
use crate::error::Error;
use async_trait::async_trait; use async_trait::async_trait;
use chrono::NaiveDate; use chrono::NaiveDate;
use rustical_ical::CalendarObject;
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct CalendarQuery { pub struct CalendarQuery {

View File

@@ -1,12 +1,9 @@
use std::{collections::HashMap, sync::Arc}; use crate::{Addressbook, AddressbookStore, Calendar, CalendarStore, Error};
use crate::{
AddressObject, Addressbook, AddressbookStore, Calendar, CalendarObject, CalendarStore, Error,
calendar::CalendarObjectType,
};
use async_trait::async_trait; use async_trait::async_trait;
use derive_more::derive::Constructor; use derive_more::derive::Constructor;
use rustical_ical::{AddressObject, CalendarObject, CalendarObjectType};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{collections::HashMap, sync::Arc};
#[derive(Constructor, Clone)] #[derive(Constructor, Clone)]
pub struct ContactBirthdayStore<AS: AddressbookStore>(Arc<AS>); pub struct ContactBirthdayStore<AS: AddressbookStore>(Arc<AS>);
@@ -85,7 +82,7 @@ impl<AS: AddressbookStore> CalendarStore for ContactBirthdayStore<AS> {
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> { ) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
let (objects, deleted_objects, new_synctoken) = let (objects, deleted_objects, new_synctoken) =
self.0.sync_changes(principal, cal_id, synctoken).await?; self.0.sync_changes(principal, cal_id, synctoken).await?;
let objects: Result<Vec<Option<CalendarObject>>, Error> = objects let objects: Result<Vec<Option<CalendarObject>>, rustical_ical::Error> = objects
.iter() .iter()
.map(AddressObject::get_birthday_object) .map(AddressObject::get_birthday_object)
.collect(); .collect();
@@ -99,13 +96,13 @@ impl<AS: AddressbookStore> CalendarStore for ContactBirthdayStore<AS> {
principal: &str, principal: &str,
cal_id: &str, cal_id: &str,
) -> Result<Vec<CalendarObject>, Error> { ) -> Result<Vec<CalendarObject>, Error> {
let objects: Result<Vec<HashMap<&'static str, CalendarObject>>, Error> = self let objects: Result<Vec<HashMap<&'static str, CalendarObject>>, rustical_ical::Error> =
.0 self.0
.get_objects(principal, cal_id) .get_objects(principal, cal_id)
.await? .await?
.iter() .iter()
.map(AddressObject::get_significant_dates) .map(AddressObject::get_significant_dates)
.collect(); .collect();
let objects = objects? let objects = objects?
.into_iter() .into_iter()
.flat_map(HashMap::into_values) .flat_map(HashMap::into_values)

View File

@@ -1,5 +1,4 @@
use actix_web::{ResponseError, http::StatusCode}; use actix_web::{ResponseError, http::StatusCode};
use rustical_ical::CalDateTimeError;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
@@ -9,8 +8,8 @@ pub enum Error {
#[error("Resource already exists and overwrite=false")] #[error("Resource already exists and overwrite=false")]
AlreadyExists, AlreadyExists,
#[error("Invalid ics/vcf input: {0}")] #[error("Invalid principal type: {0}")]
InvalidData(String), InvalidPrincipalType(String),
#[error("Read-only")] #[error("Read-only")]
ReadOnly, ReadOnly,
@@ -21,17 +20,11 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
#[error(transparent)]
ParserError(#[from] ical::parser::ParserError),
#[error(transparent)] #[error(transparent)]
Other(#[from] anyhow::Error), Other(#[from] anyhow::Error),
#[error(transparent)] #[error(transparent)]
CalDateTimeError(#[from] CalDateTimeError), IcalError(#[from] rustical_ical::Error),
#[error(transparent)]
RRuleError(#[from] rrule::RRuleError),
} }
impl ResponseError for Error { impl ResponseError for Error {
@@ -39,8 +32,9 @@ impl ResponseError for Error {
match self { match self {
Self::NotFound => StatusCode::NOT_FOUND, Self::NotFound => StatusCode::NOT_FOUND,
Self::AlreadyExists => StatusCode::CONFLICT, Self::AlreadyExists => StatusCode::CONFLICT,
Self::InvalidData(_) => StatusCode::BAD_REQUEST,
Self::ReadOnly => StatusCode::FORBIDDEN, Self::ReadOnly => StatusCode::FORBIDDEN,
Self::IcalError(err) => err.status_code(),
Self::InvalidPrincipalType(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR,
} }
} }

View File

@@ -4,7 +4,7 @@ pub mod calendar_store;
pub mod error; pub mod error;
pub use error::Error; pub use error::Error;
pub mod auth; pub mod auth;
pub mod calendar; mod calendar;
mod contact_birthday_store; mod contact_birthday_store;
mod secret; mod secret;
mod subscription_store; mod subscription_store;
@@ -16,8 +16,8 @@ pub use contact_birthday_store::ContactBirthdayStore;
pub use secret::Secret; pub use secret::Secret;
pub use subscription_store::*; pub use subscription_store::*;
pub use addressbook::{AddressObject, Addressbook}; pub use addressbook::Addressbook;
pub use calendar::{Calendar, CalendarObject}; pub use calendar::Calendar;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum CollectionOperationType { pub enum CollectionOperationType {

View File

@@ -1,8 +1,9 @@
use super::ChangeOperation; use super::ChangeOperation;
use async_trait::async_trait; use async_trait::async_trait;
use derive_more::derive::Constructor; use derive_more::derive::Constructor;
use rustical_ical::AddressObject;
use rustical_store::{ use rustical_store::{
AddressObject, Addressbook, AddressbookStore, CollectionOperation, CollectionOperationDomain, Addressbook, AddressbookStore, CollectionOperation, CollectionOperationDomain,
CollectionOperationType, Error, synctoken::format_synctoken, CollectionOperationType, Error, synctoken::format_synctoken,
}; };
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction}; use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};

View File

@@ -2,11 +2,10 @@ use super::ChangeOperation;
use async_trait::async_trait; use async_trait::async_trait;
use chrono::TimeDelta; use chrono::TimeDelta;
use derive_more::derive::Constructor; use derive_more::derive::Constructor;
use rustical_ical::CalDateTime; use rustical_ical::{CalDateTime, CalendarObject, CalendarObjectType};
use rustical_store::calendar::CalendarObjectType;
use rustical_store::calendar_store::CalendarQuery; use rustical_store::calendar_store::CalendarQuery;
use rustical_store::synctoken::format_synctoken; use rustical_store::synctoken::format_synctoken;
use rustical_store::{Calendar, CalendarObject, CalendarStore, Error}; use rustical_store::{Calendar, CalendarStore, Error};
use rustical_store::{CollectionOperation, CollectionOperationType}; use rustical_store::{CollectionOperation, CollectionOperationType};
use sqlx::types::chrono::NaiveDateTime; use sqlx::types::chrono::NaiveDateTime;
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction}; use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};
@@ -23,7 +22,7 @@ impl TryFrom<CalendarObjectRow> for CalendarObject {
type Error = rustical_store::Error; type Error = rustical_store::Error;
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> { fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
CalendarObject::from_ics(value.id, value.ics) Ok(CalendarObject::from_ics(value.id, value.ics)?)
} }
} }

View File

@@ -5,6 +5,9 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
StoreError(rustical_store::Error), StoreError(rustical_store::Error),
#[error(transparent)]
IcalError(#[from] rustical_ical::Error),
} }
impl From<sqlx::Error> for Error { impl From<sqlx::Error> for Error {
@@ -27,6 +30,7 @@ impl From<Error> for rustical_store::Error {
fn from(value: Error) -> Self { fn from(value: Error) -> Self {
match value { match value {
Error::SqlxError(err) => Self::Other(err.into()), Error::SqlxError(err) => Self::Other(err.into()),
Error::IcalError(err) => Self::Other(err.into()),
Error::StoreError(err) => err, Error::StoreError(err) => err,
} }
} }