refactor(uploads): drop legacy multipart code paths
Backend CI / Test (push) Has been cancelled
Backend CI / Contract Tests (push) Has been cancelled
Backend CI / Build (push) Has been cancelled
Backend CI / Lint (push) Has been cancelled
Backend CI / Secret Scanning (push) Has been cancelled

The presigned-URL upload flow (POST /api/uploads/presign + direct B2 POST
+ upload_ids[] in entity creation) is now the only image upload path. The
legacy multipart routes and DTO fields used by older clients are removed:

Removed:
  - POST /api/uploads/image/        (legacy multipart upload → URL)
  - POST /api/uploads/document/     (legacy multipart upload → URL)
  - POST /api/uploads/completion/   (legacy multipart upload → URL)
  - Multipart branch in POST /api/task-completions/ (now JSON-only)
  - CreateTaskCompletionRequest.ImageURLs DTO field
  - UpdateTaskCompletionRequest.ImageURLs DTO field
  - CreateDocumentRequest.ImageURLs DTO field
  - Service-layer ImageURLs loops in task_service.CreateCompletion,
    task_service.UpdateCompletion, document_service.CreateDocument
  - Tests exercising the removed paths
  - Now-unused imports (strings/time/decimal) in task_handler.go

Kept:
  - DELETE /api/uploads/  (orphan-cleanup endpoint, still useful)
  - POST /api/uploads/presign/  (the new path)
  - POST /api/documents/:id/images/  (uses storage_service.Upload directly,
    same multipart pattern but separate code path; deferred for now)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-05-01 15:19:21 -07:00
parent 29c9014a33
commit b7f83293b8
9 changed files with 43 additions and 261 deletions
-54
View File
@@ -44,60 +44,6 @@ func (h *UploadHandler) SetUploadService(s *services.UploadService) {
h.uploadService = s
}
// UploadImage handles POST /api/uploads/image
// Accepts multipart/form-data with "file" field
func (h *UploadHandler) UploadImage(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return apperrors.BadRequest("error.no_file_provided")
}
// Get category from query param (default: images)
category := c.QueryParam("category")
if category == "" {
category = "images"
}
result, err := h.storageService.Upload(c.Request().Context(), file, category)
if err != nil {
return err
}
return c.JSON(http.StatusOK, result)
}
// UploadDocument handles POST /api/uploads/document
// Accepts multipart/form-data with "file" field
func (h *UploadHandler) UploadDocument(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return apperrors.BadRequest("error.no_file_provided")
}
result, err := h.storageService.Upload(c.Request().Context(), file, "documents")
if err != nil {
return err
}
return c.JSON(http.StatusOK, result)
}
// UploadCompletion handles POST /api/uploads/completion
// For task completion photos
func (h *UploadHandler) UploadCompletion(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return apperrors.BadRequest("error.no_file_provided")
}
result, err := h.storageService.Upload(c.Request().Context(), file, "completions")
if err != nil {
return err
}
return c.JSON(http.StatusOK, result)
}
// DeleteFileRequest is the request body for deleting a file.
type DeleteFileRequest struct {
URL string `json:"url" validate:"required"`