Better API to reflect optional yet related fields in an iCal item
This commit is contained in:
parent
3bf1fed5b9
commit
4f68296f93
5 changed files with 135 additions and 45 deletions
|
@ -7,6 +7,7 @@ use ics::properties::{Completed, Created, LastModified, PercentComplete, Status,
|
||||||
use ics::{ICalendar, ToDo};
|
use ics::{ICalendar, ToDo};
|
||||||
|
|
||||||
use crate::item::Item;
|
use crate::item::Item;
|
||||||
|
use crate::task::CompletionStatus;
|
||||||
use crate::settings::{ORG_NAME, PRODUCT_NAME};
|
use crate::settings::{ORG_NAME, PRODUCT_NAME};
|
||||||
|
|
||||||
fn ical_product_id() -> String {
|
fn ical_product_id() -> String {
|
||||||
|
@ -30,14 +31,17 @@ pub fn build_from(item: &Item) -> Result<String, Box<dyn Error>> {
|
||||||
|
|
||||||
match item {
|
match item {
|
||||||
Item::Task(t) => {
|
Item::Task(t) => {
|
||||||
if t.completed() {
|
match t.completion_status() {
|
||||||
todo.push(PercentComplete::new("100"));
|
CompletionStatus::Uncompleted => {
|
||||||
t.completion_date().map(|dt| todo.push(
|
todo.push(Status::needs_action());
|
||||||
Completed::new(format_date_time(dt))
|
},
|
||||||
));
|
CompletionStatus::Completed(completion_date) => {
|
||||||
todo.push(Status::completed());
|
todo.push(PercentComplete::new("100"));
|
||||||
} else {
|
completion_date.as_ref().map(|dt| todo.push(
|
||||||
todo.push(Status::needs_action());
|
Completed::new(format_date_time(dt))
|
||||||
|
));
|
||||||
|
todo.push(Status::completed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -108,12 +112,9 @@ mod tests {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let s_now = format_date_time(&now);
|
let s_now = format_date_time(&now);
|
||||||
|
|
||||||
let mut task = Item::Task(Task::new(
|
let task = Item::Task(Task::new(
|
||||||
String::from("This is a task with ÜTF-8 characters"), completed, &cal_id
|
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();
|
let ical = build_from(&task).unwrap();
|
||||||
(s_now, task.uid().to_string(), ical)
|
(s_now, task.uid().to_string(), ical)
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::Item;
|
||||||
use crate::item::SyncStatus;
|
use crate::item::SyncStatus;
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
use crate::Task;
|
use crate::Task;
|
||||||
|
use crate::task::CompletionStatus;
|
||||||
use crate::Event;
|
use crate::Event;
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,13 +54,15 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
|
||||||
uid = prop.value.clone();
|
uid = prop.value.clone();
|
||||||
}
|
}
|
||||||
if prop.name == "DTSTAMP" {
|
if prop.name == "DTSTAMP" {
|
||||||
// this property specifies the date and time that the information associated with
|
// The property can be specified once, but is not mandatory
|
||||||
// the calendar component was last revised in the calendar store.
|
// "This property specifies the date and time that the information associated with
|
||||||
|
// the calendar component was last revised in the calendar store."
|
||||||
last_modified = parse_date_time_from_property(&prop.value)
|
last_modified = parse_date_time_from_property(&prop.value)
|
||||||
}
|
}
|
||||||
if prop.name == "COMPLETED" {
|
if prop.name == "COMPLETED" {
|
||||||
// this property specifies the date and time that the information associated with
|
// The property can be specified once, but is not mandatory
|
||||||
// the calendar component was last revised in the calendar store.
|
// "This property defines the date and time that a to-do was
|
||||||
|
// actually completed."
|
||||||
completion_date = parse_date_time_from_property(&prop.value)
|
completion_date = parse_date_time_from_property(&prop.value)
|
||||||
}
|
}
|
||||||
if prop.name == "CREATED" {
|
if prop.name == "CREATED" {
|
||||||
|
@ -79,13 +82,17 @@ pub fn parse(content: &str, item_id: ItemId, sync_status: SyncStatus) -> Result<
|
||||||
Some(dt) => dt,
|
Some(dt) => dt,
|
||||||
None => return Err(format!("Missing DTSTAMP for item {}, but this is required by RFC5545", item_id).into()),
|
None => return Err(format!("Missing DTSTAMP for item {}, but this is required by RFC5545", item_id).into()),
|
||||||
};
|
};
|
||||||
if completion_date.is_none() && completed ||
|
let completion_status = match completed {
|
||||||
completion_date.is_some() && !completed
|
false => {
|
||||||
{
|
if completion_date.is_some() {
|
||||||
log::warn!("Inconsistant iCal data: completion date is {:?} but completion status is {:?}", completion_date, completed);
|
log::warn!("Task {:?} has an inconsistent content: its STATUS is not completed, yet it has a COMPLETED timestamp at {:?}", uid, completion_date);
|
||||||
}
|
}
|
||||||
|
CompletionStatus::Uncompleted
|
||||||
|
},
|
||||||
|
true => CompletionStatus::Completed(completion_date),
|
||||||
|
};
|
||||||
|
|
||||||
Item::Task(Task::new_with_parameters(name, uid, item_id, sync_status, creation_date, last_modified, completion_date))
|
Item::Task(Task::new_with_parameters(name, uid, item_id, completion_status, sync_status, creation_date, last_modified))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,7 +167,7 @@ END:VTODO
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
const EXAMPLE_ICAL_COMPLETED: &str = r#"BEGIN:VCALENDAR
|
const EXAMPLE_ICAL_COMPLETED: &str = r#"BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
PRODID:-//Nextcloud Tasks v0.13.6
|
PRODID:-//Nextcloud Tasks v0.13.6
|
||||||
BEGIN:VTODO
|
BEGIN:VTODO
|
||||||
|
@ -174,6 +181,20 @@ COMPLETED:20210402T081557
|
||||||
STATUS:COMPLETED
|
STATUS:COMPLETED
|
||||||
END:VTODO
|
END:VTODO
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
|
"#;
|
||||||
|
|
||||||
|
const EXAMPLE_ICAL_COMPLETED_WITHOUT_A_COMPLETION_DATE: &str = r#"BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
PRODID:-//Nextcloud Tasks v0.13.6
|
||||||
|
BEGIN:VTODO
|
||||||
|
UID:19960401T080045Z-4000F192713-0052@example.com
|
||||||
|
CREATED:20210321T001600
|
||||||
|
LAST-MODIFIED:20210402T081557
|
||||||
|
DTSTAMP:20210402T081557
|
||||||
|
SUMMARY:Clean up your room or Mom will be angry
|
||||||
|
STATUS:COMPLETED
|
||||||
|
END:VTODO
|
||||||
|
END:VCALENDAR
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
const EXAMPLE_MULTIPLE_ICAL: &str = r#"BEGIN:VCALENDAR
|
const EXAMPLE_MULTIPLE_ICAL: &str = r#"BEGIN:VCALENDAR
|
||||||
|
@ -214,12 +235,13 @@ END:VCALENDAR
|
||||||
assert_eq!(task.id(), &item_id);
|
assert_eq!(task.id(), &item_id);
|
||||||
assert_eq!(task.uid(), "0633de27-8c32-42be-bcb8-63bc879c6185@some-domain.com");
|
assert_eq!(task.uid(), "0633de27-8c32-42be-bcb8-63bc879c6185@some-domain.com");
|
||||||
assert_eq!(task.completed(), false);
|
assert_eq!(task.completed(), false);
|
||||||
|
assert_eq!(task.completion_status(), &CompletionStatus::Uncompleted);
|
||||||
assert_eq!(task.sync_status(), &sync_status);
|
assert_eq!(task.sync_status(), &sync_status);
|
||||||
assert_eq!(task.last_modified(), &Utc.ymd(2021, 03, 21).and_hms(0, 16, 0));
|
assert_eq!(task.last_modified(), &Utc.ymd(2021, 03, 21).and_hms(0, 16, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ical_completion_parsing() {
|
fn test_completed_ical_parsing() {
|
||||||
let version_tag = VersionTag::from(String::from("test-tag"));
|
let version_tag = VersionTag::from(String::from("test-tag"));
|
||||||
let sync_status = SyncStatus::Synced(version_tag);
|
let sync_status = SyncStatus::Synced(version_tag);
|
||||||
let item_id: ItemId = "http://some.id/for/testing".parse().unwrap();
|
let item_id: ItemId = "http://some.id/for/testing".parse().unwrap();
|
||||||
|
@ -228,6 +250,20 @@ END:VCALENDAR
|
||||||
let task = item.unwrap_task();
|
let task = item.unwrap_task();
|
||||||
|
|
||||||
assert_eq!(task.completed(), true);
|
assert_eq!(task.completed(), true);
|
||||||
|
assert_eq!(task.completion_status(), &CompletionStatus::Completed(Some(Utc.ymd(2021, 04, 02).and_hms(8, 15, 57))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_completed_without_date_ical_parsing() {
|
||||||
|
let version_tag = VersionTag::from(String::from("test-tag"));
|
||||||
|
let sync_status = SyncStatus::Synced(version_tag);
|
||||||
|
let item_id: ItemId = "http://some.id/for/testing".parse().unwrap();
|
||||||
|
|
||||||
|
let item = parse(EXAMPLE_ICAL_COMPLETED_WITHOUT_A_COMPLETION_DATE, item_id.clone(), sync_status.clone()).unwrap();
|
||||||
|
let task = item.unwrap_task();
|
||||||
|
|
||||||
|
assert_eq!(task.completed(), true);
|
||||||
|
assert_eq!(task.completion_status(), &CompletionStatus::Completed(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub use item::Item;
|
||||||
pub use item::ItemId;
|
pub use item::ItemId;
|
||||||
pub use item::VersionTag;
|
pub use item::VersionTag;
|
||||||
pub use item::SyncStatus;
|
pub use item::SyncStatus;
|
||||||
mod task;
|
pub mod task;
|
||||||
pub use task::Task;
|
pub use task::Task;
|
||||||
mod event;
|
mod event;
|
||||||
pub use event::Event;
|
pub use event::Event;
|
||||||
|
|
53
src/task.rs
53
src/task.rs
|
@ -6,6 +6,26 @@ use crate::item::ItemId;
|
||||||
use crate::item::SyncStatus;
|
use crate::item::SyncStatus;
|
||||||
use crate::calendar::CalendarId;
|
use crate::calendar::CalendarId;
|
||||||
|
|
||||||
|
/// RFC5545 defines the completion as several optional fields, yet some combinations make no sense.
|
||||||
|
/// This enum provides an API that forbids such impossible combinations.
|
||||||
|
///
|
||||||
|
/// * `COMPLETED` is an optional timestamp that tells whether this task is completed
|
||||||
|
/// * `STATUS` is an optional field, that can be set to `NEEDS-ACTION`, `COMPLETED`, or others.
|
||||||
|
/// Even though having a `COMPLETED` date but a `STATUS:NEEDS-ACTION` is theorically possible, it obviously makes no sense. This API ensures this cannot happen
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum CompletionStatus {
|
||||||
|
Completed(Option<DateTime<Utc>>),
|
||||||
|
Uncompleted,
|
||||||
|
}
|
||||||
|
impl CompletionStatus {
|
||||||
|
pub fn is_completed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
CompletionStatus::Completed(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A to-do task
|
/// A to-do task
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
|
@ -23,13 +43,15 @@ pub struct Task {
|
||||||
creation_date: Option<DateTime<Utc>>,
|
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>,
|
||||||
|
/// The completion status of this task
|
||||||
|
completion_status: CompletionStatus,
|
||||||
|
|
||||||
/// The display name of the task
|
/// The display name of the task
|
||||||
name: String,
|
name: String,
|
||||||
/// The time it was completed. Set to None if this task has not been completed
|
|
||||||
completion_date: Option<DateTime<Utc>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
/// Create a brand new Task that is not on a server yet.
|
/// Create a brand new Task that is not on a server yet.
|
||||||
/// This will pick a new (random) task ID.
|
/// This will pick a new (random) task ID.
|
||||||
|
@ -39,20 +61,23 @@ impl Task {
|
||||||
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_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_status = if completed {
|
||||||
Self::new_with_parameters(name, new_uid, new_item_id, new_sync_status, new_creation_date, new_last_modified, new_completion_date)
|
CompletionStatus::Completed(Some(Utc::now()))
|
||||||
|
} else { CompletionStatus::Uncompleted };
|
||||||
|
Self::new_with_parameters(name, new_uid, new_item_id, new_completion_status, new_sync_status, new_creation_date, new_last_modified)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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, creation_date: Option<DateTime<Utc>>, last_modified: DateTime<Utc>, completion_date: Option<DateTime<Utc>>) -> Self
|
completion_status: CompletionStatus,
|
||||||
|
sync_status: SyncStatus, creation_date: Option<DateTime<Utc>>, last_modified: DateTime<Utc>) -> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
uid,
|
uid,
|
||||||
name,
|
name,
|
||||||
|
completion_status,
|
||||||
sync_status,
|
sync_status,
|
||||||
completion_date,
|
|
||||||
creation_date,
|
creation_date,
|
||||||
last_modified,
|
last_modified,
|
||||||
}
|
}
|
||||||
|
@ -61,16 +86,16 @@ impl Task {
|
||||||
pub fn id(&self) -> &ItemId { &self.id }
|
pub fn id(&self) -> &ItemId { &self.id }
|
||||||
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_status.is_completed() }
|
||||||
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 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_status(&self) -> &CompletionStatus { &self.completion_status }
|
||||||
|
|
||||||
pub fn has_same_observable_content_as(&self, other: &Task) -> bool {
|
pub fn has_same_observable_content_as(&self, other: &Task) -> bool {
|
||||||
self.id == other.id
|
self.id == other.id
|
||||||
&& self.name == other.name
|
&& self.name == other.name
|
||||||
&& self.completion_date == other.completion_date
|
&& self.completion_status == other.completion_status
|
||||||
&& self.last_modified == other.last_modified
|
&& self.last_modified == other.last_modified
|
||||||
// sync status must be the same variant, but we ignore its embedded version tag
|
// sync status must be the same variant, but we ignore its embedded version tag
|
||||||
&& std::mem::discriminant(&self.sync_status) == std::mem::discriminant(&other.sync_status)
|
&& std::mem::discriminant(&self.sync_status) == std::mem::discriminant(&other.sync_status)
|
||||||
|
@ -113,16 +138,16 @@ impl Task {
|
||||||
self.name = new_name;
|
self.name = new_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the completion date (or pass None to un-complete the task)
|
/// Set the completion status
|
||||||
pub fn set_completed_on(&mut self, new_completion_date: Option<DateTime<Utc>>) {
|
pub fn set_completion_status(&mut self, new_completion_status: CompletionStatus) {
|
||||||
self.update_sync_status();
|
self.update_sync_status();
|
||||||
self.update_last_modified();
|
self.update_last_modified();
|
||||||
self.completion_date = new_completion_date;
|
self.completion_status = new_completion_status;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
/// Set the completion status, but forces a "master" SyncStatus, just like CalDAV servers are always "masters"
|
/// Set the completion status, but forces a "master" SyncStatus, just like CalDAV servers are always "masters"
|
||||||
pub fn mock_remote_calendar_set_completed_on(&mut self, nnew_completion_date: Option<DateTime<Utc>>) {
|
pub fn mock_remote_calendar_set_completion_status(&mut self, new_completion_status: CompletionStatus) {
|
||||||
self.sync_status = SyncStatus::random_synced();
|
self.sync_status = SyncStatus::random_synced();
|
||||||
self.completion_date = new_completion_date;
|
self.completion_status = new_completion_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
use my_tasks::calendar::CalendarId;
|
use my_tasks::calendar::CalendarId;
|
||||||
use my_tasks::calendar::SupportedComponents;
|
use my_tasks::calendar::SupportedComponents;
|
||||||
use my_tasks::traits::CalDavSource;
|
use my_tasks::traits::CalDavSource;
|
||||||
|
@ -23,6 +25,7 @@ use my_tasks::Item;
|
||||||
use my_tasks::ItemId;
|
use my_tasks::ItemId;
|
||||||
use my_tasks::SyncStatus;
|
use my_tasks::SyncStatus;
|
||||||
use my_tasks::Task;
|
use my_tasks::Task;
|
||||||
|
use my_tasks::task::CompletionStatus;
|
||||||
use my_tasks::calendar::cached_calendar::CachedCalendar;
|
use my_tasks::calendar::cached_calendar::CachedCalendar;
|
||||||
use my_tasks::Provider;
|
use my_tasks::Provider;
|
||||||
use my_tasks::mock_behaviour::MockBehaviour;
|
use my_tasks::mock_behaviour::MockBehaviour;
|
||||||
|
@ -373,7 +376,11 @@ pub fn scenarii_basic() -> Vec<ItemScenario> {
|
||||||
initial_state: LocatedState::None,
|
initial_state: LocatedState::None,
|
||||||
local_changes_to_apply: Vec::new(),
|
local_changes_to_apply: Vec::new(),
|
||||||
remote_changes_to_apply: vec![ChangeToApply::Create(third_cal.clone(), Item::Task(
|
remote_changes_to_apply: vec![ChangeToApply::Create(third_cal.clone(), Item::Task(
|
||||||
Task::new_with_parameters(String::from("Task Q, created on the server"), false, id_q, SyncStatus::random_synced() )
|
Task::new_with_parameters(
|
||||||
|
String::from("Task Q, created on the server"),
|
||||||
|
id_q.to_string(), id_q,
|
||||||
|
CompletionStatus::Uncompleted,
|
||||||
|
SyncStatus::random_synced(), Some(Utc::now()), Utc::now() )
|
||||||
))],
|
))],
|
||||||
after_sync: LocatedState::BothSynced( ItemState{
|
after_sync: LocatedState::BothSynced( ItemState{
|
||||||
calendar: third_cal.clone(),
|
calendar: third_cal.clone(),
|
||||||
|
@ -389,7 +396,11 @@ pub fn scenarii_basic() -> Vec<ItemScenario> {
|
||||||
id: id_r.clone(),
|
id: id_r.clone(),
|
||||||
initial_state: LocatedState::None,
|
initial_state: LocatedState::None,
|
||||||
local_changes_to_apply: vec![ChangeToApply::Create(third_cal.clone(), Item::Task(
|
local_changes_to_apply: vec![ChangeToApply::Create(third_cal.clone(), Item::Task(
|
||||||
Task::new_with_parameters(String::from("Task R, created locally"), false, id_r, SyncStatus::NotSynced )
|
Task::new_with_parameters(
|
||||||
|
String::from("Task R, created locally"),
|
||||||
|
id_r.to_string(), id_r,
|
||||||
|
CompletionStatus::Uncompleted,
|
||||||
|
SyncStatus::NotSynced, Some(Utc::now()), Utc::now() )
|
||||||
))],
|
))],
|
||||||
remote_changes_to_apply: Vec::new(),
|
remote_changes_to_apply: Vec::new(),
|
||||||
after_sync: LocatedState::BothSynced( ItemState{
|
after_sync: LocatedState::BothSynced( ItemState{
|
||||||
|
@ -563,7 +574,11 @@ pub fn scenarii_transient_task() -> Vec<ItemScenario> {
|
||||||
initial_state: LocatedState::None,
|
initial_state: LocatedState::None,
|
||||||
local_changes_to_apply: vec![
|
local_changes_to_apply: vec![
|
||||||
ChangeToApply::Create(cal, Item::Task(
|
ChangeToApply::Create(cal, Item::Task(
|
||||||
Task::new_with_parameters(String::from("A transient task that will be deleted before the sync"), false, id_transient, SyncStatus::NotSynced )
|
Task::new_with_parameters(
|
||||||
|
String::from("A transient task that will be deleted before the sync"),
|
||||||
|
id_transient.to_string(), id_transient,
|
||||||
|
CompletionStatus::Uncompleted,
|
||||||
|
SyncStatus::NotSynced, Some(Utc::now()), Utc::now() )
|
||||||
)),
|
)),
|
||||||
|
|
||||||
ChangeToApply::Rename(String::from("A new name")),
|
ChangeToApply::Rename(String::from("A new name")),
|
||||||
|
@ -612,12 +627,21 @@ async fn populate_test_provider(scenarii: &[ItemScenario], mock_behaviour: Arc<M
|
||||||
LocatedState::BothSynced(s) => (s, SyncStatus::random_synced()),
|
LocatedState::BothSynced(s) => (s, SyncStatus::random_synced()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let now = Utc::now();
|
||||||
|
let completion_status = match state.completed {
|
||||||
|
false => CompletionStatus::Uncompleted,
|
||||||
|
true => CompletionStatus::Completed(Some(now)),
|
||||||
|
};
|
||||||
|
|
||||||
let new_item = Item::Task(
|
let new_item = Item::Task(
|
||||||
Task::new_with_parameters(
|
Task::new_with_parameters(
|
||||||
state.name.clone(),
|
state.name.clone(),
|
||||||
state.completed,
|
item.id.to_string(),
|
||||||
item.id.clone(),
|
item.id.clone(),
|
||||||
|
completion_status,
|
||||||
sync_status,
|
sync_status,
|
||||||
|
Some(now),
|
||||||
|
now,
|
||||||
));
|
));
|
||||||
|
|
||||||
match required_state {
|
match required_state {
|
||||||
|
@ -713,10 +737,14 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChangeToApply::SetCompletion(new_status) => {
|
ChangeToApply::SetCompletion(new_status) => {
|
||||||
|
let completion_status = match new_status {
|
||||||
|
false => CompletionStatus::Uncompleted,
|
||||||
|
true => CompletionStatus::Completed(Some(Utc::now())),
|
||||||
|
};
|
||||||
if is_remote {
|
if is_remote {
|
||||||
task.mock_remote_calendar_set_completed(new_status.clone());
|
task.mock_remote_calendar_set_completion_status(completion_status);
|
||||||
} else {
|
} else {
|
||||||
task.set_completed(new_status.clone());
|
task.set_completion_status(completion_status);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChangeToApply::Remove => {
|
ChangeToApply::Remove => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue