111 lines
2.4 KiB
Go
111 lines
2.4 KiB
Go
|
package website
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"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.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 := ""
|
||
|
if hasFilename {
|
||
|
originalFilename = strings.ReplaceAll(filenameHeader[0], " ", "_")
|
||
|
}
|
||
|
|
||
|
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.Context(), 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
|
||
|
}
|