Add Endpoint for Batch add/removal of tags on a file
This commit is contained in:
@@ -489,6 +489,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
.route(web::delete().to(remove_tagged_photo::<SqliteTagDao>)),
|
.route(web::delete().to(remove_tagged_photo::<SqliteTagDao>)),
|
||||||
)
|
)
|
||||||
.service(web::resource("image/tags/all").route(web::get().to(get_all_tags::<SqliteTagDao>)))
|
.service(web::resource("image/tags/all").route(web::get().to(get_all_tags::<SqliteTagDao>)))
|
||||||
|
.service(web::resource("image/tags/batch").route(web::post().to(update_tags::<SqliteTagDao>)))
|
||||||
.app_data(app_data.clone())
|
.app_data(app_data.clone())
|
||||||
.app_data::<Data<Mutex<SqliteUserDao>>>(Data::new(Mutex::new(user_dao)))
|
.app_data::<Data<Mutex<SqliteUserDao>>>(Data::new(Mutex::new(user_dao)))
|
||||||
.app_data::<Data<Mutex<Box<dyn FavoriteDao>>>>(Data::new(Mutex::new(Box::new(
|
.app_data::<Data<Mutex<Box<dyn FavoriteDao>>>>(Data::new(Mutex::new(Box::new(
|
||||||
|
|||||||
51
src/tags.rs
51
src/tags.rs
@@ -5,7 +5,7 @@ use chrono::Utc;
|
|||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use schema::{tagged_photo, tags};
|
use schema::{tagged_photo, tags};
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
@@ -70,7 +70,42 @@ pub async fn remove_tagged_photo<D: TagDao>(
|
|||||||
.into_http_internal_err()
|
.into_http_internal_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Queryable, Clone, Debug)]
|
pub async fn update_tags<D: TagDao>(_: Claims, tag_dao: web::Data<Mutex<D>>, request: web::Json<AddTagsRequest>) -> impl Responder {
|
||||||
|
let mut dao = tag_dao.lock()
|
||||||
|
.expect("Unable to get TagDao");
|
||||||
|
|
||||||
|
return dao.get_tags_for_path(&request.file_name)
|
||||||
|
.and_then(|existing_tags| {
|
||||||
|
dao.get_all_tags().map(|all| (existing_tags, all))
|
||||||
|
})
|
||||||
|
.and_then(|(existing_tags, all_tags)| {
|
||||||
|
let tags_to_remove = existing_tags.iter()
|
||||||
|
.filter(|&t| !request.tag_ids.contains(&t.id))
|
||||||
|
.collect::<Vec<&Tag>>();
|
||||||
|
|
||||||
|
for tag in tags_to_remove {
|
||||||
|
info!("Removing tag {:?} from file: {:?}", tag.name, request.file_name);
|
||||||
|
dao.remove_tag(&tag.name, &request.file_name)
|
||||||
|
.expect(&format!("Unable to remove tag {:?}", &tag.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_tags = all_tags.iter()
|
||||||
|
.filter(|&t| !existing_tags.contains(t) && request.tag_ids.contains(&t.id))
|
||||||
|
.collect::<Vec<&Tag>>();
|
||||||
|
|
||||||
|
for new_tag in new_tags {
|
||||||
|
info!("Adding tag {:?} to file: {:?}", new_tag.name, request.file_name);
|
||||||
|
|
||||||
|
dao.tag_file(&request.file_name, new_tag.id)
|
||||||
|
.with_context(|| format!("Unable to tag file {:?} with tag: {:?}", request.file_name, new_tag.name))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok())
|
||||||
|
}).into_http_internal_err()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Queryable, Clone, Debug, PartialEq)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -100,6 +135,12 @@ pub struct TaggedPhoto {
|
|||||||
pub created_time: i64,
|
pub created_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct AddTagsRequest {
|
||||||
|
pub file_name: String,
|
||||||
|
pub tag_ids: Vec<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait TagDao {
|
pub trait TagDao {
|
||||||
fn get_all_tags(&mut self) -> anyhow::Result<Vec<Tag>>;
|
fn get_all_tags(&mut self) -> anyhow::Result<Vec<Tag>>;
|
||||||
fn get_tags_for_path(&mut self, path: &str) -> anyhow::Result<Vec<Tag>>;
|
fn get_tags_for_path(&mut self, path: &str) -> anyhow::Result<Vec<Tag>>;
|
||||||
@@ -184,9 +225,9 @@ impl TagDao for SqliteTagDao {
|
|||||||
.filter(tagged_photo::tag_id.eq(tag.id))
|
.filter(tagged_photo::tag_id.eq(tag.id))
|
||||||
.filter(tagged_photo::photo_name.eq(path)),
|
.filter(tagged_photo::photo_name.eq(path)),
|
||||||
)
|
)
|
||||||
.execute(&mut self.connection)
|
.execute(&mut self.connection)
|
||||||
.with_context(|| format!("Unable to delete tag: '{}'", &tag.name))
|
.with_context(|| format!("Unable to delete tag: '{}'", &tag.name))
|
||||||
.map(|_| Some(()))
|
.map(|_| Some(()))
|
||||||
} else {
|
} else {
|
||||||
info!("No tag found with name '{}'", tag_name);
|
info!("No tag found with name '{}'", tag_name);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
Reference in New Issue
Block a user