package handlers import ( "crypto/sha256" "encoding/hex" "encoding/json" "io" "net/http" "os" "cmr-backend/internal/apperr" "cmr-backend/internal/httpx" "cmr-backend/internal/service" ) type AdminAssetHandler struct { service *service.AdminAssetService } func NewAdminAssetHandler(service *service.AdminAssetService) *AdminAssetHandler { return &AdminAssetHandler{service: service} } func (h *AdminAssetHandler) ListAssets(w http.ResponseWriter, r *http.Request) { result, err := h.service.ListManagedAssets(r.Context(), parseAdminLimit(r)) if err != nil { httpx.WriteError(w, err) return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"data": result}) } func (h *AdminAssetHandler) GetAsset(w http.ResponseWriter, r *http.Request) { result, err := h.service.GetManagedAsset(r.Context(), r.PathValue("assetPublicID")) if err != nil { httpx.WriteError(w, err) return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"data": result}) } func (h *AdminAssetHandler) RegisterLink(w http.ResponseWriter, r *http.Request) { var req service.RegisterLinkAssetInput if err := httpx.DecodeJSON(r, &req); err != nil { httpx.WriteError(w, apperr.New(http.StatusBadRequest, "invalid_json", "invalid request body: "+err.Error())) return } result, err := h.service.RegisterExternalLink(r.Context(), req) if err != nil { httpx.WriteError(w, err) return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"data": result}) } func (h *AdminAssetHandler) UploadFile(w http.ResponseWriter, r *http.Request) { if err := r.ParseMultipartForm(64 << 20); err != nil { httpx.WriteError(w, apperr.New(http.StatusBadRequest, "invalid_multipart", "invalid multipart form: "+err.Error())) return } file, header, err := r.FormFile("file") if err != nil { httpx.WriteError(w, apperr.New(http.StatusBadRequest, "file_required", "multipart file field 'file' is required")) return } defer file.Close() tmpFile, err := os.CreateTemp("", "cmr-upload-*"+header.Filename) if err != nil { httpx.WriteError(w, err) return } tmpPath := tmpFile.Name() defer os.Remove(tmpPath) hash := sha256.New() written, err := io.Copy(io.MultiWriter(tmpFile, hash), file) if err != nil { tmpFile.Close() httpx.WriteError(w, err) return } if err := tmpFile.Close(); err != nil { httpx.WriteError(w, err) return } input := service.UploadAssetFileInput{ AssetType: r.FormValue("assetType"), AssetCode: r.FormValue("assetCode"), Version: r.FormValue("version"), Title: stringPtrOrNil(r.FormValue("title")), ObjectDir: stringPtrOrNil(r.FormValue("objectDir")), FileName: header.Filename, ContentType: header.Header.Get("Content-Type"), FileSize: written, Checksum: hex.EncodeToString(hash.Sum(nil)), TempPath: tmpPath, Status: r.FormValue("status"), Metadata: parseMetadataJSON(r.FormValue("metadataJson")), } result, err := h.service.UploadAssetFile(r.Context(), input) if err != nil { httpx.WriteError(w, err) return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{ "data": result, "meta": map[string]any{ "uploadedBytes": written, "checksumSha256": input.Checksum, }, }) } func stringPtrOrNil(value string) *string { if value == "" { return nil } return &value } func parseMetadataJSON(raw string) map[string]any { if raw == "" { return nil } var payload map[string]any _ = json.Unmarshal([]byte(raw), &payload) return payload }