186 lines
6.7 KiB
Rust
186 lines
6.7 KiB
Rust
use anyhow::Result;
|
|
use crate::models::FileIngestionInfo;
|
|
use super::config::WebDAVConfig;
|
|
|
|
/// Centralized URL and path management for WebDAV operations
|
|
///
|
|
/// This module handles all the messy WebDAV URL construction, path normalization,
|
|
/// and conversion between full WebDAV paths and relative paths. It's designed to
|
|
/// prevent the URL doubling issues that plague WebDAV integrations.
|
|
pub struct WebDAVUrlManager {
|
|
config: WebDAVConfig,
|
|
}
|
|
|
|
impl WebDAVUrlManager {
|
|
pub fn new(config: WebDAVConfig) -> Self {
|
|
Self { config }
|
|
}
|
|
|
|
/// Get the base WebDAV URL for the configured server
|
|
/// Returns something like: "https://nas.example.com/remote.php/dav/files/username"
|
|
pub fn base_url(&self) -> String {
|
|
self.config.webdav_url()
|
|
}
|
|
|
|
/// Convert full WebDAV href (from XML response) to relative path
|
|
///
|
|
/// Input: "/remote.php/dav/files/username/Photos/image.jpg"
|
|
/// Output: "/Photos/image.jpg"
|
|
pub fn href_to_relative_path(&self, href: &str) -> String {
|
|
match self.config.server_type.as_deref() {
|
|
Some("nextcloud") => {
|
|
let prefix = format!("/remote.php/dav/files/{}", self.config.username);
|
|
if href.starts_with(&prefix) {
|
|
let relative = &href[prefix.len()..];
|
|
if relative.is_empty() { "/" } else { relative }.to_string()
|
|
} else {
|
|
href.to_string()
|
|
}
|
|
}
|
|
Some("owncloud") => {
|
|
if href.starts_with("/remote.php/webdav") {
|
|
let relative = &href[18..]; // Remove "/remote.php/webdav"
|
|
if relative.is_empty() { "/" } else { relative }.to_string()
|
|
} else {
|
|
href.to_string()
|
|
}
|
|
}
|
|
Some("generic") => {
|
|
if href.starts_with("/webdav") {
|
|
let relative = &href[7..]; // Remove "/webdav"
|
|
if relative.is_empty() { "/" } else { relative }.to_string()
|
|
} else {
|
|
href.to_string()
|
|
}
|
|
}
|
|
_ => href.to_string(),
|
|
}
|
|
}
|
|
|
|
/// Convert relative path to full URL for WebDAV requests
|
|
///
|
|
/// Input: "/Photos/image.jpg"
|
|
/// Output: "https://nas.example.com/remote.php/dav/files/username/Photos/image.jpg"
|
|
pub fn relative_path_to_url(&self, relative_path: &str) -> String {
|
|
let base_url = self.base_url();
|
|
let clean_path = relative_path.trim_start_matches('/');
|
|
|
|
if clean_path.is_empty() {
|
|
base_url
|
|
} else {
|
|
let normalized_base = base_url.trim_end_matches('/');
|
|
format!("{}/{}", normalized_base, clean_path)
|
|
}
|
|
}
|
|
|
|
/// Process FileIngestionInfo from XML parser to set correct paths
|
|
///
|
|
/// This takes the raw XML parser output and fixes the path fields:
|
|
/// - Sets relative_path from href conversion
|
|
/// - Keeps full_path as the original href
|
|
/// - Sets legacy path field for backward compatibility
|
|
pub fn process_file_info(&self, mut file_info: FileIngestionInfo) -> FileIngestionInfo {
|
|
// The XML parser puts the href in full_path (which is correct)
|
|
let href = &file_info.full_path;
|
|
|
|
// Convert to relative path
|
|
file_info.relative_path = self.href_to_relative_path(href);
|
|
|
|
// Legacy path field should be relative for backward compatibility
|
|
#[allow(deprecated)]
|
|
{
|
|
file_info.path = file_info.relative_path.clone();
|
|
}
|
|
|
|
file_info
|
|
}
|
|
|
|
/// Process a collection of FileIngestionInfo items
|
|
pub fn process_file_infos(&self, file_infos: Vec<FileIngestionInfo>) -> Vec<FileIngestionInfo> {
|
|
file_infos.into_iter()
|
|
.map(|file_info| self.process_file_info(file_info))
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn create_nextcloud_config() -> WebDAVConfig {
|
|
WebDAVConfig {
|
|
server_url: "https://nas.example.com".to_string(),
|
|
username: "testuser".to_string(),
|
|
password: "password".to_string(),
|
|
watch_folders: vec!["/Photos".to_string()],
|
|
file_extensions: vec!["jpg".to_string(), "pdf".to_string()],
|
|
timeout_seconds: 30,
|
|
server_type: Some("nextcloud".to_string()),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_nextcloud_href_to_relative_path() {
|
|
let manager = WebDAVUrlManager::new(create_nextcloud_config());
|
|
|
|
// Test file path conversion
|
|
let href = "/remote.php/dav/files/testuser/Photos/image.jpg";
|
|
let relative = manager.href_to_relative_path(href);
|
|
assert_eq!(relative, "/Photos/image.jpg");
|
|
|
|
// Test directory path conversion
|
|
let href = "/remote.php/dav/files/testuser/Photos/";
|
|
let relative = manager.href_to_relative_path(href);
|
|
assert_eq!(relative, "/Photos/");
|
|
|
|
// Test root path
|
|
let href = "/remote.php/dav/files/testuser";
|
|
let relative = manager.href_to_relative_path(href);
|
|
assert_eq!(relative, "/");
|
|
}
|
|
|
|
#[test]
|
|
fn test_relative_path_to_url() {
|
|
let manager = WebDAVUrlManager::new(create_nextcloud_config());
|
|
|
|
// Test file URL construction
|
|
let relative = "/Photos/image.jpg";
|
|
let url = manager.relative_path_to_url(relative);
|
|
assert_eq!(url, "https://nas.example.com/remote.php/dav/files/testuser/Photos/image.jpg");
|
|
|
|
// Test root URL
|
|
let relative = "/";
|
|
let url = manager.relative_path_to_url(relative);
|
|
assert_eq!(url, "https://nas.example.com/remote.php/dav/files/testuser");
|
|
}
|
|
|
|
#[test]
|
|
fn test_process_file_info() {
|
|
let manager = WebDAVUrlManager::new(create_nextcloud_config());
|
|
|
|
let file_info = FileIngestionInfo {
|
|
relative_path: "TEMP".to_string(), // Will be overwritten
|
|
full_path: "/remote.php/dav/files/testuser/Photos/image.jpg".to_string(),
|
|
#[allow(deprecated)]
|
|
path: "OLD".to_string(), // Will be overwritten
|
|
name: "image.jpg".to_string(),
|
|
size: 1024,
|
|
mime_type: "image/jpeg".to_string(),
|
|
last_modified: None,
|
|
etag: "abc123".to_string(),
|
|
is_directory: false,
|
|
created_at: None,
|
|
permissions: None,
|
|
owner: None,
|
|
group: None,
|
|
metadata: None,
|
|
};
|
|
|
|
let processed = manager.process_file_info(file_info);
|
|
|
|
assert_eq!(processed.relative_path, "/Photos/image.jpg");
|
|
assert_eq!(processed.full_path, "/remote.php/dav/files/testuser/Photos/image.jpg");
|
|
#[allow(deprecated)]
|
|
assert_eq!(processed.path, "/Photos/image.jpg");
|
|
}
|
|
} |