Update account name when refreshing DAV caches (closes ##1694)

This commit is contained in:
mdecimus 2025-06-24 10:41:02 +02:00
parent 854bfcb249
commit 020bcaef8b
2 changed files with 110 additions and 55 deletions

View file

@ -5,6 +5,7 @@
*/ */
use crate::{ use crate::{
DavResourceName, RFC_3986,
cache::calcard::{build_scheduling_resources, path_from_scheduling, resource_from_scheduling}, cache::calcard::{build_scheduling_resources, path_from_scheduling, resource_from_scheduling},
calendar::{Calendar, CalendarEvent, CalendarPreferences}, calendar::{Calendar, CalendarEvent, CalendarPreferences},
contact::{AddressBook, ContactCard}, contact::{AddressBook, ContactCard},
@ -16,6 +17,7 @@ use calcard::{
resource_from_calendar, resource_from_card, resource_from_event, resource_from_calendar, resource_from_card, resource_from_event,
}; };
use common::{CacheSwap, DavResource, DavResources, Server, auth::AccessToken}; use common::{CacheSwap, DavResource, DavResources, Server, auth::AccessToken};
use directory::backend::internal::manage::ManageDirectory;
use file::{build_file_resources, build_nested_hierarchy, resource_from_file}; use file::{build_file_resources, build_nested_hierarchy, resource_from_file};
use jmap_proto::types::collection::{Collection, SyncCollection}; use jmap_proto::types::collection::{Collection, SyncCollection};
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
@ -174,62 +176,41 @@ impl GroupwareCache for Server {
return Ok(cache); return Ok(cache);
} }
// Build base path
let base_path = if access_token.primary_id() == account_id {
format!(
"{}/{}/",
DavResourceName::from(collection).base_path(),
percent_encoding::utf8_percent_encode(&access_token.name, RFC_3986)
)
} else {
let name = self
.store()
.get_principal_name(account_id)
.await
.caused_by(trc::location!())?
.unwrap_or_else(|| format!("_{account_id}"));
format!(
"{}/{}/",
DavResourceName::from(collection).base_path(),
percent_encoding::utf8_percent_encode(&name, RFC_3986)
)
};
let num_changes = changes.changes.len(); let num_changes = changes.changes.len();
let cache = if !matches!(collection, SyncCollection::CalendarScheduling) { let cache = if !matches!(collection, SyncCollection::CalendarScheduling) {
let mut updated_resources = AHashMap::with_capacity(8); let mut updated_resources = AHashMap::with_capacity(8);
let has_no_children = collection == SyncCollection::FileNode; let has_no_children = collection == SyncCollection::FileNode;
for change in changes.changes { process_changes(
match change { self,
Change::InsertItem(id) | Change::UpdateItem(id) => { account_id,
let document_id = id as u32; collection,
if let Some(archive) = self has_no_children,
.get_archive(account_id, collection.collection(false), document_id) &mut updated_resources,
.await changes.changes,
.caused_by(trc::location!())? )
{ .await?;
updated_resources.insert(
(has_no_children, document_id),
Some(resource_from_archive(
archive,
document_id,
collection,
false,
)?),
);
} else {
updated_resources.insert((has_no_children, document_id), None);
}
}
Change::DeleteItem(id) => {
updated_resources.insert((has_no_children, id as u32), None);
}
Change::InsertContainer(id) | Change::UpdateContainer(id) => {
let document_id = id as u32;
if let Some(archive) = self
.get_archive(account_id, collection.collection(true), document_id)
.await
.caused_by(trc::location!())?
{
updated_resources.insert(
(true, document_id),
Some(resource_from_archive(
archive,
document_id,
collection,
true,
)?),
);
} else {
updated_resources.insert((true, document_id), None);
}
}
Change::DeleteContainer(id) => {
updated_resources.insert((true, id as u32), None);
}
Change::UpdateContainerProperty(_) => (),
}
}
let mut rebuild_hierarchy = false; let mut rebuild_hierarchy = false;
let mut resources = Vec::with_capacity(cache.resources.len()); let mut resources = Vec::with_capacity(cache.resources.len());
@ -260,7 +241,7 @@ impl GroupwareCache for Server {
if rebuild_hierarchy { if rebuild_hierarchy {
let mut cache = DavResources { let mut cache = DavResources {
base_path: cache.base_path.clone(), base_path,
paths: Default::default(), paths: Default::default(),
resources, resources,
item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id), item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id),
@ -280,7 +261,7 @@ impl GroupwareCache for Server {
cache cache
} else { } else {
DavResources { DavResources {
base_path: cache.base_path.clone(), base_path,
paths: cache.paths.clone(), paths: cache.paths.clone(),
resources, resources,
item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id), item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id),
@ -323,7 +304,7 @@ impl GroupwareCache for Server {
} }
DavResources { DavResources {
base_path: cache.base_path.clone(), base_path,
paths, paths,
resources, resources,
item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id), item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id),
@ -440,6 +421,68 @@ impl GroupwareCache for Server {
} }
} }
async fn process_changes(
server: &Server,
account_id: u32,
collection: SyncCollection,
has_no_children: bool,
updated_resources: &mut AHashMap<(bool, u32), Option<DavResource>>,
changes: Vec<Change>,
) -> trc::Result<()> {
for change in changes {
match change {
Change::InsertItem(id) | Change::UpdateItem(id) => {
let document_id = id as u32;
if let Some(archive) = server
.get_archive(account_id, collection.collection(false), document_id)
.await
.caused_by(trc::location!())?
{
updated_resources.insert(
(has_no_children, document_id),
Some(resource_from_archive(
archive,
document_id,
collection,
false,
)?),
);
} else {
updated_resources.insert((has_no_children, document_id), None);
}
}
Change::DeleteItem(id) => {
updated_resources.insert((has_no_children, id as u32), None);
}
Change::InsertContainer(id) | Change::UpdateContainer(id) => {
let document_id = id as u32;
if let Some(archive) = server
.get_archive(account_id, collection.collection(true), document_id)
.await
.caused_by(trc::location!())?
{
updated_resources.insert(
(true, document_id),
Some(resource_from_archive(
archive,
document_id,
collection,
true,
)?),
);
} else {
updated_resources.insert((true, document_id), None);
}
}
Change::DeleteContainer(id) => {
updated_resources.insert((true, id as u32), None);
}
Change::UpdateContainerProperty(_) => (),
}
}
Ok(())
}
async fn full_cache_build( async fn full_cache_build(
server: &Server, server: &Server,
account_id: u32, account_id: u32,

View file

@ -6,7 +6,7 @@
use calcard::common::timezone::Tz; use calcard::common::timezone::Tz;
use common::DavResources; use common::DavResources;
use jmap_proto::types::collection::Collection; use jmap_proto::types::collection::{Collection, SyncCollection};
use percent_encoding::{AsciiSet, CONTROLS}; use percent_encoding::{AsciiSet, CONTROLS};
pub mod cache; pub mod cache;
@ -124,6 +124,18 @@ impl From<Collection> for DavResourceName {
} }
} }
impl From<SyncCollection> for DavResourceName {
fn from(value: SyncCollection) -> Self {
match value {
SyncCollection::AddressBook => DavResourceName::Card,
SyncCollection::Calendar => DavResourceName::Cal,
SyncCollection::FileNode => DavResourceName::File,
SyncCollection::CalendarScheduling => DavResourceName::Scheduling,
_ => unreachable!(),
}
}
}
pub trait DavCalendarResource { pub trait DavCalendarResource {
fn calendar_default_tz(&self, calendar_id: u32) -> Option<Tz>; fn calendar_default_tz(&self, calendar_id: u32) -> Option<Tz>;
} }