From 7745684a357207e56acbd9a69e496d40a7b77b49 Mon Sep 17 00:00:00 2001 From: Yvette Carlisle Date: Mon, 29 Jun 2026 23:45:10 +0800 Subject: [PATCH] {"schema":"decodex/commit/1","summary":"Split API notes publish route implementation into a child module after strict validation.","authority":"manual"} --- apps/elf-api/src/routes/notes.rs | 77 ++------------------ apps/elf-api/src/routes/notes/publish.rs | 92 ++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 70 deletions(-) create mode 100644 apps/elf-api/src/routes/notes/publish.rs diff --git a/apps/elf-api/src/routes/notes.rs b/apps/elf-api/src/routes/notes.rs index d22cbb89..05fe623e 100644 --- a/apps/elf-api/src/routes/notes.rs +++ b/apps/elf-api/src/routes/notes.rs @@ -1,10 +1,12 @@ +mod publish; + use crate::routes::{ self, AddNoteRequest, AddNoteResponse, ApiError, AppState, DeleteRequest, DeleteResponse, ErrorBody, Extension, HeaderMap, Json, JsonRejection, ListRequest, ListResponse, MAX_NOTES_PER_INGEST, NoteFetchRequest, NoteFetchResponse, NotePatchRequest, - NotesIngestRequest, NotesListQuery, Path, PublishNoteRequest, PublishResponseV2, Query, - QueryRejection, RequestContext, SecurityAuthRole, ShareScope, ShareScopeBody, State, - StatusCode, UnpublishNoteRequest, UpdateRequest, UpdateResponse, Uuid, + NotesIngestRequest, NotesListQuery, Path, PublishResponseV2, Query, QueryRejection, + RequestContext, SecurityAuthRole, ShareScopeBody, State, StatusCode, UpdateRequest, + UpdateResponse, Uuid, }; #[utoipa::path( @@ -255,42 +257,9 @@ pub(super) async fn notes_publish( Path(note_id): Path, payload: Result, JsonRejection>, ) -> Result, ApiError> { - let ctx = RequestContext::from_headers(&headers)?; - let Json(payload) = payload.map_err(|err| { - tracing::warn!(error = %err, "Invalid request payload."); - - routes::json_error( - StatusCode::BAD_REQUEST, - "INVALID_REQUEST", - "Invalid request payload.", - None, - ) - })?; - let scope = routes::parse_space(payload.space.as_str())?; let role = role.map(|Extension(role)| role); - if matches!(scope, ShareScope::OrgShared) { - routes::require_admin_for_org_shared_writes( - state.service.cfg.security.auth_mode.as_str(), - role, - )?; - } - - let response = state - .service - .publish_note(PublishNoteRequest { - tenant_id: ctx.tenant_id, - project_id: ctx.project_id, - agent_id: ctx.agent_id, - note_id, - scope, - }) - .await?; - - Ok(Json(PublishResponseV2 { - note_id: response.note_id, - space: routes::format_scope(response.scope.as_str())?.to_string(), - })) + publish::notes_publish_inner(state, headers, role, note_id, payload).await } #[utoipa::path( @@ -315,39 +284,7 @@ pub(super) async fn notes_unpublish( Path(note_id): Path, payload: Result, JsonRejection>, ) -> Result, ApiError> { - let ctx = RequestContext::from_headers(&headers)?; - let Json(payload) = payload.map_err(|err| { - tracing::warn!(error = %err, "Invalid request payload."); - - routes::json_error( - StatusCode::BAD_REQUEST, - "INVALID_REQUEST", - "Invalid request payload.", - None, - ) - })?; - let scope = routes::parse_space(payload.space.as_str())?; let role = role.map(|Extension(role)| role); - if matches!(scope, ShareScope::OrgShared) { - routes::require_admin_for_org_shared_writes( - state.service.cfg.security.auth_mode.as_str(), - role, - )?; - } - - let response = state - .service - .unpublish_note(UnpublishNoteRequest { - tenant_id: ctx.tenant_id, - project_id: ctx.project_id, - agent_id: ctx.agent_id, - note_id, - }) - .await?; - - Ok(Json(PublishResponseV2 { - note_id: response.note_id, - space: routes::format_scope(response.scope.as_str())?.to_string(), - })) + publish::notes_unpublish_inner(state, headers, role, note_id, payload).await } diff --git a/apps/elf-api/src/routes/notes/publish.rs b/apps/elf-api/src/routes/notes/publish.rs new file mode 100644 index 00000000..4130ab98 --- /dev/null +++ b/apps/elf-api/src/routes/notes/publish.rs @@ -0,0 +1,92 @@ +use crate::routes::{ + self, ApiError, AppState, HeaderMap, Json, JsonRejection, PublishNoteRequest, + PublishResponseV2, RequestContext, SecurityAuthRole, ShareScope, ShareScopeBody, StatusCode, + UnpublishNoteRequest, Uuid, +}; + +pub(super) async fn notes_publish_inner( + state: AppState, + headers: HeaderMap, + role: Option, + note_id: Uuid, + payload: Result, JsonRejection>, +) -> Result, ApiError> { + let ctx = RequestContext::from_headers(&headers)?; + let Json(payload) = payload.map_err(|err| { + tracing::warn!(error = %err, "Invalid request payload."); + + routes::json_error( + StatusCode::BAD_REQUEST, + "INVALID_REQUEST", + "Invalid request payload.", + None, + ) + })?; + let scope = routes::parse_space(payload.space.as_str())?; + + if matches!(scope, ShareScope::OrgShared) { + routes::require_admin_for_org_shared_writes( + state.service.cfg.security.auth_mode.as_str(), + role, + )?; + } + + let response = state + .service + .publish_note(PublishNoteRequest { + tenant_id: ctx.tenant_id, + project_id: ctx.project_id, + agent_id: ctx.agent_id, + note_id, + scope, + }) + .await?; + + Ok(Json(PublishResponseV2 { + note_id: response.note_id, + space: routes::format_scope(response.scope.as_str())?.to_string(), + })) +} + +pub(super) async fn notes_unpublish_inner( + state: AppState, + headers: HeaderMap, + role: Option, + note_id: Uuid, + payload: Result, JsonRejection>, +) -> Result, ApiError> { + let ctx = RequestContext::from_headers(&headers)?; + let Json(payload) = payload.map_err(|err| { + tracing::warn!(error = %err, "Invalid request payload."); + + routes::json_error( + StatusCode::BAD_REQUEST, + "INVALID_REQUEST", + "Invalid request payload.", + None, + ) + })?; + let scope = routes::parse_space(payload.space.as_str())?; + + if matches!(scope, ShareScope::OrgShared) { + routes::require_admin_for_org_shared_writes( + state.service.cfg.security.auth_mode.as_str(), + role, + )?; + } + + let response = state + .service + .unpublish_note(UnpublishNoteRequest { + tenant_id: ctx.tenant_id, + project_id: ctx.project_id, + agent_id: ctx.agent_id, + note_id, + }) + .await?; + + Ok(Json(PublishResponseV2 { + note_id: response.note_id, + space: routes::format_scope(response.scope.as_str())?.to_string(), + })) +}