batch upload impl
This commit is contained in:
+55
-32
@@ -5,6 +5,7 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"queryorchestration/internal/document/batch/storage"
|
||||
documentupload "queryorchestration/internal/document/upload"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -128,48 +129,70 @@ func (s *Controllers) ListDocumentBatches(ctx echo.Context, clientId ClientID, p
|
||||
|
||||
// UploadDocumentBatch handles ZIP archive upload containing multiple PDFs
|
||||
func (s *Controllers) UploadDocumentBatch(ctx echo.Context, clientId ClientID) error {
|
||||
// Get the multipart form
|
||||
form, err := ctx.MultipartForm()
|
||||
// Parse multipart form to get ZIP file
|
||||
file, err := ctx.FormFile("archive")
|
||||
if err != nil {
|
||||
slog.Error("unable to get form data", "error", err)
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "unable to get form data")
|
||||
slog.Error("failed to get uploaded file", "error", err, "client_id", clientId)
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "file upload required")
|
||||
}
|
||||
|
||||
// Get the archive file
|
||||
files := form.File["archive"]
|
||||
if len(files) == 0 {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "missing archive file")
|
||||
} else if len(files) > 1 {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "too many files")
|
||||
}
|
||||
file := files[0]
|
||||
|
||||
// Skip ZIP validation for tests - in production this would check file content
|
||||
// if file.Header.Get("Content-Type") != "application/zip" {
|
||||
// return echo.NewHTTPError(http.StatusBadRequest, "file must be a ZIP archive")
|
||||
// }
|
||||
|
||||
// For now, we'll create a batch record with placeholder total documents
|
||||
// In the real implementation, we would:
|
||||
// 1. Store the ZIP file to S3
|
||||
// 2. Start an async process to extract and process PDFs
|
||||
// 3. Return immediately with 202 Accepted
|
||||
|
||||
// Create batch record
|
||||
batchID, err := s.svc.DocumentBatch.Create(ctx.Request().Context(), clientId, file.Filename, 0)
|
||||
// Open uploaded file
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
slog.Error("unable to create batch", "error", err)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "unable to create batch")
|
||||
slog.Error("failed to open uploaded file", "error", err, "client_id", clientId)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to process uploaded file")
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
// Initialize storage service with objectstore config
|
||||
storageService := storage.New(s.cfg)
|
||||
|
||||
// Validate ZIP file
|
||||
err = storageService.ValidateZIPFile(file.Filename, file.Size)
|
||||
if err != nil {
|
||||
slog.Error("ZIP validation failed", "filename", file.Filename, "size", file.Size, "error", err, "client_id", clientId)
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("invalid ZIP file: %v", err))
|
||||
}
|
||||
|
||||
// Build response
|
||||
// Store ZIP file to S3
|
||||
storageResult, err := storageService.StoreZIPFile(ctx.Request().Context(), string(clientId), file.Filename, src)
|
||||
if err != nil {
|
||||
slog.Error("failed to store ZIP file", "error", err, "client_id", clientId)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to store ZIP file")
|
||||
}
|
||||
|
||||
// Create batch record with storage metadata
|
||||
// Note: totalDocs is unknown at this point, will be determined during extraction in later parts
|
||||
batchID, err := s.svc.DocumentBatch.CreateWithStorage(
|
||||
ctx.Request().Context(),
|
||||
string(clientId),
|
||||
file.Filename,
|
||||
0, // totalDocs unknown in Part 1
|
||||
storageResult.Bucket,
|
||||
storageResult.Key,
|
||||
storageResult.SizeBytes,
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error("failed to create batch record", "error", err, "client_id", clientId)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to create batch record")
|
||||
}
|
||||
|
||||
slog.Info("ZIP batch upload completed",
|
||||
"batch_id", batchID,
|
||||
"filename", file.Filename,
|
||||
"size_bytes", storageResult.SizeBytes,
|
||||
"s3_key", storageResult.Key,
|
||||
"client_id", clientId,
|
||||
)
|
||||
|
||||
// Return 202 Accepted with batch ID and status URL
|
||||
statusUrl := fmt.Sprintf("/clients/%s/documents/batches/%s", clientId, batchID)
|
||||
response := BatchUploadResponse{
|
||||
BatchId: BatchID(batchID),
|
||||
Status: BatchStatusProcessing,
|
||||
StatusUrl: fmt.Sprintf("/client/%s/document/batch/%s", clientId, batchID.String()),
|
||||
Status: "processing",
|
||||
StatusUrl: statusUrl,
|
||||
}
|
||||
|
||||
// Return 202 Accepted for async processing
|
||||
return ctx.JSON(http.StatusAccepted, response)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user