package infra import ( "net/http" ) // UploadHandler retorna un http.HandlerFunc completo para multipart upload. Compone // internamente UploadParse + FileValidateType + FileSaveDisk segun cfg. // // Comportamiento: // - Parsea el multipart con maxSize = cfg.MaxFileSize. // - Para cada archivo: valida tipo por magic bytes contra cfg.AllowedTypes, // guarda en cfg.BaseDir con FileSaveDisk, sobreescribe ContentType con el // MIME real detectado. // - Responde 200 con JSON `{"files": [UploadedFile, ...]}`. // - Errores: 400 si el parse falla, 415 si algun archivo es de tipo no permitido, // 500 si falla el guardado. func UploadHandler(cfg StorageConfig) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { files, err := UploadParse(r, cfg.MaxFileSize) if err != nil { HTTPErrorResponse(w, HTTPError{ Status: http.StatusBadRequest, Code: "parse_error", Message: err.Error(), }) return } var saved []UploadedFile for _, pf := range files { mime, ok := FileValidateType(pf.Header, cfg.AllowedTypes) if !ok { HTTPErrorResponse(w, HTTPError{ Status: http.StatusUnsupportedMediaType, Code: "invalid_type", Message: "tipo no permitido: " + mime, }) return } uploaded, err := FileSaveDisk(cfg.BaseDir, pf.Filename, pf.Content) if err != nil { HTTPErrorResponse(w, HTTPError{ Status: http.StatusInternalServerError, Code: "save_error", Message: err.Error(), }) return } uploaded.ContentType = mime saved = append(saved, uploaded) } HTTPJSONResponse(w, http.StatusOK, map[string]any{"files": saved}) } }