fix: align inbox project routes
This commit is contained in:
@@ -50,7 +50,15 @@ export async function apiRequest<T>(path: string, options: RequestOptions = {}):
|
|||||||
throw new Error(message)
|
throw new Error(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json() as Promise<T>
|
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) {
|
function normalizeBaseUrl(value: string) {
|
||||||
|
|||||||
52
apps/senlinai-acro-react/src/api/inbox.ts
Normal file
52
apps/senlinai-acro-react/src/api/inbox.ts
Normal file
@@ -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<BackendInboxItem>(`/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<void>(`/api/inbox/${inboxId}/confirm`, {
|
||||||
|
method: 'POST',
|
||||||
|
token: session.token,
|
||||||
|
body: { suggestions },
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -92,8 +92,8 @@ export async function fetchProjects(session: ApiSession) {
|
|||||||
return apiRequest<BackendProject[]>('/api/projects', { token: session.token })
|
return apiRequest<BackendProject[]>('/api/projects', { token: session.token })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchProjectWorkspace(session: ApiSession, projectID: string | number) {
|
export async function fetchProjectWorkspace(session: ApiSession, projectId: string | number) {
|
||||||
return apiRequest<BackendProjectWorkspace>(`/api/projects/${projectID}/workspace`, { token: session.token })
|
return apiRequest<BackendProjectWorkspace>(`/api/projects/${projectId}/workspace`, { token: session.token })
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateProjectInput = {
|
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) {
|
export async function createTask(session: ApiSession, projectId: string | number, input: CreateTaskInput) {
|
||||||
return apiRequest<BackendTask>(`/api/projects/${projectID}/tasks`, {
|
return apiRequest<BackendTask>(`/api/projects/${projectId}/tasks`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
token: session.token,
|
token: session.token,
|
||||||
body: input,
|
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()
|
const body = new FormData()
|
||||||
body.append('file', input.file)
|
body.append('file', input.file)
|
||||||
if (input.title) body.append('title', input.title)
|
if (input.title) body.append('title', input.title)
|
||||||
return apiRequest<BackendNoteSource>(`/api/projects/${projectID}/sources`, {
|
return apiRequest<BackendNoteSource>(`/api/projects/${projectId}/sources`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
token: session.token,
|
token: session.token,
|
||||||
body,
|
body,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCronPlan(session: ApiSession, projectID: string | number, input: CreateCronPlanInput) {
|
export async function createCronPlan(session: ApiSession, projectId: string | number, input: CreateCronPlanInput) {
|
||||||
return apiRequest<BackendCronPlan>(`/api/projects/${projectID}/cron-plans`, {
|
return apiRequest<BackendCronPlan>(`/api/projects/${projectId}/cron-plans`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
token: session.token,
|
token: session.token,
|
||||||
body: input,
|
body: input,
|
||||||
|
|||||||
22
backend/internal/httpx/router_integration_test.go
Normal file
22
backend/internal/httpx/router_integration_test.go
Normal file
@@ -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{})),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ func NewHandler(service *Service) *Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Register(router gin.IRouter) {
|
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/analyze", h.analyze)
|
||||||
router.POST("/inbox/:id/confirm", h.confirm)
|
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"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing current user"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
projectID, err := strconv.ParseUint(c.Param("projectID"), 10, 64)
|
projectID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project id"})
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user