feature/tagging #16

Merged
cameron merged 22 commits from feature/tagging into master 2023-04-10 12:55:28 +00:00
3 changed files with 41 additions and 9 deletions
Showing only changes of commit 7d05c9b8bf - Show all commits

View File

@@ -100,6 +100,19 @@ pub struct PhotosResponse {
pub dirs: Vec<String>, pub dirs: Vec<String>,
} }
#[derive(Deserialize)]
pub struct FilesRequest {
pub path: String,
pub tag_ids: Option<Vec<i32>>,
pub tag_filter_mode: Option<FilterMode>,
}
#[derive(Copy, Clone, Deserialize)]
pub enum FilterMode {
Any,
All,
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ThumbnailRequest { pub struct ThumbnailRequest {
pub path: String, pub path: String,

View File

@@ -2,6 +2,7 @@ use std::fmt::Debug;
use std::fs::read_dir; use std::fs::read_dir;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Mutex;
use ::anyhow; use ::anyhow;
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
@@ -10,18 +11,19 @@ use actix_web::{
web::{self, Query}, web::{self, Query},
HttpResponse, HttpResponse,
}; };
use log::{debug, error}; use log::{debug, error};
use crate::data::{Claims, PhotosResponse, ThumbnailRequest}; use crate::data::{Claims, FilesRequest, FilterMode, PhotosResponse, ThumbnailRequest};
use crate::AppState; use crate::AppState;
use crate::tags::TagDao;
use path_absolutize::*; use path_absolutize::*;
pub async fn list_photos( pub async fn list_photos<TagD: TagDao>(
_: Claims, _: Claims,
req: Query<ThumbnailRequest>, req: Query<FilesRequest>,
app_state: web::Data<AppState>, app_state: web::Data<AppState>,
tag_dao: web::Data<Mutex<TagD>>,
) -> HttpResponse { ) -> HttpResponse {
let path = &req.path; let path = &req.path;
if let Some(path) = is_valid_full_path(&PathBuf::from(&app_state.base_path), path) { if let Some(path) = is_valid_full_path(&PathBuf::from(&app_state.base_path), path) {
@@ -44,6 +46,19 @@ pub async fn list_photos(
relative.to_path_buf() relative.to_path_buf()
}) })
.map(|f| f.to_str().unwrap().to_string()) .map(|f| f.to_str().unwrap().to_string())
.filter(|path| {
if let (Some(tag_ids), Ok(mut tag_dao)) = (&req.tag_ids, tag_dao.lock()) {
let filter_mode = &req.tag_filter_mode.unwrap_or(FilterMode::Any);
let file_tags = tag_dao.get_tags_for_path(path).unwrap_or_default();
return match filter_mode {
FilterMode::Any => file_tags.iter().any(|t| tag_ids.contains(&t.id)),
FilterMode::All => file_tags.iter().all(|t| tag_ids.contains(&t.id)),
};
}
true
})
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let dirs = files let dirs = files
@@ -153,6 +168,8 @@ mod tests {
}; };
use std::{fs, sync::Arc}; use std::{fs, sync::Arc};
use actix_web::web::Data;
use crate::tags::SqliteTagDao;
fn setup() { fn setup() {
let _ = env_logger::builder().is_test(true).try_init(); let _ = env_logger::builder().is_test(true).try_init();
@@ -167,7 +184,7 @@ mod tests {
exp: 12345, exp: 12345,
}; };
let request: Query<ThumbnailRequest> = Query::from_query("path=").unwrap(); let request: Query<FilesRequest> = Query::from_query("path=").unwrap();
let mut temp_photo = std::env::temp_dir(); let mut temp_photo = std::env::temp_dir();
let mut tmp = temp_photo.clone(); let mut tmp = temp_photo.clone();
@@ -187,8 +204,9 @@ mod tests {
String::from("/tmp"), String::from("/tmp"),
String::from("/tmp/thumbs"), String::from("/tmp/thumbs"),
)), )),
Data::new(Mutex::new(SqliteTagDao::default())),
) )
.await; .await;
let status = response.status(); let status = response.status();
let body: PhotosResponse = serde_json::from_str(&response.read_to_str()).unwrap(); let body: PhotosResponse = serde_json::from_str(&response.read_to_str()).unwrap();
@@ -215,7 +233,7 @@ mod tests {
exp: 12345, exp: 12345,
}; };
let request: Query<ThumbnailRequest> = Query::from_query("path=..").unwrap(); let request: Query<FilesRequest> = Query::from_query("path=..").unwrap();
let response = list_photos( let response = list_photos(
claims, claims,
@@ -225,8 +243,9 @@ mod tests {
String::from("/tmp"), String::from("/tmp"),
String::from("/tmp/thumbs"), String::from("/tmp/thumbs"),
)), )),
Data::new(Mutex::new(SqliteTagDao::default())),
) )
.await; .await;
assert_eq!(response.status(), 400); assert_eq!(response.status(), 400);
} }

View File

@@ -474,7 +474,7 @@ fn main() -> std::io::Result<()> {
App::new() App::new()
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.service(web::resource("/login").route(web::post().to(login::<SqliteUserDao>))) .service(web::resource("/login").route(web::post().to(login::<SqliteUserDao>)))
.service(web::resource("/photos").route(web::get().to(files::list_photos))) .service(web::resource("/photos").route(web::get().to(files::list_photos::<SqliteTagDao>)))
.service(get_image) .service(get_image)
.service(upload_image) .service(upload_image)
.service(generate_video) .service(generate_video)