mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-15 03:30:39 +03:00
Add owner_id
to playlist
This commit is contained in:
parent
84bbcdbfc2
commit
133fed344f
@ -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 {
|
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)
|
pls, err := s.ds.Playlist(ctx).FindByPath(newPls.Path)
|
||||||
if err != nil && err != model.ErrNotFound {
|
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.ID = pls.ID
|
||||||
newPls.Name = pls.Name
|
newPls.Name = pls.Name
|
||||||
newPls.Comment = pls.Comment
|
newPls.Comment = pls.Comment
|
||||||
newPls.Owner = pls.Owner
|
newPls.OwnerID = pls.OwnerID
|
||||||
newPls.Public = pls.Public
|
newPls.Public = pls.Public
|
||||||
newPls.EvaluatedAt = time.Time{}
|
newPls.EvaluatedAt = time.Time{}
|
||||||
} else {
|
} else {
|
||||||
log.Info(ctx, "Adding synced playlist", "playlist", newPls.Name, "path", newPls.Path, "owner", owner)
|
log.Info(ctx, "Adding synced playlist", "playlist", newPls.Name, "path", newPls.Path, "owner", owner.UserName)
|
||||||
newPls.Owner = owner
|
newPls.OwnerID = owner.ID
|
||||||
}
|
}
|
||||||
return s.ds.Playlist(ctx).Put(newPls)
|
return s.ds.Playlist(ctx).Put(newPls)
|
||||||
}
|
}
|
||||||
|
60
db/migration/20211029213200_add_userid_to_playlist.go
Normal file
60
db/migration/20211029213200_add_userid_to_playlist.go
Normal file
@ -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
|
||||||
|
}
|
@ -15,7 +15,8 @@ type Playlist struct {
|
|||||||
Duration float32 `structs:"duration" json:"duration"`
|
Duration float32 `structs:"duration" json:"duration"`
|
||||||
Size int64 `structs:"size" json:"size"`
|
Size int64 `structs:"size" json:"size"`
|
||||||
SongCount int `structs:"song_count" json:"songCount"`
|
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"`
|
Public bool `structs:"public" json:"public"`
|
||||||
Tracks PlaylistTracks `structs:"-" json:"tracks,omitempty"`
|
Tracks PlaylistTracks `structs:"-" json:"tracks,omitempty"`
|
||||||
Path string `structs:"path" json:"path"`
|
Path string `structs:"path" json:"path"`
|
||||||
|
@ -85,7 +85,14 @@ var _ = Describe("Initialize test DB", func() {
|
|||||||
BeforeSuite(func() {
|
BeforeSuite(func() {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
ctx := log.NewContext(context.TODO())
|
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)
|
gr := NewGenreRepository(ctx, o)
|
||||||
for i := range testGenres {
|
for i := range testGenres {
|
||||||
@ -126,12 +133,13 @@ var _ = Describe("Initialize test DB", func() {
|
|||||||
plsBest = model.Playlist{
|
plsBest = model.Playlist{
|
||||||
Name: "Best",
|
Name: "Best",
|
||||||
Comment: "No Comments",
|
Comment: "No Comments",
|
||||||
Owner: "userid",
|
OwnerID: "userid",
|
||||||
|
OwnerName: "userid",
|
||||||
Public: true,
|
Public: true,
|
||||||
SongCount: 2,
|
SongCount: 2,
|
||||||
}
|
}
|
||||||
plsBest.AddTracks([]string{"1001", "1003"})
|
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"})
|
plsCool.AddTracks([]string{"1004"})
|
||||||
testPlaylists = []*model.Playlist{&plsBest, &plsCool}
|
testPlaylists = []*model.Playlist{&plsBest, &plsCool}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func (r *playlistRepository) userFilter() Sqlizer {
|
|||||||
}
|
}
|
||||||
return Or{
|
return Or{
|
||||||
Eq{"public": true},
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if pls.Owner != usr.UserName {
|
if pls.OwnerID != usr.ID {
|
||||||
return rest.ErrPermissionDenied
|
return rest.ErrPermissionDenied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,11 +117,11 @@ func (r *playlistRepository) Put(p *model.Playlist) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *playlistRepository) Get(id string) (*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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
func (r *playlistRepository) findBy(sql Sqlizer) (*model.Playlist, error) {
|
||||||
sel := r.newSelect().Columns("*").Where(sql)
|
sel := r.selectPlaylist().Where(sql)
|
||||||
var pls []dbPlaylist
|
var pls []dbPlaylist
|
||||||
err := r.queryAll(sel, &pls)
|
err := r.queryAll(sel, &pls)
|
||||||
if err != nil {
|
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) {
|
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
|
var res []dbPlaylist
|
||||||
err := r.queryAll(sel, &res)
|
err := r.queryAll(sel, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -186,6 +186,11 @@ func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playli
|
|||||||
return playlists, err
|
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 {
|
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
|
// 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 {
|
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
|
// Never refresh other users' playlists
|
||||||
usr := loggedUser(r.ctx)
|
usr := loggedUser(r.ctx)
|
||||||
if pls.Owner != usr.UserName {
|
if pls.OwnerID != usr.ID {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +367,8 @@ func (r *playlistRepository) NewInstance() interface{} {
|
|||||||
|
|
||||||
func (r *playlistRepository) Save(entity interface{}) (string, error) {
|
func (r *playlistRepository) Save(entity interface{}) (string, error) {
|
||||||
pls := entity.(*model.Playlist)
|
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)
|
err := r.Put(pls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -373,7 +379,7 @@ func (r *playlistRepository) Save(entity interface{}) (string, error) {
|
|||||||
func (r *playlistRepository) Update(entity interface{}, cols ...string) error {
|
func (r *playlistRepository) Update(entity interface{}, cols ...string) error {
|
||||||
pls := entity.(*model.Playlist)
|
pls := entity.(*model.Playlist)
|
||||||
usr := loggedUser(r.ctx)
|
usr := loggedUser(r.ctx)
|
||||||
if !usr.IsAdmin && pls.Owner != usr.UserName {
|
if !usr.IsAdmin && pls.OwnerID != usr.ID {
|
||||||
return rest.ErrPermissionDenied
|
return rest.ErrPermissionDenied
|
||||||
}
|
}
|
||||||
err := r.Put(pls)
|
err := r.Put(pls)
|
||||||
@ -432,7 +438,7 @@ func (r *playlistRepository) isWritable(playlistId string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
pls, err := r.Get(playlistId)
|
pls, err := r.Get(playlistId)
|
||||||
return err == nil && pls.Owner == usr.UserName
|
return err == nil && pls.OwnerID == usr.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ model.PlaylistRepository = (*playlistRepository)(nil)
|
var _ model.PlaylistRepository = (*playlistRepository)(nil)
|
||||||
|
@ -76,7 +76,7 @@ var _ = Describe("PlaylistRepository", func() {
|
|||||||
|
|
||||||
It("Put/Exists/Delete", func() {
|
It("Put/Exists/Delete", func() {
|
||||||
By("saves the playlist to the DB")
|
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"})
|
newPls.AddTracks([]string{"1004", "1003"})
|
||||||
|
|
||||||
By("saves the playlist to the DB")
|
By("saves the playlist to the DB")
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Název",
|
"name": "Název",
|
||||||
"duration": "Délka",
|
"duration": "Délka",
|
||||||
"owner": "Vlastník",
|
"ownerName": "Vlastník",
|
||||||
"public": "Veřejný",
|
"public": "Veřejný",
|
||||||
"updatedAt": "Nahrán",
|
"updatedAt": "Nahrán",
|
||||||
"createdAt": "Vytvořen",
|
"createdAt": "Vytvořen",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Přidat tuto skladbu do oblíbených"
|
"toggle_love": "Přidat tuto skladbu do oblíbených"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Navn",
|
"name": "Navn",
|
||||||
"duration": "Varighed",
|
"duration": "Varighed",
|
||||||
"owner": "Ejer",
|
"ownerName": "Ejer",
|
||||||
"public": "Offentlig",
|
"public": "Offentlig",
|
||||||
"updatedAt": "Opdateret den",
|
"updatedAt": "Opdateret den",
|
||||||
"createdAt": "Oprettet den",
|
"createdAt": "Oprettet den",
|
||||||
@ -324,4 +324,4 @@
|
|||||||
"serverUptime": "Server uptime",
|
"serverUptime": "Server uptime",
|
||||||
"serverDown": "OFFLINE"
|
"serverDown": "OFFLINE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"duration": "Dauer",
|
"duration": "Dauer",
|
||||||
"owner": "Inhaber",
|
"ownerName": "Inhaber",
|
||||||
"public": "Öffentlich",
|
"public": "Öffentlich",
|
||||||
"updatedAt": "Aktualisiert um",
|
"updatedAt": "Aktualisiert um",
|
||||||
"createdAt": "Erstellt um",
|
"createdAt": "Erstellt um",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Song zu Favoriten hinzufügen"
|
"toggle_love": "Song zu Favoriten hinzufügen"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nomo",
|
"name": "Nomo",
|
||||||
"duration": "Daŭro",
|
"duration": "Daŭro",
|
||||||
"owner": "Posedanto",
|
"ownerName": "Posedanto",
|
||||||
"public": "Publika",
|
"public": "Publika",
|
||||||
"updatedAt": "Ĝisdatigita je",
|
"updatedAt": "Ĝisdatigita je",
|
||||||
"createdAt": "Kreita je",
|
"createdAt": "Kreita je",
|
||||||
@ -348,4 +348,4 @@
|
|||||||
"toggle_love": "Baskuli la stelon de nuna kanto"
|
"toggle_love": "Baskuli la stelon de nuna kanto"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nombre",
|
"name": "Nombre",
|
||||||
"duration": "Duración",
|
"duration": "Duración",
|
||||||
"owner": "Dueño",
|
"ownerName": "Dueño",
|
||||||
"public": "Público",
|
"public": "Público",
|
||||||
"updatedAt": "Actualizado el",
|
"updatedAt": "Actualizado el",
|
||||||
"createdAt": "Creado el",
|
"createdAt": "Creado el",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Marca esta canción como favorita"
|
"toggle_love": "Marca esta canción como favorita"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "نام",
|
"name": "نام",
|
||||||
"duration": "مدّت زمان",
|
"duration": "مدّت زمان",
|
||||||
"owner": "مالک",
|
"ownerName": "مالک",
|
||||||
"public": "عمومی",
|
"public": "عمومی",
|
||||||
"updatedAt": "بروزشده در",
|
"updatedAt": "بروزشده در",
|
||||||
"createdAt": "ایجادشده در",
|
"createdAt": "ایجادشده در",
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nimi",
|
"name": "Nimi",
|
||||||
"duration": "Kesto",
|
"duration": "Kesto",
|
||||||
"owner": "Omistaja",
|
"ownerName": "Omistaja",
|
||||||
"public": "Julkinen",
|
"public": "Julkinen",
|
||||||
"updatedAt": "Päivitetty",
|
"updatedAt": "Päivitetty",
|
||||||
"createdAt": "Luotu",
|
"createdAt": "Luotu",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Lisää kappale suosikkeihin"
|
"toggle_love": "Lisää kappale suosikkeihin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"duration": "Durée",
|
"duration": "Durée",
|
||||||
"owner": "Propriétaire",
|
"ownerName": "Propriétaire",
|
||||||
"public": "Public",
|
"public": "Public",
|
||||||
"updatedAt": "Mise à jour le",
|
"updatedAt": "Mise à jour le",
|
||||||
"createdAt": "Créé le",
|
"createdAt": "Créé le",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Ajouter/Enlever le morceau des favoris"
|
"toggle_love": "Ajouter/Enlever le morceau des favoris"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nome",
|
"name": "Nome",
|
||||||
"duration": "Durata",
|
"duration": "Durata",
|
||||||
"owner": "Creatore",
|
"ownerName": "Creatore",
|
||||||
"public": "Pubblica",
|
"public": "Pubblica",
|
||||||
"updatedAt": "Ultimo aggiornamento",
|
"updatedAt": "Ultimo aggiornamento",
|
||||||
"createdAt": "Data creazione",
|
"createdAt": "Data creazione",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Aggiungi questa traccia ai preferiti"
|
"toggle_love": "Aggiungi questa traccia ai preferiti"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "名前",
|
"name": "名前",
|
||||||
"duration": "時間",
|
"duration": "時間",
|
||||||
"owner": "所有者",
|
"ownerName": "所有者",
|
||||||
"public": "公開",
|
"public": "公開",
|
||||||
"updatedAt": "更新日",
|
"updatedAt": "更新日",
|
||||||
"createdAt": "作成日",
|
"createdAt": "作成日",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "星の付け外し"
|
"toggle_love": "星の付け外し"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Titel",
|
"name": "Titel",
|
||||||
"duration": "Lengte",
|
"duration": "Lengte",
|
||||||
"owner": "Eigenaar",
|
"ownerName": "Eigenaar",
|
||||||
"public": "Publiek",
|
"public": "Publiek",
|
||||||
"updatedAt": "Laatst gewijzigd op",
|
"updatedAt": "Laatst gewijzigd op",
|
||||||
"createdAt": "Aangemaakt op",
|
"createdAt": "Aangemaakt op",
|
||||||
@ -380,4 +380,4 @@
|
|||||||
"toggle_love": "Voeg toe aan favorieten"
|
"toggle_love": "Voeg toe aan favorieten"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nazwa",
|
"name": "Nazwa",
|
||||||
"duration": "Czas trwania",
|
"duration": "Czas trwania",
|
||||||
"owner": "Właściciel",
|
"ownerName": "Właściciel",
|
||||||
"public": "Publiczna",
|
"public": "Publiczna",
|
||||||
"updatedAt": "Zaktualizowana",
|
"updatedAt": "Zaktualizowana",
|
||||||
"createdAt": "Stworzona",
|
"createdAt": "Stworzona",
|
||||||
@ -380,4 +380,4 @@
|
|||||||
"toggle_love": "Dodaj ten utwór do ulubionych"
|
"toggle_love": "Dodaj ten utwór do ulubionych"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Nome",
|
"name": "Nome",
|
||||||
"duration": "Duração",
|
"duration": "Duração",
|
||||||
"owner": "Dono",
|
"ownerName": "Dono",
|
||||||
"public": "Pública",
|
"public": "Pública",
|
||||||
"updatedAt": "Últ. Atualização",
|
"updatedAt": "Últ. Atualização",
|
||||||
"createdAt": "Data de Criação ",
|
"createdAt": "Data de Criação ",
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Название",
|
"name": "Название",
|
||||||
"duration": "Длительность",
|
"duration": "Длительность",
|
||||||
"owner": "Владелец",
|
"ownerName": "Владелец",
|
||||||
"public": "Публичный",
|
"public": "Публичный",
|
||||||
"updatedAt": "Обновлен",
|
"updatedAt": "Обновлен",
|
||||||
"createdAt": "Создан",
|
"createdAt": "Создан",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Добавить / удалить песню из избранного"
|
"toggle_love": "Добавить / удалить песню из избранного"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Ime",
|
"name": "Ime",
|
||||||
"duration": "Dolžina",
|
"duration": "Dolžina",
|
||||||
"owner": "Lastnik",
|
"ownerName": "Lastnik",
|
||||||
"public": "Javno",
|
"public": "Javno",
|
||||||
"updatedAt": "Posodobljen",
|
"updatedAt": "Posodobljen",
|
||||||
"createdAt": "Ustvarjen",
|
"createdAt": "Ustvarjen",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "Dodaj med priljubljene"
|
"toggle_love": "Dodaj med priljubljene"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Namn",
|
"name": "Namn",
|
||||||
"duration": "Längd",
|
"duration": "Längd",
|
||||||
"owner": "Ägare",
|
"ownerName": "Ägare",
|
||||||
"public": "Offentlig",
|
"public": "Offentlig",
|
||||||
"updatedAt": "Uppdaterad",
|
"updatedAt": "Uppdaterad",
|
||||||
"createdAt": "Skapad",
|
"createdAt": "Skapad",
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "ชื่อ",
|
"name": "ชื่อ",
|
||||||
"duration": "เวลา",
|
"duration": "เวลา",
|
||||||
"owner": "เจ้าของ",
|
"ownerName": "เจ้าของ",
|
||||||
"public": "สาธารณะ",
|
"public": "สาธารณะ",
|
||||||
"updatedAt": "อัปเดตเมื่อ",
|
"updatedAt": "อัปเดตเมื่อ",
|
||||||
"createdAt": "สร้างขึ้นเมื่อ",
|
"createdAt": "สร้างขึ้นเมื่อ",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "เพิ่มเพลงนี้ไปยังรายการโปรด"
|
"toggle_love": "เพิ่มเพลงนี้ไปยังรายการโปรด"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Isim",
|
"name": "Isim",
|
||||||
"duration": "Süre",
|
"duration": "Süre",
|
||||||
"owner": "Sahibi",
|
"ownerName": "Sahibi",
|
||||||
"public": "Görülebilir",
|
"public": "Görülebilir",
|
||||||
"updatedAt": "Güncelleme tarihi:",
|
"updatedAt": "Güncelleme tarihi:",
|
||||||
"createdAt": "Oluşturma tarihi:",
|
"createdAt": "Oluşturma tarihi:",
|
||||||
@ -324,4 +324,4 @@
|
|||||||
"serverUptime": "",
|
"serverUptime": "",
|
||||||
"serverDown": ""
|
"serverDown": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Назва",
|
"name": "Назва",
|
||||||
"duration": "Тривалість",
|
"duration": "Тривалість",
|
||||||
"owner": "Власник",
|
"ownerName": "Власник",
|
||||||
"public": "Публічний",
|
"public": "Публічний",
|
||||||
"updatedAt": "Оновлено",
|
"updatedAt": "Оновлено",
|
||||||
"createdAt": "Створено",
|
"createdAt": "Створено",
|
||||||
@ -380,4 +380,4 @@
|
|||||||
"toggle_love": "Відмітити поточні пісні"
|
"toggle_love": "Відмітити поточні пісні"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "名称",
|
"name": "名称",
|
||||||
"duration": "时长",
|
"duration": "时长",
|
||||||
"owner": "所有者",
|
"ownerName": "所有者",
|
||||||
"public": "公开",
|
"public": "公开",
|
||||||
"updatedAt": "更新于",
|
"updatedAt": "更新于",
|
||||||
"createdAt": "创建于",
|
"createdAt": "创建于",
|
||||||
@ -380,4 +380,4 @@
|
|||||||
"toggle_love": "添加/移除星标"
|
"toggle_love": "添加/移除星标"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "名稱",
|
"name": "名稱",
|
||||||
"duration": "長度",
|
"duration": "長度",
|
||||||
"owner": "擁有者",
|
"ownerName": "擁有者",
|
||||||
"public": "公開",
|
"public": "公開",
|
||||||
"updatedAt": "更新於",
|
"updatedAt": "更新於",
|
||||||
"createdAt": "創建於",
|
"createdAt": "創建於",
|
||||||
@ -386,4 +386,4 @@
|
|||||||
"toggle_love": "添加或移除星標"
|
"toggle_love": "添加或移除星標"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,12 @@ func (e subError) Error() string {
|
|||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUser(ctx context.Context) string {
|
func getUser(ctx context.Context) model.User {
|
||||||
user, ok := request.UserFrom(ctx)
|
user, ok := request.UserFrom(ctx)
|
||||||
if ok {
|
if ok {
|
||||||
return user.UserName
|
return user
|
||||||
}
|
}
|
||||||
return ""
|
return model.User{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
|
func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
|
||||||
|
@ -74,14 +74,12 @@ func (c *PlaylistsController) create(ctx context.Context, playlistId, name strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if owner != pls.Owner {
|
if owner.ID != pls.OwnerID {
|
||||||
return model.ErrNotAuthorized
|
return model.ErrNotAuthorized
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pls = &model.Playlist{
|
pls = &model.Playlist{Name: name}
|
||||||
Name: name,
|
pls.OwnerID = owner.ID
|
||||||
Owner: owner,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pls.Tracks = nil
|
pls.Tracks = nil
|
||||||
pls.AddTracks(ids)
|
pls.AddTracks(ids)
|
||||||
@ -178,7 +176,7 @@ func (c *PlaylistsController) buildPlaylist(p model.Playlist) *responses.Playlis
|
|||||||
pls.Name = p.Name
|
pls.Name = p.Name
|
||||||
pls.Comment = p.Comment
|
pls.Comment = p.Comment
|
||||||
pls.SongCount = p.SongCount
|
pls.SongCount = p.SongCount
|
||||||
pls.Owner = p.Owner
|
pls.Owner = p.OwnerName
|
||||||
pls.Duration = int(p.Duration)
|
pls.Duration = int(p.Duration)
|
||||||
pls.Public = p.Public
|
pls.Public = p.Public
|
||||||
pls.Created = p.CreatedAt
|
pls.Created = p.CreatedAt
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { cloneElement, Children, isValidElement } from 'react'
|
import { cloneElement, Children, isValidElement } from 'react'
|
||||||
|
|
||||||
export const isWritable = (owner) => {
|
export const isWritable = (ownerId) => {
|
||||||
return (
|
return (
|
||||||
localStorage.getItem('username') === owner ||
|
localStorage.getItem('userId') === ownerId ||
|
||||||
localStorage.getItem('role') === 'admin'
|
localStorage.getItem('role') === 'admin'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isReadOnly = (owner) => {
|
export const isReadOnly = (ownerId) => {
|
||||||
return !isWritable(owner)
|
return !isWritable(ownerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Writable = (props) => {
|
export const Writable = (props) => {
|
||||||
const { record = {}, children } = props
|
const { record = {}, children } = props
|
||||||
if (isWritable(record.owner)) {
|
if (isWritable(record.ownerId)) {
|
||||||
return Children.map(children, (child) =>
|
return Children.map(children, (child) =>
|
||||||
isValidElement(child) ? cloneElement(child, props) : child
|
isValidElement(child) ? cloneElement(child, props) : child
|
||||||
)
|
)
|
||||||
@ -24,4 +24,4 @@ export const Writable = (props) => {
|
|||||||
export const isSmartPlaylist = (pls) => !!pls.rules
|
export const isSmartPlaylist = (pls) => !!pls.rules
|
||||||
|
|
||||||
export const canChangeTracks = (pls) =>
|
export const canChangeTracks = (pls) =>
|
||||||
isWritable(pls.owner) && !isSmartPlaylist(pls)
|
isWritable(pls.ownerId) && !isSmartPlaylist(pls)
|
||||||
|
@ -22,7 +22,8 @@ export const useSelectedFields = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
!resourceFields ||
|
!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 = {}
|
const obj = {}
|
||||||
for (const key of Object.keys(columns)) {
|
for (const key of Object.keys(columns)) {
|
||||||
|
@ -5,22 +5,23 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
|
|||||||
import { AddToPlaylistDialog } from './AddToPlaylistDialog'
|
import { AddToPlaylistDialog } from './AddToPlaylistDialog'
|
||||||
|
|
||||||
describe('AddToPlaylistDialog', () => {
|
describe('AddToPlaylistDialog', () => {
|
||||||
|
beforeAll(() => localStorage.setItem('userId', 'admin'))
|
||||||
afterEach(cleanup)
|
afterEach(cleanup)
|
||||||
|
|
||||||
const mockData = [
|
const mockData = [
|
||||||
{ id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
|
{ id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
|
||||||
{ id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
|
{ id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
|
||||||
]
|
]
|
||||||
const mockIndexedData = {
|
const mockIndexedData = {
|
||||||
'sample-id1': {
|
'sample-id1': {
|
||||||
id: 'sample-id1',
|
id: 'sample-id1',
|
||||||
name: 'sample playlist 1',
|
name: 'sample playlist 1',
|
||||||
owner: 'admin',
|
ownerId: 'admin',
|
||||||
},
|
},
|
||||||
'sample-id2': {
|
'sample-id2': {
|
||||||
id: 'sample-id2',
|
id: 'sample-id2',
|
||||||
name: 'sample playlist 2',
|
name: 'sample playlist 2',
|
||||||
owner: 'admin',
|
ownerId: 'admin',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const selectedIds = ['song-1', 'song-2']
|
const selectedIds = ['song-1', 'song-2']
|
||||||
|
@ -30,7 +30,7 @@ export const SelectPlaylistInput = ({ onChange }) => {
|
|||||||
|
|
||||||
const options =
|
const options =
|
||||||
ids &&
|
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) => {
|
const handleOnChange = (event, newValue) => {
|
||||||
let newState = []
|
let newState = []
|
||||||
|
@ -5,24 +5,25 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
|
|||||||
import { SelectPlaylistInput } from './SelectPlaylistInput'
|
import { SelectPlaylistInput } from './SelectPlaylistInput'
|
||||||
|
|
||||||
describe('SelectPlaylistInput', () => {
|
describe('SelectPlaylistInput', () => {
|
||||||
|
beforeAll(() => localStorage.setItem('userId', 'admin'))
|
||||||
afterEach(cleanup)
|
afterEach(cleanup)
|
||||||
const onChangeHandler = jest.fn()
|
const onChangeHandler = jest.fn()
|
||||||
|
|
||||||
it('should call the handler with the selections', async () => {
|
it('should call the handler with the selections', async () => {
|
||||||
const mockData = [
|
const mockData = [
|
||||||
{ id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
|
{ id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
|
||||||
{ id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
|
{ id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
|
||||||
]
|
]
|
||||||
const mockIndexedData = {
|
const mockIndexedData = {
|
||||||
'sample-id1': {
|
'sample-id1': {
|
||||||
id: 'sample-id1',
|
id: 'sample-id1',
|
||||||
name: 'sample playlist 1',
|
name: 'sample playlist 1',
|
||||||
owner: 'admin',
|
ownerId: 'admin',
|
||||||
},
|
},
|
||||||
'sample-id2': {
|
'sample-id2': {
|
||||||
id: 'sample-id2',
|
id: 'sample-id2',
|
||||||
name: 'sample playlist 2',
|
name: 'sample playlist 2',
|
||||||
owner: 'admin',
|
ownerId: 'admin',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ describe('SelectPlaylistInput', () => {
|
|||||||
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(onChangeHandler).toHaveBeenCalledWith([
|
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' })
|
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(onChangeHandler).toHaveBeenCalledWith([
|
expect(onChangeHandler).toHaveBeenCalledWith([
|
||||||
{ id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
|
{ id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
|
||||||
{ id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
|
{ id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -94,8 +95,8 @@ describe('SelectPlaylistInput', () => {
|
|||||||
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(onChangeHandler).toHaveBeenCalledWith([
|
expect(onChangeHandler).toHaveBeenCalledWith([
|
||||||
{ id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
|
{ id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
|
||||||
{ id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
|
{ id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
|
||||||
{ name: 'new playlist' },
|
{ name: 'new playlist' },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -106,8 +107,8 @@ describe('SelectPlaylistInput', () => {
|
|||||||
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(onChangeHandler).toHaveBeenCalledWith([
|
expect(onChangeHandler).toHaveBeenCalledWith([
|
||||||
{ id: 'sample-id1', name: 'sample playlist 1', owner: 'admin' },
|
{ id: 'sample-id1', name: 'sample playlist 1', ownerId: 'admin' },
|
||||||
{ id: 'sample-id2', name: 'sample playlist 2', owner: 'admin' },
|
{ id: 'sample-id2', name: 'sample playlist 2', ownerId: 'admin' },
|
||||||
{ name: 'new playlist' },
|
{ name: 'new playlist' },
|
||||||
{ name: 'another new playlist' },
|
{ name: 'another new playlist' },
|
||||||
])
|
])
|
||||||
|
@ -138,7 +138,7 @@
|
|||||||
"fields": {
|
"fields": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"duration": "Duration",
|
"duration": "Duration",
|
||||||
"owner": "Owner",
|
"ownerName": "Owner",
|
||||||
"public": "Public",
|
"public": "Public",
|
||||||
"updatedAt": "Updated at",
|
"updatedAt": "Updated at",
|
||||||
"createdAt": "Created at",
|
"createdAt": "Created at",
|
||||||
|
@ -74,7 +74,7 @@ const PlaylistsSubMenu = ({ state, setState, sidebarIsOpen, dense }) => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
const user = localStorage.getItem('username')
|
const userId = localStorage.getItem('userId')
|
||||||
const myPlaylists = []
|
const myPlaylists = []
|
||||||
const sharedPlaylists = []
|
const sharedPlaylists = []
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ const PlaylistsSubMenu = ({ state, setState, sidebarIsOpen, dense }) => {
|
|||||||
const allPlaylists = Object.keys(data).map((id) => data[id])
|
const allPlaylists = Object.keys(data).map((id) => data[id])
|
||||||
|
|
||||||
allPlaylists.forEach((pls) => {
|
allPlaylists.forEach((pls) => {
|
||||||
if (user === pls.owner) {
|
if (userId === pls.ownerId) {
|
||||||
myPlaylists.push(pls)
|
myPlaylists.push(pls)
|
||||||
} else {
|
} else {
|
||||||
sharedPlaylists.push(pls)
|
sharedPlaylists.push(pls)
|
||||||
|
@ -35,7 +35,7 @@ const PlaylistEditForm = (props) => {
|
|||||||
<TextInput multiline source="comment" />
|
<TextInput multiline source="comment" />
|
||||||
<BooleanInput
|
<BooleanInput
|
||||||
source="public"
|
source="public"
|
||||||
disabled={!isWritable(record.owner) || isSmartPlaylist(record)}
|
disabled={!isWritable(record.ownerId) || isSmartPlaylist(record)}
|
||||||
/>
|
/>
|
||||||
<FormDataConsumer>
|
<FormDataConsumer>
|
||||||
{(formDataProps) => <SyncFragment {...formDataProps} />}
|
{(formDataProps) => <SyncFragment {...formDataProps} />}
|
||||||
|
@ -58,7 +58,7 @@ const TogglePublicInput = ({ resource, source }) => {
|
|||||||
<Switch
|
<Switch
|
||||||
checked={record[source]}
|
checked={record[source]}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
disabled={!isWritable(record.owner) || isSmartPlaylist(record)}
|
disabled={!isWritable(record.ownerId) || isSmartPlaylist(record)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ const PlaylistList = (props) => {
|
|||||||
|
|
||||||
const toggleableFields = useMemo(() => {
|
const toggleableFields = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
owner: <TextField source="owner" />,
|
ownerName: <TextField source="ownerName" />,
|
||||||
songCount: isDesktop && <NumberField source="songCount" />,
|
songCount: isDesktop && <NumberField source="songCount" />,
|
||||||
duration: isDesktop && <DurationField source="duration" />,
|
duration: isDesktop && <DurationField source="duration" />,
|
||||||
updatedAt: isDesktop && (
|
updatedAt: isDesktop && (
|
||||||
@ -94,10 +94,7 @@ const PlaylistList = (props) => {
|
|||||||
filters={<PlaylistFilter />}
|
filters={<PlaylistFilter />}
|
||||||
actions={<PlaylistListActions />}
|
actions={<PlaylistListActions />}
|
||||||
>
|
>
|
||||||
<Datagrid
|
<Datagrid rowClick="show" isRowSelectable={(r) => isWritable(r?.ownerId)}>
|
||||||
rowClick="show"
|
|
||||||
isRowSelectable={(r) => isWritable(r && r.owner)}
|
|
||||||
>
|
|
||||||
<TextField source="name" />
|
<TextField source="name" />
|
||||||
{columns}
|
{columns}
|
||||||
<Writable>
|
<Writable>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user