Trait is closer to what caldav servers provide
This commit is contained in:
parent
7af147e417
commit
86f3566532
11 changed files with 122 additions and 94 deletions
11
src/cache.rs
11
src/cache.rs
|
@ -14,7 +14,6 @@ use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use crate::traits::CalDavSource;
|
use crate::traits::CalDavSource;
|
||||||
use crate::traits::SyncSlave;
|
|
||||||
use crate::traits::PartialCalendar;
|
use crate::traits::PartialCalendar;
|
||||||
use crate::traits::CompleteCalendar;
|
use crate::traits::CompleteCalendar;
|
||||||
use crate::calendar::cached_calendar::CachedCalendar;
|
use crate::calendar::cached_calendar::CachedCalendar;
|
||||||
|
@ -192,16 +191,6 @@ impl CalDavSource<CachedCalendar> for Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyncSlave for Cache {
|
|
||||||
fn get_last_sync(&self) -> Option<DateTime<Utc>> {
|
|
||||||
self.data.last_sync
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_last_sync(&mut self, timepoint: Option<DateTime<Utc>>) {
|
|
||||||
self.data.last_sync = Some(timepoint.unwrap_or_else(|| Utc::now()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::traits::{PartialCalendar, CompleteCalendar};
|
||||||
use crate::calendar::{CalendarId, SupportedComponents, SearchFilter};
|
use crate::calendar::{CalendarId, SupportedComponents, SearchFilter};
|
||||||
use crate::Item;
|
use crate::Item;
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
|
use crate::item::VersionTag;
|
||||||
|
|
||||||
|
|
||||||
/// A calendar used by the [`cache`](crate::cache) module
|
/// A calendar used by the [`cache`](crate::cache) module
|
||||||
|
@ -69,6 +70,32 @@ impl PartialCalendar for CachedCalendar {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_item_version_tags(&self) -> Result<HashMap<ItemId, VersionTag>, Box<dyn Error>> {
|
||||||
|
Ok(self.items.iter()
|
||||||
|
.map(|(id, item)| (id.clone(), item.version_tag().clone()))
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_item_by_id_mut<'a>(&'a mut self, id: &ItemId) -> Option<&'a mut Item> {
|
||||||
|
self.items.get_mut(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl CompleteCalendar for CachedCalendar {
|
||||||
|
/// Returns the items that have been deleted after `since`
|
||||||
|
async fn get_items_deleted_since(&self, since: DateTime<Utc>) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
||||||
|
Ok(self.deleted_items.range(since..)
|
||||||
|
.map(|(_key, id)| id.clone())
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the list of items that this calendar contains
|
||||||
|
async fn get_items(&self) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>> {
|
||||||
|
self.get_items_modified_since(None, None).await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_items_modified_since(&self, since: Option<DateTime<Utc>>, filter: Option<SearchFilter>) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>> {
|
async fn get_items_modified_since(&self, since: Option<DateTime<Utc>>, filter: Option<SearchFilter>) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>> {
|
||||||
let filter = filter.unwrap_or_default();
|
let filter = filter.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -96,28 +123,4 @@ impl PartialCalendar for CachedCalendar {
|
||||||
|
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
|
||||||
Ok(self.items.keys().cloned().collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_item_by_id_mut<'a>(&'a mut self, id: &ItemId) -> Option<&'a mut Item> {
|
|
||||||
self.items.get_mut(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl CompleteCalendar for CachedCalendar {
|
|
||||||
/// Returns the items that have been deleted after `since`
|
|
||||||
async fn get_items_deleted_since(&self, since: DateTime<Utc>) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
|
||||||
Ok(self.deleted_items.range(since..)
|
|
||||||
.map(|(_key, id)| id.clone())
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the list of items that this calendar contains
|
|
||||||
async fn get_items(&self) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>> {
|
|
||||||
self.get_items_modified_since(None, None).await
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ use async_trait::async_trait;
|
||||||
use crate::traits::PartialCalendar;
|
use crate::traits::PartialCalendar;
|
||||||
use crate::calendar::SupportedComponents;
|
use crate::calendar::SupportedComponents;
|
||||||
use crate::calendar::CalendarId;
|
use crate::calendar::CalendarId;
|
||||||
use crate::item::ItemId;
|
|
||||||
use crate::item::Item;
|
use crate::item::Item;
|
||||||
|
use crate::item::ItemId;
|
||||||
|
use crate::item::VersionTag;
|
||||||
use crate::resource::Resource;
|
use crate::resource::Resource;
|
||||||
|
|
||||||
static TASKS_BODY: &str = r#"
|
static TASKS_BODY: &str = r#"
|
||||||
|
@ -51,14 +52,6 @@ impl PartialCalendar for RemoteCalendar {
|
||||||
self.supported_components
|
self.supported_components
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the items that have been last-modified after `since`
|
|
||||||
async fn get_items_modified_since(&self, since: Option<DateTime<Utc>>, _filter: Option<crate::calendar::SearchFilter>)
|
|
||||||
-> Result<HashMap<ItemId, &Item>, Box<dyn Error>>
|
|
||||||
{
|
|
||||||
log::error!("Not implemented");
|
|
||||||
Ok(HashMap::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the IDs of all current items in this calendar
|
/// Get the IDs of all current items in this calendar
|
||||||
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
||||||
let responses = crate::client::sub_request_and_extract_elems(&self.resource, "REPORT", TASKS_BODY.to_string(), "response").await?;
|
let responses = crate::client::sub_request_and_extract_elems(&self.resource, "REPORT", TASKS_BODY.to_string(), "response").await?;
|
||||||
|
@ -82,6 +75,11 @@ impl PartialCalendar for RemoteCalendar {
|
||||||
Ok(item_ids)
|
Ok(item_ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_item_version_tags(&self) -> Result<HashMap<ItemId, VersionTag>, Box<dyn Error>> {
|
||||||
|
log::error!("Not implemented");
|
||||||
|
Ok(HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a particular item
|
/// Returns a particular item
|
||||||
async fn get_item_by_id_mut<'a>(&'a mut self, _id: &ItemId) -> Option<&'a mut Item> {
|
async fn get_item_by_id_mut<'a>(&'a mut self, _id: &ItemId) -> Option<&'a mut Item> {
|
||||||
log::error!("Not implemented");
|
log::error!("Not implemented");
|
||||||
|
|
|
@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use chrono::{Utc, DateTime};
|
use chrono::{Utc, DateTime};
|
||||||
|
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
|
use crate::item::VersionTag;
|
||||||
|
|
||||||
/// TODO: implement Event one day.
|
/// TODO: implement Event one day.
|
||||||
/// This crate currently only supports tasks, not calendar events.
|
/// This crate currently only supports tasks, not calendar events.
|
||||||
|
@ -12,6 +13,7 @@ pub struct Event {
|
||||||
id: ItemId,
|
id: ItemId,
|
||||||
name: String,
|
name: String,
|
||||||
last_modified: DateTime<Utc>,
|
last_modified: DateTime<Utc>,
|
||||||
|
version_tag: VersionTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
|
@ -26,4 +28,8 @@ impl Event {
|
||||||
pub fn last_modified(&self) -> DateTime<Utc> {
|
pub fn last_modified(&self) -> DateTime<Utc> {
|
||||||
self.last_modified
|
self.last_modified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn version_tag(&self) -> &VersionTag {
|
||||||
|
&self.version_tag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/item.rs
30
src/item.rs
|
@ -7,6 +7,8 @@ use url::Url;
|
||||||
|
|
||||||
use crate::resource::Resource;
|
use crate::resource::Resource;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Item {
|
pub enum Item {
|
||||||
Event(crate::event::Event),
|
Event(crate::event::Event),
|
||||||
|
@ -35,6 +37,13 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn version_tag(&self) -> &VersionTag {
|
||||||
|
match self {
|
||||||
|
Item::Event(e) => e.version_tag(),
|
||||||
|
Item::Task(t) => t.version_tag(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_event(&self) -> bool {
|
pub fn is_event(&self) -> bool {
|
||||||
match &self {
|
match &self {
|
||||||
Item::Event(_) => true,
|
Item::Event(_) => true,
|
||||||
|
@ -109,3 +118,24 @@ impl Display for ItemId {
|
||||||
write!(f, "{}", self.content)
|
write!(f, "{}", self.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A VersionTag is basically a CalDAV `ctag` or `etag`. Whenever it changes, this means the data has changed.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct VersionTag {
|
||||||
|
tag: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for VersionTag {
|
||||||
|
fn from(tag: String) -> VersionTag {
|
||||||
|
Self { tag }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionTag {
|
||||||
|
/// Generate a random VesionTag. This is only useful in tests
|
||||||
|
pub fn random() -> Self {
|
||||||
|
let random = uuid::Uuid::new_v4().to_hyphenated().to_string();
|
||||||
|
Self { tag: random }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub use calendar::cached_calendar::CachedCalendar;
|
||||||
mod item;
|
mod item;
|
||||||
pub use item::Item;
|
pub use item::Item;
|
||||||
pub use item::ItemId;
|
pub use item::ItemId;
|
||||||
|
pub use item::VersionTag;
|
||||||
mod task;
|
mod task;
|
||||||
pub use task::Task;
|
pub use task::Task;
|
||||||
mod event;
|
mod event;
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::marker::PhantomData;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use crate::traits::{CalDavSource, CompleteCalendar};
|
use crate::traits::{CalDavSource, CompleteCalendar};
|
||||||
use crate::traits::SyncSlave;
|
|
||||||
use crate::traits::PartialCalendar;
|
use crate::traits::PartialCalendar;
|
||||||
use crate::Item;
|
use crate::Item;
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
|
@ -16,7 +15,7 @@ use crate::item::ItemId;
|
||||||
/// A data source that combines two `CalDavSources` (usually a server and a local cache), which is able to sync both sources.
|
/// A data source that combines two `CalDavSources` (usually a server and a local cache), which is able to sync both sources.
|
||||||
pub struct Provider<L, T, S, U>
|
pub struct Provider<L, T, S, U>
|
||||||
where
|
where
|
||||||
L: CalDavSource<T> + SyncSlave,
|
L: CalDavSource<T>,
|
||||||
T: CompleteCalendar,
|
T: CompleteCalendar,
|
||||||
S: CalDavSource<U>,
|
S: CalDavSource<U>,
|
||||||
U: PartialCalendar + Sync + Send,
|
U: PartialCalendar + Sync + Send,
|
||||||
|
@ -32,7 +31,7 @@ where
|
||||||
|
|
||||||
impl<L, T, S, U> Provider<L, T, S, U>
|
impl<L, T, S, U> Provider<L, T, S, U>
|
||||||
where
|
where
|
||||||
L: CalDavSource<T> + SyncSlave,
|
L: CalDavSource<T>,
|
||||||
T: CompleteCalendar,
|
T: CompleteCalendar,
|
||||||
S: CalDavSource<U>,
|
S: CalDavSource<U>,
|
||||||
U: PartialCalendar + Sync + Send,
|
U: PartialCalendar + Sync + Send,
|
||||||
|
@ -51,19 +50,14 @@ where
|
||||||
pub fn server(&self) -> &S { &self.server }
|
pub fn server(&self) -> &S { &self.server }
|
||||||
/// Returns the data source described as the `local`
|
/// Returns the data source described as the `local`
|
||||||
pub fn local(&self) -> &L { &self.local }
|
pub fn local(&self) -> &L { &self.local }
|
||||||
/// Returns the last time the `local` source has been synced
|
|
||||||
pub fn last_sync_timestamp(&self) -> Option<DateTime<Utc>> {
|
|
||||||
self.local.get_last_sync()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a synchronisation between `local` and `server`.
|
/// Performs a synchronisation between `local` and `server`.
|
||||||
///
|
///
|
||||||
/// This bidirectional sync applies additions/deletions made on a source to the other source.
|
/// This bidirectional sync applies additions/deletions made on a source to the other source.
|
||||||
/// In case of conflicts (the same item has been modified on both ends since the last sync, `server` always wins)
|
/// In case of conflicts (the same item has been modified on both ends since the last sync, `server` always wins)
|
||||||
pub async fn sync(&mut self) -> Result<(), Box<dyn Error>> {
|
pub async fn sync(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let last_sync = self.local.get_last_sync();
|
log::info!("Starting a sync.");
|
||||||
log::info!("Starting a sync. Last sync was at {:?}", last_sync);
|
/*
|
||||||
|
|
||||||
let cals_server = self.server.get_calendars().await?;
|
let cals_server = self.server.get_calendars().await?;
|
||||||
for (id, cal_server) in cals_server {
|
for (id, cal_server) in cals_server {
|
||||||
let mut cal_server = cal_server.lock().unwrap();
|
let mut cal_server = cal_server.lock().unwrap();
|
||||||
|
@ -77,8 +71,8 @@ where
|
||||||
};
|
};
|
||||||
let mut cal_local = cal_local.lock().unwrap();
|
let mut cal_local = cal_local.lock().unwrap();
|
||||||
|
|
||||||
// Step 1 - "Server always wins", so a delteion from the server must be applied locally, even if it was locally modified.
|
// Step 1 - "Server always wins", so a deletion from the server must be applied locally, even if it was locally modified.
|
||||||
let mut local_dels = match last_sync {
|
let mut local_dels = match cal_local.get_last_sync() {
|
||||||
None => HashSet::new(),
|
None => HashSet::new(),
|
||||||
Some(date) => cal_local.get_items_deleted_since(date).await?,
|
Some(date) => cal_local.get_items_deleted_since(date).await?,
|
||||||
};
|
};
|
||||||
|
@ -138,7 +132,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
self.local.update_last_sync(None);
|
self.local.update_last_sync(None);
|
||||||
|
*/
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use chrono::{Utc, DateTime};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
|
use crate::item::VersionTag;
|
||||||
|
|
||||||
/// A to-do task
|
/// A to-do task
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -11,6 +12,8 @@ pub struct Task {
|
||||||
|
|
||||||
/// The last modification date of this task
|
/// The last modification date of this task
|
||||||
last_modified: DateTime<Utc>,
|
last_modified: DateTime<Utc>,
|
||||||
|
/// The version tag of this item
|
||||||
|
version_tag: VersionTag,
|
||||||
|
|
||||||
/// The display name of the task
|
/// The display name of the task
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -20,11 +23,12 @@ pub struct Task {
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
/// Create a new Task
|
/// Create a new Task
|
||||||
pub fn new(name: String, id: ItemId, last_modified: DateTime<Utc>) -> Self {
|
pub fn new(name: String, id: ItemId, last_modified: DateTime<Utc>, version_tag: VersionTag) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
last_modified,
|
last_modified,
|
||||||
|
version_tag,
|
||||||
completed: false,
|
completed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +37,7 @@ impl Task {
|
||||||
pub fn name(&self) -> &str { &self.name }
|
pub fn name(&self) -> &str { &self.name }
|
||||||
pub fn completed(&self) -> bool { self.completed }
|
pub fn completed(&self) -> bool { self.completed }
|
||||||
pub fn last_modified(&self) -> DateTime<Utc> { self.last_modified }
|
pub fn last_modified(&self) -> DateTime<Utc> { self.last_modified }
|
||||||
|
pub fn version_tag(&self) -> &VersionTag { &self.version_tag }
|
||||||
|
|
||||||
fn update_last_modified(&mut self) {
|
fn update_last_modified(&mut self) {
|
||||||
self.last_modified = Utc::now();
|
self.last_modified = Utc::now();
|
||||||
|
|
|
@ -7,6 +7,7 @@ use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use crate::item::Item;
|
use crate::item::Item;
|
||||||
use crate::item::ItemId;
|
use crate::item::ItemId;
|
||||||
|
use crate::item::VersionTag;
|
||||||
use crate::calendar::CalendarId;
|
use crate::calendar::CalendarId;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -18,14 +19,6 @@ pub trait CalDavSource<T: PartialCalendar> {
|
||||||
async fn get_calendar(&self, id: &CalendarId) -> Option<Arc<Mutex<T>>>;
|
async fn get_calendar(&self, id: &CalendarId) -> Option<Arc<Mutex<T>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SyncSlave {
|
|
||||||
/// Returns the last time this source successfully synced from a master source (e.g. from a server)
|
|
||||||
/// (or None in case it has never been synchronized)
|
|
||||||
fn get_last_sync(&self) -> Option<DateTime<Utc>>;
|
|
||||||
/// Update the last sync timestamp to now, or to a custom time in case `timepoint` is `Some`
|
|
||||||
fn update_last_sync(&mut self, timepoint: Option<DateTime<Utc>>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A calendar we have a partial knowledge of.
|
/// A calendar we have a partial knowledge of.
|
||||||
///
|
///
|
||||||
/// Usually, this is a calendar from a remote source, that is synced to a CompleteCalendar
|
/// Usually, this is a calendar from a remote source, that is synced to a CompleteCalendar
|
||||||
|
@ -40,12 +33,8 @@ pub trait PartialCalendar {
|
||||||
/// Returns the supported kinds of components for this calendar
|
/// Returns the supported kinds of components for this calendar
|
||||||
fn supported_components(&self) -> crate::calendar::SupportedComponents;
|
fn supported_components(&self) -> crate::calendar::SupportedComponents;
|
||||||
|
|
||||||
/// Returns the items that have been last-modified after `since`
|
/// Get the IDs and the version tags of every item in this calendar
|
||||||
async fn get_items_modified_since(&self, since: Option<DateTime<Utc>>, filter: Option<crate::calendar::SearchFilter>)
|
async fn get_item_version_tags(&self) -> Result<HashMap<ItemId, VersionTag>, Box<dyn Error>>;
|
||||||
-> Result<HashMap<ItemId, &Item>, Box<dyn Error>>;
|
|
||||||
|
|
||||||
/// Get the IDs of all current items in this calendar
|
|
||||||
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>>;
|
|
||||||
|
|
||||||
/// Returns a particular item
|
/// Returns a particular item
|
||||||
async fn get_item_by_id_mut<'a>(&'a mut self, id: &ItemId) -> Option<&'a mut Item>;
|
async fn get_item_by_id_mut<'a>(&'a mut self, id: &ItemId) -> Option<&'a mut Item>;
|
||||||
|
@ -67,6 +56,14 @@ pub trait PartialCalendar {
|
||||||
self.supported_components().contains(crate::calendar::SupportedComponents::EVENT)
|
self.supported_components().contains(crate::calendar::SupportedComponents::EVENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the IDs of all current items in this calendar
|
||||||
|
async fn get_item_ids(&self) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
||||||
|
let items = self.get_item_version_tags().await?;
|
||||||
|
Ok(items.iter()
|
||||||
|
.map(|(id, _tag)| id.clone())
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds the IDs of the items that are missing compared to a reference set
|
/// Finds the IDs of the items that are missing compared to a reference set
|
||||||
async fn find_deletions_from(&self, reference_set: HashSet<ItemId>) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
async fn find_deletions_from(&self, reference_set: HashSet<ItemId>) -> Result<HashSet<ItemId>, Box<dyn Error>> {
|
||||||
let current_items = self.get_item_ids().await?;
|
let current_items = self.get_item_ids().await?;
|
||||||
|
@ -84,6 +81,10 @@ pub trait CompleteCalendar : PartialCalendar {
|
||||||
/// See also [`PartialCalendar::get_items_deleted_since`]
|
/// See also [`PartialCalendar::get_items_deleted_since`]
|
||||||
async fn get_items_deleted_since(&self, since: DateTime<Utc>) -> Result<HashSet<ItemId>, Box<dyn Error>>;
|
async fn get_items_deleted_since(&self, since: DateTime<Utc>) -> Result<HashSet<ItemId>, Box<dyn Error>>;
|
||||||
|
|
||||||
|
/// Returns the items that have been last-modified after `since`
|
||||||
|
async fn get_items_modified_since(&self, since: Option<DateTime<Utc>>, filter: Option<crate::calendar::SearchFilter>)
|
||||||
|
-> Result<HashMap<ItemId, &Item>, Box<dyn Error>>;
|
||||||
|
|
||||||
/// Returns the list of items that this calendar contains
|
/// Returns the list of items that this calendar contains
|
||||||
async fn get_items(&self) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>>;
|
async fn get_items(&self) -> Result<HashMap<ItemId, &Item>, Box<dyn Error>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,9 @@ async fn show_calendars() {
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(" Most recent changes:");
|
println!(" Most recent changes:");
|
||||||
for (_id, task) in cal.get_items_modified_since(None, None).await.unwrap() {
|
// for (_id, task) in cal.get_item_version_tags(None, None).await.unwrap() {
|
||||||
my_tasks::utils::print_task(task);
|
// my_tasks::utils::print_task(task);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,12 @@ use std::sync::{Arc, Mutex};
|
||||||
use chrono::{Utc, TimeZone};
|
use chrono::{Utc, TimeZone};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use my_tasks::traits::{CalDavSource, SyncSlave};
|
use my_tasks::traits::CalDavSource;
|
||||||
use my_tasks::traits::PartialCalendar;
|
use my_tasks::traits::PartialCalendar;
|
||||||
use my_tasks::cache::Cache;
|
use my_tasks::cache::Cache;
|
||||||
use my_tasks::Item;
|
use my_tasks::Item;
|
||||||
use my_tasks::ItemId;
|
use my_tasks::ItemId;
|
||||||
|
use my_tasks::VersionTag;
|
||||||
use my_tasks::Task;
|
use my_tasks::Task;
|
||||||
use my_tasks::calendar::cached_calendar::CachedCalendar;
|
use my_tasks::calendar::cached_calendar::CachedCalendar;
|
||||||
use my_tasks::Provider;
|
use my_tasks::Provider;
|
||||||
|
@ -53,23 +54,23 @@ async fn populate_test_provider() -> Provider<Cache, CachedCalendar, Cache, Cach
|
||||||
|
|
||||||
let cal_id = Url::parse("http://todo.list/cal").unwrap();
|
let cal_id = Url::parse("http://todo.list/cal").unwrap();
|
||||||
|
|
||||||
let task_a = Item::Task(Task::new("task A".into(), ItemId::random(), Utc.ymd(2000, 1, 1).and_hms(0, 0, 0)));
|
let task_a = Item::Task(Task::new("task A".into(), ItemId::random(), Utc.ymd(2000, 1, 1).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_b = Item::Task(Task::new("task B".into(), ItemId::random(), Utc.ymd(2000, 1, 2).and_hms(0, 0, 0)));
|
let task_b = Item::Task(Task::new("task B".into(), ItemId::random(), Utc.ymd(2000, 1, 2).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_c = Item::Task(Task::new("task C".into(), ItemId::random(), Utc.ymd(2000, 1, 3).and_hms(0, 0, 0)));
|
let task_c = Item::Task(Task::new("task C".into(), ItemId::random(), Utc.ymd(2000, 1, 3).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_d = Item::Task(Task::new("task D".into(), ItemId::random(), Utc.ymd(2000, 1, 4).and_hms(0, 0, 0)));
|
let task_d = Item::Task(Task::new("task D".into(), ItemId::random(), Utc.ymd(2000, 1, 4).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_e = Item::Task(Task::new("task E".into(), ItemId::random(), Utc.ymd(2000, 1, 5).and_hms(0, 0, 0)));
|
let task_e = Item::Task(Task::new("task E".into(), ItemId::random(), Utc.ymd(2000, 1, 5).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_f = Item::Task(Task::new("task F".into(), ItemId::random(), Utc.ymd(2000, 1, 6).and_hms(0, 0, 0)));
|
let task_f = Item::Task(Task::new("task F".into(), ItemId::random(), Utc.ymd(2000, 1, 6).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_g = Item::Task(Task::new("task G".into(), ItemId::random(), Utc.ymd(2000, 1, 7).and_hms(0, 0, 0)));
|
let task_g = Item::Task(Task::new("task G".into(), ItemId::random(), Utc.ymd(2000, 1, 7).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_h = Item::Task(Task::new("task H".into(), ItemId::random(), Utc.ymd(2000, 1, 8).and_hms(0, 0, 0)));
|
let task_h = Item::Task(Task::new("task H".into(), ItemId::random(), Utc.ymd(2000, 1, 8).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_i = Item::Task(Task::new("task I".into(), ItemId::random(), Utc.ymd(2000, 1, 9).and_hms(0, 0, 0)));
|
let task_i = Item::Task(Task::new("task I".into(), ItemId::random(), Utc.ymd(2000, 1, 9).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_j = Item::Task(Task::new("task J".into(), ItemId::random(), Utc.ymd(2000, 1, 10).and_hms(0, 0, 0)));
|
let task_j = Item::Task(Task::new("task J".into(), ItemId::random(), Utc.ymd(2000, 1, 10).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_k = Item::Task(Task::new("task K".into(), ItemId::random(), Utc.ymd(2000, 1, 11).and_hms(0, 0, 0)));
|
let task_k = Item::Task(Task::new("task K".into(), ItemId::random(), Utc.ymd(2000, 1, 11).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_l = Item::Task(Task::new("task L".into(), ItemId::random(), Utc.ymd(2000, 1, 12).and_hms(0, 0, 0)));
|
let task_l = Item::Task(Task::new("task L".into(), ItemId::random(), Utc.ymd(2000, 1, 12).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
let task_m = Item::Task(Task::new("task M".into(), ItemId::random(), Utc.ymd(2000, 1, 12).and_hms(0, 0, 0)));
|
let task_m = Item::Task(Task::new("task M".into(), ItemId::random(), Utc.ymd(2000, 1, 12).and_hms(0, 0, 0), VersionTag::random()));
|
||||||
|
|
||||||
let last_sync = task_m.last_modified();
|
// let last_sync = task_m.last_modified();
|
||||||
local.update_last_sync(Some(last_sync));
|
// local.update_last_sync(Some(last_sync));
|
||||||
assert!(last_sync < Utc::now());
|
// assert!(last_sync < Utc::now());
|
||||||
|
|
||||||
let task_b_id = task_b.id().clone();
|
let task_b_id = task_b.id().clone();
|
||||||
let task_c_id = task_c.id().clone();
|
let task_c_id = task_c.id().clone();
|
||||||
|
@ -129,7 +130,7 @@ async fn populate_test_provider() -> Provider<Cache, CachedCalendar, Cache, Cach
|
||||||
|
|
||||||
cal_server.delete_item(&task_l_id).await.unwrap();
|
cal_server.delete_item(&task_l_id).await.unwrap();
|
||||||
|
|
||||||
let task_n = Item::Task(Task::new("task N (new from server)".into(), ItemId::random(), Utc::now()));
|
let task_n = Item::Task(Task::new("task N (new from server)".into(), ItemId::random(), Utc::now(), VersionTag::random()));
|
||||||
cal_server.add_item(task_n).await;
|
cal_server.add_item(task_n).await;
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ async fn populate_test_provider() -> Provider<Cache, CachedCalendar, Cache, Cach
|
||||||
cal_local.delete_item(&task_k_id).await.unwrap();
|
cal_local.delete_item(&task_k_id).await.unwrap();
|
||||||
cal_local.delete_item(&task_l_id).await.unwrap();
|
cal_local.delete_item(&task_l_id).await.unwrap();
|
||||||
|
|
||||||
let task_o = Item::Task(Task::new("task O (new from local)".into(), ItemId::random(), Utc::now()));
|
let task_o = Item::Task(Task::new("task O (new from local)".into(), ItemId::random(), Utc::now(), VersionTag::random()));
|
||||||
cal_local.add_item(task_o).await;
|
cal_local.add_item(task_o).await;
|
||||||
|
|
||||||
Provider::new(server, local)
|
Provider::new(server, local)
|
||||||
|
|
Loading…
Add table
Reference in a new issue