diff --git a/mediarepo-daemon/Cargo.lock b/mediarepo-daemon/Cargo.lock index 19f822f..fddbf24 100644 --- a/mediarepo-daemon/Cargo.lock +++ b/mediarepo-daemon/Cargo.lock @@ -849,8 +849,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.5.1" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=17a7ade9a8112d3c8450ab6ea67c4f184d05744e#17a7ade9a8112d3c8450ab6ea67c4f184d05744e" +version = "0.6.0" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=ddebf4bf0c3e96ede64182ff52bd84f134acc33a#ddebf4bf0c3e96ede64182ff52bd84f134acc33a" dependencies = [ "chrono", "serde", diff --git a/mediarepo-daemon/mediarepo-model/src/file.rs b/mediarepo-daemon/mediarepo-model/src/file.rs index e17500b..c28e6fe 100644 --- a/mediarepo-daemon/mediarepo-model/src/file.rs +++ b/mediarepo-daemon/mediarepo-model/src/file.rs @@ -140,16 +140,17 @@ impl File { hash_id: i64, file_type: FileType, mime_type: Option, + creation_time: NaiveDateTime, + change_time: NaiveDateTime, ) -> RepoResult { - let now = Local::now().naive_local(); let file = file::ActiveModel { hash_id: Set(hash_id), file_type: Set(file_type as u32), mime_type: Set(mime_type), storage_id: Set(storage_id), - import_time: Set(now.clone()), - creation_time: Set(now.clone()), - change_time: Set(now), + import_time: Set(Local::now().naive_local()), + creation_time: Set(creation_time), + change_time: Set(change_time), ..Default::default() }; let file: file::ActiveModel = file.insert(&db).await?.into(); diff --git a/mediarepo-daemon/mediarepo-model/src/repo.rs b/mediarepo-daemon/mediarepo-model/src/repo.rs index 5fc14fa..8a45919 100644 --- a/mediarepo-daemon/mediarepo-model/src/repo.rs +++ b/mediarepo-daemon/mediarepo-model/src/repo.rs @@ -4,16 +4,18 @@ use crate::namespace::Namespace; use crate::storage::Storage; use crate::tag::Tag; use crate::thumbnail::Thumbnail; +use chrono::{Local, NaiveDateTime}; use mediarepo_core::error::{RepoError, RepoResult}; use mediarepo_core::thumbnailer::ThumbnailSize; use mediarepo_core::utils::parse_namespace_and_tag; use mediarepo_database::get_database; use sea_orm::DatabaseConnection; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::io::Cursor; use std::iter::FromIterator; use std::path::PathBuf; +use std::str::FromStr; use tokio::fs::OpenOptions; use tokio::io::BufReader; @@ -129,6 +131,36 @@ impl Repo { File::find_by_tags(self.db.clone(), tag_ids).await } + /// Adds a file from bytes to the database + #[tracing::instrument(level = "debug", skip(self))] + pub async fn add_file( + &self, + mime_type: Option, + content: Vec, + creation_time: NaiveDateTime, + change_time: NaiveDateTime, + ) -> RepoResult { + let storage = self.get_main_storage()?; + let reader = Cursor::new(content); + let hash = storage.store_entry(reader).await?; + + let (mime_type, file_type) = mime_type + .and_then(|m| mime::Mime::from_str(&m).ok()) + .map(|m| (Some(m.to_string()), FileType::from(m))) + .unwrap_or((None, FileType::Unknown)); + + File::add( + self.db.clone(), + storage.id(), + hash.id(), + file_type, + mime_type, + creation_time, + change_time, + ) + .await + } + /// Adds a file to the database by its readable path in the file system #[tracing::instrument(level = "debug", skip(self))] pub async fn add_file_by_path(&self, path: PathBuf) -> RepoResult { @@ -150,6 +182,8 @@ impl Repo { hash.id(), file_type, mime_type, + Local::now().naive_local(), + Local::now().naive_local(), ) .await } @@ -243,6 +277,31 @@ impl Repo { Tag::for_hash_list(self.db.clone(), hashes).await } + /// Adds all tags that are not in the database to the database and returns the ones already existing as well + #[tracing::instrument(level = "debug", skip_all)] + pub async fn add_all_tags(&self, tags: Vec<(Option, String)>) -> RepoResult> { + let mut tags_to_add = tags; + let mut existing_tags = self.tags_by_names(tags_to_add.clone()).await?; + { + let existing_tags_set = existing_tags + .iter() + .map(|t| (t.namespace().map(|n| n.name().clone()), t.name().clone())) + .collect::, String)>>(); + + tags_to_add.retain(|t| !existing_tags_set.contains(t)); + } + for (namespace, name) in tags_to_add { + let tag = if let Some(namespace) = namespace { + self.add_namespaced_tag(namespace, name).await? + } else { + self.add_unnamespaced_tag(name).await? + }; + existing_tags.push(tag); + } + + Ok(existing_tags) + } + /// Adds or finds a tag #[tracing::instrument(level = "debug", skip(self))] pub async fn add_or_find_tag(&self, tag: S) -> RepoResult { diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.lock b/mediarepo-daemon/mediarepo-socket/Cargo.lock index 09c42a8..7e4e323 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.lock +++ b/mediarepo-daemon/mediarepo-socket/Cargo.lock @@ -790,8 +790,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.5.1" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=17a7ade9a8112d3c8450ab6ea67c4f184d05744e#17a7ade9a8112d3c8450ab6ea67c4f184d05744e" +version = "0.6.0" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=ddebf4bf0c3e96ede64182ff52bd84f134acc33a#ddebf4bf0c3e96ede64182ff52bd84f134acc33a" dependencies = [ "chrono", "serde", diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.toml b/mediarepo-daemon/mediarepo-socket/Cargo.toml index 3328ee4..242db0e 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.toml +++ b/mediarepo-daemon/mediarepo-socket/Cargo.toml @@ -34,4 +34,4 @@ features = ["tokio-executor"] [dependencies.mediarepo-api] git = "https://github.com/Trivernis/mediarepo-api.git" -rev = "17a7ade9a8112d3c8450ab6ea67c4f184d05744e" \ No newline at end of file +rev = "ddebf4bf0c3e96ede64182ff52bd84f134acc33a" \ No newline at end of file diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs index cdbae40..e3c20ba 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs @@ -2,18 +2,18 @@ use crate::from_model::FromModel; use crate::utils::{file_by_identifier, get_repo_from_context}; use compare::Compare; use mediarepo_api::types::files::{ - AddFileRequest, FileMetadataResponse, FindFilesByTagsRequest, GetFileThumbnailOfSizeRequest, - GetFileThumbnailsRequest, ReadFileRequest, SortDirection, SortKey, ThumbnailMetadataResponse, - UpdateFileNameRequest, + AddFileRequestHeader, FileMetadataResponse, FindFilesByTagsRequest, + GetFileThumbnailOfSizeRequest, GetFileThumbnailsRequest, ReadFileRequest, SortDirection, + SortKey, ThumbnailMetadataResponse, UpdateFileNameRequest, }; use mediarepo_core::error::RepoError; use mediarepo_core::rmp_ipc::prelude::*; use mediarepo_core::thumbnailer::ThumbnailSize; +use mediarepo_core::utils::parse_namespace_and_tag; use mediarepo_database::queries::tags::get_hashes_with_namespaced_tags; use mediarepo_model::file::File; use std::cmp::Ordering; use std::collections::HashMap; -use std::path::PathBuf; use tokio::io::AsyncReadExt; pub struct FilesNamespace; @@ -95,10 +95,27 @@ impl FilesNamespace { /// Adds a file to the repository #[tracing::instrument(skip_all)] async fn add_file(ctx: &Context, event: Event) -> IPCResult<()> { - let request = event.data::()?; - let path = PathBuf::from(request.path); + let (request, bytes) = event + .data::>()? + .into_inner(); + let AddFileRequestHeader { metadata, tags } = request; let repo = get_repo_from_context(ctx).await; - let file = repo.add_file_by_path(path).await?; + + let mut file = repo + .add_file( + metadata.mime_type, + bytes.into_inner(), + metadata.creation_time, + metadata.change_time, + ) + .await?; + file.set_name(metadata.name).await?; + + let tags = repo + .add_all_tags(tags.into_iter().map(parse_namespace_and_tag).collect()) + .await?; + let tag_ids: Vec = tags.into_iter().map(|t| t.id()).collect(); + file.add_tags(tag_ids).await?; ctx.emitter .emit_response_to(