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::{
DavResourceName, RFC_3986,
cache::calcard::{build_scheduling_resources, path_from_scheduling, resource_from_scheduling},
calendar::{Calendar, CalendarEvent, CalendarPreferences},
contact::{AddressBook, ContactCard},
@ -16,6 +17,7 @@ use calcard::{
resource_from_calendar, resource_from_card, resource_from_event,
};
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 jmap_proto::types::collection::{Collection, SyncCollection};
use std::{sync::Arc, time::Instant};
@ -174,62 +176,41 @@ impl GroupwareCache for Server {
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 cache = if !matches!(collection, SyncCollection::CalendarScheduling) {
let mut updated_resources = AHashMap::with_capacity(8);
let has_no_children = collection == SyncCollection::FileNode;
for change in changes.changes {
match change {
Change::InsertItem(id) | Change::UpdateItem(id) => {
let document_id = id as u32;
if let Some(archive) = self
.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,
process_changes(
self,
account_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(_) => (),
}
}
has_no_children,
&mut updated_resources,
changes.changes,
)
.await?;
let mut rebuild_hierarchy = false;
let mut resources = Vec::with_capacity(cache.resources.len());
@ -260,7 +241,7 @@ impl GroupwareCache for Server {
if rebuild_hierarchy {
let mut cache = DavResources {
base_path: cache.base_path.clone(),
base_path,
paths: Default::default(),
resources,
item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id),
@ -280,7 +261,7 @@ impl GroupwareCache for Server {
cache
} else {
DavResources {
base_path: cache.base_path.clone(),
base_path,
paths: cache.paths.clone(),
resources,
item_change_id: changes.item_change_id.unwrap_or(cache.item_change_id),
@ -323,7 +304,7 @@ impl GroupwareCache for Server {
}
DavResources {
base_path: cache.base_path.clone(),
base_path,
paths,
resources,
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(
server: &Server,
account_id: u32,

View file

@ -6,7 +6,7 @@
use calcard::common::timezone::Tz;
use common::DavResources;
use jmap_proto::types::collection::Collection;
use jmap_proto::types::collection::{Collection, SyncCollection};
use percent_encoding::{AsciiSet, CONTROLS};
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 {
fn calendar_default_tz(&self, calendar_id: u32) -> Option<Tz>;
}