2021-09-21 23:13:11 +00:00
|
|
|
package website
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2021-09-22 19:18:39 +00:00
|
|
|
"encoding/base64"
|
2021-09-21 23:13:11 +00:00
|
|
|
"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"]
|
2021-09-22 19:18:39 +00:00
|
|
|
originalFilename := "upload"
|
2021-09-21 23:13:11 +00:00
|
|
|
if hasFilename {
|
2021-09-22 19:18:39 +00:00
|
|
|
decodedFilename, err := base64.StdEncoding.DecodeString(filenameHeader[0])
|
|
|
|
if err == nil {
|
|
|
|
originalFilename = string(decodedFilename)
|
|
|
|
}
|
2021-09-21 23:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|