diff --git a/core/playlists.go b/core/playlists.go
index c31ea32cc..744139371 100644
--- a/core/playlists.go
+++ b/core/playlists.go
@@ -136,7 +136,7 @@ func (s *playlists) parseM3U(ctx context.Context, pls *model.Playlist, baseDir s
}
func (s *playlists) updatePlaylist(ctx context.Context, newPls *model.Playlist) error {
- owner, _ := request.UsernameFrom(ctx)
+ owner, _ := request.UserFrom(ctx)
pls, err := s.ds.Playlist(ctx).FindByPath(newPls.Path)
if err != nil && err != model.ErrNotFound {
@@ -152,12 +152,12 @@ func (s *playlists) updatePlaylist(ctx context.Context, newPls *model.Playlist)
newPls.ID = pls.ID
newPls.Name = pls.Name
newPls.Comment = pls.Comment
- newPls.Owner = pls.Owner
+ newPls.OwnerID = pls.OwnerID
newPls.Public = pls.Public
newPls.EvaluatedAt = time.Time{}
} else {
- log.Info(ctx, "Adding synced playlist", "playlist", newPls.Name, "path", newPls.Path, "owner", owner)
- newPls.Owner = owner
+ log.Info(ctx, "Adding synced playlist", "playlist", newPls.Name, "path", newPls.Path, "owner", owner.UserName)
+ newPls.OwnerID = owner.ID
}
return s.ds.Playlist(ctx).Put(newPls)
}
diff --git a/db/migration/20211029213200_add_userid_to_playlist.go b/db/migration/20211029213200_add_userid_to_playlist.go
new file mode 100644
index 000000000..2c7c86cbb
--- /dev/null
+++ b/db/migration/20211029213200_add_userid_to_playlist.go
@@ -0,0 +1,60 @@
+package migrations
+
+import (
+ "database/sql"
+
+ "github.com/pressly/goose"
+)
+
+func init() {
+ goose.AddMigration(upAddUseridToPlaylist, downAddUseridToPlaylist)
+}
+
+func upAddUseridToPlaylist(tx *sql.Tx) error {
+ _, err := tx.Exec(`
+create table playlist_dg_tmp
+(
+ id varchar(255) not null
+ primary key,
+ name varchar(255) default '' not null,
+ comment varchar(255) default '' not null,
+ duration real default 0 not null,
+ song_count integer default 0 not null,
+ public bool default FALSE not null,
+ created_at datetime,
+ updated_at datetime,
+ path string default '' not null,
+ sync bool default false not null,
+ size integer default 0 not null,
+ rules varchar,
+ evaluated_at datetime,
+ owner_id varchar(255) not null
+ constraint playlist_user_user_id_fk
+ references user
+ on update cascade on delete cascade
+);
+
+insert into playlist_dg_tmp(id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at, owner_id)
+select id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at,
+ (select id from user where user_name = owner) as user_id from playlist;
+
+drop table playlist;
+alter table playlist_dg_tmp rename to playlist;
+create index playlist_created_at
+ on playlist (created_at);
+create index playlist_evaluated_at
+ on playlist (evaluated_at);
+create index playlist_name
+ on playlist (name);
+create index playlist_size
+ on playlist (size);
+create index playlist_updated_at
+ on playlist (updated_at);
+
+`)
+ return err
+}
+
+func downAddUseridToPlaylist(tx *sql.Tx) error {
+ return nil
+}
diff --git a/model/playlist.go b/model/playlist.go
index e05556d5c..262d724d9 100644
--- a/model/playlist.go
+++ b/model/playlist.go
@@ -15,7 +15,8 @@ type Playlist struct {
Duration float32 `structs:"duration" json:"duration"`
Size int64 `structs:"size" json:"size"`
SongCount int `structs:"song_count" json:"songCount"`
- Owner string `structs:"owner" json:"owner"`
+ OwnerName string `structs:"-" json:"ownerName"`
+ OwnerID string `structs:"owner_id" json:"ownerId" orm:"column(owner_id)"`
Public bool `structs:"public" json:"public"`
Tracks PlaylistTracks `structs:"-" json:"tracks,omitempty"`
Path string `structs:"path" json:"path"`
diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go
index 44ebfcaea..69f836e22 100644
--- a/persistence/persistence_suite_test.go
+++ b/persistence/persistence_suite_test.go
@@ -85,7 +85,14 @@ var _ = Describe("Initialize test DB", func() {
BeforeSuite(func() {
o := orm.NewOrm()
ctx := log.NewContext(context.TODO())
- ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "userid"})
+ user := model.User{ID: "userid", UserName: "userid"}
+ ctx = request.WithUser(ctx, user)
+
+ ur := NewUserRepository(ctx, o)
+ err := ur.Put(&user)
+ if err != nil {
+ panic(err)
+ }
gr := NewGenreRepository(ctx, o)
for i := range testGenres {
@@ -126,12 +133,13 @@ var _ = Describe("Initialize test DB", func() {
plsBest = model.Playlist{
Name: "Best",
Comment: "No Comments",
- Owner: "userid",
+ OwnerID: "userid",
+ OwnerName: "userid",
Public: true,
SongCount: 2,
}
plsBest.AddTracks([]string{"1001", "1003"})
- plsCool = model.Playlist{Name: "Cool", Owner: "userid"}
+ plsCool = model.Playlist{Name: "Cool", OwnerID: "userid", OwnerName: "userid"}
plsCool.AddTracks([]string{"1004"})
testPlaylists = []*model.Playlist{&plsBest, &plsCool}
diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go
index 5f780206e..aa832f5d2 100644
--- a/persistence/playlist_repository.go
+++ b/persistence/playlist_repository.go
@@ -50,7 +50,7 @@ func (r *playlistRepository) userFilter() Sqlizer {
}
return Or{
Eq{"public": true},
- Eq{"owner": user.UserName},
+ Eq{"owner_id": user.ID},
}
}
@@ -70,7 +70,7 @@ func (r *playlistRepository) Delete(id string) error {
if err != nil {
return err
}
- if pls.Owner != usr.UserName {
+ if pls.OwnerID != usr.ID {
return rest.ErrPermissionDenied
}
}
@@ -117,11 +117,11 @@ func (r *playlistRepository) Put(p *model.Playlist) error {
}
func (r *playlistRepository) Get(id string) (*model.Playlist, error) {
- return r.findBy(And{Eq{"id": id}, r.userFilter()})
+ return r.findBy(And{Eq{"playlist.id": id}, r.userFilter()})
}
func (r *playlistRepository) GetWithTracks(id string) (*model.Playlist, error) {
- pls, err := r.findBy(And{Eq{"id": id}, r.userFilter()})
+ pls, err := r.Get(id)
if err != nil {
return nil, err
}
@@ -140,7 +140,7 @@ func (r *playlistRepository) FindByPath(path string) (*model.Playlist, error) {
}
func (r *playlistRepository) findBy(sql Sqlizer) (*model.Playlist, error) {
- sel := r.newSelect().Columns("*").Where(sql)
+ sel := r.selectPlaylist().Where(sql)
var pls []dbPlaylist
err := r.queryAll(sel, &pls)
if err != nil {
@@ -169,7 +169,7 @@ func (r *playlistRepository) toModel(pls dbPlaylist) (*model.Playlist, error) {
}
func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playlists, error) {
- sel := r.newSelect(options...).Columns("*").Where(r.userFilter())
+ sel := r.selectPlaylist(options...).Where(r.userFilter())
var res []dbPlaylist
err := r.queryAll(sel, &res)
if err != nil {
@@ -186,6 +186,11 @@ func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playli
return playlists, err
}
+func (r *playlistRepository) selectPlaylist(options ...model.QueryOptions) SelectBuilder {
+ return r.newSelect(options...).Join("user on user.id = owner_id").
+ Columns(r.tableName+".*", "user.user_name as owner_name")
+}
+
func (r *playlistRepository) refreshSmartPlaylist(pls *model.Playlist) bool {
// Only refresh if it is a smart playlist and was not refreshed in the last 5 seconds
if !pls.IsSmartPlaylist() || time.Since(pls.EvaluatedAt) < 5*time.Second {
@@ -194,7 +199,7 @@ func (r *playlistRepository) refreshSmartPlaylist(pls *model.Playlist) bool {
// Never refresh other users' playlists
usr := loggedUser(r.ctx)
- if pls.Owner != usr.UserName {
+ if pls.OwnerID != usr.ID {
return false
}
@@ -362,7 +367,8 @@ func (r *playlistRepository) NewInstance() interface{} {
func (r *playlistRepository) Save(entity interface{}) (string, error) {
pls := entity.(*model.Playlist)
- pls.Owner = loggedUser(r.ctx).UserName
+ pls.OwnerID = loggedUser(r.ctx).ID
+ pls.ID = "" // Make sure we don't override an existing playlist
err := r.Put(pls)
if err != nil {
return "", err
@@ -373,7 +379,7 @@ func (r *playlistRepository) Save(entity interface{}) (string, error) {
func (r *playlistRepository) Update(entity interface{}, cols ...string) error {
pls := entity.(*model.Playlist)
usr := loggedUser(r.ctx)
- if !usr.IsAdmin && pls.Owner != usr.UserName {
+ if !usr.IsAdmin && pls.OwnerID != usr.ID {
return rest.ErrPermissionDenied
}
err := r.Put(pls)
@@ -432,7 +438,7 @@ func (r *playlistRepository) isWritable(playlistId string) bool {
return true
}
pls, err := r.Get(playlistId)
- return err == nil && pls.Owner == usr.UserName
+ return err == nil && pls.OwnerID == usr.ID
}
var _ model.PlaylistRepository = (*playlistRepository)(nil)
diff --git a/persistence/playlist_repository_test.go b/persistence/playlist_repository_test.go
index 833aa0230..37a8242c9 100644
--- a/persistence/playlist_repository_test.go
+++ b/persistence/playlist_repository_test.go
@@ -76,7 +76,7 @@ var _ = Describe("PlaylistRepository", func() {
It("Put/Exists/Delete", func() {
By("saves the playlist to the DB")
- newPls := model.Playlist{Name: "Great!", Owner: "userid"}
+ newPls := model.Playlist{Name: "Great!", OwnerID: "userid"}
newPls.AddTracks([]string{"1004", "1003"})
By("saves the playlist to the DB")
diff --git a/resources/i18n/cs.json b/resources/i18n/cs.json
index 23c6fd389..0054a1ec1 100644
--- a/resources/i18n/cs.json
+++ b/resources/i18n/cs.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Název",
"duration": "Délka",
- "owner": "Vlastník",
+ "ownerName": "Vlastník",
"public": "Veřejný",
"updatedAt": "Nahrán",
"createdAt": "Vytvořen",
@@ -386,4 +386,4 @@
"toggle_love": "Přidat tuto skladbu do oblíbených"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/da.json b/resources/i18n/da.json
index 315c5b3c3..80ec8b4ec 100644
--- a/resources/i18n/da.json
+++ b/resources/i18n/da.json
@@ -110,7 +110,7 @@
"fields": {
"name": "Navn",
"duration": "Varighed",
- "owner": "Ejer",
+ "ownerName": "Ejer",
"public": "Offentlig",
"updatedAt": "Opdateret den",
"createdAt": "Oprettet den",
@@ -324,4 +324,4 @@
"serverUptime": "Server uptime",
"serverDown": "OFFLINE"
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/de.json b/resources/i18n/de.json
index 37bbebdc0..be7e0cf64 100644
--- a/resources/i18n/de.json
+++ b/resources/i18n/de.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Name",
"duration": "Dauer",
- "owner": "Inhaber",
+ "ownerName": "Inhaber",
"public": "Öffentlich",
"updatedAt": "Aktualisiert um",
"createdAt": "Erstellt um",
@@ -386,4 +386,4 @@
"toggle_love": "Song zu Favoriten hinzufügen"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/eo.json b/resources/i18n/eo.json
index 74fa5958b..545e2b42b 100644
--- a/resources/i18n/eo.json
+++ b/resources/i18n/eo.json
@@ -115,7 +115,7 @@
"fields": {
"name": "Nomo",
"duration": "Daŭro",
- "owner": "Posedanto",
+ "ownerName": "Posedanto",
"public": "Publika",
"updatedAt": "Ĝisdatigita je",
"createdAt": "Kreita je",
@@ -348,4 +348,4 @@
"toggle_love": "Baskuli la stelon de nuna kanto"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/es.json b/resources/i18n/es.json
index abaf65131..bbdf4d56f 100644
--- a/resources/i18n/es.json
+++ b/resources/i18n/es.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Nombre",
"duration": "Duración",
- "owner": "Dueño",
+ "ownerName": "Dueño",
"public": "Público",
"updatedAt": "Actualizado el",
"createdAt": "Creado el",
@@ -386,4 +386,4 @@
"toggle_love": "Marca esta canción como favorita"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/fa.json b/resources/i18n/fa.json
index 22dbe02f6..453e19b20 100644
--- a/resources/i18n/fa.json
+++ b/resources/i18n/fa.json
@@ -133,7 +133,7 @@
"fields": {
"name": "نام",
"duration": "مدّت زمان",
- "owner": "مالک",
+ "ownerName": "مالک",
"public": "عمومی",
"updatedAt": "بروزشده در",
"createdAt": "ایجادشده در",
diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json
index 4d6be595f..0652c05f9 100644
--- a/resources/i18n/fi.json
+++ b/resources/i18n/fi.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Nimi",
"duration": "Kesto",
- "owner": "Omistaja",
+ "ownerName": "Omistaja",
"public": "Julkinen",
"updatedAt": "Päivitetty",
"createdAt": "Luotu",
@@ -386,4 +386,4 @@
"toggle_love": "Lisää kappale suosikkeihin"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json
index 1c62da262..048298f0e 100644
--- a/resources/i18n/fr.json
+++ b/resources/i18n/fr.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Nom",
"duration": "Durée",
- "owner": "Propriétaire",
+ "ownerName": "Propriétaire",
"public": "Public",
"updatedAt": "Mise à jour le",
"createdAt": "Créé le",
@@ -386,4 +386,4 @@
"toggle_love": "Ajouter/Enlever le morceau des favoris"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/it.json b/resources/i18n/it.json
index cc07f4b99..fc819190d 100644
--- a/resources/i18n/it.json
+++ b/resources/i18n/it.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Nome",
"duration": "Durata",
- "owner": "Creatore",
+ "ownerName": "Creatore",
"public": "Pubblica",
"updatedAt": "Ultimo aggiornamento",
"createdAt": "Data creazione",
@@ -386,4 +386,4 @@
"toggle_love": "Aggiungi questa traccia ai preferiti"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json
index f4404914c..f9d3eb6e4 100644
--- a/resources/i18n/ja.json
+++ b/resources/i18n/ja.json
@@ -133,7 +133,7 @@
"fields": {
"name": "名前",
"duration": "時間",
- "owner": "所有者",
+ "ownerName": "所有者",
"public": "公開",
"updatedAt": "更新日",
"createdAt": "作成日",
@@ -386,4 +386,4 @@
"toggle_love": "星の付け外し"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/nl.json b/resources/i18n/nl.json
index 4424af9f9..226b514e9 100644
--- a/resources/i18n/nl.json
+++ b/resources/i18n/nl.json
@@ -130,7 +130,7 @@
"fields": {
"name": "Titel",
"duration": "Lengte",
- "owner": "Eigenaar",
+ "ownerName": "Eigenaar",
"public": "Publiek",
"updatedAt": "Laatst gewijzigd op",
"createdAt": "Aangemaakt op",
@@ -380,4 +380,4 @@
"toggle_love": "Voeg toe aan favorieten"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json
index da1fad648..6cb72b906 100644
--- a/resources/i18n/pl.json
+++ b/resources/i18n/pl.json
@@ -130,7 +130,7 @@
"fields": {
"name": "Nazwa",
"duration": "Czas trwania",
- "owner": "Właściciel",
+ "ownerName": "Właściciel",
"public": "Publiczna",
"updatedAt": "Zaktualizowana",
"createdAt": "Stworzona",
@@ -380,4 +380,4 @@
"toggle_love": "Dodaj ten utwór do ulubionych"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json
index 15f272802..a6468031f 100644
--- a/resources/i18n/pt.json
+++ b/resources/i18n/pt.json
@@ -138,7 +138,7 @@
"fields": {
"name": "Nome",
"duration": "Duração",
- "owner": "Dono",
+ "ownerName": "Dono",
"public": "Pública",
"updatedAt": "Últ. Atualização",
"createdAt": "Data de Criação ",
diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json
index a24c81fc1..18893b912 100644
--- a/resources/i18n/ru.json
+++ b/resources/i18n/ru.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Название",
"duration": "Длительность",
- "owner": "Владелец",
+ "ownerName": "Владелец",
"public": "Публичный",
"updatedAt": "Обновлен",
"createdAt": "Создан",
@@ -386,4 +386,4 @@
"toggle_love": "Добавить / удалить песню из избранного"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/sl.json b/resources/i18n/sl.json
index a822280cc..15dcc07b9 100644
--- a/resources/i18n/sl.json
+++ b/resources/i18n/sl.json
@@ -133,7 +133,7 @@
"fields": {
"name": "Ime",
"duration": "Dolžina",
- "owner": "Lastnik",
+ "ownerName": "Lastnik",
"public": "Javno",
"updatedAt": "Posodobljen",
"createdAt": "Ustvarjen",
@@ -386,4 +386,4 @@
"toggle_love": "Dodaj med priljubljene"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/sv.json b/resources/i18n/sv.json
index d1a3f099c..0540ecb1a 100644
--- a/resources/i18n/sv.json
+++ b/resources/i18n/sv.json
@@ -127,7 +127,7 @@
"fields": {
"name": "Namn",
"duration": "Längd",
- "owner": "Ägare",
+ "ownerName": "Ägare",
"public": "Offentlig",
"updatedAt": "Uppdaterad",
"createdAt": "Skapad",
diff --git a/resources/i18n/th.json b/resources/i18n/th.json
index 63a3d329f..f161fae34 100644
--- a/resources/i18n/th.json
+++ b/resources/i18n/th.json
@@ -133,7 +133,7 @@
"fields": {
"name": "ชื่อ",
"duration": "เวลา",
- "owner": "เจ้าของ",
+ "ownerName": "เจ้าของ",
"public": "สาธารณะ",
"updatedAt": "อัปเดตเมื่อ",
"createdAt": "สร้างขึ้นเมื่อ",
@@ -386,4 +386,4 @@
"toggle_love": "เพิ่มเพลงนี้ไปยังรายการโปรด"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json
index ad1342ec9..b6d498918 100644
--- a/resources/i18n/tr.json
+++ b/resources/i18n/tr.json
@@ -110,7 +110,7 @@
"fields": {
"name": "Isim",
"duration": "Süre",
- "owner": "Sahibi",
+ "ownerName": "Sahibi",
"public": "Görülebilir",
"updatedAt": "Güncelleme tarihi:",
"createdAt": "Oluşturma tarihi:",
@@ -324,4 +324,4 @@
"serverUptime": "",
"serverDown": ""
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/uk.json b/resources/i18n/uk.json
index 14d6b1c51..86982f77f 100644
--- a/resources/i18n/uk.json
+++ b/resources/i18n/uk.json
@@ -130,7 +130,7 @@
"fields": {
"name": "Назва",
"duration": "Тривалість",
- "owner": "Власник",
+ "ownerName": "Власник",
"public": "Публічний",
"updatedAt": "Оновлено",
"createdAt": "Створено",
@@ -380,4 +380,4 @@
"toggle_love": "Відмітити поточні пісні"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/zh-Hans.json b/resources/i18n/zh-Hans.json
index 1174a2719..61ad10d96 100644
--- a/resources/i18n/zh-Hans.json
+++ b/resources/i18n/zh-Hans.json
@@ -130,7 +130,7 @@
"fields": {
"name": "名称",
"duration": "时长",
- "owner": "所有者",
+ "ownerName": "所有者",
"public": "公开",
"updatedAt": "更新于",
"createdAt": "创建于",
@@ -380,4 +380,4 @@
"toggle_love": "添加/移除星标"
}
}
-}
\ No newline at end of file
+}
diff --git a/resources/i18n/zh-Hant.json b/resources/i18n/zh-Hant.json
index 2b05b9cf0..dc0e55c86 100644
--- a/resources/i18n/zh-Hant.json
+++ b/resources/i18n/zh-Hant.json
@@ -133,7 +133,7 @@
"fields": {
"name": "名稱",
"duration": "長度",
- "owner": "擁有者",
+ "ownerName": "擁有者",
"public": "公開",
"updatedAt": "更新於",
"createdAt": "創建於",
@@ -386,4 +386,4 @@
"toggle_love": "添加或移除星標"
}
}
-}
\ No newline at end of file
+}
diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go
index 6b2d1a07f..a79442e7a 100644
--- a/server/subsonic/helpers.go
+++ b/server/subsonic/helpers.go
@@ -64,12 +64,12 @@ func (e subError) Error() string {
return msg
}
-func getUser(ctx context.Context) string {
+func getUser(ctx context.Context) model.User {
user, ok := request.UserFrom(ctx)
if ok {
- return user.UserName
+ return user
}
- return ""
+ return model.User{}
}
func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
diff --git a/server/subsonic/playlists.go b/server/subsonic/playlists.go
index aa6563d39..2d1850256 100644
--- a/server/subsonic/playlists.go
+++ b/server/subsonic/playlists.go
@@ -74,14 +74,12 @@ func (c *PlaylistsController) create(ctx context.Context, playlistId, name strin
if err != nil {
return err
}
- if owner != pls.Owner {
+ if owner.ID != pls.OwnerID {
return model.ErrNotAuthorized
}
} else {
- pls = &model.Playlist{
- Name: name,
- Owner: owner,
- }
+ pls = &model.Playlist{Name: name}
+ pls.OwnerID = owner.ID
}
pls.Tracks = nil
pls.AddTracks(ids)
@@ -178,7 +176,7 @@ func (c *PlaylistsController) buildPlaylist(p model.Playlist) *responses.Playlis
pls.Name = p.Name
pls.Comment = p.Comment
pls.SongCount = p.SongCount
- pls.Owner = p.Owner
+ pls.Owner = p.OwnerName
pls.Duration = int(p.Duration)
pls.Public = p.Public
pls.Created = p.CreatedAt
diff --git a/ui/src/common/Writable.js b/ui/src/common/Writable.js
index 577bc1fc2..27a46f9e0 100644
--- a/ui/src/common/Writable.js
+++ b/ui/src/common/Writable.js
@@ -1,19 +1,19 @@
import { cloneElement, Children, isValidElement } from 'react'
-export const isWritable = (owner) => {
+export const isWritable = (ownerId) => {
return (
- localStorage.getItem('username') === owner ||
+ localStorage.getItem('userId') === ownerId ||
localStorage.getItem('role') === 'admin'
)
}
-export const isReadOnly = (owner) => {
- return !isWritable(owner)
+export const isReadOnly = (ownerId) => {
+ return !isWritable(ownerId)
}
export const Writable = (props) => {
const { record = {}, children } = props
- if (isWritable(record.owner)) {
+ if (isWritable(record.ownerId)) {
return Children.map(children, (child) =>
isValidElement(child) ? cloneElement(child, props) : child
)
@@ -24,4 +24,4 @@ export const Writable = (props) => {
export const isSmartPlaylist = (pls) => !!pls.rules
export const canChangeTracks = (pls) =>
- isWritable(pls.owner) && !isSmartPlaylist(pls)
+ isWritable(pls.ownerId) && !isSmartPlaylist(pls)
diff --git a/ui/src/common/useSelectedFields.js b/ui/src/common/useSelectedFields.js
index 7ebdcf60e..9784cf32b 100644
--- a/ui/src/common/useSelectedFields.js
+++ b/ui/src/common/useSelectedFields.js
@@ -22,7 +22,8 @@ export const useSelectedFields = ({
useEffect(() => {
if (
!resourceFields ||
- Object.keys(resourceFields).length !== Object.keys(columns).length
+ Object.keys(resourceFields).length !== Object.keys(columns).length ||
+ !Object.keys(columns).every((c) => c in resourceFields)
) {
const obj = {}
for (const key of Object.keys(columns)) {
diff --git a/ui/src/dialogs/AddToPlaylistDialog.test.js b/ui/src/dialogs/AddToPlaylistDialog.test.js
index e2bf9b057..dbe2e1f56 100644
--- a/ui/src/dialogs/AddToPlaylistDialog.test.js
+++ b/ui/src/dialogs/AddToPlaylistDialog.test.js
@@ -5,22 +5,23 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
import { AddToPlaylistDialog } from './AddToPlaylistDialog'
describe('AddToPlaylistDialog', () => {
+ beforeAll(() => localStorage.setItem('userId', 'admin'))
afterEach(cleanup)
const mockData = [
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
- { id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
+ { id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
]
const mockIndexedData = {
'sample-id1': {
id: 'sample-id1',
name: 'sample playlist 1',
- owner: 'admin',
+ ownerId: 'admin',
},
'sample-id2': {
id: 'sample-id2',
name: 'sample playlist 2',
- owner: 'admin',
+ ownerId: 'admin',
},
}
const selectedIds = ['song-1', 'song-2']
diff --git a/ui/src/dialogs/SelectPlaylistInput.js b/ui/src/dialogs/SelectPlaylistInput.js
index fd076ed66..5e2df7b57 100644
--- a/ui/src/dialogs/SelectPlaylistInput.js
+++ b/ui/src/dialogs/SelectPlaylistInput.js
@@ -30,7 +30,7 @@ export const SelectPlaylistInput = ({ onChange }) => {
const options =
ids &&
- ids.map((id) => data[id]).filter((option) => isWritable(option.owner))
+ ids.map((id) => data[id]).filter((option) => isWritable(option.ownerId))
const handleOnChange = (event, newValue) => {
let newState = []
diff --git a/ui/src/dialogs/SelectPlaylistInput.test.js b/ui/src/dialogs/SelectPlaylistInput.test.js
index c667ad3e0..f3485594e 100644
--- a/ui/src/dialogs/SelectPlaylistInput.test.js
+++ b/ui/src/dialogs/SelectPlaylistInput.test.js
@@ -5,24 +5,25 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
import { SelectPlaylistInput } from './SelectPlaylistInput'
describe('SelectPlaylistInput', () => {
+ beforeAll(() => localStorage.setItem('userId', 'admin'))
afterEach(cleanup)
const onChangeHandler = jest.fn()
it('should call the handler with the selections', async () => {
const mockData = [
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
- { id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
+ { id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
]
const mockIndexedData = {
'sample-id1': {
id: 'sample-id1',
name: 'sample playlist 1',
- owner: 'admin',
+ ownerId: 'admin',
},
'sample-id2': {
id: 'sample-id2',
name: 'sample playlist 2',
- owner: 'admin',
+ ownerId: 'admin',
},
}
@@ -74,7 +75,7 @@ describe('SelectPlaylistInput', () => {
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
await waitFor(() => {
expect(onChangeHandler).toHaveBeenCalledWith([
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
])
})
@@ -82,8 +83,8 @@ describe('SelectPlaylistInput', () => {
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
await waitFor(() => {
expect(onChangeHandler).toHaveBeenCalledWith([
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
- { id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
+ { id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
])
})
@@ -94,8 +95,8 @@ describe('SelectPlaylistInput', () => {
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
await waitFor(() => {
expect(onChangeHandler).toHaveBeenCalledWith([
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
- { id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
+ { id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
{ name: 'new playlist' },
])
})
@@ -106,8 +107,8 @@ describe('SelectPlaylistInput', () => {
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
await waitFor(() => {
expect(onChangeHandler).toHaveBeenCalledWith([
- { id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
- { id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
+ { id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
+ { id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
{ name: 'new playlist' },
{ name: 'another new playlist' },
])
diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json
index d4f143b75..46742a88c 100644
--- a/ui/src/i18n/en.json
+++ b/ui/src/i18n/en.json
@@ -138,7 +138,7 @@
"fields": {
"name": "Name",
"duration": "Duration",
- "owner": "Owner",
+ "ownerName": "Owner",
"public": "Public",
"updatedAt": "Updated at",
"createdAt": "Created at",
diff --git a/ui/src/layout/PlaylistsSubMenu.js b/ui/src/layout/PlaylistsSubMenu.js
index ad4e243db..84f7cb400 100644
--- a/ui/src/layout/PlaylistsSubMenu.js
+++ b/ui/src/layout/PlaylistsSubMenu.js
@@ -74,7 +74,7 @@ const PlaylistsSubMenu = ({ state, setState, sidebarIsOpen, dense }) => {
/>
)
- const user = localStorage.getItem('username')
+ const userId = localStorage.getItem('userId')
const myPlaylists = []
const sharedPlaylists = []
@@ -82,7 +82,7 @@ const PlaylistsSubMenu = ({ state, setState, sidebarIsOpen, dense }) => {
const allPlaylists = Object.keys(data).map((id) => data[id])
allPlaylists.forEach((pls) => {
- if (user === pls.owner) {
+ if (userId === pls.ownerId) {
myPlaylists.push(pls)
} else {
sharedPlaylists.push(pls)
diff --git a/ui/src/playlist/PlaylistEdit.js b/ui/src/playlist/PlaylistEdit.js
index 8f0b6029b..212783d04 100644
--- a/ui/src/playlist/PlaylistEdit.js
+++ b/ui/src/playlist/PlaylistEdit.js
@@ -35,7 +35,7 @@ const PlaylistEditForm = (props) => {
{(formDataProps) => }
diff --git a/ui/src/playlist/PlaylistList.js b/ui/src/playlist/PlaylistList.js
index 33446a212..68785c65a 100644
--- a/ui/src/playlist/PlaylistList.js
+++ b/ui/src/playlist/PlaylistList.js
@@ -58,7 +58,7 @@ const TogglePublicInput = ({ resource, source }) => {
)
}
@@ -70,7 +70,7 @@ const PlaylistList = (props) => {
const toggleableFields = useMemo(() => {
return {
- owner: ,
+ ownerName: ,
songCount: isDesktop && ,
duration: isDesktop && ,
updatedAt: isDesktop && (
@@ -94,10 +94,7 @@ const PlaylistList = (props) => {
filters={}
actions={}
>
- isWritable(r && r.owner)}
- >
+ isWritable(r?.ownerId)}>
{columns}