mirror of https://github.com/gabehf/Koito.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
6.1 KiB
199 lines
6.1 KiB
package handlers
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gabehf/koito/internal/catalog"
|
|
"github.com/gabehf/koito/internal/cfg"
|
|
"github.com/gabehf/koito/internal/db"
|
|
"github.com/gabehf/koito/internal/logger"
|
|
"github.com/gabehf/koito/internal/utils"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type ReplaceImageResponse struct {
|
|
Success bool `json:"success"`
|
|
Image string `json:"image"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
func ReplaceImageHandler(store db.DB) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
l := logger.FromContext(ctx)
|
|
|
|
l.Debug().Msg("ReplaceImageHandler: Received request to replace image")
|
|
|
|
artistIdStr := r.FormValue("artist_id")
|
|
artistId, _ := strconv.Atoi(artistIdStr)
|
|
albumIdStr := r.FormValue("album_id")
|
|
albumId, _ := strconv.Atoi(albumIdStr)
|
|
|
|
if artistId != 0 && albumId != 0 {
|
|
l.Debug().Msg("ReplaceImageHandler: Both artist_id and album_id are set, rejecting request")
|
|
utils.WriteError(w, "Only one of artist_id and album_id can be set", http.StatusBadRequest)
|
|
return
|
|
} else if artistId == 0 && albumId == 0 {
|
|
l.Debug().Msg("ReplaceImageHandler: Neither artist_id nor album_id are set, rejecting request")
|
|
utils.WriteError(w, "One of artist_id and album_id must be set", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var oldImage *uuid.UUID
|
|
if artistId != 0 {
|
|
l.Debug().Msgf("ReplaceImageHandler: Fetching artist with ID %d", artistId)
|
|
a, err := store.GetArtist(ctx, db.GetArtistOpts{
|
|
ID: int32(artistId),
|
|
})
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Artist with specified ID could not be found")
|
|
utils.WriteError(w, "Artist with specified id could not be found", http.StatusBadRequest)
|
|
return
|
|
}
|
|
oldImage = a.Image
|
|
} else if albumId != 0 {
|
|
l.Debug().Msgf("ReplaceImageHandler: Fetching album with ID %d", albumId)
|
|
a, err := store.GetAlbum(ctx, db.GetAlbumOpts{
|
|
ID: int32(albumId),
|
|
})
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Album with specified ID could not be found")
|
|
utils.WriteError(w, "Album with specified id could not be found", http.StatusBadRequest)
|
|
return
|
|
}
|
|
oldImage = a.Image
|
|
}
|
|
|
|
l.Debug().Msg("ReplaceImageHandler: Getting image from request")
|
|
|
|
var id uuid.UUID
|
|
var err error
|
|
|
|
fileUrl := r.FormValue("image_url")
|
|
if fileUrl != "" {
|
|
l.Debug().Msg("ReplaceImageHandler: Image identified as remote file")
|
|
err = catalog.ValidateImageURL(fileUrl)
|
|
if err != nil {
|
|
l.Debug().AnErr("error", err).Msg("ReplaceImageHandler: Invalid image URL")
|
|
utils.WriteError(w, "url is invalid or not an image file", http.StatusBadRequest)
|
|
return
|
|
}
|
|
id = uuid.New()
|
|
var dlSize catalog.ImageSize
|
|
if cfg.FullImageCacheEnabled() {
|
|
dlSize = catalog.ImageSizeFull
|
|
} else {
|
|
dlSize = catalog.ImageSizeLarge
|
|
}
|
|
l.Debug().Msg("ReplaceImageHandler: Downloading album image from source")
|
|
err = catalog.DownloadAndCacheImage(ctx, id, fileUrl, dlSize)
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Failed to cache image")
|
|
utils.WriteError(w, "Failed to cache image", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else {
|
|
l.Debug().Msg("ReplaceImageHandler: Image identified as uploaded file")
|
|
file, _, err := r.FormFile("image")
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Invalid file upload")
|
|
utils.WriteError(w, "Invalid file", http.StatusBadRequest)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
buf := make([]byte, 512)
|
|
if _, err := file.Read(buf); err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Could not read file")
|
|
utils.WriteError(w, "Could not read file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
contentType := http.DetectContentType(buf)
|
|
if !strings.HasPrefix(contentType, "image/") {
|
|
l.Debug().Msg("ReplaceImageHandler: Uploaded file is not an image")
|
|
utils.WriteError(w, "Only image uploads are allowed", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if _, err := file.Seek(0, io.SeekStart); err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Could not seek file")
|
|
utils.WriteError(w, "Could not seek file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
l.Debug().Msg("ReplaceImageHandler: Saving image to cache")
|
|
|
|
id = uuid.New()
|
|
|
|
var dlSize catalog.ImageSize
|
|
if cfg.FullImageCacheEnabled() {
|
|
dlSize = catalog.ImageSizeFull
|
|
} else {
|
|
dlSize = catalog.ImageSizeLarge
|
|
}
|
|
|
|
err = catalog.CompressAndSaveImage(ctx, id.String(), dlSize, file)
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Could not save file")
|
|
utils.WriteError(w, "Could not save file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
l.Debug().Msg("ReplaceImageHandler: Updating database")
|
|
|
|
var imgsrc string
|
|
if fileUrl != "" {
|
|
imgsrc = fileUrl
|
|
} else {
|
|
imgsrc = catalog.ImageSourceUserUpload
|
|
}
|
|
|
|
if artistId != 0 {
|
|
l.Debug().Msgf("ReplaceImageHandler: Updating artist with ID %d", artistId)
|
|
err := store.UpdateArtist(ctx, db.UpdateArtistOpts{
|
|
ID: int32(artistId),
|
|
Image: id,
|
|
ImageSrc: imgsrc,
|
|
})
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Artist image could not be updated")
|
|
utils.WriteError(w, "Artist image could not be updated", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else if albumId != 0 {
|
|
l.Debug().Msgf("ReplaceImageHandler: Updating album with ID %d", albumId)
|
|
err := store.UpdateAlbum(ctx, db.UpdateAlbumOpts{
|
|
ID: int32(albumId),
|
|
Image: id,
|
|
ImageSrc: imgsrc,
|
|
})
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Album image could not be updated")
|
|
utils.WriteError(w, "Album image could not be updated", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
if oldImage != nil {
|
|
l.Debug().Msg("ReplaceImageHandler: Cleaning up old image file")
|
|
err = catalog.DeleteImage(*oldImage)
|
|
if err != nil {
|
|
l.Err(err).Msg("ReplaceImageHandler: Failed to delete old image file")
|
|
utils.WriteError(w, "Could not delete old image file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
l.Debug().Msg("ReplaceImageHandler: Successfully replaced image")
|
|
utils.WriteJSON(w, http.StatusOK, ReplaceImageResponse{
|
|
Success: true,
|
|
Image: id.String(),
|
|
})
|
|
}
|
|
}
|