Add owner_id to playlist

This commit is contained in:
Deluan 2021-10-29 22:55:28 -04:00 committed by Deluan Quintão
parent 84bbcdbfc2
commit 133fed344f
38 changed files with 173 additions and 100 deletions

View file

@ -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)
}

View 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
}

View file

@ -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"`

View file

@ -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}

View file

@ -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)

View file

@ -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")

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -133,7 +133,7 @@
"fields": {
"name": "نام",
"duration": "مدّت زمان",
"owner": "مالک",
"ownerName": "مالک",
"public": "عمومی",
"updatedAt": "بروزشده در",
"createdAt": "ایجادشده در",

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -133,7 +133,7 @@
"fields": {
"name": "名前",
"duration": "時間",
"owner": "所有者",
"ownerName": "所有者",
"public": "公開",
"updatedAt": "更新日",
"createdAt": "作成日",
@ -386,4 +386,4 @@
"toggle_love": "星の付け外し"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -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 ",

View file

@ -133,7 +133,7 @@
"fields": {
"name": "Название",
"duration": "Длительность",
"owner": "Владелец",
"ownerName": "Владелец",
"public": "Публичный",
"updatedAt": "Обновлен",
"createdAt": "Создан",
@ -386,4 +386,4 @@
"toggle_love": "Добавить / удалить песню из избранного"
}
}
}
}

View file

@ -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"
}
}
}
}

View file

@ -127,7 +127,7 @@
"fields": {
"name": "Namn",
"duration": "Längd",
"owner": "Ägare",
"ownerName": "Ägare",
"public": "Offentlig",
"updatedAt": "Uppdaterad",
"createdAt": "Skapad",

View file

@ -133,7 +133,7 @@
"fields": {
"name": "ชื่อ",
"duration": "เวลา",
"owner": "เจ้าของ",
"ownerName": "เจ้าของ",
"public": "สาธารณะ",
"updatedAt": "อัปเดตเมื่อ",
"createdAt": "สร้างขึ้นเมื่อ",
@ -386,4 +386,4 @@
"toggle_love": "เพิ่มเพลงนี้ไปยังรายการโปรด"
}
}
}
}

View file

@ -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": ""
}
}
}

View file

@ -130,7 +130,7 @@
"fields": {
"name": "Назва",
"duration": "Тривалість",
"owner": "Власник",
"ownerName": "Власник",
"public": "Публічний",
"updatedAt": "Оновлено",
"createdAt": "Створено",
@ -380,4 +380,4 @@
"toggle_love": "Відмітити поточні пісні"
}
}
}
}

View file

@ -130,7 +130,7 @@
"fields": {
"name": "名称",
"duration": "时长",
"owner": "所有者",
"ownerName": "所有者",
"public": "公开",
"updatedAt": "更新于",
"createdAt": "创建于",
@ -380,4 +380,4 @@
"toggle_love": "添加/移除星标"
}
}
}
}

View file

@ -133,7 +133,7 @@
"fields": {
"name": "名稱",
"duration": "長度",
"owner": "擁有者",
"ownerName": "擁有者",
"public": "公開",
"updatedAt": "更新於",
"createdAt": "創建於",
@ -386,4 +386,4 @@
"toggle_love": "添加或移除星標"
}
}
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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)

View file

@ -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)) {

View file

@ -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']

View file

@ -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 = []

View file

@ -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' },
])

View file

@ -138,7 +138,7 @@
"fields": {
"name": "Name",
"duration": "Duration",
"owner": "Owner",
"ownerName": "Owner",
"public": "Public",
"updatedAt": "Updated at",
"createdAt": "Created at",

View file

@ -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)

View file

@ -35,7 +35,7 @@ const PlaylistEditForm = (props) => {
<TextInput multiline source="comment" />
<BooleanInput
source="public"
disabled={!isWritable(record.owner) || isSmartPlaylist(record)}
disabled={!isWritable(record.ownerId) || isSmartPlaylist(record)}
/>
<FormDataConsumer>
{(formDataProps) => <SyncFragment {...formDataProps} />}

View file

@ -58,7 +58,7 @@ const TogglePublicInput = ({ resource, source }) => {
<Switch
checked={record[source]}
onClick={handleClick}
disabled={!isWritable(record.owner) || isSmartPlaylist(record)}
disabled={!isWritable(record.ownerId) || isSmartPlaylist(record)}
/>
)
}
@ -70,7 +70,7 @@ const PlaylistList = (props) => {
const toggleableFields = useMemo(() => {
return {
owner: <TextField source="owner" />,
ownerName: <TextField source="ownerName" />,
songCount: isDesktop && <NumberField source="songCount" />,
duration: isDesktop && <DurationField source="duration" />,
updatedAt: isDesktop && (
@ -94,10 +94,7 @@ const PlaylistList = (props) => {
filters={<PlaylistFilter />}
actions={<PlaylistListActions />}
>
<Datagrid
rowClick="show"
isRowSelectable={(r) => isWritable(r && r.owner)}
>
<Datagrid rowClick="show" isRowSelectable={(r) => isWritable(r?.ownerId)}>
<TextField source="name" />
{columns}
<Writable>