don't upload duplicates

This commit is contained in:
Brandon Thomas committed 2023-04-21 05:54:10 -07:00
1 parent ba9f716ff8
commit da05885d7d
4 files changed
+144 -7

No files matched your search

@@ -0,0 +1,104 @@
use anyhow::anyhow;
use chrono::{DateTime, Utc};
use crate::helpers::boolean_converters::i8_to_bool;
use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
use enums::common::visibility::Visibility;
use errors::AnyhowResult;
use log::{warn, info, error};
use sqlx::pool::PoolConnection;
use sqlx::{MySql, MySqlPool};
use enums::by_table::media_uploads::media_upload_type::MediaUploadType;
use tokens::files::media_upload::MediaUploadToken;
use tokens::users::user::UserToken;
use tokens::voice_conversion::model::VoiceConversionModelToken;
pub struct MediaUploadRecord {
pub token: MediaUploadToken,
pub media_type: MediaUploadType,
pub maybe_original_filename: Option<String>,
pub original_file_size_bytes: u32,
pub original_duration_millis: u32,
pub creator_set_visibility: Visibility,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Query for a media upload to see if we already uploaded it.
pub async fn get_media_upload_by_uuid(
uuid_idempotency_token: &str,
mysql_pool: &MySqlPool,
) -> AnyhowResult<Option<MediaUploadRecord>> {
let mut connection = mysql_pool.acquire().await?;
get_media_upload_by_uuid_with_connection(
uuid_idempotency_token,
&mut connection
).await
}
/// Query for a media upload to see if we already uploaded it.
pub async fn get_media_upload_by_uuid_with_connection(
uuid_idempotency_token: &str,
mysql_connection: &mut PoolConnection<MySql>,
) -> AnyhowResult<Option<MediaUploadRecord>> {
let maybe_result = sqlx::query_as!(
RawMediaUploadRecord,
r#"
SELECT
mu.token as `token: tokens::files::media_upload::MediaUploadToken`,
mu.media_type as `media_type: enums::by_table::media_uploads::media_upload_type::MediaUploadType`,
mu.maybe_original_filename,
mu.original_file_size_bytes,
mu.original_duration_millis,
mu.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,
mu.created_at,
mu.updated_at
FROM media_uploads as mu
WHERE
mu.uuid_idempotency_token = ?
AND mu.user_deleted_at IS NULL
AND mu.mod_deleted_at IS NULL
"#,
uuid_idempotency_token,
)
.fetch_one(mysql_connection)
.await;
match maybe_result {
Err(err) => match err {
sqlx::Error::RowNotFound => Ok(None),
_ => {
error!("list media uploads db error: {:?}", err);
Err(anyhow!("error with query: {:?}", err))
}
},
Ok(upload) => Ok(Some(MediaUploadRecord {
token: upload.token,
media_type: upload.media_type,
maybe_original_filename: upload.maybe_original_filename,
original_file_size_bytes: upload.original_file_size_bytes as u32,
original_duration_millis: upload.original_duration_millis as u32,
creator_set_visibility: upload.creator_set_visibility,
created_at: upload.created_at,
updated_at: upload.updated_at,
}))
}
}
struct RawMediaUploadRecord {
pub token: MediaUploadToken,
pub media_type: MediaUploadType,
pub maybe_original_filename: Option<String>,
pub original_file_size_bytes: i32,
pub original_duration_millis: i32,
pub creator_set_visibility: Visibility,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
@@ -1,2 +1,3 @@
pub mod get_media_upload_by_uuid;
pub mod insert_media_upload;
pub mod reverse_list_user_media_uploads_of_type;
@@ -12,7 +12,6 @@ use tokens::files::media_upload::MediaUploadToken;
use tokens::users::user::UserToken;
use tokens::voice_conversion::model::VoiceConversionModelToken;
#[derive(Serialize)]
pub struct MediaUploadRecord {
pub token: MediaUploadToken,
pub media_type: MediaUploadType,
@@ -22,7 +22,7 @@ use files::hash::hash_bytes_sha2;
use files::mimetype::{get_mimetype_for_bytes, get_mimetype_for_bytes_or_default};
use http_server_common::request::get_request_ip::get_request_ip;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use log::{info, warn, log};
use log::{info, warn, log, error};
use media::decode_basic_audio_info::decode_basic_audio_info;
use regex::Regex;
use sqlx::error::DatabaseError;
@@ -35,6 +35,7 @@ use symphonia::core::formats::FormatOptions;
use symphonia::core::io::{MediaSourceStream, ReadOnlySource};
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
use mysql_queries::queries::media_uploads::get_media_upload_by_uuid::{get_media_upload_by_uuid, get_media_upload_by_uuid_with_connection};
use tokens::files::media_upload::MediaUploadToken;
#[derive(Serialize)]
@@ -81,11 +82,19 @@ pub async fn upload_media_handler(
mut multipart_payload: Multipart,
) -> Result<HttpResponse, UploadMediaError> {
let mut mysql_connection = server_state.mysql_pool
.acquire()
.await
.map_err(|err| {
warn!("MySql pool error: {:?}", err);
UploadMediaError::ServerError
})?;
// ==================== READ SESSION ==================== //
let maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.maybe_get_user_session_from_connection(&http_request, &mut mysql_connection)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
@@ -125,6 +134,27 @@ pub async fn upload_media_handler(
let uuid_idempotency_token = upload_media_request.uuid_idempotency_token
.ok_or(UploadMediaError::BadInput("no uuid".to_string()))?;
let maybe_existing_upload =
get_media_upload_by_uuid_with_connection(&uuid_idempotency_token, &mut mysql_connection)
.await;
match maybe_existing_upload {
Err(err) => {
error!("Error checking for previous upload: {:?}", err);
return Err(UploadMediaError::ServerError);
}
Ok(Some(upload)) => {
// File already uploaded and frontend didn't protect us.
return render_ok_response(UploadMediaSuccessResponse {
success: true,
upload_token: upload.token,
});
}
Ok(None) => {
// Proceed.
}
}
if let Err(reason) = validate_idempotency_token_format(&uuid_idempotency_token) {
return Err(UploadMediaError::BadInput(reason));
}
@@ -271,15 +301,18 @@ pub async fn upload_media_handler(
UploadMediaError::ServerError
})?;
let response = UploadMediaSuccessResponse {
render_ok_response(UploadMediaSuccessResponse {
success: true,
upload_token: token,
};
})
}
fn render_ok_response(response: UploadMediaSuccessResponse) -> Result<HttpResponse, UploadMediaError> {
let body = serde_json::to_string(&response)
.map_err(|e| UploadMediaError::ServerError)?;
Ok(HttpResponse::Ok()
return Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
.body(body));
}