change: change get from json cache file to multipart
Signed-off-by: Pakin <pakin.t@forth.co.th>
This commit is contained in:
parent
d19dab7561
commit
5bb2a6c192
3 changed files with 187 additions and 24 deletions
159
src/app.rs
159
src/app.rs
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue