Items include a last modified (DTSTAMP) date

This commit is contained in:
daladim 2021-04-14 21:19:32 +02:00
parent e24fab2ccb
commit 8e35f4c579
7 changed files with 119 additions and 12 deletions

View file

@ -2,7 +2,8 @@
use std::error::Error;
use ics::properties::{Comment, Status, Summary};
use chrono::{DateTime, Utc};
use ics::properties::{LastModified, Status, Summary};
use ics::{ICalendar, ToDo};
use crate::item::Item;
@ -14,9 +15,14 @@ fn ical_product_id() -> String {
/// Create an iCal item from a `crate::item::Item`
pub fn build_from(item: &Item) -> Result<String, Box<dyn Error>> {
let mut todo = ToDo::new(item.uid(), "20181021T190000");
todo.push(Summary::new("Take pictures of squirrels (with ÜTF-8 chars)"));
todo.push(Comment::new("That's really something I'd like to do one day"));
let s_last_modified = format_date_time(item.last_modified());
let mut todo = ToDo::new(
item.uid(),
s_last_modified.clone(),
);
todo.push(LastModified::new(s_last_modified));
todo.push(Summary::new(item.name()));
match item {
Item::Task(t) => {
@ -34,6 +40,9 @@ pub fn build_from(item: &Item) -> Result<String, Box<dyn Error>> {
Ok(calendar.to_string())
}
fn format_date_time(dt: &DateTime<Utc>) -> String {
dt.format("%Y%m%dT%H%M%S").to_string()
}
#[cfg(test)]
@ -44,20 +53,21 @@ mod tests {
#[test]
fn test_ical_from_task() {
let cal_id = "http://my.calend.ar/id".parse().unwrap();
let now = format_date_time(&Utc::now());
let task = Item::Task(Task::new(
String::from("This is a task"), true, &cal_id
String::from("This is a task with ÜTF-8 characters"), true, &cal_id
));
let expected_ical = format!("BEGIN:VCALENDAR\r\n\
VERSION:2.0\r\n\
PRODID:-//{}//{}//EN\r\n\
BEGIN:VTODO\r\n\
UID:{}\r\n\
DTSTAMP:20181021T190000\r\n\
SUMMARY:Take pictures of squirrels (with ÜTF-8 chars)\r\n\
COMMENT:That's really something I'd like to do one day\r\n\
DTSTAMP:{}\r\n\
SUMMARY:This is a task with ÜTF-8 characters\r\n\
STATUS:COMPLETED\r\n\
END:VTODO\r\n\
END:VCALENDAR\r\n", ORG_NAME, PRODUCT_NAME, task.uid());
END:VCALENDAR\r\n", ORG_NAME, PRODUCT_NAME, task.uid(), now);
let ical = build_from(&task);
assert_eq!(ical.unwrap(), expected_ical);

View file

@ -3,6 +3,7 @@
use std::error::Error;
use ical::parser::ical::component::{IcalCalendar, IcalEvent, IcalTodo};
use chrono::{DateTime, TimeZone, Utc};
use crate::Item;
use crate::item::SyncStatus;
@ -31,6 +32,7 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
let mut name = None;
let mut uid = None;
let mut completed = false;
let mut last_modified = None;
for prop in &todo.properties {
if prop.name == "SUMMARY" {
name = prop.value.clone();
@ -48,6 +50,19 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
if prop.name == "UID" {
uid = prop.value.clone();
}
if prop.name == "DTSTAMP" {
// this property specifies the date and time that the information associated with
// the calendar component was last revised in the calendar store.
last_modified = prop.value.as_ref()
.and_then(|s| {
parse_date_time(s)
.map_err(|err| {
log::warn!("Invalid DTSTAMP: {}", s);
err
})
.ok()
})
}
}
let name = match name {
Some(name) => name,
@ -57,8 +72,12 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
Some(uid) => uid,
None => return Err(format!("Missing UID for item {}", item_id).into()),
};
let last_modified = match last_modified {
Some(dt) => dt,
None => return Err(format!("Missing DTSTAMP for item {}, but this is required by RFC5545", item_id).into()),
};
Item::Task(Task::new_with_parameters(name, completed, uid, item_id, sync_status))
Item::Task(Task::new_with_parameters(name, completed, uid, item_id, sync_status, last_modified))
},
};
@ -71,6 +90,12 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
Ok(item)
}
fn parse_date_time(dt: &str) -> Result<DateTime<Utc>, chrono::format::ParseError> {
Utc.datetime_from_str(dt, "%Y%m%dT%H%M%S")
}
enum CurrentType<'a> {
Event(&'a IcalEvent),
Todo(&'a IcalTodo),
@ -171,6 +196,7 @@ END:VCALENDAR
assert_eq!(task.uid(), "0633de27-8c32-42be-bcb8-63bc879c6185@some-domain.com");
assert_eq!(task.completed(), false);
assert_eq!(task.sync_status(), &sync_status);
assert_eq!(task.last_modified(), &Utc.ymd(2021, 03, 21).and_hms(0, 16, 0));
}
#[test]