From a9109fc52d9d52bb89563715d27cf652cfe5c4ee Mon Sep 17 00:00:00 2001 From: Cameron Cordes Date: Sat, 25 Mar 2023 20:52:51 -0400 Subject: [PATCH] Add the ability to query files by tags independent of file path --- src/data/mod.rs | 2 +- src/files.rs | 29 +++++++++++++++++++++++++++++ src/tags.rs | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/data/mod.rs b/src/data/mod.rs index bc93e7e..063e8bf 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -107,7 +107,7 @@ pub struct FilesRequest { pub tag_filter_mode: Option, } -#[derive(Copy, Clone, Deserialize)] +#[derive(Copy, Clone, Deserialize, PartialEq)] pub enum FilterMode { Any, All, diff --git a/src/files.rs b/src/files.rs index a6ac3d9..8f64730 100644 --- a/src/files.rs +++ b/src/files.rs @@ -16,6 +16,7 @@ use log::{debug, error}; use crate::data::{Claims, FilesRequest, FilterMode, PhotosResponse}; use crate::AppState; +use crate::error::IntoHttpError; use crate::tags::TagDao; use path_absolutize::*; @@ -28,6 +29,34 @@ pub async fn list_photos( ) -> HttpResponse { let path = &req.path; + if let (Some(tag_ids), Some(filter_mode)) = (&req.tag_ids, &req.tag_filter_mode) { + if *filter_mode == FilterMode::All { + let mut dao = tag_dao.lock().expect("Unable to get TagDao"); + let tag_ids = tag_ids + .split(',') + .filter_map(|t| t.parse().ok()) + .collect::>(); + + return dao + .get_files_with_tag_ids(tag_ids.clone()) + .map(|tagged_file| { + tagged_file + .iter() + .map(|photo_name| photo_name.clone()) + .collect() + }) + .context(format!("Failed to files with tag_ids: {:?}", tag_ids)) + .map(|tagged_files| { + HttpResponse::Ok().json(PhotosResponse { + photos: tagged_files, + dirs: vec![], + }) + }) + .into_http_internal_err() + .unwrap_or_else(|e| e.error_response()); + } + } + if let Ok(files) = file_system.get_files_for_path(path) { debug!("Valid path: {:?}", path); diff --git a/src/tags.rs b/src/tags.rs index 40bfb1e..da1c268 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -177,6 +177,7 @@ pub trait TagDao { fn create_tag(&mut self, name: &str) -> anyhow::Result; fn remove_tag(&mut self, tag_name: &str, path: &str) -> anyhow::Result>; fn tag_file(&mut self, path: &str, tag_id: i32) -> anyhow::Result; + fn get_files_with_tag_ids(&mut self, tag_ids: Vec) -> anyhow::Result>; } pub struct SqliteTagDao { @@ -294,6 +295,19 @@ impl TagDao for SqliteTagDao { }) }) } + + fn get_files_with_tag_ids(&mut self, tag_ids: Vec) -> anyhow::Result> { + use diesel::dsl::*; + + tagged_photo::table + .filter(tagged_photo::tag_id.eq_any(tag_ids.clone())) + .group_by(tagged_photo::photo_name) + .select((tagged_photo::photo_name, count(tagged_photo::tag_id))) + .having(count(tagged_photo::tag_id).eq(tag_ids.len() as i64)) + .select(tagged_photo::photo_name) + .get_results::(&mut self.connection) + .with_context(|| format!("Unable to get Tagged photos with ids: {:?}", tag_ids)) + } } #[cfg(test)] @@ -407,6 +421,10 @@ mod tests { Err(NotFound.into()) } } + + fn get_files_with_tag_ids(&mut self, _tag_ids: Vec) -> anyhow::Result> { + todo!() + } } #[actix_rt::test]