admin_asset_handler.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package handlers
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "encoding/json"
  6. "io"
  7. "net/http"
  8. "os"
  9. "cmr-backend/internal/apperr"
  10. "cmr-backend/internal/httpx"
  11. "cmr-backend/internal/service"
  12. )
  13. type AdminAssetHandler struct {
  14. service *service.AdminAssetService
  15. }
  16. func NewAdminAssetHandler(service *service.AdminAssetService) *AdminAssetHandler {
  17. return &AdminAssetHandler{service: service}
  18. }
  19. func (h *AdminAssetHandler) ListAssets(w http.ResponseWriter, r *http.Request) {
  20. result, err := h.service.ListManagedAssets(r.Context(), parseAdminLimit(r))
  21. if err != nil {
  22. httpx.WriteError(w, err)
  23. return
  24. }
  25. httpx.WriteJSON(w, http.StatusOK, map[string]any{"data": result})
  26. }
  27. func (h *AdminAssetHandler) GetAsset(w http.ResponseWriter, r *http.Request) {
  28. result, err := h.service.GetManagedAsset(r.Context(), r.PathValue("assetPublicID"))
  29. if err != nil {
  30. httpx.WriteError(w, err)
  31. return
  32. }
  33. httpx.WriteJSON(w, http.StatusOK, map[string]any{"data": result})
  34. }
  35. func (h *AdminAssetHandler) RegisterLink(w http.ResponseWriter, r *http.Request) {
  36. var req service.RegisterLinkAssetInput
  37. if err := httpx.DecodeJSON(r, &req); err != nil {
  38. httpx.WriteError(w, apperr.New(http.StatusBadRequest, "invalid_json", "invalid request body: "+err.Error()))
  39. return
  40. }
  41. result, err := h.service.RegisterExternalLink(r.Context(), req)
  42. if err != nil {
  43. httpx.WriteError(w, err)
  44. return
  45. }
  46. httpx.WriteJSON(w, http.StatusCreated, map[string]any{"data": result})
  47. }
  48. func (h *AdminAssetHandler) UploadFile(w http.ResponseWriter, r *http.Request) {
  49. if err := r.ParseMultipartForm(64 << 20); err != nil {
  50. httpx.WriteError(w, apperr.New(http.StatusBadRequest, "invalid_multipart", "invalid multipart form: "+err.Error()))
  51. return
  52. }
  53. file, header, err := r.FormFile("file")
  54. if err != nil {
  55. httpx.WriteError(w, apperr.New(http.StatusBadRequest, "file_required", "multipart file field 'file' is required"))
  56. return
  57. }
  58. defer file.Close()
  59. tmpFile, err := os.CreateTemp("", "cmr-upload-*"+header.Filename)
  60. if err != nil {
  61. httpx.WriteError(w, err)
  62. return
  63. }
  64. tmpPath := tmpFile.Name()
  65. defer os.Remove(tmpPath)
  66. hash := sha256.New()
  67. written, err := io.Copy(io.MultiWriter(tmpFile, hash), file)
  68. if err != nil {
  69. tmpFile.Close()
  70. httpx.WriteError(w, err)
  71. return
  72. }
  73. if err := tmpFile.Close(); err != nil {
  74. httpx.WriteError(w, err)
  75. return
  76. }
  77. input := service.UploadAssetFileInput{
  78. AssetType: r.FormValue("assetType"),
  79. AssetCode: r.FormValue("assetCode"),
  80. Version: r.FormValue("version"),
  81. Title: stringPtrOrNil(r.FormValue("title")),
  82. ObjectDir: stringPtrOrNil(r.FormValue("objectDir")),
  83. FileName: header.Filename,
  84. ContentType: header.Header.Get("Content-Type"),
  85. FileSize: written,
  86. Checksum: hex.EncodeToString(hash.Sum(nil)),
  87. TempPath: tmpPath,
  88. Status: r.FormValue("status"),
  89. Metadata: parseMetadataJSON(r.FormValue("metadataJson")),
  90. }
  91. result, err := h.service.UploadAssetFile(r.Context(), input)
  92. if err != nil {
  93. httpx.WriteError(w, err)
  94. return
  95. }
  96. httpx.WriteJSON(w, http.StatusCreated, map[string]any{
  97. "data": result,
  98. "meta": map[string]any{
  99. "uploadedBytes": written,
  100. "checksumSha256": input.Checksum,
  101. },
  102. })
  103. }
  104. func stringPtrOrNil(value string) *string {
  105. if value == "" {
  106. return nil
  107. }
  108. return &value
  109. }
  110. func parseMetadataJSON(raw string) map[string]any {
  111. if raw == "" {
  112. return nil
  113. }
  114. var payload map[string]any
  115. _ = json.Unmarshal([]byte(raw), &payload)
  116. return payload
  117. }