feat(subsonic): populate Folder field with user's accessible library IDs

Added functionality to populate the Folder field in GetUser and GetUsers API responses
with the library IDs that the user has access to. This allows Subsonic API clients
to understand which music folders (libraries) a user can access for proper
content filtering and UI presentation.

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan
2025-07-29 17:59:58 -04:00
parent 949bff993e
commit 94d2696c84
2 changed files with 25 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import (
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/model/request"
"github.com/navidrome/navidrome/server/subsonic/responses"
"github.com/navidrome/navidrome/utils/slice"
)
// buildUserResponse creates a User response object from a User model
@@ -19,6 +20,7 @@ func buildUserResponse(user model.User) responses.User {
ScrobblingEnabled: true,
DownloadRole: conf.Server.EnableDownloads,
ShareRole: conf.Server.EnableSharing,
Folder: slice.Map(user.Libraries, func(lib model.Library) int32 { return int32(lib.ID) }),
}
if conf.Server.Jukebox.Enabled {
@@ -28,7 +30,6 @@ func buildUserResponse(user model.User) responses.User {
return userResponse
}
// TODO This is a placeholder. The real one has to read this info from a config file or the database
func (api *Router) GetUser(r *http.Request) (*responses.Subsonic, error) {
loggedUser, ok := request.UserFrom(r.Context())
if !ok {

View File

@@ -36,6 +36,12 @@ var _ = Describe("Users", func() {
conf.Server.EnableSharing = true
conf.Server.Jukebox.Enabled = false
// Set up user with libraries
testUser.Libraries = model.Libraries{
{ID: 10, Name: "Music"},
{ID: 20, Name: "Podcasts"},
}
// Create request with user in context
req := httptest.NewRequest("GET", "/rest/getUser", nil)
ctx := request.WithUser(context.Background(), testUser)
@@ -57,6 +63,7 @@ var _ = Describe("Users", func() {
Expect(userResponse.User.ScrobblingEnabled).To(BeTrue())
Expect(userResponse.User.DownloadRole).To(BeTrue())
Expect(userResponse.User.ShareRole).To(BeTrue())
Expect(userResponse.User.Folder).To(ContainElements(int32(10), int32(20)))
// Verify GetUsers response structure
Expect(usersResponse.Status).To(Equal(responses.StatusOK))
@@ -75,6 +82,7 @@ var _ = Describe("Users", func() {
Expect(singleUser.DownloadRole).To(Equal(userFromList.DownloadRole))
Expect(singleUser.ShareRole).To(Equal(userFromList.ShareRole))
Expect(singleUser.JukeboxRole).To(Equal(userFromList.JukeboxRole))
Expect(singleUser.Folder).To(Equal(userFromList.Folder))
})
})
@@ -93,4 +101,19 @@ var _ = Describe("Users", func() {
Entry("jukebox enabled, admin-only, regular user", true, true, false, false),
Entry("jukebox enabled, admin-only, admin user", true, true, true, true),
)
Describe("Folder list population", func() {
It("should populate Folder field with user's accessible library IDs", func() {
testUser.Libraries = model.Libraries{
{ID: 1, Name: "Music"},
{ID: 2, Name: "Podcasts"},
{ID: 5, Name: "Audiobooks"},
}
response := buildUserResponse(testUser)
Expect(response.Folder).To(HaveLen(3))
Expect(response.Folder).To(ContainElements(int32(1), int32(2), int32(5)))
})
})
})