diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go index 8a16027ea..dbeb51893 100644 --- a/persistence/playlist_repository.go +++ b/persistence/playlist_repository.go @@ -185,6 +185,12 @@ func (r *playlistRepository) refreshSmartPlaylist(pls *model.Playlist) bool { return false } + // Never refresh other users' playlists + usr := loggedUser(r.ctx) + if pls.Owner != usr.UserName { + return false + } + log.Debug(r.ctx, "Refreshing smart playlist", "playlist", pls.Name, "id", pls.ID) start := time.Now() diff --git a/persistence/playlist_track_repository.go b/persistence/playlist_track_repository.go index 96889c535..b8141e1a4 100644 --- a/persistence/playlist_track_repository.go +++ b/persistence/playlist_track_repository.go @@ -12,6 +12,7 @@ type playlistTrackRepository struct { sqlRepository sqlRestful playlistId string + playlist *model.Playlist playlistRepo *playlistRepository } @@ -32,6 +33,7 @@ func (r *playlistRepository) Tracks(playlistId string) model.PlaylistTrackReposi if pls.IsSmartPlaylist() { r.refreshSmartPlaylist(pls) } + p.playlist = pls return p } @@ -79,8 +81,12 @@ func (r *playlistTrackRepository) NewInstance() interface{} { return &model.PlaylistTrack{} } +func (r *playlistTrackRepository) isTracksEditable() bool { + return r.playlistRepo.isWritable(r.playlistId) && !r.playlist.IsSmartPlaylist() +} + func (r *playlistTrackRepository) Add(mediaFileIds []string) (int, error) { - if !r.playlistRepo.isWritable(r.playlistId) { + if !r.isTracksEditable() { return 0, rest.ErrPermissionDenied } @@ -158,7 +164,7 @@ func (r *playlistTrackRepository) getTracks() ([]string, error) { } func (r *playlistTrackRepository) Delete(id string) error { - if !r.playlistRepo.isWritable(r.playlistId) { + if !r.isTracksEditable() { return rest.ErrPermissionDenied } err := r.delete(And{Eq{"playlist_id": r.playlistId}, Eq{"id": id}}) @@ -172,7 +178,7 @@ func (r *playlistTrackRepository) Delete(id string) error { } func (r *playlistTrackRepository) Reorder(pos int, newPos int) error { - if !r.playlistRepo.isWritable(r.playlistId) { + if !r.isTracksEditable() { return rest.ErrPermissionDenied } ids, err := r.getTracks() diff --git a/server/nativeapi/playlists.go b/server/nativeapi/playlists.go index 11be6ddb4..0685536a7 100644 --- a/server/nativeapi/playlists.go +++ b/server/nativeapi/playlists.go @@ -176,6 +176,10 @@ func reorderItem(ds model.DataStore) http.HandlerFunc { } tracksRepo := ds.Playlist(r.Context()).Tracks(playlistId) err = tracksRepo.Reorder(id, newPos) + if err == rest.ErrPermissionDenied { + http.Error(w, err.Error(), http.StatusForbidden) + return + } if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/ui/src/common/Writable.js b/ui/src/common/Writable.js index 0adedb1a3..577bc1fc2 100644 --- a/ui/src/common/Writable.js +++ b/ui/src/common/Writable.js @@ -20,3 +20,8 @@ export const Writable = (props) => { } return null } + +export const isSmartPlaylist = (pls) => !!pls.rules + +export const canChangeTracks = (pls) => + isWritable(pls.owner) && !isSmartPlaylist(pls) diff --git a/ui/src/layout/PlaylistsSubMenu.js b/ui/src/layout/PlaylistsSubMenu.js index 28c7c8d4f..6cca07ea8 100644 --- a/ui/src/layout/PlaylistsSubMenu.js +++ b/ui/src/layout/PlaylistsSubMenu.js @@ -12,7 +12,7 @@ import QueueMusicOutlinedIcon from '@material-ui/icons/QueueMusicOutlined' import { BiCog } from 'react-icons/all' import { useDrop } from 'react-dnd' import SubMenu from './SubMenu' -import { isWritable } from '../common' +import { canChangeTracks } from '../common' import { DraggableTypes, MAX_SIDEBAR_PLAYLISTS } from '../consts' const PlaylistMenuItemLink = ({ pls, sidebarIsOpen }) => { @@ -20,7 +20,7 @@ const PlaylistMenuItemLink = ({ pls, sidebarIsOpen }) => { const notify = useNotify() const [, dropRef] = useDrop(() => ({ - accept: isWritable(pls.owner) ? DraggableTypes.ALL : [], + accept: canChangeTracks(pls) ? DraggableTypes.ALL : [], drop: (item) => dataProvider .addToPlaylist(pls.id, item) diff --git a/ui/src/playlist/PlaylistEdit.js b/ui/src/playlist/PlaylistEdit.js index affe1143e..8f0b6029b 100644 --- a/ui/src/playlist/PlaylistEdit.js +++ b/ui/src/playlist/PlaylistEdit.js @@ -10,7 +10,7 @@ import { required, useTranslate, } from 'react-admin' -import { Title } from '../common' +import { isSmartPlaylist, isWritable, Title } from '../common' const SyncFragment = ({ formData, variant, ...rest }) => { return ( @@ -27,16 +27,26 @@ const PlaylistTitle = ({ record }) => { return