package media import ( "errors" "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type Handler struct { service *Service } func NewHandler(service *Service) *Handler { return &Handler{service: service} } type mediaResponse struct { ID uuid.UUID `json:"id"` Filename string `json:"filename"` URL string `json:"url"` MimeType string `json:"mime_type"` SizeBytes int64 `json:"size_bytes"` AltText string `json:"alt_text"` } func toResponse(m *Media) mediaResponse { return mediaResponse{ ID: m.ID, Filename: m.Filename, URL: m.URL, MimeType: m.MimeType, SizeBytes: m.SizeBytes, AltText: m.AltText, } } func (h *Handler) List(c *gin.Context) { list, err := h.service.List(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list media"}) return } resp := make([]mediaResponse, 0, len(list)) for _, m := range list { resp = append(resp, toResponse(m)) } c.JSON(http.StatusOK, gin.H{"media": resp}) } func (h *Handler) Upload(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "missing file field"}) return } file, err := fileHeader.Open() if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "failed to open uploaded file"}) return } defer file.Close() contentType := fileHeader.Header.Get("Content-Type") altText := c.PostForm("alt_text") m, err := h.service.Upload(c.Request.Context(), fileHeader.Filename, file, fileHeader.Size, contentType, altText) if err != nil { switch { case errors.Is(err, ErrFileTooLarge): c.JSON(http.StatusRequestEntityTooLarge, gin.H{"error": "file exceeds the maximum allowed size"}) case errors.Is(err, ErrUnsupportedType): c.JSON(http.StatusUnsupportedMediaType, gin.H{"error": "unsupported file type"}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to upload file"}) } return } c.JSON(http.StatusCreated, toResponse(m)) } type updateRequest struct { AltText string `json:"alt_text"` } func (h *Handler) Update(c *gin.Context) { id, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"}) return } var req updateRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "validation error", "details": err.Error()}) return } m, err := h.service.UpdateAltText(c.Request.Context(), id, req.AltText) if err != nil { if errors.Is(err, ErrNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "media not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update media"}) return } c.JSON(http.StatusOK, toResponse(m)) } func (h *Handler) Delete(c *gin.Context) { id, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"}) return } if err := h.service.Delete(c.Request.Context(), id); err != nil { if errors.Is(err, ErrNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "media not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete media"}) return } c.Status(http.StatusNoContent) }