From 39867a9f150324d30e2a4020fbba88de22944010 Mon Sep 17 00:00:00 2001 From: daladim Date: Fri, 5 Nov 2021 23:31:17 +0100 Subject: [PATCH] PRODID is parsed, stored and generated --- src/event.rs | 4 ++++ src/ical/builder.rs | 7 ++----- src/ical/mod.rs | 7 +++++++ src/ical/parser.rs | 16 +++++++++++++++- src/item.rs | 1 + src/task.rs | 11 +++++++++-- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/event.rs b/src/event.rs index 621091d..c2149ca 100644 --- a/src/event.rs +++ b/src/event.rs @@ -32,6 +32,10 @@ impl Event { &self.name } + pub fn ical_prod_id(&self) -> &str { + unimplemented!() + } + pub fn creation_date(&self) -> Option<&DateTime> { unimplemented!() } diff --git a/src/ical/builder.rs b/src/ical/builder.rs index 182e6c9..0b3b99c 100644 --- a/src/ical/builder.rs +++ b/src/ical/builder.rs @@ -12,11 +12,7 @@ use ical::property::Property as IcalProperty; use crate::Task; use crate::item::Item; use crate::task::CompletionStatus; -use crate::settings::{ORG_NAME, PRODUCT_NAME}; -fn ical_product_id() -> String { - format!("-//{}//{}//EN", ORG_NAME, PRODUCT_NAME) -} /// Create an iCal item from a `crate::item::Item` pub fn build_from(item: &Item) -> Result> { @@ -59,7 +55,7 @@ pub fn build_from_task(task: &Task) -> Result> { todo.push(ics_property); } - let mut calendar = ICalendar::new("2.0", ical_product_id()); + let mut calendar = ICalendar::new("2.0", task.ical_prod_id()); calendar.add_todo(todo); Ok(calendar.to_string()) @@ -89,6 +85,7 @@ fn ical_to_ics_property(prop: IcalProperty) -> IcsProperty<'static> { mod tests { use super::*; use crate::Task; + use crate::settings::{ORG_NAME, PRODUCT_NAME}; #[test] fn test_ical_from_completed_task() { diff --git a/src/ical/mod.rs b/src/ical/mod.rs index b8a520e..a454ae1 100644 --- a/src/ical/mod.rs +++ b/src/ical/mod.rs @@ -6,3 +6,10 @@ mod parser; pub use parser::parse; mod builder; pub use builder::build_from; + +use crate::settings::{ORG_NAME, PRODUCT_NAME}; + +pub fn default_prod_id() -> String { + format!("-//{}//{}//EN", ORG_NAME, PRODUCT_NAME) +} + diff --git a/src/ical/parser.rs b/src/ical/parser.rs index 4a683af..8be5da5 100644 --- a/src/ical/parser.rs +++ b/src/ical/parser.rs @@ -24,6 +24,10 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result< } }; + let ical_prod_id = extract_ical_prod_id(&parsed_item) + .map(|s| s.to_string()) + .unwrap_or_else(|| super::default_prod_id()); + let item = match assert_single_type(&parsed_item)? { CurrentType::Event(_) => { Item::Event(Event::new()) @@ -96,7 +100,7 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result< true => CompletionStatus::Completed(completion_date), }; - Item::Task(Task::new_with_parameters(name, uid, item_id, completion_status, sync_status, creation_date, last_modified, extra_parameters)) + Item::Task(Task::new_with_parameters(name, uid, item_id, completion_status, sync_status, creation_date, last_modified, ical_prod_id, extra_parameters)) }, }; @@ -126,6 +130,16 @@ fn parse_date_time_from_property(value: &Option) -> Option } +fn extract_ical_prod_id(item: &IcalCalendar) -> Option<&str> { + for prop in &item.properties { + if &prop.name == "PRODID" { + return prop.value.as_ref().map(|s| s.as_str()) + } + } + None +} + + enum CurrentType<'a> { Event(&'a IcalEvent), Todo(&'a IcalTodo), diff --git a/src/item.rs b/src/item.rs index 8466232..c2aaa53 100644 --- a/src/item.rs +++ b/src/item.rs @@ -38,6 +38,7 @@ impl Item { synthetise_common_getter!(creation_date, Option<&DateTime>); synthetise_common_getter!(last_modified, &DateTime); synthetise_common_getter!(sync_status, &SyncStatus); + synthetise_common_getter!(ical_prod_id, &str); pub fn set_sync_status(&mut self, new_status: SyncStatus) { match self { diff --git a/src/task.rs b/src/task.rs index e7f0568..91e180a 100644 --- a/src/task.rs +++ b/src/task.rs @@ -52,6 +52,10 @@ pub struct Task { /// The display name of the task name: String, + + /// The PRODID, as defined in iCal files + ical_prod_id: String, + /// Extra parameters that have not been parsed from the iCal file (because they're not supported (yet) by this crate). /// They are needed to serialize this item into an equivalent iCal file extra_parameters: Vec, @@ -70,15 +74,16 @@ impl Task { let new_completion_status = if completed { CompletionStatus::Completed(Some(Utc::now())) } else { CompletionStatus::Uncompleted }; + let ical_prod_id = crate::ical::default_prod_id(); let extra_parameters = Vec::new(); - Self::new_with_parameters(name, new_uid, new_item_id, new_completion_status, new_sync_status, new_creation_date, new_last_modified, extra_parameters) + Self::new_with_parameters(name, new_uid, new_item_id, new_completion_status, new_sync_status, new_creation_date, new_last_modified, ical_prod_id, extra_parameters) } /// Create a new Task instance, that may be synced on the server already pub fn new_with_parameters(name: String, uid: String, id: ItemId, completion_status: CompletionStatus, sync_status: SyncStatus, creation_date: Option>, last_modified: DateTime, - extra_parameters: Vec, + ical_prod_id: String, extra_parameters: Vec, ) -> Self { Self { @@ -89,6 +94,7 @@ impl Task { sync_status, creation_date, last_modified, + ical_prod_id, extra_parameters, } } @@ -97,6 +103,7 @@ impl Task { pub fn uid(&self) -> &str { &self.uid } pub fn name(&self) -> &str { &self.name } pub fn completed(&self) -> bool { self.completion_status.is_completed() } + pub fn ical_prod_id(&self) -> &str { &self.ical_prod_id } pub fn sync_status(&self) -> &SyncStatus { &self.sync_status } pub fn last_modified(&self) -> &DateTime { &self.last_modified } pub fn creation_date(&self) -> Option<&DateTime> { self.creation_date.as_ref() }