feat(subsonic): implement user-specific library access in GetMusicFolders

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2025-06-26 16:55:50 -04:00
commit c1365cd236
3 changed files with 70 additions and 1 deletions

View file

@ -17,7 +17,11 @@ import (
)
func (api *Router) GetMusicFolders(r *http.Request) (*responses.Subsonic, error) {
libraries, _ := api.ds.Library(r.Context()).GetAll()
libraries, err := getUserAccessibleLibraries(r.Context(), api.ds)
if err != nil {
return nil, err
}
folders := make([]responses.MusicFolder, len(libraries))
for i, f := range libraries {
folders[i].Id = int32(f.ID)

View file

@ -0,0 +1,55 @@
package subsonic
import (
"context"
"net/http/httptest"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/model/request"
"github.com/navidrome/navidrome/tests"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Browsing", func() {
var api *Router
var ctx context.Context
var ds model.DataStore
BeforeEach(func() {
ds = &tests.MockDataStore{}
api = &Router{ds: ds}
ctx = context.Background()
})
Describe("GetMusicFolders", func() {
It("should return all libraries the user has access", func() {
// Create mock user
user := model.User{
ID: "user-id",
}
ctx = request.WithUser(ctx, user)
// Setup mock expectations - admin users get all libraries via GetUserLibraries
mockUserRepo := ds.User(ctx).(*tests.MockedUserRepo)
err := mockUserRepo.SetUserLibraries("user-id", []int{1, 2, 3})
Expect(err).ToNot(HaveOccurred())
// Create request
r := httptest.NewRequest("GET", "/rest/getMusicFolders", nil)
r = r.WithContext(ctx)
// Call endpoint
response, err := api.GetMusicFolders(r)
// Verify results
Expect(err).ToNot(HaveOccurred())
Expect(response).ToNot(BeNil())
Expect(response.MusicFolders).ToNot(BeNil())
Expect(response.MusicFolders.Folders).To(HaveLen(3))
Expect(response.MusicFolders.Folders[0].Name).To(Equal("Test Library 1"))
Expect(response.MusicFolders.Folders[1].Name).To(Equal("Test Library 2"))
Expect(response.MusicFolders.Folders[2].Name).To(Equal("Test Library 3"))
})
})
})

View file

@ -474,3 +474,13 @@ func buildLyricsList(mf *model.MediaFile, lyricsList model.LyricList) *responses
}
return res
}
// getUserAccessibleLibraries returns the list of libraries the current user has access to
// Admin users get all libraries (auto-assigned), regular users get their assigned libraries
func getUserAccessibleLibraries(ctx context.Context, ds model.DataStore) ([]model.Library, error) {
user := getUser(ctx)
// All users (admin and regular) use the same method since admin users
// are automatically assigned to all libraries via user_library table
return ds.User(ctx).GetUserLibraries(user.ID)
}