package server import ( "errors" "net/http" "strings" "github.com/Autumn-27/artex/db" ) const maxTaskAssetRequestBytes = 512 << 10 // 작업 자산 API 가 사용자에게 돌려주는 오류 응답 문구. 필드명(scope·asset_ids)은 // 요청 본문 키라 원문 그대로 두고, 사람이 읽는 메시지만 한국어로 둔다. const ( errTaskAssetRequestTooLarge = "请求体过大" errTaskAssetScopeConflict = "scope 与 asset_ids 不能同时提交" ) func writeTaskAssetError(w http.ResponseWriter, err error) { switch { case errors.Is(err, db.ErrTaskAssetInvalid): writeErr(w, http.StatusBadRequest, err.Error()) case errors.Is(err, db.ErrTaskAssetTaskNotFound), errors.Is(err, db.ErrTaskAssetAssetNotFound): writeErr(w, http.StatusNotFound, err.Error()) default: writeErr(w, http.StatusInternalServerError, err.Error()) } } func (s *Server) attachTaskAssets(w http.ResponseWriter, r *http.Request) { task, ok := s.m.Task(r.PathValue("id")) if !ok { writeErr(w, http.StatusNotFound, "task not found") return } r.Body = http.MaxBytesReader(w, r.Body, maxTaskAssetRequestBytes) var request struct { AssetIDs []int64 `json:"asset_ids"` SourceSummary string `json:"source_summary"` Scope companyScopeInputs `json:"scope"` } if err := decode(r, &request); err != nil { var tooLarge *http.MaxBytesError if errors.As(err, &tooLarge) { writeErr(w, http.StatusRequestEntityTooLarge, errTaskAssetRequestTooLarge) } else { writeErr(w, http.StatusBadRequest, err.Error()) } return } request.SourceSummary = strings.TrimSpace(request.SourceSummary) taskID, _ := parseTaskID(task.ID) if request.Scope != nil && len(request.AssetIDs) > 0 { writeErr(w, http.StatusBadRequest, errTaskAssetScopeConflict) return } if request.Scope != nil { mutation, err := s.m.Assets().RegisterTaskAssetScopes(taskID, request.Scope) if err != nil { writeTaskAssetError(w, err) return } task.Notify() writeJSON(w, http.StatusOK, mutation) return } mutation, err := s.m.Assets().AttachAssetsToTask(taskID, request.AssetIDs, request.SourceSummary) if err != nil { writeTaskAssetError(w, err) return } task.Notify() writeJSON(w, http.StatusOK, mutation) } func (s *Server) detachTaskAsset(w http.ResponseWriter, r *http.Request) { task, ok := s.m.Task(r.PathValue("id")) if !ok { writeErr(w, http.StatusNotFound, "task not found") return } assetID, ok := pathInt(r, "assetID") if !ok { writeErr(w, http.StatusBadRequest, "bad asset id") return } taskID, _ := parseTaskID(task.ID) detached, err := s.m.Assets().DetachAssetFromTask(taskID, assetID) if err != nil { writeTaskAssetError(w, err) return } if !detached { writeErr(w, http.StatusNotFound, "asset is not associated with this task") return } task.Notify() writeJSON(w, http.StatusOK, map[string]any{"detached": assetID}) } func (s *Server) taskIntentAssets(w http.ResponseWriter, r *http.Request) { task, ok := s.m.Task(r.PathValue("id")) if !ok { writeErr(w, http.StatusNotFound, "task not found") return } taskID, _ := parseTaskID(task.ID) assets, err := s.m.Assets().IntentAssets(taskID) if err != nil { writeTaskAssetError(w, err) return } writeJSON(w, http.StatusOK, map[string]any{"assets": assets}) }