hmn/src/website/assets.go

115 lines
2.5 KiB
Go

package website
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"image"
"io"
"net/http"
"strconv"
"strings"
"git.handmade.network/hmn/hmn/src/assets"
"git.handmade.network/hmn/hmn/src/hmnurl"
"git.handmade.network/hmn/hmn/src/models"
)
type AssetUploadResult struct {
Url string `json:"url,omitempty"`
Mime string `json:"mime,omitempty"`
Error string `json:"error,omitempty"`
}
const assetMaxSize = 10 * 1024 * 1024
const assetMaxSizeAdmin = 10 * 1024 * 1024 * 1024
func AssetMaxSize(user *models.User) int {
if user != nil && user.IsStaff {
return assetMaxSizeAdmin
} else {
return assetMaxSize
}
}
func AssetUpload(c *RequestContext) ResponseData {
maxFilesize := AssetMaxSize(c.CurrentUser)
contentLength, hasLength := c.Req.Header["Content-Length"]
if hasLength {
filesize, err := strconv.Atoi(contentLength[0])
if err == nil && filesize > maxFilesize {
res := ResponseData{
StatusCode: http.StatusOK,
}
jsonString, _ := json.Marshal(AssetUploadResult{
Error: fmt.Sprintf("Filesize too big. Maximum size is %d.", maxFilesize),
})
res.Write(jsonString)
return res
}
}
filenameHeader, hasFilename := c.Req.Header["Hmn-Upload-Filename"]
originalFilename := "upload"
if hasFilename {
decodedFilename, err := base64.StdEncoding.DecodeString(filenameHeader[0])
if err == nil {
originalFilename = string(decodedFilename)
}
}
bodyReader := http.MaxBytesReader(c.Res, c.Req.Body, int64(maxFilesize))
data, err := io.ReadAll(bodyReader)
if err != nil {
res := ResponseData{
StatusCode: http.StatusBadRequest,
Errors: []error{err},
}
return res
}
mimeType := http.DetectContentType(data)
width := 0
height := 0
if strings.HasPrefix(mimeType, "image") {
config, _, err := image.DecodeConfig(bytes.NewReader(data))
if err == nil {
width = config.Width
height = config.Height
} else {
// NOTE(asaf): Not image
mimeType = "application/octet-stream"
}
}
asset, err := assets.Create(c, c.Conn, assets.CreateInput{
Content: data,
Filename: originalFilename,
ContentType: mimeType,
UploaderID: &c.CurrentUser.ID,
Width: width,
Height: height,
})
if err != nil {
res := ResponseData{
StatusCode: http.StatusBadRequest,
Errors: []error{err},
}
return res
}
res := ResponseData{
StatusCode: http.StatusOK,
}
jsonString, err := json.Marshal(AssetUploadResult{
Url: hmnurl.BuildS3Asset(asset.S3Key),
Mime: asset.MimeType,
})
res.Write(jsonString)
return res
}