feature/tagging #16
@@ -2,7 +2,7 @@ use crate::database::schema::{favorites, users};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "users"]
|
||||
#[diesel(table_name = users)]
|
||||
pub struct InsertUser<'a> {
|
||||
pub username: &'a str,
|
||||
pub password: &'a str,
|
||||
@@ -17,7 +17,7 @@ pub struct User {
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "favorites"]
|
||||
#[diesel(table_name = favorites)]
|
||||
pub struct InsertFavorite<'a> {
|
||||
pub userid: &'a i32,
|
||||
pub path: &'a str,
|
||||
|
||||
14
src/files.rs
14
src/files.rs
@@ -184,13 +184,8 @@ impl FileSystemAccess for RealFileSystem {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::database::connect;
|
||||
use crate::tags::SqliteTagDao;
|
||||
use actix_web::web::Data;
|
||||
use diesel::{Connection, SqliteConnection};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
|
||||
use super::*;
|
||||
@@ -342,7 +337,7 @@ mod tests {
|
||||
let mut tag_dao = SqliteTagDao::new(in_memory_db_connection());
|
||||
|
||||
let tag1 = tag_dao.create_tag("tag1").unwrap();
|
||||
let tag2 = tag_dao.create_tag("tag2").unwrap();
|
||||
let _tag2 = tag_dao.create_tag("tag2").unwrap();
|
||||
let tag3 = tag_dao.create_tag("tag3").unwrap();
|
||||
|
||||
let _ = &tag_dao.tag_file("test.jpg", tag1.id).unwrap();
|
||||
@@ -409,8 +404,11 @@ mod tests {
|
||||
],
|
||||
);
|
||||
|
||||
let request: Query<FilesRequest> =
|
||||
Query::from_query("path=&tag_ids=1,3&tag_filter_mode=All").unwrap();
|
||||
let request: Query<FilesRequest> = Query::from_query(&*format!(
|
||||
"path=&tag_ids={},{}&tag_filter_mode=All",
|
||||
tag1.id, tag3.id
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let response: HttpResponse = list_photos(
|
||||
claims,
|
||||
|
||||
39
src/main.rs
39
src/main.rs
@@ -216,7 +216,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).is_some() {
|
||||
if !playlist.starts_with("tmp") && is_valid_full_path(&app_state.base_path, playlist).is_some()
|
||||
{
|
||||
HttpResponse::BadRequest().finish()
|
||||
} else if let Ok(file) = NamedFile::open(playlist) {
|
||||
file.into_response(&request)
|
||||
@@ -354,27 +355,21 @@ fn create_thumbnails() {
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| entry.file_type().is_file())
|
||||
.filter(|entry| {
|
||||
debug!("{:?}", entry.path());
|
||||
if let Some(ext) = entry
|
||||
.path()
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str().map(|ext| ext.to_lowercase()))
|
||||
{
|
||||
if ext == "mp4" || ext == "mov" {
|
||||
let relative_path = &entry.path().strip_prefix(&images).unwrap();
|
||||
let thumb_path = Path::new(thumbnail_directory).join(relative_path);
|
||||
std::fs::create_dir_all(thumb_path.parent().unwrap_or_else(|| panic!("Thumbnail {:?} has no parent?", thumb_path)))
|
||||
.expect("Error creating directory");
|
||||
if is_video(entry) {
|
||||
let relative_path = &entry.path().strip_prefix(&images).unwrap();
|
||||
let thumb_path = Path::new(thumbnail_directory).join(relative_path);
|
||||
std::fs::create_dir_all(
|
||||
thumb_path
|
||||
.parent()
|
||||
.unwrap_or_else(|| panic!("Thumbnail {:?} has no parent?", thumb_path)),
|
||||
)
|
||||
.expect("Error creating directory");
|
||||
|
||||
debug!("Generating video thumbnail: {:?}", thumb_path);
|
||||
generate_video_thumbnail(entry.path(), &thumb_path);
|
||||
false
|
||||
} else {
|
||||
is_image(entry)
|
||||
}
|
||||
} else {
|
||||
error!("Unable to get extension for file: {:?}", entry.path());
|
||||
debug!("Generating video thumbnail: {:?}", thumb_path);
|
||||
generate_video_thumbnail(entry.path(), &thumb_path);
|
||||
false
|
||||
} else {
|
||||
is_image(entry)
|
||||
}
|
||||
})
|
||||
.filter(|entry| {
|
||||
@@ -490,7 +485,9 @@ fn main() -> std::io::Result<()> {
|
||||
.service(get_file_metadata)
|
||||
.add_feature(add_tag_services::<_, SqliteTagDao>)
|
||||
.app_data(app_data.clone())
|
||||
.app_data::<Data<RealFileSystem>>(Data::new(RealFileSystem::new(app_data.base_path.clone())))
|
||||
.app_data::<Data<RealFileSystem>>(Data::new(RealFileSystem::new(
|
||||
app_data.base_path.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(
|
||||
favorites_dao,
|
||||
|
||||
38
src/tags.rs
38
src/tags.rs
@@ -92,8 +92,7 @@ async fn update_tags<D: TagDao>(
|
||||
) -> impl Responder {
|
||||
let mut dao = tag_dao.lock().expect("Unable to get TagDao");
|
||||
|
||||
dao
|
||||
.get_tags_for_path(&request.file_name)
|
||||
dao.get_tags_for_path(&request.file_name)
|
||||
.and_then(|existing_tags| dao.get_all_tags().map(|all| (existing_tags, all)))
|
||||
.map(|(existing_tags, all_tags)| {
|
||||
let tags_to_remove = existing_tags
|
||||
@@ -144,14 +143,14 @@ pub struct Tag {
|
||||
}
|
||||
|
||||
#[derive(Insertable, Clone, Debug)]
|
||||
#[table_name = "tags"]
|
||||
#[diesel(table_name = tags)]
|
||||
pub struct InsertTag {
|
||||
pub name: String,
|
||||
pub created_time: i64,
|
||||
}
|
||||
|
||||
#[derive(Insertable, Clone, Debug)]
|
||||
#[table_name = "tagged_photo"]
|
||||
#[diesel(table_name = tagged_photo)]
|
||||
pub struct InsertTaggedPhoto {
|
||||
pub tag_id: i32,
|
||||
pub photo_name: String,
|
||||
@@ -220,15 +219,13 @@ impl TagDao for SqliteTagDao {
|
||||
created_time: Utc::now().timestamp(),
|
||||
})
|
||||
.execute(&mut self.connection)
|
||||
.with_context(|| "Unable to insert tag in Sqlite")
|
||||
.with_context(|| format!("Unable to insert tag {:?} in Sqlite", name))
|
||||
.and_then(|_| {
|
||||
debug!("Inserted tag: {:?}", name);
|
||||
no_arg_sql_function!(
|
||||
last_insert_rowid,
|
||||
diesel::sql_types::Integer,
|
||||
"Represents the SQL last_insert_row() function"
|
||||
);
|
||||
diesel::select(last_insert_rowid)
|
||||
info!("Inserted tag: {:?}", name);
|
||||
sql_function! {
|
||||
fn last_insert_rowid() -> diesel::sql_types::Integer;
|
||||
}
|
||||
diesel::select(last_insert_rowid())
|
||||
.get_result::<i32>(&mut self.connection)
|
||||
.with_context(|| "Unable to get last inserted tag from Sqlite")
|
||||
})
|
||||
@@ -238,7 +235,9 @@ impl TagDao for SqliteTagDao {
|
||||
.filter(tags::id.eq(id))
|
||||
.select((tags::id, tags::name, tags::created_time))
|
||||
.get_result::<Tag>(self.connection.borrow_mut())
|
||||
.with_context(|| "Unable to get tagged photo from Sqlite")
|
||||
.with_context(|| {
|
||||
format!("Unable to get tagged photo with id: {:?} from Sqlite", id)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -275,18 +274,15 @@ impl TagDao for SqliteTagDao {
|
||||
.execute(self.connection.borrow_mut())
|
||||
.with_context(|| format!("Unable to tag file {:?} in sqlite", path))
|
||||
.and_then(|_| {
|
||||
debug!("Inserted tagged photo: {:#} -> {:?}", tag_id, path);
|
||||
no_arg_sql_function!(
|
||||
last_insert_rowid,
|
||||
diesel::sql_types::Integer,
|
||||
"Represents the SQL last_insert_row() function"
|
||||
);
|
||||
diesel::select(last_insert_rowid)
|
||||
info!("Inserted tagged photo: {:#} -> {:?}", tag_id, path);
|
||||
sql_function! {
|
||||
fn last_insert_rowid() -> diesel::sql_types::Integer;
|
||||
}
|
||||
diesel::select(last_insert_rowid())
|
||||
.get_result::<i32>(&mut self.connection)
|
||||
.with_context(|| "Unable to get last inserted tag from Sqlite")
|
||||
})
|
||||
.and_then(|tagged_id| {
|
||||
debug!("Inserted tagged photo: {:?}", tagged_id);
|
||||
tagged_photo::table
|
||||
.find(tagged_id)
|
||||
.first(self.connection.borrow_mut())
|
||||
|
||||
Reference in New Issue
Block a user