Added the update_item function
This commit is contained in:
parent
5b1adca42c
commit
849cbbc07a
5 changed files with 90 additions and 18 deletions
|
@ -36,19 +36,41 @@ impl CachedCalendar {
|
||||||
self.mock_behaviour = mock_behaviour;
|
self.mock_behaviour = mock_behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an item
|
|
||||||
async fn regular_add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
// TODO: here (and in the remote version, display an errror in case we overwrite something?)
|
async fn add_item_maybe_mocked(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
|
self.mock_behaviour.as_ref().map_or(Ok(()), |b| b.lock().unwrap().can_add_item())?;
|
||||||
|
|
||||||
|
if self.mock_behaviour.is_some() {
|
||||||
|
self.add_or_update_item_force_synced(item).await
|
||||||
|
} else {
|
||||||
|
self.regular_add_or_update_item(item).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
|
async fn update_item_maybe_mocked(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
|
self.mock_behaviour.as_ref().map_or(Ok(()), |b| b.lock().unwrap().can_update_item())?;
|
||||||
|
|
||||||
|
if self.mock_behaviour.is_some() {
|
||||||
|
self.add_or_update_item_force_synced(item).await
|
||||||
|
} else {
|
||||||
|
self.regular_add_or_update_item(item).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add or update an item
|
||||||
|
async fn regular_add_or_update_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
let ss_clone = item.sync_status().clone();
|
let ss_clone = item.sync_status().clone();
|
||||||
log::debug!("Adding an item with {:?}", ss_clone);
|
log::debug!("Adding or updating an item with {:?}", ss_clone);
|
||||||
self.items.insert(item.id().clone(), item);
|
self.items.insert(item.id().clone(), item);
|
||||||
Ok(ss_clone)
|
Ok(ss_clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an item, but force a "synced" SyncStatus. This is the typical behaviour on a remote calendar
|
/// Add or update an item, but force a "synced" SyncStatus. This is the normal behaviour that would happen on a server
|
||||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
async fn add_item_force_synced(&mut self, mut item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
async fn add_or_update_item_force_synced(&mut self, mut item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
log::debug!("Adding an item, but forces a synced SyncStatus");
|
log::debug!("Adding or updating an item, but forces a synced SyncStatus");
|
||||||
match item.sync_status() {
|
match item.sync_status() {
|
||||||
SyncStatus::Synced(_) => (),
|
SyncStatus::Synced(_) => (),
|
||||||
_ => item.set_sync_status(SyncStatus::random_synced()),
|
_ => item.set_sync_status(SyncStatus::random_synced()),
|
||||||
|
@ -108,20 +130,26 @@ impl BaseCalendar for CachedCalendar {
|
||||||
self.supported_components
|
self.supported_components
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "local_calendar_mocks_remote_calendars"))]
|
|
||||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
self.regular_add_item(item).await
|
if self.items.contains_key(item.id()) {
|
||||||
|
return Err(format!("Item {:?} cannot be added, it exists already", item.id()).into());
|
||||||
}
|
}
|
||||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
#[cfg(not(feature = "local_calendar_mocks_remote_calendars"))]
|
||||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
return self.regular_add_or_update_item(item).await;
|
||||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
|
||||||
self.mock_behaviour.as_ref().map_or(Ok(()), |b| b.lock().unwrap().can_add_item())?;
|
|
||||||
|
|
||||||
if self.mock_behaviour.is_some() {
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
self.add_item_force_synced(item).await
|
return self.add_item_maybe_mocked(item).await;
|
||||||
} else {
|
}
|
||||||
self.regular_add_item(item).await
|
|
||||||
|
async fn update_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
|
if self.items.contains_key(item.id()) == false {
|
||||||
|
return Err(format!("Item {:?} cannot be updated, it does not already exist", item.id()).into());
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "local_calendar_mocks_remote_calendars"))]
|
||||||
|
return self.regular_add_or_update_item(item).await;
|
||||||
|
|
||||||
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
|
return self.update_item_maybe_mocked(item).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ impl BaseCalendar for RemoteCalendar {
|
||||||
self.supported_components
|
self.supported_components
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an item into this calendar
|
|
||||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
let ical_text = crate::ical::build_from(&item)?;
|
let ical_text = crate::ical::build_from(&item)?;
|
||||||
|
|
||||||
|
@ -72,6 +71,36 @@ impl BaseCalendar for RemoteCalendar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>> {
|
||||||
|
let old_etag = match item.sync_status() {
|
||||||
|
SyncStatus::NotSynced => return Err("Cannot update an item that has not been synced already".into()),
|
||||||
|
SyncStatus::Synced(_) => return Err("Cannot update an item that has not changed".into()),
|
||||||
|
SyncStatus::LocallyModified(etag) => etag,
|
||||||
|
SyncStatus::LocallyDeleted(etag) => etag,
|
||||||
|
};
|
||||||
|
let ical_text = crate::ical::build_from(&item)?;
|
||||||
|
|
||||||
|
let request = reqwest::Client::new()
|
||||||
|
.put(item.id().as_url().clone())
|
||||||
|
.header("If-Match", old_etag.as_str())
|
||||||
|
.header(CONTENT_TYPE, "text/calendar")
|
||||||
|
.header(CONTENT_LENGTH, ical_text.len())
|
||||||
|
.basic_auth(self.resource.username(), Some(self.resource.password()))
|
||||||
|
.body(ical_text)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let reply_hdrs = request.headers();
|
||||||
|
match reply_hdrs.get("ETag") {
|
||||||
|
None => Err(format!("No ETag in these response headers: {:?} (request was {:?})", reply_hdrs, item.id()).into()),
|
||||||
|
Some(etag) => {
|
||||||
|
let vtag_str = etag.to_str()?;
|
||||||
|
let vtag = VersionTag::from(String::from(vtag_str));
|
||||||
|
Ok(SyncStatus::Synced(vtag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
|
@ -190,6 +190,11 @@ impl From<String> for VersionTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionTag {
|
impl VersionTag {
|
||||||
|
/// Get the inner version tag (usually a WebDAV `ctag` or `etag`)
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
&self.tag
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate a random VesionTag
|
/// Generate a random VesionTag
|
||||||
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
|
||||||
pub fn random() -> Self {
|
pub fn random() -> Self {
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub struct MockBehaviour {
|
||||||
|
|
||||||
// From the BaseCalendar trait
|
// From the BaseCalendar trait
|
||||||
pub add_item_behaviour: (u32, u32),
|
pub add_item_behaviour: (u32, u32),
|
||||||
|
pub update_item_behaviour: (u32, u32),
|
||||||
|
|
||||||
// From the DavCalendar trait
|
// From the DavCalendar trait
|
||||||
pub get_item_version_tags_behaviour: (u32, u32),
|
pub get_item_version_tags_behaviour: (u32, u32),
|
||||||
|
@ -37,6 +38,7 @@ impl MockBehaviour {
|
||||||
//get_calendar_behaviour: (0, n_fails),
|
//get_calendar_behaviour: (0, n_fails),
|
||||||
create_calendar_behaviour: (0, n_fails),
|
create_calendar_behaviour: (0, n_fails),
|
||||||
add_item_behaviour: (0, n_fails),
|
add_item_behaviour: (0, n_fails),
|
||||||
|
update_item_behaviour: (0, n_fails),
|
||||||
get_item_version_tags_behaviour: (0, n_fails),
|
get_item_version_tags_behaviour: (0, n_fails),
|
||||||
get_item_by_id_behaviour: (0, n_fails),
|
get_item_by_id_behaviour: (0, n_fails),
|
||||||
delete_item_behaviour: (0, n_fails),
|
delete_item_behaviour: (0, n_fails),
|
||||||
|
@ -73,6 +75,10 @@ impl MockBehaviour {
|
||||||
if self.is_suspended { return Ok(()) }
|
if self.is_suspended { return Ok(()) }
|
||||||
decrement(&mut self.add_item_behaviour, "add_item")
|
decrement(&mut self.add_item_behaviour, "add_item")
|
||||||
}
|
}
|
||||||
|
pub fn can_update_item(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
if self.is_suspended { return Ok(()) }
|
||||||
|
decrement(&mut self.update_item_behaviour, "update_item")
|
||||||
|
}
|
||||||
pub fn can_get_item_version_tags(&mut self) -> Result<(), Box<dyn Error>> {
|
pub fn can_get_item_version_tags(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
if self.is_suspended { return Ok(()) }
|
if self.is_suspended { return Ok(()) }
|
||||||
decrement(&mut self.get_item_version_tags_behaviour, "get_item_version_tags")
|
decrement(&mut self.get_item_version_tags_behaviour, "get_item_version_tags")
|
||||||
|
|
|
@ -42,6 +42,10 @@ pub trait BaseCalendar {
|
||||||
/// For remote calendars, the sync status is updated by the server
|
/// For remote calendars, the sync status is updated by the server
|
||||||
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>>;
|
async fn add_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>>;
|
||||||
|
|
||||||
|
/// Update an item that already exists in this calendar and returns its new `SyncStatus`
|
||||||
|
/// This replaces a given item at a given URL
|
||||||
|
async fn update_item(&mut self, item: Item) -> Result<SyncStatus, Box<dyn Error>>;
|
||||||
|
|
||||||
/// Returns whether this calDAV calendar supports to-do items
|
/// Returns whether this calDAV calendar supports to-do items
|
||||||
fn supports_todo(&self) -> bool {
|
fn supports_todo(&self) -> bool {
|
||||||
self.supported_components().contains(crate::calendar::SupportedComponents::TODO)
|
self.supported_components().contains(crate::calendar::SupportedComponents::TODO)
|
||||||
|
|
Loading…
Add table
Reference in a new issue