validate file version on upload
This commit is contained in:
parent
50d0f6dfa5
commit
c239819376
@ -1,3 +1,4 @@
|
||||
use crate::db::repository::models::FileModel;
|
||||
use crate::db::repository::{insert, Repository};
|
||||
use crate::errors::to_internal_error;
|
||||
use crate::files::PathInfo;
|
||||
@ -17,6 +18,7 @@ use std::io::Error;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::fs::{create_dir_all, File};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::debug;
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn handle_file_uploads(
|
||||
@ -46,13 +48,17 @@ async fn handle_single_file_upload<'field_lifetime>(
|
||||
None | Some("") => Err(ProblemDetails::from_status_code(StatusCode::BAD_REQUEST)
|
||||
.with_detail(errors::ERROR_DETAILS_NO_NAME_PROVIDED_MULTIPART_FIELD)),
|
||||
Some(field_name) => {
|
||||
let path = PathBuf::from(field_name);
|
||||
let path_info = PathInfo::build(&state.config.files.directory, user_id, &path)?;
|
||||
let parsed = UploadParameter::from_string(field_name)?;
|
||||
let path_info = PathInfo::build(&state.config.files.directory, user_id, &parsed.path)?;
|
||||
let lock_id = &build_lock_id(user_id, &path_info.relative_user_location);
|
||||
if state
|
||||
.get_lock()
|
||||
.lock(lock_id).await
|
||||
{
|
||||
if state.get_lock().lock(lock_id).await {
|
||||
validate_file_version(
|
||||
state.get_repository(),
|
||||
user_id,
|
||||
&path_info.relative_user_location,
|
||||
&parsed.version,
|
||||
)
|
||||
.await?;
|
||||
let result = update_file(state, user_id, field, &path_info).await;
|
||||
state.get_lock().unlock(lock_id).await;
|
||||
result
|
||||
@ -64,6 +70,71 @@ async fn handle_single_file_upload<'field_lifetime>(
|
||||
}
|
||||
}
|
||||
|
||||
async fn validate_file_version(
|
||||
repo: &impl Repository,
|
||||
user_id: &str,
|
||||
path: &Path,
|
||||
version: &u64,
|
||||
) -> Result<(), ProblemDetails> {
|
||||
match repo.get_file(user_id, &path.to_string_lossy()).await? {
|
||||
None => validate_initial_version(version)?,
|
||||
Some(file_model) => validate_version_increment(&file_model, version)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_version_increment(model: &FileModel, version: &u64) -> Result<(), ProblemDetails> {
|
||||
if model.version + 1 != *version {
|
||||
return Err(
|
||||
ProblemDetails::from_status_code(StatusCode::CONFLICT).with_detail(format!(
|
||||
"Version does not match. Provided {} is not one higher than existing {}",
|
||||
version, model.version
|
||||
)),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_initial_version(version: &u64) -> Result<(), ProblemDetails> {
|
||||
if *version != 0 {
|
||||
return Err(
|
||||
ProblemDetails::from_status_code(StatusCode::BAD_REQUEST).with_detail(format!(
|
||||
"Version for new files must be 0. Provided version {}",
|
||||
version
|
||||
)),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct UploadParameter {
|
||||
path: PathBuf,
|
||||
version: u64,
|
||||
}
|
||||
|
||||
impl UploadParameter {
|
||||
fn from_string(name: &str) -> Result<Self, ProblemDetails> {
|
||||
let mut split = name.split(';');
|
||||
let path = split.next().ok_or_else(build_wrong_field_name_error)?;
|
||||
let version: u64 = split
|
||||
.next()
|
||||
.ok_or_else(build_wrong_field_name_error)?
|
||||
.parse()
|
||||
.map_err(|err| {
|
||||
debug!("Error while parsing version: {}", err);
|
||||
ProblemDetails::from_status_code(StatusCode::BAD_REQUEST)
|
||||
.with_detail("Version cannot be parsed as a number")
|
||||
})?;
|
||||
let path = PathBuf::from(path);
|
||||
Ok(Self { path, version })
|
||||
}
|
||||
}
|
||||
|
||||
fn build_wrong_field_name_error() -> ProblemDetails {
|
||||
ProblemDetails::from_status_code(StatusCode::BAD_REQUEST)
|
||||
.with_detail("Multipart field name must have the following structure: {path_to_file};{version_number + 1}. Example: folder/nested/file.pdf;15")
|
||||
}
|
||||
|
||||
async fn update_file<'field_lifetime>(
|
||||
state: &AppState,
|
||||
user_id: &str,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user