feat(server/m7-352): AssertEditable + ErrSystemPlaylistReadonly on playlists service
This commit is contained in:
@@ -30,10 +30,11 @@ import (
|
||||
// Typed errors. The API layer maps each to its wire status code; tests
|
||||
// use errors.Is to assert the right path was taken.
|
||||
var (
|
||||
ErrNotFound = errors.New("playlists: playlist not found")
|
||||
ErrForbidden = errors.New("playlists: forbidden")
|
||||
ErrInvalidInput = errors.New("playlists: invalid input")
|
||||
ErrTrackNotFound = errors.New("playlists: track not found")
|
||||
ErrNotFound = errors.New("playlists: playlist not found")
|
||||
ErrForbidden = errors.New("playlists: forbidden")
|
||||
ErrInvalidInput = errors.New("playlists: invalid input")
|
||||
ErrTrackNotFound = errors.New("playlists: track not found")
|
||||
ErrSystemPlaylistReadonly = errors.New("playlists: system playlist is read-only")
|
||||
)
|
||||
|
||||
// Service wires the sqlc queries + on-disk cover-art directory together.
|
||||
@@ -292,6 +293,32 @@ func (s *Service) Delete(ctx context.Context, callerID, playlistID pgtype.UUID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertEditable returns nil if the playlist exists, the caller owns it,
|
||||
// AND the playlist is user-created (kind='user'). Returns:
|
||||
// - ErrNotFound — playlist doesn't exist
|
||||
// - ErrForbidden — caller is not the owner
|
||||
// - ErrSystemPlaylistReadonly — playlist exists but kind='system'
|
||||
//
|
||||
// Edit handlers call this first; on error, the API layer maps the typed
|
||||
// error to the appropriate status code.
|
||||
func (s *Service) AssertEditable(ctx context.Context, callerID, playlistID pgtype.UUID) error {
|
||||
q := dbq.New(s.pool)
|
||||
p, err := q.GetPlaylist(ctx, playlistID)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return ErrNotFound
|
||||
}
|
||||
return fmt.Errorf("playlists: load for editability check: %w", err)
|
||||
}
|
||||
if !pgtypeUUIDEqual(p.UserID, callerID) {
|
||||
return ErrForbidden
|
||||
}
|
||||
if p.Kind == "system" {
|
||||
return ErrSystemPlaylistReadonly
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendTracks adds the given track ids at the end of the playlist,
|
||||
// preserving order. Snapshot fields (title, artist, album, duration_sec)
|
||||
// are populated from the tracks/albums/artists join at insert time.
|
||||
|
||||
Reference in New Issue
Block a user