mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-18 07:30:29 +00:00
feat(model): add uploaded_image column and avatar helpers to user
This commit is contained in:
parent
962910f0de
commit
42008a1b88
5
db/migrations/20260907225736_add_user_uploaded_image.sql
Normal file
5
db/migrations/20260907225736_add_user_uploaded_image.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE user ADD COLUMN uploaded_image VARCHAR(255) DEFAULT '';
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE user DROP COLUMN uploaded_image;
|
||||
@ -13,5 +13,8 @@ func UploadedImagePath(entityType, filename string) string {
|
||||
if filename == "" {
|
||||
return ""
|
||||
}
|
||||
if entityType == consts.EntityUser {
|
||||
return filepath.Join(conf.Server.DataFolder.String(), consts.AvatarFolder, filename)
|
||||
}
|
||||
return filepath.Join(conf.Server.DataFolder.String(), consts.ArtworkFolder, entityType, filename)
|
||||
}
|
||||
|
||||
29
model/image_test.go
Normal file
29
model/image_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/conf/configtest"
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("UploadedImagePath", func() {
|
||||
BeforeEach(func() {
|
||||
DeferCleanup(configtest.SetupConfig())
|
||||
conf.Server.DataFolder = conf.NewDir("/data")
|
||||
})
|
||||
|
||||
It("puts user avatars in the avatar folder, not under artwork", func() {
|
||||
Expect(model.UploadedImagePath(consts.EntityUser, "abc_deluan.png")).
|
||||
To(Equal(filepath.Join("/data", "avatar", "abc_deluan.png")))
|
||||
})
|
||||
|
||||
It("keeps other entities under the artwork folder", func() {
|
||||
Expect(model.UploadedImagePath(consts.EntityArtist, "abc_bowie.png")).
|
||||
To(Equal(filepath.Join("/data", "artwork", "artist", "abc_bowie.png")))
|
||||
})
|
||||
})
|
||||
@ -1,7 +1,12 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@ -17,6 +22,10 @@ type User struct {
|
||||
// Smart-playlist criteria JSON; matching songs are not sent to external scrobblers
|
||||
ScrobbleFilter string `structs:"scrobble_filter" json:"scrobbleFilter"`
|
||||
|
||||
// structs:"-" because userRepository.Put writes every mapped column with no column list, so a
|
||||
// profile save from the UI would blank this. UpdateImage is the only writer.
|
||||
UploadedImage string `structs:"-" json:"uploadedImage,omitempty"`
|
||||
|
||||
// Library associations (many-to-many relationship)
|
||||
Libraries Libraries `structs:"-" json:"libraries,omitempty"`
|
||||
|
||||
@ -43,6 +52,18 @@ func (u User) HasLibraryAccess(libraryID int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (u User) UploadedImagePath() string {
|
||||
return UploadedImagePath(consts.EntityUser, u.UploadedImage)
|
||||
}
|
||||
|
||||
func (u User) AvatarTag() string {
|
||||
if u.UploadedImage == "" {
|
||||
return ""
|
||||
}
|
||||
sum := md5.Sum(fmt.Appendf(nil, "%s|%d", u.UploadedImage, u.UpdatedAt.UnixNano()))
|
||||
return hex.EncodeToString(sum[:])[:16]
|
||||
}
|
||||
|
||||
type Users []User
|
||||
|
||||
type UserRepository interface {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/navidrome/navidrome/model"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -80,4 +82,25 @@ var _ = Describe("User", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("AvatarTag", func() {
|
||||
It("returns an empty tag when there is no avatar", func() {
|
||||
u := model.User{ID: "1", UpdatedAt: time.Now()}
|
||||
Expect(u.AvatarTag()).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("changes the tag when the image changes", func() {
|
||||
at := time.Unix(1000, 0)
|
||||
a := model.User{ID: "1", UploadedImage: "1_deluan.png", UpdatedAt: at}
|
||||
b := model.User{ID: "1", UploadedImage: "1_deluan.jpg", UpdatedAt: at}
|
||||
Expect(a.AvatarTag()).NotTo(BeEmpty())
|
||||
Expect(a.AvatarTag()).NotTo(Equal(b.AvatarTag()))
|
||||
})
|
||||
|
||||
It("changes the tag when the same file is replaced", func() {
|
||||
a := model.User{ID: "1", UploadedImage: "1_deluan.png", UpdatedAt: time.Unix(1000, 0)}
|
||||
b := model.User{ID: "1", UploadedImage: "1_deluan.png", UpdatedAt: time.Unix(2000, 0)}
|
||||
Expect(a.AvatarTag()).NotTo(Equal(b.AvatarTag()))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user