feature/tagging #16
@@ -489,6 +489,7 @@ fn main() -> std::io::Result<()> {
|
||||
.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/batch").route(web::post().to(update_tags::<SqliteTagDao>)))
|
||||
.app_data(app_data.clone())
|
||||
.app_data::<Data<Mutex<SqliteUserDao>>>(Data::new(Mutex::new(user_dao)))
|
||||
.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 log::{debug, info};
|
||||
use schema::{tagged_photo, tags};
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::borrow::BorrowMut;
|
||||
use std::sync::Mutex;
|
||||
|
||||
@@ -70,7 +70,42 @@ pub async fn remove_tagged_photo<D: TagDao>(
|
||||
.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 id: i32,
|
||||
pub name: String,
|
||||
@@ -100,6 +135,12 @@ pub struct TaggedPhoto {
|
||||
pub created_time: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AddTagsRequest {
|
||||
pub file_name: String,
|
||||
pub tag_ids: Vec<i32>,
|
||||
}
|
||||
|
||||
pub trait TagDao {
|
||||
fn get_all_tags(&mut self) -> 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::photo_name.eq(path)),
|
||||
)
|
||||
.execute(&mut self.connection)
|
||||
.with_context(|| format!("Unable to delete tag: '{}'", &tag.name))
|
||||
.map(|_| Some(()))
|
||||
.execute(&mut self.connection)
|
||||
.with_context(|| format!("Unable to delete tag: '{}'", &tag.name))
|
||||
.map(|_| Some(()))
|
||||
} else {
|
||||
info!("No tag found with name '{}'", tag_name);
|
||||
Ok(None)
|
||||
|
||||
Reference in New Issue
Block a user