mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 21:42:34 +00:00
Move ical-related stuff to rustical_ical crate
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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
35
crates/ical/src/error.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)]
|
||||||
@@ -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::*;
|
||||||
@@ -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(),
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod address_object;
|
|
||||||
pub mod addressbook;
|
|
||||||
|
|
||||||
pub use address_object::*;
|
|
||||||
pub use addressbook::*;
|
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)]
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user