fix: complete exploration data flow
This commit is contained in:
@@ -3,6 +3,7 @@ package dataset
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -25,6 +26,7 @@ type SourceDTO struct {
|
||||
IconURL string `json:"iconUrl"`
|
||||
Description string `json:"description"`
|
||||
Enabled bool `json:"enabled"`
|
||||
BuiltIn bool `json:"builtIn"`
|
||||
LastSyncedAt *time.Time `json:"lastSyncedAt"`
|
||||
ItemCount int64 `json:"itemCount"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
@@ -45,19 +47,28 @@ type ItemDTO struct {
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type ItemPageDTO struct {
|
||||
Items []ItemDTO `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
type CronDTO struct {
|
||||
ID string `json:"id"`
|
||||
SourceID string `json:"sourceId"`
|
||||
Schedule string `json:"schedule"`
|
||||
Status string `json:"status"`
|
||||
Enabled bool `json:"enabled"`
|
||||
NextRunAt *time.Time `json:"nextRunAt"`
|
||||
LastRunAt *time.Time `json:"lastRunAt"`
|
||||
LastResult string `json:"lastResult"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type DepositDTO struct {
|
||||
NoteID string `json:"noteId"`
|
||||
ProjectID string `json:"projectId"`
|
||||
}
|
||||
|
||||
type sourceRequest struct {
|
||||
Name string `json:"name"`
|
||||
Kind string `json:"kind"`
|
||||
@@ -79,6 +90,7 @@ func (h *Handler) Register(router gin.IRouter) {
|
||||
router.GET("/dataset-items", h.listItems)
|
||||
router.POST("/dataset-items", h.createItem)
|
||||
router.PATCH("/dataset-items/:id", h.updateItem)
|
||||
router.POST("/dataset-items/:id/deposit", h.depositItem)
|
||||
router.GET("/dataset-crons", h.listCrons)
|
||||
router.POST("/dataset-crons/sync", h.queueSync)
|
||||
}
|
||||
@@ -134,18 +146,21 @@ func (h *Handler) updateSource(c *gin.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var input sourceRequest
|
||||
var input struct {
|
||||
Name *string `json:"name"`
|
||||
Kind *string `json:"kind"`
|
||||
URL *string `json:"url"`
|
||||
IconURL *string `json:"iconUrl"`
|
||||
Description *string `json:"description"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
writeInvalidRequest(c)
|
||||
return
|
||||
}
|
||||
enabled := true
|
||||
if input.Enabled != nil {
|
||||
enabled = *input.Enabled
|
||||
}
|
||||
source, err := h.service.UpdateSource(userID, identity, SourceInput{
|
||||
source, err := h.service.PatchSource(userID, identity, SourcePatch{
|
||||
Name: input.Name, Kind: input.Kind, URL: input.URL, IconURL: input.IconURL,
|
||||
Description: input.Description, Enabled: enabled,
|
||||
Description: input.Description, Enabled: input.Enabled,
|
||||
})
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
@@ -180,16 +195,34 @@ func (h *Handler) listItems(c *gin.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
items, err := h.service.ListItems(userID, c.Query("sourceId"))
|
||||
limit, err := optionalNonNegativeInt(c.Query("limit"))
|
||||
if err != nil {
|
||||
writeInvalidRequest(c)
|
||||
return
|
||||
}
|
||||
offset, err := optionalNonNegativeInt(c.Query("offset"))
|
||||
if err != nil {
|
||||
writeInvalidRequest(c)
|
||||
return
|
||||
}
|
||||
page, err := h.service.ListItemsPage(userID, c.Query("sourceId"), limit, offset)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
result := make([]ItemDTO, 0, len(items))
|
||||
for _, item := range items {
|
||||
result := make([]ItemDTO, 0, len(page.Items))
|
||||
for _, item := range page.Items {
|
||||
result = append(result, itemDTO(item))
|
||||
}
|
||||
c.JSON(http.StatusOK, result)
|
||||
_, hasLimit := c.GetQuery("limit")
|
||||
_, hasOffset := c.GetQuery("offset")
|
||||
if !hasLimit && !hasOffset {
|
||||
c.JSON(http.StatusOK, result)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, ItemPageDTO{
|
||||
Items: result, Total: page.Total, Limit: page.Limit, Offset: page.Offset,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) createItem(c *gin.Context) {
|
||||
@@ -235,14 +268,14 @@ func (h *Handler) updateItem(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
var input struct {
|
||||
Status string `json:"status"`
|
||||
Starred bool `json:"starred"`
|
||||
Status *string `json:"status"`
|
||||
Starred *bool `json:"starred"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
writeInvalidRequest(c)
|
||||
return
|
||||
}
|
||||
item, err := h.service.UpdateItem(userID, identity, ItemUpdate{Status: input.Status, Starred: input.Starred})
|
||||
item, err := h.service.PatchItem(userID, identity, ItemPatch{Status: input.Status, Starred: input.Starred})
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
@@ -250,6 +283,32 @@ func (h *Handler) updateItem(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, itemDTO(*item))
|
||||
}
|
||||
|
||||
func (h *Handler) depositItem(c *gin.Context) {
|
||||
userID, ok := currentUser(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
identity, ok := httpx.IdentityParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var input struct {
|
||||
ProjectID string `json:"projectId"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil || strings.TrimSpace(input.ProjectID) == "" {
|
||||
writeInvalidRequest(c)
|
||||
return
|
||||
}
|
||||
result, err := h.service.DepositItem(userID, identity, input.ProjectID)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, DepositDTO{
|
||||
NoteID: result.NoteIdentity, ProjectID: result.ProjectIdentity,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) listCrons(c *gin.Context) {
|
||||
userID, ok := currentUser(c)
|
||||
if !ok {
|
||||
@@ -272,7 +331,7 @@ func (h *Handler) queueSync(c *gin.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
crons, err := h.service.SyncSources(c.Request.Context(), userID)
|
||||
crons, err := h.service.QueueSources(userID)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
@@ -281,7 +340,7 @@ func (h *Handler) queueSync(c *gin.Context) {
|
||||
for _, cron := range crons {
|
||||
result = append(result, cronDTO(cron))
|
||||
}
|
||||
c.JSON(http.StatusOK, result)
|
||||
c.JSON(http.StatusAccepted, result)
|
||||
}
|
||||
|
||||
func currentUser(c *gin.Context) (uint, bool) {
|
||||
@@ -297,6 +356,10 @@ func writeError(c *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, gorm.ErrRecordNotFound):
|
||||
httpx.Error(c, http.StatusNotFound, "not_found", "数据源或数据条目不存在")
|
||||
case errors.Is(err, ErrBuiltInSource):
|
||||
httpx.Error(c, http.StatusConflict, "built_in_source", "内置数据源不能删除,可以将其停用")
|
||||
case errors.Is(err, ErrSyncInProgress):
|
||||
httpx.Error(c, http.StatusConflict, "sync_in_progress", "已有数据源采集任务正在运行")
|
||||
case errors.Is(err, ErrNameRequired), errors.Is(err, ErrKindInvalid),
|
||||
errors.Is(err, ErrURLInvalid), errors.Is(err, ErrTitleRequired), errors.Is(err, ErrStatusInvalid):
|
||||
writeInvalidRequest(c)
|
||||
@@ -313,7 +376,7 @@ func sourceDTO(source models.SaDatasetSource, itemCount int64) SourceDTO {
|
||||
return SourceDTO{
|
||||
ID: source.Identity, Name: source.Name, Kind: source.Kind, URL: source.URL,
|
||||
IconURL: source.IconURL, Description: source.Description, Enabled: source.Enabled,
|
||||
LastSyncedAt: utcTime(source.LastSyncedAt), ItemCount: itemCount,
|
||||
BuiltIn: source.SeedKey != nil, LastSyncedAt: utcTime(source.LastSyncedAt), ItemCount: itemCount,
|
||||
CreatedAt: source.CreatedAt.UTC(), UpdatedAt: source.UpdatedAt.UTC(),
|
||||
}
|
||||
}
|
||||
@@ -329,13 +392,23 @@ func itemDTO(item models.SaDatasetItem) ItemDTO {
|
||||
|
||||
func cronDTO(cron models.SaDatasetCron) CronDTO {
|
||||
return CronDTO{
|
||||
ID: cron.Identity, SourceID: cron.SourceIdentity, Schedule: cron.Schedule,
|
||||
Status: cron.Status, Enabled: cron.Enabled, NextRunAt: utcTime(cron.NextRunAt),
|
||||
ID: cron.Identity, SourceID: cron.SourceIdentity, Status: cron.Status,
|
||||
LastRunAt: utcTime(cron.LastRunAt), LastResult: cron.LastResult,
|
||||
CreatedAt: cron.CreatedAt.UTC(), UpdatedAt: cron.UpdatedAt.UTC(),
|
||||
}
|
||||
}
|
||||
|
||||
func optionalNonNegativeInt(value string) (int, error) {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return 0, nil
|
||||
}
|
||||
parsed, err := strconv.Atoi(value)
|
||||
if err != nil || parsed < 0 {
|
||||
return 0, errors.New("invalid non-negative integer")
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func parseOptionalTime(value string) (*time.Time, error) {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return nil, nil
|
||||
|
||||
Reference in New Issue
Block a user