mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-03 20:47:35 +03:00
Add owner_id
to playlist
This commit is contained in:
parent
84bbcdbfc2
commit
133fed344f
38 changed files with 173 additions and 100 deletions
|
@ -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)
|
||||
}
|
||||
|
|
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"`
|
||||
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"`
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"fields": {
|
||||
"name": "نام",
|
||||
"duration": "مدّت زمان",
|
||||
"owner": "مالک",
|
||||
"ownerName": "مالک",
|
||||
"public": "عمومی",
|
||||
"updatedAt": "بروزشده در",
|
||||
"createdAt": "ایجادشده در",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"fields": {
|
||||
"name": "名前",
|
||||
"duration": "時間",
|
||||
"owner": "所有者",
|
||||
"ownerName": "所有者",
|
||||
"public": "公開",
|
||||
"updatedAt": "更新日",
|
||||
"createdAt": "作成日",
|
||||
|
@ -386,4 +386,4 @@
|
|||
"toggle_love": "星の付け外し"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ",
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"fields": {
|
||||
"name": "Название",
|
||||
"duration": "Длительность",
|
||||
"owner": "Владелец",
|
||||
"ownerName": "Владелец",
|
||||
"public": "Публичный",
|
||||
"updatedAt": "Обновлен",
|
||||
"createdAt": "Создан",
|
||||
|
@ -386,4 +386,4 @@
|
|||
"toggle_love": "Добавить / удалить песню из избранного"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
"fields": {
|
||||
"name": "Namn",
|
||||
"duration": "Längd",
|
||||
"owner": "Ägare",
|
||||
"ownerName": "Ägare",
|
||||
"public": "Offentlig",
|
||||
"updatedAt": "Uppdaterad",
|
||||
"createdAt": "Skapad",
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"fields": {
|
||||
"name": "ชื่อ",
|
||||
"duration": "เวลา",
|
||||
"owner": "เจ้าของ",
|
||||
"ownerName": "เจ้าของ",
|
||||
"public": "สาธารณะ",
|
||||
"updatedAt": "อัปเดตเมื่อ",
|
||||
"createdAt": "สร้างขึ้นเมื่อ",
|
||||
|
@ -386,4 +386,4 @@
|
|||
"toggle_love": "เพิ่มเพลงนี้ไปยังรายการโปรด"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
"fields": {
|
||||
"name": "Назва",
|
||||
"duration": "Тривалість",
|
||||
"owner": "Власник",
|
||||
"ownerName": "Власник",
|
||||
"public": "Публічний",
|
||||
"updatedAt": "Оновлено",
|
||||
"createdAt": "Створено",
|
||||
|
@ -380,4 +380,4 @@
|
|||
"toggle_love": "Відмітити поточні пісні"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
"fields": {
|
||||
"name": "名称",
|
||||
"duration": "时长",
|
||||
"owner": "所有者",
|
||||
"ownerName": "所有者",
|
||||
"public": "公开",
|
||||
"updatedAt": "更新于",
|
||||
"createdAt": "创建于",
|
||||
|
@ -380,4 +380,4 @@
|
|||
"toggle_love": "添加/移除星标"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"fields": {
|
||||
"name": "名稱",
|
||||
"duration": "長度",
|
||||
"owner": "擁有者",
|
||||
"ownerName": "擁有者",
|
||||
"public": "公開",
|
||||
"updatedAt": "更新於",
|
||||
"createdAt": "創建於",
|
||||
|
@ -386,4 +386,4 @@
|
|||
"toggle_love": "添加或移除星標"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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' },
|
||||
])
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
"fields": {
|
||||
"name": "Name",
|
||||
"duration": "Duration",
|
||||
"owner": "Owner",
|
||||
"ownerName": "Owner",
|
||||
"public": "Public",
|
||||
"updatedAt": "Updated 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 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)
|
||||
|
|
|
@ -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} />}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue