From ccd16ba9877d01036fde1a1e403d95cfab3916bd Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 26 Dec 2025 22:20:01 -0500 Subject: [PATCH] Files endpoint refactoring --- src/files.rs | 178 +++++++++++++++++++++------------------------------ 1 file changed, 73 insertions(+), 105 deletions(-) diff --git a/src/files.rs b/src/files.rs index bf0260a..a23b226 100644 --- a/src/files.rs +++ b/src/files.rs @@ -43,6 +43,56 @@ pub struct FileWithMetadata { } use serde::Deserialize; +/// Apply sorting to files with EXIF data support for date-based sorting +/// Handles both date sorting (with EXIF/filename fallback) and regular sorting +fn apply_sorting_with_exif( + files: Vec, + sort_type: SortType, + exif_dao: &mut Box, + span_context: &opentelemetry::Context, +) -> Vec { + match sort_type { + SortType::DateTakenAsc | SortType::DateTakenDesc => { + info!("Date sorting requested, fetching EXIF data"); + + // Collect file paths for batch EXIF query + let file_paths: Vec = files.iter().map(|f| f.file_name.clone()).collect(); + + // Batch fetch EXIF data + let exif_map: std::collections::HashMap = exif_dao + .get_exif_batch(span_context, &file_paths) + .unwrap_or_default() + .into_iter() + .filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt))) + .collect(); + + // Convert to FileWithMetadata with date fallback logic + let files_with_metadata: Vec = files + .into_iter() + .map(|f| { + // Try EXIF date first + let date_taken = exif_map.get(&f.file_name).copied().or_else(|| { + // Fallback to filename extraction + extract_date_from_filename(&f.file_name).map(|dt| dt.timestamp()) + }); + + FileWithMetadata { + file_name: f.file_name, + tag_count: f.tag_count, + date_taken, + } + }) + .collect(); + + sort_with_metadata(files_with_metadata, sort_type) + } + _ => { + // Use regular sort for non-date sorting + sort(files, sort_type) + } + } +} + pub async fn list_photos( _: Claims, request: HttpRequest, @@ -264,51 +314,13 @@ pub async fn list_photos( .collect::>() }) .map(|files| { - // Handle sorting - use FileWithMetadata for date sorting to support EXIF dates + // Handle sorting - use helper function that supports EXIF date sorting let sort_type = req.sort.unwrap_or(NameAsc); - match sort_type { - SortType::DateTakenAsc | SortType::DateTakenDesc => { - info!("Date sorting requested in tagged/recursive search, fetching EXIF data"); - - // Collect file paths for batch EXIF query - let file_paths: Vec = - files.iter().map(|f| f.file_name.clone()).collect(); - - // Batch fetch EXIF data - let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao"); - let exif_map: std::collections::HashMap = exif_dao_guard - .get_exif_batch(&span_context, &file_paths) - .unwrap_or_default() - .into_iter() - .filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt))) - .collect(); - drop(exif_dao_guard); - - // Convert to FileWithMetadata with date fallback logic - let files_with_metadata: Vec = files - .into_iter() - .map(|f| { - // Try EXIF date first - let date_taken = exif_map.get(&f.file_name).copied().or_else(|| { - // Fallback to filename extraction - extract_date_from_filename(&f.file_name).map(|dt| dt.timestamp()) - }); - - FileWithMetadata { - file_name: f.file_name, - tag_count: f.tag_count, - date_taken, - } - }) - .collect(); - - sort_with_metadata(files_with_metadata, sort_type) - } - _ => { - // Use regular sort for non-date sorting - sort(files, sort_type) - } - } + let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao"); + let result = + apply_sorting_with_exif(files, sort_type, &mut exif_dao_guard, &span_context); + drop(exif_dao_guard); + result }) .inspect(|files| debug!("Found {:?} files", files.len())) .map(|tagged_files: Vec| { @@ -439,53 +451,13 @@ pub async fn list_photos( info!("After all filters, {} files remain", photos.len()); - // Handle sorting - use FileWithMetadata for date sorting to support EXIF dates + // Handle sorting - use helper function that supports EXIF date sorting let response_files = if let Some(sort_type) = req.sort { - match sort_type { - SortType::DateTakenAsc | SortType::DateTakenDesc => { - info!("Date sorting requested, fetching EXIF data"); - - // Collect file paths for batch EXIF query - let file_paths: Vec = - photos.iter().map(|f| f.file_name.clone()).collect(); - - // Batch fetch EXIF data - let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao"); - let exif_map: std::collections::HashMap = exif_dao_guard - .get_exif_batch(&span_context, &file_paths) - .unwrap_or_default() - .into_iter() - .filter_map(|exif| exif.date_taken.map(|dt| (exif.file_path, dt))) - .collect(); - drop(exif_dao_guard); - - // Convert to FileWithMetadata with date fallback logic - let files_with_metadata: Vec = photos - .into_iter() - .map(|f| { - // Try EXIF date first - let date_taken = - exif_map.get(&f.file_name).copied().or_else(|| { - // Fallback to filename extraction - extract_date_from_filename(&f.file_name) - .map(|dt| dt.timestamp()) - }); - - FileWithMetadata { - file_name: f.file_name, - tag_count: f.tag_count, - date_taken, - } - }) - .collect(); - - sort_with_metadata(files_with_metadata, sort_type) - } - _ => { - // Use regular sort for non-date sorting - sort(photos, sort_type) - } - } + let mut exif_dao_guard = exif_dao.lock().expect("Unable to get ExifDao"); + let result = + apply_sorting_with_exif(photos, sort_type, &mut exif_dao_guard, &span_context); + drop(exif_dao_guard); + result } else { // No sorting requested photos @@ -540,9 +512,9 @@ fn sort(mut files: Vec, sort_type: SortType) -> Vec { files.sort_by(|l, r| r.tag_count.cmp(&l.tag_count)); } SortType::DateTakenAsc | SortType::DateTakenDesc => { - // Date sorting not yet implemented for FileWithTagCount - // Will be implemented when integrating with FileWithMetadata - // For now, fall back to name sorting + // Date sorting not implemented for FileWithTagCount + // We shouldn't be hitting this code + warn!("Date sorting not implemented for FileWithTagCount"); files.sort_by(|l, r| l.file_name.cmp(&r.file_name)); } } @@ -569,26 +541,22 @@ fn sort_with_metadata(mut files: Vec, sort_type: SortType) -> SortType::TagCountDesc => { files.sort_by(|l, r| r.tag_count.cmp(&l.tag_count)); } - SortType::DateTakenAsc => { + SortType::DateTakenAsc | SortType::DateTakenDesc => { files.sort_by(|l, r| { match (l.date_taken, r.date_taken) { - (Some(a), Some(b)) => a.cmp(&b), + (Some(a), Some(b)) => { + if sort_type == SortType::DateTakenAsc { + a.cmp(&b) + } else { + b.cmp(&a) + } + } (Some(_), None) => std::cmp::Ordering::Less, // Dated photos first (None, Some(_)) => std::cmp::Ordering::Greater, (None, None) => l.file_name.cmp(&r.file_name), // Fallback to name } }); } - SortType::DateTakenDesc => { - files.sort_by(|l, r| { - match (l.date_taken, r.date_taken) { - (Some(a), Some(b)) => b.cmp(&a), // Reverse for descending - (Some(_), None) => std::cmp::Ordering::Less, // Dated photos first - (None, Some(_)) => std::cmp::Ordering::Greater, - (None, None) => r.file_name.cmp(&l.file_name), // Fallback reversed - } - }); - } } files