s3 support commit1
This commit is contained in:
+18
-26
@@ -616,20 +616,19 @@ pub async fn upload_pad_file(
|
||||
let (original, bytes) = file.ok_or_else(|| ApiError::bad_request("No file provided"))?;
|
||||
let safe = sanitize_filename(&original);
|
||||
let file_token = db::pad_file_token(&state.db, pad.id).await?;
|
||||
let directory = format!("{}_{}", pad.id, file_token);
|
||||
let dir = std::path::Path::new(&state.files_dir).join("pads").join(&directory);
|
||||
tokio::fs::create_dir_all(&dir).await.map_err(|_| ApiError::internal("Failed to create the files directory"))?;
|
||||
let mut stored = safe.clone();
|
||||
let mut path = dir.join(&stored);
|
||||
if path.exists() {
|
||||
let mut key = crate::storage::object_key("pads", pad.id, &file_token, &stored);
|
||||
if state.storage.exists(&key).await.map_err(|_| ApiError::internal("Failed to check file storage"))? {
|
||||
let stem = std::path::Path::new(&safe).file_stem().and_then(|v| v.to_str()).unwrap_or("plik");
|
||||
let ext = std::path::Path::new(&safe).extension().and_then(|v| v.to_str()).map(|v| format!(".{v}")).unwrap_or_default();
|
||||
stored = format!("{stem}-{}{}", db::random_suffix(6), ext);
|
||||
path = dir.join(&stored);
|
||||
key = crate::storage::object_key("pads", pad.id, &file_token, &stored);
|
||||
}
|
||||
tokio::fs::write(&path, &bytes).await.map_err(|_| ApiError::internal("Failed to save the file"))?;
|
||||
let url = format!("/f/{}/{}", file_token, stored);
|
||||
let mime = mime_guess::from_path(&stored).first_or_octet_stream().to_string();
|
||||
let cache_control = format!("public, max-age={}", state.file_cache_max_age_seconds);
|
||||
state.storage.put(&key, bytes.clone().into(), &mime, &cache_control).await
|
||||
.map_err(|_| ApiError::internal("Failed to save the file"))?;
|
||||
db::register_pad_file(&state.db, pad.id, &stored, &url, &mime, bytes.len() as i64).await?;
|
||||
Ok(Json(serde_json::json!({"name": stored, "url": url})))
|
||||
}
|
||||
@@ -680,20 +679,19 @@ pub async fn upload_note_file(
|
||||
let (original, bytes) = file.ok_or_else(|| ApiError::bad_request("No file provided"))?;
|
||||
let safe = sanitize_filename(&original);
|
||||
let file_token = db::note_file_token(&state.db, note.id).await?;
|
||||
let directory = format!("{}_{}", note.id, file_token);
|
||||
let dir = std::path::Path::new(&state.files_dir).join("notes").join(&directory);
|
||||
tokio::fs::create_dir_all(&dir).await.map_err(|_| ApiError::internal("Failed to create the files directory"))?;
|
||||
let mut stored = safe.clone();
|
||||
let mut path = dir.join(&stored);
|
||||
if path.exists() {
|
||||
let mut key = crate::storage::object_key("notes", note.id, &file_token, &stored);
|
||||
if state.storage.exists(&key).await.map_err(|_| ApiError::internal("Failed to check file storage"))? {
|
||||
let stem = std::path::Path::new(&safe).file_stem().and_then(|v| v.to_str()).unwrap_or("plik");
|
||||
let ext = std::path::Path::new(&safe).extension().and_then(|v| v.to_str()).map(|v| format!(".{v}")).unwrap_or_default();
|
||||
stored = format!("{stem}-{}{}", db::random_suffix(6), ext);
|
||||
path = dir.join(&stored);
|
||||
key = crate::storage::object_key("notes", note.id, &file_token, &stored);
|
||||
}
|
||||
tokio::fs::write(&path, &bytes).await.map_err(|_| ApiError::internal("Failed to save the file"))?;
|
||||
let url = format!("/f/{}/{}", file_token, stored);
|
||||
let mime = mime_guess::from_path(&stored).first_or_octet_stream().to_string();
|
||||
let cache_control = format!("public, max-age={}", state.file_cache_max_age_seconds);
|
||||
state.storage.put(&key, bytes.clone().into(), &mime, &cache_control).await
|
||||
.map_err(|_| ApiError::internal("Failed to save the file"))?;
|
||||
db::register_note_file(&state.db, note.id, &stored, &url, &mime, bytes.len() as i64).await?;
|
||||
Ok(Json(serde_json::json!({"name": stored, "url": url})))
|
||||
}
|
||||
@@ -742,13 +740,8 @@ pub async fn delete_note_file(
|
||||
.ok_or_else(ApiError::not_found_file)?;
|
||||
let relative = file.url.trim_start_matches('/').split('/').collect::<Vec<_>>();
|
||||
if relative.len() == 3 && relative[0] == "f" {
|
||||
let directory = format!("{}_{}", note.id, relative[1]);
|
||||
let path = std::path::Path::new(&state.files_dir).join("notes").join(directory).join(sanitize_filename(relative[2]));
|
||||
match tokio::fs::remove_file(&path).await {
|
||||
Ok(()) => {},
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {},
|
||||
Err(_) => return Err(ApiError::internal("Failed to delete the file")),
|
||||
}
|
||||
let key = crate::storage::object_key("notes", note.id, relative[1], &sanitize_filename(relative[2]));
|
||||
state.storage.delete(&key).await.map_err(|_| ApiError::internal("Failed to delete the file"))?;
|
||||
}
|
||||
db::delete_note_file(&state.db, note.id, file_id).await?;
|
||||
Ok(Json(serde_json::json!({"ok": true})))
|
||||
@@ -788,11 +781,10 @@ async fn serve_token_file(state: &SharedState, token: &str, filename: &str) -> R
|
||||
db::FileOwnerKind::Pad => "pads",
|
||||
db::FileOwnerKind::Note => "notes",
|
||||
};
|
||||
let directory = format!("{}_{}", owner.id, token);
|
||||
let canonical = std::path::Path::new(&state.files_dir).join(kind).join(&directory).join(&safe);
|
||||
let legacy = std::path::Path::new(&state.files_dir).join(&directory).join(&safe);
|
||||
let path = if canonical.is_file() { canonical } else { legacy };
|
||||
let bytes = tokio::fs::read(&path).await.map_err(|_| ApiError::not_found_file())?;
|
||||
let key = crate::storage::object_key(kind, owner.id, token, &safe);
|
||||
let legacy_key = crate::storage::legacy_key(owner.id, token, &safe);
|
||||
let bytes = state.storage.get_local_with_legacy(&key, &legacy_key).await
|
||||
.map_err(|_| ApiError::not_found_file())?;
|
||||
let mime = mime_guess::from_path(&safe).first_or_octet_stream();
|
||||
let mut response = bytes.into_response();
|
||||
response.headers_mut().insert(
|
||||
|
||||
Reference in New Issue
Block a user