Files

135 lines
3.3 KiB
Go

package server
import (
"errors"
"net/http"
"strconv"
"github.com/Autumn-27/artex/db"
)
func intelligenceError(w http.ResponseWriter, err error) {
switch {
case errors.Is(err, db.ErrIntelligenceInvalid):
writeErr(w, 400, err.Error())
case errors.Is(err, db.ErrIntelligenceNotFound):
writeErr(w, 404, "情报不存在或不属于当前范围")
default:
writeErr(w, 500, err.Error())
}
}
func (s *Server) intelligenceFilter(w http.ResponseWriter, r *http.Request) (db.IntelligenceFilter, bool) {
f := db.IntelligenceFilter{}
id, ok := pathInt(r, "id")
if !ok || id <= 0 {
writeErr(w, 400, "无效 ID")
return f, false
}
if r.PathValue("scope") == "assets" {
f.AssetID = id
} else {
f.TaskID = id
}
var exists bool
var err error
if f.TaskID > 0 {
err = s.m.pg.QueryRowContext(r.Context(), `SELECT EXISTS(SELECT 1 FROM tasks WHERE id=$1 AND deleted_at IS NULL)`, id).Scan(&exists)
} else {
err = s.m.pg.QueryRowContext(r.Context(), `SELECT EXISTS(SELECT 1 FROM assets WHERE id=$1)`, id).Scan(&exists)
}
if err != nil {
intelligenceError(w, err)
return f, false
}
if !exists {
writeErr(w, 404, "任务或资产不存在")
return f, false
}
q := r.URL.Query()
f.Kind = q.Get("kind")
f.Status = q.Get("status")
f.Query = q.Get("q")
f.Limit, _ = strconv.Atoi(q.Get("limit"))
f.Offset, _ = strconv.Atoi(q.Get("offset"))
if len(f.Query) > 500 {
writeErr(w, 400, "搜索关键词过长")
return f, false
}
return f, true
}
func (s *Server) listIntelligence(w http.ResponseWriter, r *http.Request) {
f, ok := s.intelligenceFilter(w, r)
if !ok {
return
}
page, err := s.m.pg.ListIntelligence(r.Context(), f)
if err != nil {
intelligenceError(w, err)
return
}
w.Header().Set("Cache-Control", "no-store")
writeJSON(w, 200, page)
}
func (s *Server) getIntelligence(w http.ResponseWriter, r *http.Request) {
f, ok := s.intelligenceFilter(w, r)
if !ok {
return
}
id, ok := pathInt(r, "intelID")
if !ok {
writeErr(w, 400, "无效情报 ID")
return
}
item, err := s.m.pg.GetIntelligence(r.Context(), id)
if err != nil {
intelligenceError(w, err)
return
}
allowed := false
if f.TaskID > 0 {
err = s.m.pg.QueryRowContext(r.Context(), `SELECT $1::bigint=$2::bigint OR EXISTS(SELECT 1 FROM task_relations WHERE task_id=$1 AND source_task_id=$2)`, f.TaskID, item.TaskID).Scan(&allowed)
} else {
for _, assetID := range item.AssetIDs {
if assetID == f.AssetID {
allowed = true
}
}
}
if err != nil {
intelligenceError(w, err)
return
}
if !allowed {
intelligenceError(w, db.ErrIntelligenceNotFound)
return
}
item.Inherited = f.TaskID > 0 && item.TaskID != f.TaskID
w.Header().Set("Cache-Control", "no-store")
writeJSON(w, 200, item)
}
func (s *Server) updateIntelligence(w http.ResponseWriter, r *http.Request) {
taskID, ok := pathInt(r, "id")
if !ok {
writeErr(w, 400, "无效任务 ID")
return
}
id, ok := pathInt(r, "intelID")
if !ok {
writeErr(w, 400, "无效情报 ID")
return
}
r.Body = http.MaxBytesReader(w, r.Body, 4096)
var req struct {
Status string `json:"status"`
}
if err := decode(r, &req); err != nil {
writeErr(w, 400, "无效请求")
return
}
if err := s.m.pg.UpdateIntelligenceStatus(r.Context(), taskID, id, req.Status); err != nil {
intelligenceError(w, err)
return
}
writeJSON(w, 200, map[string]bool{"updated": true})
}