change: change get from json cache file to multipart

Signed-off-by: Pakin <pakin.t@forth.co.th>
This commit is contained in:
Pakin 2026-04-27 15:47:11 +07:00
parent d19dab7561
commit 5bb2a6c192
3 changed files with 187 additions and 24 deletions

View file

@ -8,6 +8,7 @@ use axum::{
response::{IntoResponse, Response},
routing::{get, post},
};
use axum_extra::extract::multipart::Multipart;
use axum_macros::debug_handler;
use bb8::{Pool, PooledConnection};
use bb8_redis::RedisConnectionManager;
@ -378,37 +379,148 @@ struct Signature {
#[debug_handler]
async fn commit_handler(
State(state): State<AppState>,
// request body
Json(payload): Json<CommitBody>,
// request body as multipart/form-data
mut payload: Multipart,
) -> impl IntoResponse {
let mut content = match fetch_content_from_redis(state.redis.clone(), &payload.patch_key).await
{
Ok(c) => c,
Err(e) => {
// Extract multipart fields
let mut path: Option<String> = None;
let mut signature_username: Option<String> = None;
let mut signature_email: Option<String> = None;
let mut message: Option<String> = None;
let mut file_bytes: Option<Vec<u8>> = None;
// Process each field in the multipart payload
while let Ok(Some(field)) = payload.next_field().await {
let name = field.name().unwrap_or("").to_string();
match name.as_str() {
"path" => {
path = Some(match field.text().await {
Ok(t) => t,
Err(e) => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": format!("Failed to read path field: {}", e)})),
);
}
});
}
"signature_username" => {
signature_username = Some(match field.text().await {
Ok(t) => t,
Err(e) => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(
json!({"error": format!("Failed to read signature_username field: {}", e)}),
),
);
}
});
}
"signature_email" => {
signature_email = Some(match field.text().await {
Ok(t) => t,
Err(e) => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(
json!({"error": format!("Failed to read signature_email field: {}", e)}),
),
);
}
});
}
"message" => {
message = Some(match field.text().await {
Ok(t) => t,
Err(e) => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": format!("Failed to read message field: {}", e)})),
);
}
});
}
"file" => {
file_bytes = Some(match field.bytes().await {
Ok(b) => b.to_vec(),
Err(e) => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": format!("Failed to read file field: {}", e)})),
);
}
});
}
_ => {
// Ignore unknown fields
}
}
}
// Validate required fields
let path = match path {
Some(p) => p,
None => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": e})),
Json(json!({"error": "Missing required field: path"})),
);
}
};
let is_patch_file = content.starts_with("patch");
// do apply patch first
if is_patch_file {
content = apply_patch_to_file(state.redis.clone(), &payload.path, &mut content).await;
}
let signature_username = match signature_username {
Some(su) => su,
None => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": "Missing required field: signature_username"})),
);
}
};
let signature_email = match signature_email {
Some(se) => se,
None => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": "Missing required field: signature_email"})),
);
}
};
let file_bytes = match file_bytes {
Some(fb) => fb,
None => {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({"error": "Missing required field: file"})),
);
}
};
// Create signature
let signature = Signature {
username: signature_username,
email: signature_email,
};
// Get branch name from config
let branch = state
.clone()
.get_config("GIT_REPO_BRANCH_NAME")
.map(|x| x.to_string())
.unwrap_or("master".to_string());
// Commit the file content directly from multipart upload
let commit_oid = match commit_file_content(
state.clone().repo,
&payload.path,
&content.as_bytes(),
payload.signature,
&payload.message.unwrap_or("update: from api".to_string()),
state
.clone()
.get_config("GIT_REPO_BRANCH_NAME")
.map(|x| x.to_string())
.unwrap_or("master".to_string()),
&path,
&file_bytes,
signature,
&message.unwrap_or("update: from api".to_string()),
branch,
)
.await
{
@ -425,7 +537,10 @@ async fn commit_handler(
let redis_pre_lock = state.redis.clone();
{
if let Ok(mut rl) = redis_pre_lock.get().await {
let _ = rl.rpush(format!("{}.history", payload.path), payload.patch_key);
let _ = rl.rpush(
format!("{}.history", path),
format!("commit-{}", commit_oid),
);
}
}