resource_manager/api/api.go

191 lines
4.7 KiB
Go

package api
import (
"bytes"
"encoding/base64"
"github.com/gin-gonic/gin"
"log"
"net/http"
"resource-manager/domain/resize"
"resource-manager/domain/resource"
"strings"
"time"
)
type UploadRequest struct {
Content string `json:"content"`
Path string `json:"path"`
Properties struct {
Overwrite bool `json:"overwrite"`
MimeType string `json:"mimeType"`
} `json:"properties"`
Resize *struct {
Width int `json:"width"`
Height int `json:"height"`
Type string `json:"type"`
} `json:"resize"`
}
func NoMethod() gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{
"status": 404,
"created": time.Now(),
"message": "no handler for method '" + c.Request.Method + "'",
})
}
}
func NoRoute() gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{
"status": 404,
"created": time.Now(),
"message": "no handler for " + c.Request.Method + " '" + c.Request.URL.RequestURI() + "'",
})
}
}
func HandleUpload(resourceManager resource.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
var request UploadRequest
if err := c.BindJSON(&request); err != nil {
c.AbortWithStatusJSON(400, gin.H{"error": "bad request"})
return
}
content, err := base64.StdEncoding.DecodeString(request.Content)
if err != nil {
c.AbortWithStatusJSON(400, gin.H{"error": "bad request"})
return
}
if resize.IsResizable(readMimeType(request.Path, request.Properties.MimeType)) && request.Resize != nil {
content, err = resize.ResizeImage(content, resize.Resize{
Height: request.Resize.Height,
Width: request.Resize.Width,
Type: mapResizeType(request.Resize.Type),
})
if err != nil {
c.AbortWithStatusJSON(400, gin.H{"error": "bad request"})
return
}
}
log.Printf("Uploading '%s'...", request.Path)
resourceManager.Upload(resource.UploadRequest{
Buffer: bytes.NewBuffer(content),
Path: request.Path,
MimeType: request.Properties.MimeType,
Overwrite: request.Properties.Overwrite,
})
log.Printf("Uploaded '%s'", request.Path)
// we return this as success
c.Status(http.StatusNoContent)
}
}
func HandleCopy(resourceManager resource.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
from := c.Query("from")
to := c.Query("to")
overwrite := c.Query("overwrite") == "true"
log.Printf("Copying from '%s' to '%s' (overwrite=%v)...", from, to, overwrite)
if err := resourceManager.Copy(from, to, overwrite); err != nil {
log.Println(err)
c.AbortWithStatus(500)
} else {
log.Printf("Done copyting from '%s' to '%s' (overwrite=%v)", from, to, overwrite)
c.Status(201)
}
}
}
func HandlePresign(resourceManager resource.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Query("path")
url, err := resourceManager.Presign(c, path)
if err != nil {
c.AbortWithStatus(404)
return
}
log.Printf("Presigned '%s'", path)
if c.Query("redirect") == "true" {
c.Redirect(http.StatusTemporaryRedirect, url)
} else {
c.JSON(200, gin.H{"url": url})
}
}
}
func HandleDownload(resourceManager resource.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Query("path")
log.Printf("Downloading '%s'...", path)
data, err := resourceManager.Download(c, path)
if err == nil {
log.Printf("Downloaded '%s'", path)
c.Header("content-disposition", "inline; filename=\""+filename(path)+"\"")
c.Data(200, readMimeType(path, ""), data)
} else {
c.AbortWithStatus(http.StatusNotFound)
}
}
}
func HandleDelete(resourceManager resource.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Query("path")
log.Printf("Deleting '%s'...", path)
if err := resourceManager.Delete(path); err != nil {
c.AbortWithError(400, err)
} else {
log.Printf("Deleted '%s'", path)
c.Status(204)
}
}
}
var mimeTypes = map[string]string{
"jpg": "image/jpg",
"jpeg": "image/jpeg",
"png": "image/png",
"gif": "image/gif",
"json": "application/json",
"pdf": "application/pdf",
"html": "text/html",
"xml": "application/xml",
}
func readMimeType(path string, mimeType string) string {
if mimeType != "" {
return mimeType
}
parts := strings.Split(path, ".")
fileType := strings.ToLower(parts[len(parts)-1])
if value, exists := mimeTypes[fileType]; exists {
return value
}
return "application/octet-stream"
}
func mapResizeType(resizeType string) resize.ResizeType {
switch resizeType {
case "cover":
return resize.Cover
case "contain":
return resize.Contain
case "exact_height":
return resize.ExactHeight
case "exact_width":
return resize.ExactWidth
default:
return resize.Exact
}
}
func filename(path string) string {
substrings := strings.Split(path, "/")
return substrings[len(substrings)-1]
}