115 lines
2.8 KiB
Go
115 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"reanimator/internal/repository/timeline"
|
|
)
|
|
|
|
func writeTimelineResponse(w http.ResponseWriter, r *http.Request, repo *timeline.EventRepository, subjectType string, subjectID string) {
|
|
limit := 50
|
|
if raw := r.URL.Query().Get("limit"); raw != "" {
|
|
if parsed, err := strconv.Atoi(raw); err == nil {
|
|
limit = parsed
|
|
} else {
|
|
writeError(w, http.StatusBadRequest, "invalid limit")
|
|
return
|
|
}
|
|
}
|
|
|
|
var cursor *timeline.Cursor
|
|
if raw := r.URL.Query().Get("cursor"); raw != "" {
|
|
decoded, err := timeline.DecodeCursor(raw)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid cursor")
|
|
return
|
|
}
|
|
cursor = &decoded
|
|
}
|
|
|
|
items, next, err := repo.List(r.Context(), subjectType, subjectID, limit, cursor)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "list timeline failed")
|
|
return
|
|
}
|
|
|
|
var nextCursor *string
|
|
if next != nil {
|
|
value := timeline.EncodeCursor(*next)
|
|
nextCursor = &value
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"items": items,
|
|
"next_cursor": nextCursor,
|
|
})
|
|
}
|
|
|
|
func writeImportHistoryResponse(w http.ResponseWriter, r *http.Request, repo *timeline.EventRepository, subjectType string, subjectID string) {
|
|
limit := 20
|
|
if raw := r.URL.Query().Get("limit"); raw != "" {
|
|
if parsed, err := strconv.Atoi(raw); err == nil {
|
|
limit = parsed
|
|
} else {
|
|
writeError(w, http.StatusBadRequest, "invalid limit")
|
|
return
|
|
}
|
|
}
|
|
|
|
var cursor *timeline.Cursor
|
|
if raw := r.URL.Query().Get("cursor"); raw != "" {
|
|
decoded, err := timeline.DecodeCursor(raw)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid cursor")
|
|
return
|
|
}
|
|
cursor = &decoded
|
|
}
|
|
|
|
var (
|
|
items []timeline.ImportHistoryItem
|
|
next *timeline.Cursor
|
|
err error
|
|
)
|
|
switch subjectType {
|
|
case "asset":
|
|
items, next, err = repo.ListAssetImportHistory(r.Context(), subjectID, limit, cursor)
|
|
case "component":
|
|
items, next, err = repo.ListComponentImportHistory(r.Context(), subjectID, limit, cursor)
|
|
default:
|
|
writeError(w, http.StatusBadRequest, "unsupported subject type")
|
|
return
|
|
}
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "list import history failed")
|
|
return
|
|
}
|
|
|
|
var nextCursor *string
|
|
if next != nil {
|
|
value := timeline.EncodeCursor(*next)
|
|
nextCursor = &value
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"items": items,
|
|
"next_cursor": nextCursor,
|
|
})
|
|
}
|
|
|
|
func parseTimelineID(path, prefix string) string {
|
|
if !strings.HasPrefix(path, prefix) || !strings.HasSuffix(path, "/timeline") {
|
|
return ""
|
|
}
|
|
trimmed := strings.TrimPrefix(path, prefix)
|
|
trimmed = strings.TrimSuffix(trimmed, "/timeline")
|
|
if trimmed == "" || strings.Contains(trimmed, "/") {
|
|
return ""
|
|
}
|
|
if !entityIDPattern.MatchString(trimmed) {
|
|
return ""
|
|
}
|
|
return trimmed
|
|
}
|