mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-14 04:42:15 +00:00
Switch event representation such that properties can be extracted
This commit is contained in:
@@ -24,3 +24,6 @@ serde_json = "1.0.105"
|
|||||||
tokio = { version = "1.32.0", features = ["sync", "full"] }
|
tokio = { version = "1.32.0", features = ["sync", "full"] }
|
||||||
async-trait = "0.1.73"
|
async-trait = "0.1.73"
|
||||||
thiserror = "1.0.48"
|
thiserror = "1.0.48"
|
||||||
|
ical = { git = "https://github.com/Peltoche/ical-rs.git", rev = "4f7aeb0", features = [
|
||||||
|
"generator",
|
||||||
|
] }
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ impl<C: CalendarStore> Resource for EventResource<C> {
|
|||||||
write_string_prop(writer, "getetag", &self.event.get_etag())?;
|
write_string_prop(writer, "getetag", &self.event.get_etag())?;
|
||||||
}
|
}
|
||||||
"calendar-data" => {
|
"calendar-data" => {
|
||||||
write_string_prop(writer, "C:calendar-data", self.event.as_ics())?;
|
write_string_prop(writer, "C:calendar-data", &self.event.get_ics())?;
|
||||||
}
|
}
|
||||||
"getcontenttype" => {
|
"getcontenttype" => {
|
||||||
write_string_prop(writer, "getcontenttype", "text/calendar;charset=utf-8")?;
|
write_string_prop(writer, "getcontenttype", "text/calendar;charset=utf-8")?;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ pub async fn get_event<A: CheckAuthentication, C: CalendarStore>(
|
|||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.insert_header(("ETag", event.get_etag()))
|
.insert_header(("ETag", event.get_etag()))
|
||||||
.body(event.as_ics().to_string()))
|
.body(event.get_ics()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn put_event<A: CheckAuthentication, C: CalendarStore>(
|
pub async fn put_event<A: CheckAuthentication, C: CalendarStore>(
|
||||||
|
|||||||
@@ -22,3 +22,6 @@ sqlx = { version = "0.7.1", features = [
|
|||||||
] }
|
] }
|
||||||
tokio = { version = "1.32.0", features = ["sync", "full"] }
|
tokio = { version = "1.32.0", features = ["sync", "full"] }
|
||||||
toml = "0.7.6"
|
toml = "0.7.6"
|
||||||
|
ical = { git = "https://github.com/Peltoche/ical-rs.git", rev = "4f7aeb0", features = [
|
||||||
|
"generator",
|
||||||
|
] }
|
||||||
|
|||||||
@@ -1,17 +1,63 @@
|
|||||||
use anyhow::Result;
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use ical::generator::{Emitter, IcalCalendar};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
uid: String,
|
uid: String,
|
||||||
ics: String,
|
cal: IcalCalendar,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom implementation for Event (de)serialization
|
||||||
|
impl<'de> Deserialize<'de> for Event {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Inner {
|
||||||
|
uid: String,
|
||||||
|
ics: String,
|
||||||
|
}
|
||||||
|
let Inner { uid, ics } = Inner::deserialize(deserializer)?;
|
||||||
|
Self::from_ics(uid, ics).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Serialize for Event {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Inner {
|
||||||
|
uid: String,
|
||||||
|
ics: String,
|
||||||
|
}
|
||||||
|
Inner::serialize(
|
||||||
|
&Inner {
|
||||||
|
uid: self.get_uid().to_string(),
|
||||||
|
ics: self.get_ics().to_string(),
|
||||||
|
},
|
||||||
|
serializer,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
pub fn from_ics(uid: String, ics: String) -> Self {
|
pub fn from_ics(uid: String, ics: String) -> Result<Self> {
|
||||||
Self { uid, ics }
|
let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes()));
|
||||||
|
let cal = parser.next().ok_or(anyhow!("no calendar :("))??;
|
||||||
|
if parser.next().is_some() {
|
||||||
|
return Err(anyhow!("multiple calendars!"));
|
||||||
|
}
|
||||||
|
if cal.events.len() == 2 {
|
||||||
|
return Err(anyhow!("multiple events"));
|
||||||
|
}
|
||||||
|
Ok(Self { uid, cal })
|
||||||
}
|
}
|
||||||
pub fn get_uid(&self) -> &str {
|
pub fn get_uid(&self) -> &str {
|
||||||
&self.uid
|
&self.uid
|
||||||
@@ -19,12 +65,12 @@ impl Event {
|
|||||||
pub fn get_etag(&self) -> String {
|
pub fn get_etag(&self) -> String {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(&self.uid);
|
hasher.update(&self.uid);
|
||||||
hasher.update(self.as_ics());
|
hasher.update(self.get_ics());
|
||||||
format!("{:x}", hasher.finalize())
|
format!("{:x}", hasher.finalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ics(&self) -> &str {
|
pub fn get_ics(&self) -> String {
|
||||||
&self.ics
|
self.cal.generate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,8 +84,6 @@ pub struct Calendar {
|
|||||||
pub timezone: Option<String>,
|
pub timezone: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Calendar {}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait CalendarStore: Send + Sync + 'static {
|
pub trait CalendarStore: Send + Sync + 'static {
|
||||||
async fn get_calendar(&self, id: &str) -> Result<Calendar>;
|
async fn get_calendar(&self, id: &str) -> Result<Calendar>;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ impl CalendarStore for TomlCalendarStore {
|
|||||||
|
|
||||||
async fn upsert_event(&mut self, cid: String, uid: String, ics: String) -> Result<()> {
|
async fn upsert_event(&mut self, cid: String, uid: String, ics: String) -> Result<()> {
|
||||||
let events = self.events.entry(cid).or_insert(HashMap::new());
|
let events = self.events.entry(cid).or_insert(HashMap::new());
|
||||||
events.insert(uid.clone(), Event::from_ics(uid, ics));
|
events.insert(uid.clone(), Event::from_ics(uid, ics)?);
|
||||||
self.save().await.unwrap();
|
self.save().await.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user