diff options
Diffstat (limited to 'makima/src/server/handlers/files.rs')
| -rw-r--r-- | makima/src/server/handlers/files.rs | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/makima/src/server/handlers/files.rs b/makima/src/server/handlers/files.rs index 746d66b..c65eed5 100644 --- a/makima/src/server/handlers/files.rs +++ b/makima/src/server/handlers/files.rs @@ -9,9 +9,9 @@ use axum::{ use uuid::Uuid; use crate::db::models::{CreateFileRequest, FileListResponse, FileSummary, UpdateFileRequest}; -use crate::db::repository; +use crate::db::repository::{self, RepositoryError}; use crate::server::messages::ApiError; -use crate::server::state::SharedState; +use crate::server::state::{FileUpdateNotification, SharedState}; /// List all files for the current owner. #[utoipa::path( @@ -148,6 +148,7 @@ pub async fn create_file( responses( (status = 200, description = "File updated", body = crate::db::models::File), (status = 404, description = "File not found", body = ApiError), + (status = 409, description = "Version conflict", body = ApiError), (status = 503, description = "Database not configured", body = ApiError), (status = 500, description = "Internal server error", body = ApiError), ), @@ -166,14 +167,62 @@ pub async fn update_file( .into_response(); }; + // Collect which fields are being updated for broadcast + let mut updated_fields = Vec::new(); + if req.name.is_some() { + updated_fields.push("name".to_string()); + } + if req.description.is_some() { + updated_fields.push("description".to_string()); + } + if req.transcript.is_some() { + updated_fields.push("transcript".to_string()); + } + if req.summary.is_some() { + updated_fields.push("summary".to_string()); + } + if req.body.is_some() { + updated_fields.push("body".to_string()); + } + match repository::update_file(pool, id, req).await { - Ok(Some(file)) => Json(file).into_response(), + Ok(Some(file)) => { + // Broadcast update notification + state.broadcast_file_update(FileUpdateNotification { + file_id: id, + version: file.version, + updated_fields, + updated_by: "user".to_string(), + }); + Json(file).into_response() + } Ok(None) => ( StatusCode::NOT_FOUND, Json(ApiError::new("NOT_FOUND", "File not found")), ) .into_response(), - Err(e) => { + Err(RepositoryError::VersionConflict { expected, actual }) => { + tracing::info!( + "Version conflict on file {}: expected {}, actual {}", + id, + expected, + actual + ); + ( + StatusCode::CONFLICT, + Json(serde_json::json!({ + "code": "VERSION_CONFLICT", + "message": format!( + "File was modified by another user. Expected version {}, actual version {}", + expected, actual + ), + "expectedVersion": expected, + "actualVersion": actual, + })), + ) + .into_response() + } + Err(RepositoryError::Database(e)) => { tracing::error!("Failed to update file {}: {}", id, e); ( StatusCode::INTERNAL_SERVER_ERROR, |
