Added item's creation_date

This commit is contained in:
daladim 2021-04-16 09:05:30 +02:00
parent 092765f769
commit 3bf1fed5b9
5 changed files with 84 additions and 22 deletions

View file

@ -32,6 +32,10 @@ impl Event {
&self.name &self.name
} }
pub fn creation_date(&self) -> Option<&DateTime<Utc>> {
unimplemented!()
}
pub fn last_modified(&self) -> &DateTime<Utc> { pub fn last_modified(&self) -> &DateTime<Utc> {
unimplemented!() unimplemented!()
} }

View file

@ -3,7 +3,7 @@
use std::error::Error; use std::error::Error;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use ics::properties::{Completed, LastModified, Status, Summary}; use ics::properties::{Completed, Created, LastModified, PercentComplete, Status, Summary};
use ics::{ICalendar, ToDo}; use ics::{ICalendar, ToDo};
use crate::item::Item; use crate::item::Item;
@ -21,17 +21,24 @@ pub fn build_from(item: &Item) -> Result<String, Box<dyn Error>> {
item.uid(), item.uid(),
s_last_modified.clone(), s_last_modified.clone(),
); );
item.creation_date().map(|dt|
todo.push(Created::new(format_date_time(dt)))
);
todo.push(LastModified::new(s_last_modified)); todo.push(LastModified::new(s_last_modified));
todo.push(Summary::new(item.name())); todo.push(Summary::new(item.name()));
match item { match item {
Item::Task(t) => { Item::Task(t) => {
t.completion_date().map(|dt| todo.push( if t.completed() {
Completed::new(format_date_time(dt)) todo.push(PercentComplete::new("100"));
)); t.completion_date().map(|dt| todo.push(
Completed::new(format_date_time(dt))
let status = if t.completed() { Status::completed() } else { Status::needs_action() }; ));
todo.push(status); todo.push(Status::completed());
} else {
todo.push(Status::needs_action());
}
}, },
_ => { _ => {
unimplemented!() unimplemented!()
@ -55,29 +62,61 @@ mod tests {
use crate::Task; use crate::Task;
#[test] #[test]
fn test_ical_from_task() { fn test_ical_from_completed_task() {
let cal_id = "http://my.calend.ar/id".parse().unwrap(); let (s_now, uid, ical) = build_task(true);
let now = Utc::now();
let s_now = format_date_time(&now);
let mut task = Item::Task(Task::new(
String::from("This is a task with ÜTF-8 characters"), true, &cal_id
));
task.unwrap_task_mut().set_completed_on(Some(now));
let expected_ical = format!("BEGIN:VCALENDAR\r\n\ let expected_ical = format!("BEGIN:VCALENDAR\r\n\
VERSION:2.0\r\n\ VERSION:2.0\r\n\
PRODID:-//{}//{}//EN\r\n\ PRODID:-//{}//{}//EN\r\n\
BEGIN:VTODO\r\n\ BEGIN:VTODO\r\n\
UID:{}\r\n\ UID:{}\r\n\
DTSTAMP:{}\r\n\ DTSTAMP:{}\r\n\
CREATED:{}\r\n\
LAST-MODIFIED:{}\r\n\
SUMMARY:This is a task with ÜTF-8 characters\r\n\ SUMMARY:This is a task with ÜTF-8 characters\r\n\
PERCENT-COMPLETE:100\r\n\
COMPLETED:{}\r\n\ COMPLETED:{}\r\n\
STATUS:COMPLETED\r\n\ STATUS:COMPLETED\r\n\
END:VTODO\r\n\ END:VTODO\r\n\
END:VCALENDAR\r\n", ORG_NAME, PRODUCT_NAME, task.uid(), s_now, s_now); END:VCALENDAR\r\n", ORG_NAME, PRODUCT_NAME, uid, s_now, s_now, s_now, s_now);
let ical = build_from(&task); assert_eq!(ical, expected_ical);
assert_eq!(ical.unwrap(), expected_ical); }
#[test]
fn test_ical_from_uncompleted_task() {
let (s_now, uid, ical) = build_task(false);
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:{}\r\n\
CREATED:{}\r\n\
LAST-MODIFIED:{}\r\n\
SUMMARY:This is a task with ÜTF-8 characters\r\n\
STATUS:NEEDS-ACTION\r\n\
END:VTODO\r\n\
END:VCALENDAR\r\n", ORG_NAME, PRODUCT_NAME, uid, s_now, s_now, s_now);
assert_eq!(ical, expected_ical);
}
fn build_task(completed: bool) -> (String, String, String) {
let cal_id = "http://my.calend.ar/id".parse().unwrap();
let now = Utc::now();
let s_now = format_date_time(&now);
let mut task = Item::Task(Task::new(
String::from("This is a task with ÜTF-8 characters"), completed, &cal_id
));
if completed {
task.unwrap_task_mut().set_completed_on(Some(now));
}
let ical = build_from(&task).unwrap();
(s_now, task.uid().to_string(), ical)
} }
#[test] #[test]

View file

@ -34,6 +34,7 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
let mut completed = false; let mut completed = false;
let mut last_modified = None; let mut last_modified = None;
let mut completion_date = None; let mut completion_date = None;
let mut creation_date = None;
for prop in &todo.properties { for prop in &todo.properties {
if prop.name == "SUMMARY" { if prop.name == "SUMMARY" {
name = prop.value.clone(); name = prop.value.clone();
@ -61,6 +62,10 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
// the calendar component was last revised in the calendar store. // the calendar component was last revised in the calendar store.
completion_date = parse_date_time_from_property(&prop.value) completion_date = parse_date_time_from_property(&prop.value)
} }
if prop.name == "CREATED" {
// The property can be specified once, but is not mandatory
creation_date = parse_date_time_from_property(&prop.value)
}
} }
let name = match name { let name = match name {
Some(name) => name, Some(name) => name,
@ -80,7 +85,7 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
log::warn!("Inconsistant iCal data: completion date is {:?} but completion status is {:?}", completion_date, completed); log::warn!("Inconsistant iCal data: completion date is {:?} but completion status is {:?}", completion_date, completed);
} }
Item::Task(Task::new_with_parameters(name, uid, item_id, sync_status, last_modified, completion_date)) Item::Task(Task::new_with_parameters(name, uid, item_id, sync_status, creation_date, last_modified, completion_date))
}, },
}; };

View file

@ -40,6 +40,13 @@ impl Item {
} }
} }
pub fn creation_date(&self) -> Option<&DateTime<Utc>> {
match self {
Item::Event(e) => e.creation_date(),
Item::Task(t) => t.creation_date(),
}
}
pub fn last_modified(&self) -> &DateTime<Utc> { pub fn last_modified(&self) -> &DateTime<Utc> {
match self { match self {
Item::Event(e) => e.last_modified(), Item::Event(e) => e.last_modified(),

View file

@ -18,6 +18,9 @@ pub struct Task {
/// The sync status of this item /// The sync status of this item
sync_status: SyncStatus, sync_status: SyncStatus,
/// The time this item was created.
/// This is not required by RFC5545. This will be populated in tasks created by this crate, but can be None for tasks coming from a server
creation_date: Option<DateTime<Utc>>,
/// The last time this item was modified /// The last time this item was modified
last_modified: DateTime<Utc>, last_modified: DateTime<Utc>,
@ -34,20 +37,23 @@ impl Task {
let new_item_id = ItemId::random(parent_calendar_id); let new_item_id = ItemId::random(parent_calendar_id);
let new_sync_status = SyncStatus::NotSynced; let new_sync_status = SyncStatus::NotSynced;
let new_uid = Uuid::new_v4().to_hyphenated().to_string(); let new_uid = Uuid::new_v4().to_hyphenated().to_string();
let new_creation_date = Some(Utc::now());
let new_last_modified = Utc::now(); let new_last_modified = Utc::now();
let new_completion_date = if completed { Some(Utc::now()) } else { None }; let new_completion_date = if completed { Some(Utc::now()) } else { None };
Self::new_with_parameters(name, new_uid, new_item_id, new_sync_status, new_last_modified, new_completion_date) Self::new_with_parameters(name, new_uid, new_item_id, new_sync_status, new_creation_date, new_last_modified, new_completion_date)
} }
/// Create a new Task instance, that may be synced already /// Create a new Task instance, that may be synced already
pub fn new_with_parameters(name: String, uid: String, id: ItemId, pub fn new_with_parameters(name: String, uid: String, id: ItemId,
sync_status: SyncStatus, last_modified: DateTime<Utc>, completion_date: Option<DateTime<Utc>>) -> Self { sync_status: SyncStatus, creation_date: Option<DateTime<Utc>>, last_modified: DateTime<Utc>, completion_date: Option<DateTime<Utc>>) -> Self
{
Self { Self {
id, id,
uid, uid,
name, name,
sync_status, sync_status,
completion_date, completion_date,
creation_date,
last_modified, last_modified,
} }
} }
@ -56,8 +62,9 @@ impl Task {
pub fn uid(&self) -> &str { &self.uid } pub fn uid(&self) -> &str { &self.uid }
pub fn name(&self) -> &str { &self.name } pub fn name(&self) -> &str { &self.name }
pub fn completed(&self) -> bool { self.completion_date.is_some() } pub fn completed(&self) -> bool { self.completion_date.is_some() }
pub fn sync_status(&self) -> &SyncStatus { &self.sync_status } pub fn sync_status(&self) -> &SyncStatus { &self.sync_status }
pub fn last_modified(&self) -> &DateTime<Utc> { &self.last_modified } pub fn last_modified(&self) -> &DateTime<Utc> { &self.last_modified }
pub fn creation_date(&self) -> Option<&DateTime<Utc>> { self.creation_date.as_ref() }
pub fn completion_date(&self) -> Option<&DateTime<Utc>> { self.completion_date.as_ref() } pub fn completion_date(&self) -> Option<&DateTime<Utc>> { self.completion_date.as_ref() }
pub fn has_same_observable_content_as(&self, other: &Task) -> bool { pub fn has_same_observable_content_as(&self, other: &Task) -> bool {