Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add POST media_id call #43

Merged
merged 2 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ axum = { version = "0.6.20", features = ["ws", "headers"] }
axum-test = "12.1.0"
anyhow = "1.0.72"

bytes = "1.4.0"

core_extensions = { version = "1.5.2", default_features = false, features = ["std"] }
chrono = { version = "0.4.26", features = ["serde"] }

Expand Down
1 change: 1 addition & 0 deletions crates/media/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ axum = { workspace = true, features = ["multipart"] }
hyper = { workspace = true, features = ["full"] }
tower-http.workspace = true
mime.workspace = true
bytes.workspace = true

# persistency
uuid = { workspace = true, features = ["serde"] }
Expand Down
29 changes: 12 additions & 17 deletions crates/media/src/api/routes/post_media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@
use axum::{
extract::{Multipart, State},
http::StatusCode,
response::{IntoResponse, Redirect},
Json,
};
use common::auth::user::User;
use hyper::header::LOCATION;
use hyper::HeaderMap;
use serde::{Deserialize, Serialize};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
use tracing::debug;
use tracing::{debug, info};
use uuid::Uuid;

use crate::{data::error::DataAccessError, repository::MediaRepositoryState};
Expand All @@ -42,10 +41,11 @@ pub(crate) async fn post_media(
State(repo): State<MediaRepositoryState>,
user: User,
mut multipart: Multipart,
) -> Result<(StatusCode, Json<ResponseId>), StatusCode> {
) -> Result<impl IntoResponse, StatusCode> {
info!("POST /media");

let mut name = None;
let mut date_taken = None;
let mut headers = HeaderMap::new();

while let Some(field) = multipart.next_field().await.unwrap() {
if let Some(field_name) = field.name() {
Expand Down Expand Up @@ -88,20 +88,15 @@ pub(crate) async fn post_media(
Json(ResponseId {
id: uuid.hyphenated().to_string(),
}),
))
)
.into_response())
}
Err(error) => {
match error {
DataAccessError::AlreadyExist(id) => {
// TODO: use Redirect::permanent to add a Location header to the already existing item
let location = format!("/media/{}", id);
headers.insert(LOCATION, location.parse().unwrap());

Err(StatusCode::SEE_OTHER)
}
_ => Err(StatusCode::INTERNAL_SERVER_ERROR),
Err(error) => match error {
DataAccessError::AlreadyExist(id) => {
Ok(Redirect::to(&format!("/media/{id}")).into_response())
}
}
_ => Err(StatusCode::INTERNAL_SERVER_ERROR),
},
}
}

Expand Down
62 changes: 20 additions & 42 deletions crates/media/src/api/routes/post_media_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,12 @@

use axum::extract::{Multipart, Path, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect};
use common::auth::user::User;
use hyper::header::LOCATION;
use hyper::HeaderMap;
use tempfile::tempfile;
use tokio::fs::File;
use tracing::{debug, error};
use tracing::{debug, info};
use uuid::Uuid;

use std::io::SeekFrom;
use tokio::io::{AsyncSeekExt, AsyncWriteExt};
use bytes::Bytes;

use crate::data::error::DataAccessError;
use crate::repository::MediaRepositoryState;
Expand All @@ -39,67 +35,49 @@ pub(crate) async fn post_media_id(
Path(media_id): Path<String>,
user: User,
mut multipart: Multipart,
) -> Result<String, StatusCode> {
error!("POST /media/{} user={}", media_id, user);
let mut headers = HeaderMap::new();
let tempfile = tempfile().unwrap();
let mut tempfile = File::from_std(tempfile);
) -> Result<impl IntoResponse, StatusCode> {
info!("POST /media/..");

let mut name: String = "".to_string();
while let Some(mut field) = multipart.next_field().await.unwrap() {
let mut bytes = Bytes::new();
while let Some(field) = multipart.next_field().await.unwrap() {
if let Some(field_name) = field.name() {
match field_name {
"name" => {
name = field.text().await.unwrap();
debug!("name={}", name.clone());
}
"file" => {
while let Some(chunk) = field
.chunk()
.await
.expect("Could not read file from multipart upload!")
{
tempfile
.write_all(&chunk)
.await
.expect("Could not write reference file to tmp!")
}
tempfile.seek(SeekFrom::Start(0)).await.unwrap();

// TODO: wrap bytes and write to persistence
debug!("filesize={}", field.chunk().await.unwrap().unwrap().len());
bytes = field.bytes().await.unwrap();
debug!("{} bytes received", bytes.clone().len());
}
_ => continue,
}
}
}

debug!("{} bytes received", bytes.clone().len());

let result = repo
.add_reference_for_media_item(
Uuid::parse_str(user.uuid.as_str()).unwrap(),
media_id,
&media_id,
name,
tempfile,
bytes, // tempfile,
)
.await;

match result {
Ok(uuid) => {
debug!("reference added. uuid={}", uuid.hyphenated().to_string());

Ok(uuid.hyphenated().to_string())
Ok(uuid.hyphenated().to_string().into_response())
}
Err(error) => {
match error {
DataAccessError::AlreadyExist(id) => {
// TODO: use Redirect::permanent to add a Location header to the already existing item

let location = format!("/media/{}", id);
headers.insert(LOCATION, location.parse().unwrap());

Err(StatusCode::SEE_OTHER)
}
_ => Err(StatusCode::INTERNAL_SERVER_ERROR),
Err(error) => match error {
DataAccessError::AlreadyExist(id) => {
Ok(Redirect::to(&format!("/media/{media_id}/{id}")).into_response())
}
}
_ => Err(StatusCode::INTERNAL_SERVER_ERROR),
},
}
}
47 changes: 28 additions & 19 deletions crates/media/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
use crate::data::error::DataAccessError;
use crate::data::media_item::MediaItem;
use axum::async_trait;
use bytes::Bytes;
use common::config::configuration::Configuration;
use common::database::reference::Reference;
use common::database::Database;
use database::sqlite::SqliteDatabase;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use time::OffsetDateTime;
use tokio::fs::File;
use tracing::info;
use tracing::log::warn;
use tracing::{debug, info};
use uuid::Uuid;

#[allow(dead_code)]
Expand Down Expand Up @@ -58,9 +60,9 @@ pub trait MediaRepositoryTrait {
async fn add_reference_for_media_item(
&self,
user_id: Uuid,
media_id: String,
media_id: &str,
name: String,
file: File,
bytes: Bytes,
) -> Result<Uuid, DataAccessError>;
}

Expand Down Expand Up @@ -128,29 +130,36 @@ impl MediaRepositoryTrait for MediaRepository {
async fn add_reference_for_media_item(
&self,
user_id: Uuid,
media_id: String,
media_id: &str,
name: String,
mut tmp_file: File,
bytes: Bytes,
) -> Result<Uuid, DataAccessError> {
let path = Path::new("data/files/")
.join(user_id.hyphenated().to_string())
.join(media_id.clone())
.join(name.clone());
.join(media_id);

let mut dest_file = File::create(path.clone()).await.unwrap();
let file_path = path.join(&name);
let _ = fs::create_dir_all(&path);

let num_bytes = tokio::io::copy(&mut tmp_file, &mut dest_file)
.await
.expect("Coudl not copy tmp file to path!");
println!(
"{} bytes copied to path {}",
num_bytes,
path.clone().to_string_lossy()
);
info!("target {}", path.clone().to_str().unwrap().to_string());
debug!("got {} bytes to handle", bytes.len());

let file_result = tokio::fs::write(&path.join(&name), &bytes).await;
match file_result {
Ok(_) => {
info!("wrote to {}", file_path.to_str().unwrap().to_string());
}
Err(_) => {
warn!(
"Could not write file to path {}",
path.clone().to_str().unwrap().to_string()
);
}
}

let reference = Reference {
uuid: Uuid::new_v4().hyphenated().to_string(),
filepath: path.to_str().unwrap().to_string(),
filepath: path.clone().to_str().unwrap().to_string(),
filename: name.to_string(),
size: 0u64,
description: "",
Expand All @@ -159,7 +168,7 @@ impl MediaRepositoryTrait for MediaRepository {
};
let _ = &self
.database
.add_reference(media_id.as_str(), name.as_str(), &reference)
.add_reference(media_id, name.as_str(), &reference)
.await;
Err(DataAccessError::OtherError)
}
Expand Down
Binary file added documentation/http/DSC_1234.NEF
Binary file not shown.
9 changes: 9 additions & 0 deletions documentation/http/post_media_id.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
POST http://127.0.0.1:7777/media/75889665-7df3-4edd-8b15-d80819f7a17
Authorization: FakeToken
Connection: Keep-Alive

[MultipartFormData]
name: DSC_1234.NEF
file: file,DSC_1234.NEF;

HTTP 200
Loading