From 54958382f13b80cc41e2e88808bb9b370cbd5269 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Mon, 20 Jul 2026 22:35:45 +0800 Subject: [PATCH] fix: align inbox project routes --- apps/senlinai-acro-react/src/api/client.ts | 10 +++- apps/senlinai-acro-react/src/api/inbox.ts | 52 +++++++++++++++++++ apps/senlinai-acro-react/src/api/projects.ts | 16 +++--- .../internal/httpx/router_integration_test.go | 22 ++++++++ backend/internal/logic/inbox/handlers.go | 4 +- 5 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 apps/senlinai-acro-react/src/api/inbox.ts create mode 100644 backend/internal/httpx/router_integration_test.go diff --git a/apps/senlinai-acro-react/src/api/client.ts b/apps/senlinai-acro-react/src/api/client.ts index 34aee88..1bcb760 100644 --- a/apps/senlinai-acro-react/src/api/client.ts +++ b/apps/senlinai-acro-react/src/api/client.ts @@ -50,7 +50,15 @@ export async function apiRequest(path: string, options: RequestOptions = {}): throw new Error(message) } - return response.json() as Promise + if (response.status === 204) { + return undefined as T + } + + const text = await response.text() + if (text.trim() === '') { + return undefined as T + } + return JSON.parse(text) as T } function normalizeBaseUrl(value: string) { diff --git a/apps/senlinai-acro-react/src/api/inbox.ts b/apps/senlinai-acro-react/src/api/inbox.ts new file mode 100644 index 0000000..f09e413 --- /dev/null +++ b/apps/senlinai-acro-react/src/api/inbox.ts @@ -0,0 +1,52 @@ +import { apiRequest, type ApiSession } from './client' + +export type BackendInboxItem = { + id?: number + ID?: number + project_id?: number + projectID?: number + source_type?: string + sourceType?: string + title?: string + body?: string + status?: string +} + +export type InboxSuggestion = { + type: string + title: string + body: string +} + +export type CaptureInboxInput = { + sourceType: string + title: string + body: string +} + +export async function captureProjectInbox(session: ApiSession, projectId: string | number, input: CaptureInboxInput) { + return apiRequest(`/api/projects/${projectId}/inbox`, { + method: 'POST', + token: session.token, + body: { + source_type: input.sourceType, + title: input.title, + body: input.body, + }, + }) +} + +export async function analyzeInboxItem(session: ApiSession, inboxId: string | number) { + return apiRequest<{ suggestions: InboxSuggestion[] }>(`/api/inbox/${inboxId}/analyze`, { + method: 'POST', + token: session.token, + }) +} + +export async function confirmInboxItem(session: ApiSession, inboxId: string | number, suggestions: InboxSuggestion[]) { + return apiRequest(`/api/inbox/${inboxId}/confirm`, { + method: 'POST', + token: session.token, + body: { suggestions }, + }) +} diff --git a/apps/senlinai-acro-react/src/api/projects.ts b/apps/senlinai-acro-react/src/api/projects.ts index d90c9bf..d6e20ba 100644 --- a/apps/senlinai-acro-react/src/api/projects.ts +++ b/apps/senlinai-acro-react/src/api/projects.ts @@ -92,8 +92,8 @@ export async function fetchProjects(session: ApiSession) { return apiRequest('/api/projects', { token: session.token }) } -export async function fetchProjectWorkspace(session: ApiSession, projectID: string | number) { - return apiRequest(`/api/projects/${projectID}/workspace`, { token: session.token }) +export async function fetchProjectWorkspace(session: ApiSession, projectId: string | number) { + return apiRequest(`/api/projects/${projectId}/workspace`, { token: session.token }) } export type CreateProjectInput = { @@ -128,27 +128,27 @@ export async function createProject(session: ApiSession, input: CreateProjectInp }) } -export async function createTask(session: ApiSession, projectID: string | number, input: CreateTaskInput) { - return apiRequest(`/api/projects/${projectID}/tasks`, { +export async function createTask(session: ApiSession, projectId: string | number, input: CreateTaskInput) { + return apiRequest(`/api/projects/${projectId}/tasks`, { method: 'POST', token: session.token, body: input, }) } -export async function uploadSource(session: ApiSession, projectID: string | number, input: UploadSourceInput) { +export async function uploadSource(session: ApiSession, projectId: string | number, input: UploadSourceInput) { const body = new FormData() body.append('file', input.file) if (input.title) body.append('title', input.title) - return apiRequest(`/api/projects/${projectID}/sources`, { + return apiRequest(`/api/projects/${projectId}/sources`, { method: 'POST', token: session.token, body, }) } -export async function createCronPlan(session: ApiSession, projectID: string | number, input: CreateCronPlanInput) { - return apiRequest(`/api/projects/${projectID}/cron-plans`, { +export async function createCronPlan(session: ApiSession, projectId: string | number, input: CreateCronPlanInput) { + return apiRequest(`/api/projects/${projectId}/cron-plans`, { method: 'POST', token: session.token, body: input, diff --git a/backend/internal/httpx/router_integration_test.go b/backend/internal/httpx/router_integration_test.go new file mode 100644 index 0000000..c0967cb --- /dev/null +++ b/backend/internal/httpx/router_integration_test.go @@ -0,0 +1,22 @@ +package httpx_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "senlinai-agent/backend/internal/config" + "senlinai-agent/backend/internal/httpx" + "senlinai-agent/backend/internal/logic/inbox" + "senlinai-agent/backend/internal/logic/projects" +) + +func TestProjectAndInboxRoutesRegisterTogether(t *testing.T) { + require.NotPanics(t, func() { + httpx.NewProtectedRouter( + config.Config{Env: "test"}, + func(token string) (uint, error) { return 1, nil }, + projects.NewHandler(projects.NewService()), + inbox.NewHandler(inbox.NewService(inbox.StaticAnalyzer{})), + ) + }) +} diff --git a/backend/internal/logic/inbox/handlers.go b/backend/internal/logic/inbox/handlers.go index 7a433af..0b50733 100644 --- a/backend/internal/logic/inbox/handlers.go +++ b/backend/internal/logic/inbox/handlers.go @@ -17,7 +17,7 @@ func NewHandler(service *Service) *Handler { } func (h *Handler) Register(router gin.IRouter) { - router.POST("/projects/:projectID/inbox", h.capture) + router.POST("/projects/:id/inbox", h.capture) router.POST("/inbox/:id/analyze", h.analyze) router.POST("/inbox/:id/confirm", h.confirm) } @@ -28,7 +28,7 @@ func (h *Handler) capture(c *gin.Context) { c.JSON(http.StatusUnauthorized, gin.H{"error": "missing current user"}) return } - projectID, err := strconv.ParseUint(c.Param("projectID"), 10, 64) + projectID, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"}) return