WebDAV import materialised the account root collection as a directory named after the account displayname (fixes #18)

This commit is contained in:
Maurus Decimus
2026-07-12 18:54:43 +02:00
parent ec6b3f9d15
commit 0f28e9b17e
9 changed files with 237 additions and 64 deletions
+2 -1
View File
@@ -224,7 +224,8 @@ pub fn reconcile(
}
},
};
if let Some(tid) = find_name_collision(&targets, parent_target.as_deref(), &n.name) {
if let Some(tid) = find_name_collision(&targets, parent_target.as_deref(), &n.name)
{
record_merge(
ty,
n.local,
-42
View File
@@ -270,48 +270,6 @@ fn parse_tzid_from_vtimezone(vt: Option<&str>) -> Option<String> {
None
}
pub fn upsert_root_directory(
conn: &Connection,
source_id: i64,
root: &DiscoveredCollection,
) -> Result<i64, Error> {
let collection_href = root.href.as_str().to_owned();
let name = display_or_fallback(&root.props.displayname, &root.href);
if let Some(local) =
dav_ids::local_for_item(conn, source_id, dav_ids::FILE_NODE, &collection_href)
.map_err(|e| Error::Partial(e.to_string()))?
{
conn.execute(
"UPDATE file_nodes SET name = ?1 WHERE id = ?2",
params![name, local],
)
.map_err(|e| Error::Partial(e.to_string()))?;
return Ok(local);
}
let now = time::OffsetDateTime::now_utc()
.format(&time::format_description::well_known::Rfc3339)
.map_err(|e| Error::Partial(format!("clock: {e}")))?;
conn.execute(
"INSERT INTO file_nodes (parent_id, node_type, blob_id, target, name, media_type,
created, modified, is_subscribed, role)
VALUES (NULL, 'directory', NULL, NULL, ?1, NULL, ?2, NULL, 1, NULL)",
params![name, now],
)
.map_err(|e| Error::Partial(e.to_string()))?;
let local_id = conn.last_insert_rowid();
dav_ids::insert(
conn,
source_id,
dav_ids::FILE_NODE,
&collection_href,
&collection_href,
"",
local_id,
)
.map_err(|e| Error::Partial(e.to_string()))?;
Ok(local_id)
}
#[cfg(test)]
mod tests {
use super::*;
+9 -10
View File
@@ -26,7 +26,7 @@ use crate::sync::import_jmap::pool::Pool;
struct FilePlan {
item_href: String,
parent_href: String,
parent_local: i64,
parent_local: Option<i64>,
existing_local: Option<i64>,
propfind_etag: String,
propfind_content_type: Option<String>,
@@ -73,7 +73,6 @@ pub fn reconcile_filenodes(
let dav_connections = ctx.dav_connections;
let logger = ctx.logger;
let absolute_root = absolute(base_url, root.href.as_str())?;
let root_local = super::collections::upsert_root_directory(conn, source_id, root)?;
let known: Vec<(String, i64)> =
dav_ids::collections_of_type(conn, source_id, dav_ids::FILE_NODE)
@@ -85,8 +84,8 @@ pub fn reconcile_filenodes(
let mut visited: HashSet<String> = HashSet::new();
visited.insert(root.href.as_str().to_owned());
let mut queue: VecDeque<(String, String, i64)> = VecDeque::new();
queue.push_back((absolute_root, root.href.as_str().to_owned(), root_local));
let mut queue: VecDeque<(String, String, Option<i64>)> = VecDeque::new();
queue.push_back((absolute_root, root.href.as_str().to_owned(), None));
let mut file_plans: Vec<FilePlan> = Vec::new();
@@ -369,7 +368,7 @@ fn delete_vanished(
struct WalkPos<'a> {
url: &'a str,
parent_href: &'a str,
parent_local: i64,
parent_local: Option<i64>,
}
struct WalkState<'a> {
@@ -385,7 +384,7 @@ fn walk_one(
pos: WalkPos<'_>,
state: WalkState<'_>,
logger: Logger,
) -> Result<Vec<(String, String, i64)>, Error> {
) -> Result<Vec<(String, String, Option<i64>)>, Error> {
let url = pos.url;
let parent_href = pos.parent_href;
let parent_local = pos.parent_local;
@@ -411,7 +410,7 @@ fn walk_one(
if r.props.is_collection {
let local = upsert_directory(conn, source_id, &r, parent_local, counts)?;
let abs = absolute(url, r.href.as_str())?;
children.push((abs, r.href.as_str().to_owned(), local));
children.push((abs, r.href.as_str().to_owned(), Some(local)));
} else {
match plan_file(conn, source_id, &r, url, parent_local, parent_href) {
Ok(Some(plan)) => file_plans.push(plan),
@@ -439,7 +438,7 @@ fn plan_file(
source_id: i64,
response: &DavResponse,
collection_url: &str,
parent_local: i64,
parent_local: Option<i64>,
parent_href: &str,
) -> Result<Option<FilePlan>, Error> {
let item_href = response.href.as_str().to_owned();
@@ -496,7 +495,7 @@ fn upsert_directory(
conn: &mut Connection,
source_id: i64,
response: &DavResponse,
parent_local: i64,
parent_local: Option<i64>,
counts: &mut TypeCounts,
) -> Result<i64, Error> {
let item_href = response.href.as_str().to_owned();
@@ -625,7 +624,7 @@ mod tests {
FilePlan {
item_href: href.to_owned(),
parent_href: "/dav/file/u/".to_owned(),
parent_local: 1,
parent_local: Some(1),
existing_local: None,
propfind_etag: String::new(),
propfind_content_type: None,