Add the count of tagged files to All tags endpoint #21
@@ -459,7 +459,10 @@ mod tests {
|
||||
#[test]
|
||||
fn directory_traversal_test() {
|
||||
let base = env::temp_dir();
|
||||
assert_eq!(None, is_valid_full_path(&base, &PathBuf::from("../"), false));
|
||||
assert_eq!(
|
||||
None,
|
||||
is_valid_full_path(&base, &PathBuf::from("../"), false)
|
||||
);
|
||||
assert_eq!(None, is_valid_full_path(&base, &PathBuf::from(".."), false));
|
||||
assert_eq!(
|
||||
None,
|
||||
|
||||
@@ -217,7 +217,8 @@ async fn stream_video(
|
||||
debug!("Playlist: {}", playlist);
|
||||
|
||||
// Extract video playlist dir to dotenv
|
||||
if !playlist.starts_with("tmp") && is_valid_full_path(&app_state.base_path, playlist, false).is_some()
|
||||
if !playlist.starts_with("tmp")
|
||||
&& is_valid_full_path(&app_state.base_path, playlist, false).is_some()
|
||||
{
|
||||
HttpResponse::BadRequest().finish()
|
||||
} else if let Ok(file) = NamedFile::open(playlist) {
|
||||
|
||||
48
src/tags.rs
48
src/tags.rs
@@ -3,6 +3,7 @@ use actix_web::dev::{ServiceFactory, ServiceRequest};
|
||||
use actix_web::{web, App, HttpResponse, Responder};
|
||||
use anyhow::Context;
|
||||
use chrono::Utc;
|
||||
use diesel::dsl::{count_star};
|
||||
use diesel::prelude::*;
|
||||
use log::{debug, info};
|
||||
use schema::{tagged_photo, tags};
|
||||
@@ -11,8 +12,8 @@ use std::borrow::BorrowMut;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub fn add_tag_services<T, TagD: TagDao + 'static>(app: App<T>) -> App<T>
|
||||
where
|
||||
T: ServiceFactory<ServiceRequest, Config = (), Error = actix_web::Error, InitError = ()>,
|
||||
where
|
||||
T: ServiceFactory<ServiceRequest, Config=(), Error=actix_web::Error, InitError=()>,
|
||||
{
|
||||
app.service(
|
||||
web::resource("image/tags")
|
||||
@@ -36,7 +37,7 @@ async fn add_tag<D: TagDao>(
|
||||
tag_dao
|
||||
.get_all_tags()
|
||||
.and_then(|tags| {
|
||||
if let Some(tag) = tags.iter().find(|t| t.name == tag_name) {
|
||||
if let Some((_, tag)) = tags.iter().find(|t| t.1.name == tag_name) {
|
||||
Ok(tag.clone())
|
||||
} else {
|
||||
tag_dao.create_tag(&tag_name)
|
||||
@@ -63,7 +64,12 @@ async fn get_all_tags<D: TagDao>(_: Claims, tag_dao: web::Data<Mutex<D>>) -> imp
|
||||
let mut tag_dao = tag_dao.lock().expect("Unable to get TagDao");
|
||||
tag_dao
|
||||
.get_all_tags()
|
||||
.map(|tags| HttpResponse::Ok().json(tags))
|
||||
.map(|tags| HttpResponse::Ok().json(tags.iter().map(|(tag_count, tag)|
|
||||
TagWithTagCount {
|
||||
tag: tag.clone(),
|
||||
tag_count: *tag_count,
|
||||
}
|
||||
).collect::<Vec<TagWithTagCount>>()))
|
||||
.into_http_internal_err()
|
||||
}
|
||||
|
||||
@@ -111,10 +117,10 @@ async fn update_tags<D: TagDao>(
|
||||
|
||||
let new_tags = all_tags
|
||||
.iter()
|
||||
.filter(|&t| !existing_tags.contains(t) && request.tag_ids.contains(&t.id))
|
||||
.collect::<Vec<&Tag>>();
|
||||
.filter(|(_, t)| !existing_tags.contains(t) && request.tag_ids.contains(&t.id))
|
||||
.collect::<Vec<&(i64, Tag)>>();
|
||||
|
||||
for new_tag in new_tags {
|
||||
for (_, new_tag) in new_tags {
|
||||
info!(
|
||||
"Adding tag {:?} to file: {:?}",
|
||||
new_tag.name, request.file_name
|
||||
@@ -142,6 +148,13 @@ pub struct Tag {
|
||||
pub created_time: i64,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct TagWithTagCount {
|
||||
pub tag_count: i64,
|
||||
pub tag: Tag,
|
||||
}
|
||||
|
||||
#[derive(Insertable, Clone, Debug)]
|
||||
#[diesel(table_name = tags)]
|
||||
pub struct InsertTag {
|
||||
@@ -172,7 +185,7 @@ pub struct AddTagsRequest {
|
||||
}
|
||||
|
||||
pub trait TagDao {
|
||||
fn get_all_tags(&mut self) -> anyhow::Result<Vec<Tag>>;
|
||||
fn get_all_tags(&mut self) -> anyhow::Result<Vec<(i64, Tag)>>;
|
||||
fn get_tags_for_path(&mut self, path: &str) -> anyhow::Result<Vec<Tag>>;
|
||||
fn create_tag(&mut self, name: &str) -> anyhow::Result<Tag>;
|
||||
fn remove_tag(&mut self, tag_name: &str, path: &str) -> anyhow::Result<Option<()>>;
|
||||
@@ -197,9 +210,26 @@ impl Default for SqliteTagDao {
|
||||
}
|
||||
|
||||
impl TagDao for SqliteTagDao {
|
||||
fn get_all_tags(&mut self) -> anyhow::Result<Vec<Tag>> {
|
||||
fn get_all_tags(&mut self) -> anyhow::Result<Vec<(i64, Tag)>> {
|
||||
// select name, count(*) from tags join tagged_photo ON tags.id = tagged_photo.tag_id GROUP BY tags.name ORDER BY COUNT(*);
|
||||
let (id, name, created_time) = tags::all_columns;
|
||||
tags::table
|
||||
.inner_join(tagged_photo::table)
|
||||
.group_by(tags::id)
|
||||
.select((count_star(), id, name, created_time))
|
||||
.get_results(&mut self.connection)
|
||||
.map::<Vec<(i64, Tag)>, _>(|tags_with_count: Vec<(i64, i32, String, i64)>| {
|
||||
tags_with_count.iter().map(|tup| {
|
||||
(
|
||||
tup.0,
|
||||
Tag {
|
||||
id: tup.1,
|
||||
name: tup.2.clone(),
|
||||
created_time: tup.3,
|
||||
},
|
||||
)
|
||||
}).collect()
|
||||
})
|
||||
.with_context(|| "Unable to get all tags")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user