Skip to content

Commit

Permalink
Add POST media_id call
Browse files Browse the repository at this point in the history
  • Loading branch information
thebino committed Oct 27, 2023
1 parent ccb586f commit c54261f
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 71 deletions.
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
26 changes: 12 additions & 14 deletions crates/media/src/api/routes/post_media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use axum::{
extract::{Multipart, State},
http::StatusCode,
response::{IntoResponse, Redirect, Response},

Check warning on line 23 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `Response`

Check failure on line 23 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `Response`

Check warning on line 23 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `Response`
Json,
};
use common::auth::user::User;
Expand All @@ -28,7 +29,7 @@ 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,7 +43,9 @@ 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();

Check warning on line 51 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `headers`

Check failure on line 51 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused variable: `headers`

Check warning on line 51 in crates/media/src/api/routes/post_media.rs

View workflow job for this annotation

GitHub Actions / Tests

unused variable: `headers`
Expand Down Expand Up @@ -88,20 +91,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
61 changes: 22 additions & 39 deletions crates/media/src/api/routes/post_media_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@
//! Add files for a specific media item
//!

use core::panic;

Check warning on line 21 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `core::panic`

Check failure on line 21 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `core::panic`

Check warning on line 21 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `core::panic`

use axum::extract::{Multipart, Path, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect};
use common::auth::user::User;
use hyper::header::LOCATION;

Check warning on line 27 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `hyper::header::LOCATION`

Check failure on line 27 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `hyper::header::LOCATION`

Check warning on line 27 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `hyper::header::LOCATION`
use hyper::HeaderMap;

Check warning on line 28 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `hyper::HeaderMap`

Check failure on line 28 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `hyper::HeaderMap`

Check warning on line 28 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `hyper::HeaderMap`
use tempfile::tempfile;

Check warning on line 29 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `tempfile::tempfile`

Check failure on line 29 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `tempfile::tempfile`

Check warning on line 29 in crates/media/src/api/routes/post_media_id.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `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 +40,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),
},
}
}
48 changes: 30 additions & 18 deletions crates/media/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@
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 core::ffi::FromBytesUntilNulError;

Check warning on line 25 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `core::ffi::FromBytesUntilNulError`

Check failure on line 25 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `core::ffi::FromBytesUntilNulError`

Check warning on line 25 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `core::ffi::FromBytesUntilNulError`
use database::sqlite::SqliteDatabase;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use time::OffsetDateTime;
use tokio::fs::File;

Check warning on line 31 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `tokio::fs::File`

Check failure on line 31 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `tokio::fs::File`

Check warning on line 31 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `tokio::fs::File`
use tracing::info;
use tokio::io::AsyncWriteExt;

Check warning on line 32 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `tokio::io::AsyncWriteExt`

Check failure on line 32 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Lint checks

unused import: `tokio::io::AsyncWriteExt`

Check warning on line 32 in crates/media/src/repository.rs

View workflow job for this annotation

GitHub Actions / Tests

unused import: `tokio::io::AsyncWriteExt`
use tracing::log::warn;
use tracing::{debug, info};
use uuid::Uuid;

#[allow(dead_code)]
Expand Down Expand Up @@ -58,9 +63,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 +133,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 +171,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

0 comments on commit c54261f

Please sign in to comment.