mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-01 19:47:37 +03:00
* [bugfix] player: use userId, other fixes This PR primarily resolves #1928 by switching the foreign key of `player` from `user.user_name` to `user.id`. There are also a few other fixes/changes: - For some bizarre reason, `ip_address` is never returned from `read`/`get`. Change the field to `ip`, which works. Somehow - Update `players_test.go` mock to also check for user agent, replicating the actual code - Update `player_repository.go` `isPermitted` to check user id. I don't know how this worked before... - tests! - a few places referred to `typ`, when it is really `userAgent`. Change the field names * baseRequest -> selectPlayer * remove comment * update migration, make all of persistence foreign key enabled * maybe don't forget to save the file first
156 lines
5.3 KiB
Go
156 lines
5.3 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/model/request"
|
|
"github.com/navidrome/navidrome/tests"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Players", func() {
|
|
var players Players
|
|
var repo *mockPlayerRepository
|
|
ctx := log.NewContext(context.TODO())
|
|
ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "johndoe"})
|
|
ctx = request.WithUsername(ctx, "johndoe")
|
|
var beforeRegister time.Time
|
|
|
|
BeforeEach(func() {
|
|
repo = &mockPlayerRepository{}
|
|
ds := &tests.MockDataStore{MockedPlayer: repo, MockedTranscoding: &tests.MockTranscodingRepo{}}
|
|
players = NewPlayers(ds)
|
|
beforeRegister = time.Now()
|
|
})
|
|
|
|
Describe("Register", func() {
|
|
It("creates a new player when no ID is specified", func() {
|
|
p, trc, err := players.Register(ctx, "", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).ToNot(BeEmpty())
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(p.Client).To(Equal("client"))
|
|
Expect(p.UserId).To(Equal("userid"))
|
|
Expect(p.UserAgent).To(Equal("chrome"))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
Expect(trc).To(BeNil())
|
|
})
|
|
|
|
It("creates a new player if it cannot find any matching player", func() {
|
|
p, trc, err := players.Register(ctx, "123", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).ToNot(BeEmpty())
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
Expect(trc).To(BeNil())
|
|
})
|
|
|
|
It("creates a new player if client does not match the one in DB", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client1111", LastSeen: time.Time{}}
|
|
repo.add(plr)
|
|
p, trc, err := players.Register(ctx, "123", "client2222", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).ToNot(BeEmpty())
|
|
Expect(p.ID).ToNot(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(p.Client).To(Equal("client2222"))
|
|
Expect(trc).To(BeNil())
|
|
})
|
|
|
|
It("finds players by ID", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", LastSeen: time.Time{}}
|
|
repo.add(plr)
|
|
p, trc, err := players.Register(ctx, "123", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).To(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
Expect(trc).To(BeNil())
|
|
})
|
|
|
|
It("finds player by client and user names when ID is not found", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", UserId: "userid", UserAgent: "chrome", LastSeen: time.Time{}}
|
|
repo.add(plr)
|
|
p, _, err := players.Register(ctx, "999", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).To(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
})
|
|
|
|
It("finds player by client and user names when not ID is provided", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", UserId: "userid", UserAgent: "chrome", LastSeen: time.Time{}}
|
|
repo.add(plr)
|
|
p, _, err := players.Register(ctx, "", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).To(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
})
|
|
|
|
It("finds player by ID and return its transcoding", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", LastSeen: time.Time{}, TranscodingId: "1"}
|
|
repo.add(plr)
|
|
p, trc, err := players.Register(ctx, "123", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).To(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
Expect(trc.ID).To(Equal("1"))
|
|
})
|
|
|
|
Context("bad username casing", func() {
|
|
ctx := log.NewContext(context.TODO())
|
|
ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "Johndoe"})
|
|
ctx = request.WithUsername(ctx, "Johndoe")
|
|
|
|
It("finds player by client and user names when not ID is provided", func() {
|
|
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", UserId: "userid", UserAgent: "chrome", LastSeen: time.Time{}}
|
|
repo.add(plr)
|
|
p, _, err := players.Register(ctx, "", "client", "chrome", "1.2.3.4")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(p.ID).To(Equal("123"))
|
|
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister))
|
|
Expect(repo.lastSaved).To(Equal(p))
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
type mockPlayerRepository struct {
|
|
model.PlayerRepository
|
|
lastSaved *model.Player
|
|
data map[string]model.Player
|
|
}
|
|
|
|
func (m *mockPlayerRepository) add(p *model.Player) {
|
|
if m.data == nil {
|
|
m.data = make(map[string]model.Player)
|
|
}
|
|
m.data[p.ID] = *p
|
|
}
|
|
|
|
func (m *mockPlayerRepository) Get(id string) (*model.Player, error) {
|
|
if p, ok := m.data[id]; ok {
|
|
return &p, nil
|
|
}
|
|
return nil, model.ErrNotFound
|
|
}
|
|
|
|
func (m *mockPlayerRepository) FindMatch(userId, client, userAgent string) (*model.Player, error) {
|
|
for _, p := range m.data {
|
|
if p.Client == client && p.UserId == userId && p.UserAgent == userAgent {
|
|
return &p, nil
|
|
}
|
|
}
|
|
return nil, model.ErrNotFound
|
|
}
|
|
|
|
func (m *mockPlayerRepository) Put(p *model.Player) error {
|
|
m.lastSaved = p
|
|
return nil
|
|
}
|