Use TagDao for improved filtering
This commit is contained in:
68
src/files.rs
68
src/files.rs
@@ -24,7 +24,7 @@ use crate::tags::TagDao;
|
|||||||
use crate::video::StreamActor;
|
use crate::video::StreamActor;
|
||||||
use path_absolutize::*;
|
use path_absolutize::*;
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
use rand::{thread_rng};
|
use rand::thread_rng;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
||||||
@@ -51,54 +51,38 @@ pub async fn list_photos<TagD: TagDao, FS: FileSystemAccess>(
|
|||||||
.filter_map(|t| t.parse().ok())
|
.filter_map(|t| t.parse().ok())
|
||||||
.collect::<Vec<i32>>();
|
.collect::<Vec<i32>>();
|
||||||
|
|
||||||
let exclude_tag_ids = req.exclude_tag_ids.clone()
|
let exclude_tag_ids = req
|
||||||
|
.exclude_tag_ids
|
||||||
|
.clone()
|
||||||
.unwrap_or(String::new())
|
.unwrap_or(String::new())
|
||||||
.split(',')
|
.split(',')
|
||||||
.filter_map(|t| t.parse().ok())
|
.filter_map(|t| t.parse().ok())
|
||||||
.collect::<Vec<i32>>();
|
.collect::<Vec<i32>>();
|
||||||
|
|
||||||
return dao
|
match filter_mode {
|
||||||
.get_files_with_any_tag_ids(tag_ids.clone(), exclude_tag_ids.clone())
|
FilterMode::Any => dao.get_files_with_any_tag_ids(tag_ids.clone(), exclude_tag_ids),
|
||||||
.context(format!("Failed to get files with tag_ids: {:?}", tag_ids))
|
FilterMode::All => dao.get_files_with_all_tag_ids(tag_ids.clone(), exclude_tag_ids),
|
||||||
.map(|tagged_files| {
|
}
|
||||||
return if let Some(sort_type) = req.sort {
|
.context(format!(
|
||||||
debug!("Sorting files: {:?}", sort_type);
|
"Failed to get files with tag_ids: {:?} with filter_mode: {:?}",
|
||||||
sort(tagged_files, sort_type)
|
tag_ids, filter_mode
|
||||||
} else {
|
))
|
||||||
tagged_files
|
.map(|files| {
|
||||||
};
|
files
|
||||||
})
|
.into_iter()
|
||||||
.map(|tagged_files| match filter_mode {
|
.filter(|file_path| file_path.starts_with(search_path))
|
||||||
FilterMode::Any => tagged_files
|
.collect()
|
||||||
.iter()
|
})
|
||||||
.filter(|file| file.starts_with(search_path))
|
.map(|tagged_files| {
|
||||||
.cloned()
|
trace!("Found tagged files: {:?}", tagged_files);
|
||||||
.collect(),
|
|
||||||
FilterMode::All => tagged_files
|
|
||||||
.iter()
|
|
||||||
.filter(|&file_path| {
|
|
||||||
if !file_path.starts_with(search_path) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let file_tags = dao.get_tags_for_path(file_path).unwrap_or_default();
|
HttpResponse::Ok().json(PhotosResponse {
|
||||||
tag_ids
|
photos: tagged_files,
|
||||||
.iter()
|
dirs: vec![],
|
||||||
.all(|id| file_tags.iter().any(|tag| &tag.id == id))
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>(),
|
|
||||||
})
|
})
|
||||||
.map(|tagged_files| {
|
})
|
||||||
trace!("Found tagged files: {:?}", tagged_files);
|
.into_http_internal_err()
|
||||||
|
.unwrap_or_else(|e| e.error_response());
|
||||||
HttpResponse::Ok().json(PhotosResponse {
|
|
||||||
photos: tagged_files,
|
|
||||||
dirs: vec![],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.into_http_internal_err()
|
|
||||||
.unwrap_or_else(|e| e.error_response());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
src/main.rs
21
src/main.rs
@@ -282,7 +282,7 @@ async fn favorites(
|
|||||||
.expect("Unable to get FavoritesDao")
|
.expect("Unable to get FavoritesDao")
|
||||||
.get_favorites(claims.sub.parse::<i32>().unwrap())
|
.get_favorites(claims.sub.parse::<i32>().unwrap())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Ok(favorites)) => {
|
Ok(Ok(favorites)) => {
|
||||||
let favorites = favorites
|
let favorites = favorites
|
||||||
@@ -317,7 +317,7 @@ async fn put_add_favorite(
|
|||||||
.expect("Unable to get FavoritesDao")
|
.expect("Unable to get FavoritesDao")
|
||||||
.add_favorite(user_id, &path)
|
.add_favorite(user_id, &path)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Err(e)) if e.kind == DbErrorKind::AlreadyExists => {
|
Ok(Err(e)) if e.kind == DbErrorKind::AlreadyExists => {
|
||||||
debug!("Favorite: {} exists for user: {}", &body.path, user_id);
|
debug!("Favorite: {} exists for user: {}", &body.path, user_id);
|
||||||
@@ -356,8 +356,8 @@ async fn delete_favorite(
|
|||||||
.expect("Unable to get favorites dao")
|
.expect("Unable to get favorites dao")
|
||||||
.remove_favorite(user_id, path);
|
.remove_favorite(user_id, path);
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Removing favorite \"{}\" for userid: {}",
|
"Removing favorite \"{}\" for userid: {}",
|
||||||
@@ -391,7 +391,7 @@ fn create_thumbnails() {
|
|||||||
.parent()
|
.parent()
|
||||||
.unwrap_or_else(|| panic!("Thumbnail {:?} has no parent?", thumb_path)),
|
.unwrap_or_else(|| panic!("Thumbnail {:?} has no parent?", thumb_path)),
|
||||||
)
|
)
|
||||||
.expect("Error creating directory");
|
.expect("Error creating directory");
|
||||||
|
|
||||||
debug!("Generating video thumbnail: {:?}", thumb_path);
|
debug!("Generating video thumbnail: {:?}", thumb_path);
|
||||||
generate_video_thumbnail(entry.path(), &thumb_path);
|
generate_video_thumbnail(entry.path(), &thumb_path);
|
||||||
@@ -526,10 +526,10 @@ fn main() -> std::io::Result<()> {
|
|||||||
.app_data::<Data<Mutex<SqliteTagDao>>>(Data::new(Mutex::new(tag_dao)))
|
.app_data::<Data<Mutex<SqliteTagDao>>>(Data::new(Mutex::new(tag_dao)))
|
||||||
.wrap(prometheus.clone())
|
.wrap(prometheus.clone())
|
||||||
})
|
})
|
||||||
.bind(dotenv::var("BIND_URL").unwrap())?
|
.bind(dotenv::var("BIND_URL").unwrap())?
|
||||||
.bind("localhost:8088")?
|
.bind("localhost:8088")?
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,7 +548,8 @@ fn watch_files() {
|
|||||||
let base_str = dotenv::var("BASE_PATH").unwrap();
|
let base_str = dotenv::var("BASE_PATH").unwrap();
|
||||||
let base_path = Path::new(&base_str);
|
let base_path = Path::new(&base_str);
|
||||||
|
|
||||||
watcher.watch(base_path, RecursiveMode::Recursive)
|
watcher
|
||||||
|
.watch(base_path, RecursiveMode::Recursive)
|
||||||
.context(format!("Unable to watch BASE_PATH: '{}'", base_str))
|
.context(format!("Unable to watch BASE_PATH: '{}'", base_str))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
16
src/tags.rs
16
src/tags.rs
@@ -198,7 +198,11 @@ pub trait TagDao {
|
|||||||
fn create_tag(&mut self, name: &str) -> anyhow::Result<Tag>;
|
fn create_tag(&mut self, name: &str) -> anyhow::Result<Tag>;
|
||||||
fn remove_tag(&mut self, tag_name: &str, path: &str) -> anyhow::Result<Option<()>>;
|
fn remove_tag(&mut self, tag_name: &str, path: &str) -> anyhow::Result<Option<()>>;
|
||||||
fn tag_file(&mut self, path: &str, tag_id: i32) -> anyhow::Result<TaggedPhoto>;
|
fn tag_file(&mut self, path: &str, tag_id: i32) -> anyhow::Result<TaggedPhoto>;
|
||||||
fn get_files_with_all_tag_ids(&mut self, tag_ids: Vec<i32>) -> anyhow::Result<Vec<String>>;
|
fn get_files_with_all_tag_ids(
|
||||||
|
&mut self,
|
||||||
|
tag_ids: Vec<i32>,
|
||||||
|
exclude_tag_ids: Vec<i32>,
|
||||||
|
) -> anyhow::Result<Vec<String>>;
|
||||||
fn get_files_with_any_tag_ids(
|
fn get_files_with_any_tag_ids(
|
||||||
&mut self,
|
&mut self,
|
||||||
tag_ids: Vec<i32>,
|
tag_ids: Vec<i32>,
|
||||||
@@ -345,11 +349,16 @@ impl TagDao for SqliteTagDao {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_files_with_all_tag_ids(&mut self, tag_ids: Vec<i32>) -> anyhow::Result<Vec<String>> {
|
fn get_files_with_all_tag_ids(
|
||||||
|
&mut self,
|
||||||
|
tag_ids: Vec<i32>,
|
||||||
|
exclude_tag_ids: Vec<i32>,
|
||||||
|
) -> anyhow::Result<Vec<String>> {
|
||||||
use diesel::dsl::*;
|
use diesel::dsl::*;
|
||||||
|
|
||||||
tagged_photo::table
|
tagged_photo::table
|
||||||
.filter(tagged_photo::tag_id.eq_any(tag_ids.clone()))
|
.filter(tagged_photo::tag_id.eq_any(tag_ids.clone()))
|
||||||
|
.filter(tagged_photo::tag_id.ne_all(exclude_tag_ids))
|
||||||
.group_by(tagged_photo::photo_name)
|
.group_by(tagged_photo::photo_name)
|
||||||
.select((tagged_photo::photo_name, count(tagged_photo::tag_id)))
|
.select((tagged_photo::photo_name, count(tagged_photo::tag_id)))
|
||||||
.having(count_distinct(tagged_photo::tag_id).eq(tag_ids.len() as i64))
|
.having(count_distinct(tagged_photo::tag_id).eq(tag_ids.len() as i64))
|
||||||
@@ -496,7 +505,8 @@ mod tests {
|
|||||||
|
|
||||||
fn get_files_with_all_tag_ids(
|
fn get_files_with_all_tag_ids(
|
||||||
&mut self,
|
&mut self,
|
||||||
_tag_ids: Vec<i32>,
|
tag_ids: Vec<i32>,
|
||||||
|
exclude_tag_ids: Vec<i32>,
|
||||||
) -> anyhow::Result<Vec<String>> {
|
) -> anyhow::Result<Vec<String>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user