- Add image upload endpoints for artist/albums @ v1/albums/{uuid}/upload
This commit is contained in:
Daniel Mason 2022-01-08 22:24:36 +13:00
parent 26880e3c2b
commit a8e6b491bd
5 changed files with 157 additions and 1 deletions

View File

@ -1,3 +1,6 @@
# 0.1.5
- Add image upload endpoints for artist/albums @ v1/albums/{uuid}/upload
# 0.1.4 # 0.1.4
- Fix spotify image import on scrobble for new artists/albums - Fix spotify image import on scrobble for new artists/albums
- Create image resizer - Create image resizer

View File

@ -3,13 +3,38 @@ package goscrobble
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"mime/multipart"
"net/http" "net/http"
"os" "os"
"github.com/disintegration/imaging" "github.com/disintegration/imaging"
) )
func importUploadedImage(file multipart.File, uuid string, recordType string) error {
// Create image
out, err := os.Create(DataDirectory + string(os.PathSeparator) + "img" + string(os.PathSeparator) + uuid + "_full.jpg")
if err != nil {
return err
}
defer out.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
return err
}
// Write image
_, err = out.Write(fileBytes)
if err == nil {
// Make sure we queue it to process!
_, err = db.Exec("UPDATE `"+recordType+"` SET `img` = 'pending' WHERE `uuid` = UUID_TO_BIN(?,true)", uuid)
}
return err
}
func importImage(uuid string, url string) error { func importImage(uuid string, url string) error {
// Create image // Create image
out, err := os.Create(DataDirectory + string(os.PathSeparator) + "img" + string(os.PathSeparator) + uuid + "_full.jpg") out, err := os.Create(DataDirectory + string(os.PathSeparator) + "img" + string(os.PathSeparator) + uuid + "_full.jpg")

View File

@ -70,6 +70,10 @@ func HandleRequests(port string) {
v1.HandleFunc("/config", limitMiddleware(adminMiddleware(getConfig), standardLimiter)).Methods("GET") v1.HandleFunc("/config", limitMiddleware(adminMiddleware(getConfig), standardLimiter)).Methods("GET")
v1.HandleFunc("/config", limitMiddleware(adminMiddleware(postConfig), standardLimiter)).Methods("POST") v1.HandleFunc("/config", limitMiddleware(adminMiddleware(postConfig), standardLimiter)).Methods("POST")
// Image uploads - Mod+
v1.HandleFunc("/artists/{uuid}/upload", limitMiddleware(modMiddleware(handleArtistUpload), heavyLimiter)).Methods("POST")
v1.HandleFunc("/albums/{uuid}/upload", limitMiddleware(modMiddleware(handleAlbumUpload), heavyLimiter)).Methods("POST")
// No Auth // No Auth
v1.HandleFunc("/stats", limitMiddleware(handleStats, lightLimiter)).Methods("GET") v1.HandleFunc("/stats", limitMiddleware(handleStats, lightLimiter)).Methods("GET")
v1.HandleFunc("/recent", limitMiddleware(handleRecentScrobbles, lightLimiter)).Methods("GET") v1.HandleFunc("/recent", limitMiddleware(handleRecentScrobbles, lightLimiter)).Methods("GET")
@ -841,3 +845,101 @@ func handleRecentScrobbles(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(json) w.Write(json)
} }
// handleArtistUpload - Image uploads!
func handleArtistUpload(w http.ResponseWriter, r *http.Request, jwtUser string) {
var uuid string
for k, v := range mux.Vars(r) {
if k == "uuid" {
uuid = v
}
}
if uuid == "" {
throwOkError(w, "Invalid UUID")
return
}
// Little bit of validation
_, err := getArtistByUUID(uuid)
if err != nil {
throwOkError(w, err.Error())
return
}
// 10MB Maximum...
err = r.ParseMultipartForm(10 << 20)
if err != nil {
log.Print(err)
throwOkError(w, "Error processing upload")
return
}
// Get files from request
file, _, err := r.FormFile("file")
if err != nil {
log.Print(err)
throwOkError(w, "Error processing upload")
return
}
defer file.Close()
// Upload ze file
err = importUploadedImage(file, uuid, "artists")
if err != nil {
log.Println(err)
throwBadReq(w, "Error processing upload")
return
}
throwOkMessage(w, "Successfully uploaded!")
}
// handleAlbumUpload - Image uploads!
func handleAlbumUpload(w http.ResponseWriter, r *http.Request, jwtUser string) {
var uuid string
for k, v := range mux.Vars(r) {
if k == "uuid" {
uuid = v
}
}
if uuid == "" {
throwOkError(w, "Invalid UUID")
return
}
// Little bit of validation
_, err := getAlbumByUUID(uuid)
if err != nil {
throwOkError(w, err.Error())
return
}
// 10MB Maximum...
err = r.ParseMultipartForm(10 << 20)
if err != nil {
log.Print(err)
throwOkError(w, "Error processing upload")
return
}
// Get files from request
file, _, err := r.FormFile("file")
if err != nil {
log.Print(err)
throwOkError(w, "Error processing upload")
return
}
defer file.Close()
// Upload ze file
err = importUploadedImage(file, uuid, "albums")
if err != nil {
log.Println(err)
throwBadReq(w, "Error processing upload")
return
}
throwOkMessage(w, "Successfully uploaded!")
}

View File

@ -66,6 +66,32 @@ func jwtMiddleware(next func(http.ResponseWriter, *http.Request, CustomClaims, s
} }
} }
// modMiddleware - Validates user is admin OR mod
func modMiddleware(next func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fullToken := r.Header.Get("Authorization")
authToken := strings.Replace(fullToken, "Bearer ", "", 1)
claims, err := verifyJWTToken(authToken)
if err != nil {
throwUnauthorized(w, "Invalid JWT Token")
return
}
user, err := getUserByUUID(claims.Subject)
if err != nil {
throwUnauthorized(w, err.Error())
return
}
if !user.Admin && !user.Mod {
throwUnauthorized(w, "User is not moderator or administrator")
return
}
next(w, r, claims.Subject)
}
}
// adminMiddleware - Validates user is admin // adminMiddleware - Validates user is admin
func adminMiddleware(next func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { func adminMiddleware(next func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {

View File

@ -27,7 +27,7 @@ func throwBadReq(w http.ResponseWriter, m string) {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
} }
// throwOkError - Throws a 403 // throwOkError - Throws a 200 error
func throwOkError(w http.ResponseWriter, m string) { func throwOkError(w http.ResponseWriter, m string) {
jr := jsonResponse{ jr := jsonResponse{
Err: m, Err: m,