Skip to content

Commit 40c4677

Browse files
committed
Fix unlisted premium library tracks
1 parent dad1cc4 commit 40c4677

File tree

2 files changed

+203
-2
lines changed

2 files changed

+203
-2
lines changed

api/v1_users_library_tracks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (app *ApiServer) v1UsersLibraryTracks(c *fiber.Ctx) error {
5555
}
5656

5757
trackFilters := []string{
58-
"(is_unlisted = false OR is_purchase = true)",
58+
"is_unlisted = false",
5959
}
6060

6161
if params.Query != "" {
@@ -104,7 +104,7 @@ func (app *ApiServer) v1UsersLibraryTracks(c *fiber.Ctx) error {
104104
bool_or(is_purchase) as is_purchase
105105
FROM library_items
106106
JOIN tracks ON track_id = item_id
107-
WHERE is_unlisted = false OR is_purchase = true
107+
WHERE is_unlisted = false
108108
GROUP BY item_id
109109
)
110110
SELECT
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package api
2+
3+
import (
4+
"testing"
5+
6+
"api.audius.co/database"
7+
"api.audius.co/trashid"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestUsersLibraryTracks(t *testing.T) {
12+
app := testAppWithFixtures(t)
13+
var response struct {
14+
Data []struct {
15+
Class string `json:"class"`
16+
ItemType string `json:"item_type"`
17+
ItemID int32 `json:"item_id"`
18+
Timestamp string `json:"timestamp"`
19+
Item struct {
20+
ID string `json:"id"`
21+
Title string `json:"title"`
22+
} `json:"item"`
23+
} `json:"data"`
24+
}
25+
26+
// User 1 has saved track 100 (T1) and reposted track 200 (Culca Canyon)
27+
user1Id := trashid.MustEncodeHashID(1)
28+
29+
// Test all library tracks
30+
status, body := testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=all", &response)
31+
assert.Equal(t, 200, status)
32+
assert.GreaterOrEqual(t, len(response.Data), 2, "Should have at least saved and reposted tracks")
33+
34+
jsonAssert(t, body, map[string]any{
35+
"data.0.class": "track_activity_full",
36+
"data.0.item_type": "track",
37+
})
38+
39+
// Test favorite tracks only
40+
status, body = testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=favorite", &response)
41+
assert.Equal(t, 200, status)
42+
assert.GreaterOrEqual(t, len(response.Data), 1, "Should have at least one favorite track")
43+
44+
jsonAssert(t, body, map[string]any{
45+
"data.0.class": "track_activity_full",
46+
"data.0.item_type": "track",
47+
"data.0.item_id": 100, // Track 100 (T1) is saved
48+
})
49+
50+
// Test repost tracks only
51+
status, body = testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=repost", &response)
52+
assert.Equal(t, 200, status)
53+
assert.GreaterOrEqual(t, len(response.Data), 1, "Should have at least one reposted track")
54+
55+
jsonAssert(t, body, map[string]any{
56+
"data.0.class": "track_activity_full",
57+
"data.0.item_type": "track",
58+
"data.0.item_id": 200, // Track 200 (Culca Canyon) is reposted
59+
})
60+
61+
// Test purchase tracks only (user 11 has purchased track 303)
62+
user11Id := trashid.MustEncodeHashID(11)
63+
status, body = testGet(t, app, "/v1/full/users/"+user11Id+"/library/tracks?type=purchase", &response)
64+
assert.Equal(t, 200, status)
65+
assert.GreaterOrEqual(t, len(response.Data), 1, "Should have at least one purchased track")
66+
67+
jsonAssert(t, body, map[string]any{
68+
"data.0.class": "track_activity_full",
69+
"data.0.item_type": "track",
70+
"data.0.item_id": 303, // Track 303 (Pay Gated Stream) is purchased
71+
})
72+
}
73+
74+
func TestUsersLibraryTracksUnlistedFiltered(t *testing.T) {
75+
app := emptyTestApp(t)
76+
77+
fixtures := database.FixtureMap{
78+
"users": []map[string]any{
79+
{
80+
"user_id": 1,
81+
"handle": "user1",
82+
},
83+
},
84+
"tracks": []map[string]any{
85+
{
86+
"track_id": 100,
87+
"title": "Public Track",
88+
"owner_id": 1,
89+
"is_unlisted": false,
90+
},
91+
{
92+
"track_id": 201,
93+
"title": "Unlisted Track",
94+
"owner_id": 1,
95+
"is_unlisted": true,
96+
},
97+
},
98+
"saves": []map[string]any{
99+
{
100+
"user_id": 1,
101+
"save_item_id": 100,
102+
"save_type": "track",
103+
},
104+
{
105+
"user_id": 1,
106+
"save_item_id": 201, // Save an unlisted track
107+
"save_type": "track",
108+
},
109+
},
110+
"usdc_purchases": []map[string]any{
111+
{
112+
"signature": "test1",
113+
"buyer_user_id": 1,
114+
"seller_user_id": 1,
115+
"content_id": 201, // Purchase an unlisted track
116+
"content_type": "track",
117+
"amount": 100,
118+
},
119+
},
120+
}
121+
122+
database.Seed(app.pool.Replicas[0], fixtures)
123+
user1Id := trashid.MustEncodeHashID(1)
124+
125+
var response struct {
126+
Data []struct {
127+
ItemID int32 `json:"item_id"`
128+
} `json:"data"`
129+
}
130+
131+
// Test that unlisted tracks are filtered out from favorites
132+
status, _ := testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=favorite", &response)
133+
assert.Equal(t, 200, status)
134+
assert.Equal(t, 1, len(response.Data), "Should only have public track")
135+
assert.Equal(t, int32(100), response.Data[0].ItemID, "Should only return public track")
136+
137+
// Test that unlisted purchased tracks are filtered out
138+
status, _ = testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=purchase", &response)
139+
assert.Equal(t, 200, status)
140+
assert.Equal(t, 0, len(response.Data), "Should not return unlisted purchased tracks")
141+
142+
// Test that unlisted tracks are filtered out from all
143+
status, _ = testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=all", &response)
144+
assert.Equal(t, 200, status)
145+
assert.Equal(t, 1, len(response.Data), "Should only have public track")
146+
assert.Equal(t, int32(100), response.Data[0].ItemID, "Should only return public track")
147+
}
148+
149+
func TestUsersLibraryTracksSorting(t *testing.T) {
150+
app := testAppWithFixtures(t)
151+
user1Id := trashid.MustEncodeHashID(1)
152+
153+
var response struct {
154+
Data []struct {
155+
ItemID int32 `json:"item_id"`
156+
Item struct {
157+
Title string `json:"title"`
158+
} `json:"item"`
159+
} `json:"data"`
160+
}
161+
162+
// Test sorting by title
163+
status, _ := testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=all&sort_method=title&sort_direction=asc", &response)
164+
assert.Equal(t, 200, status)
165+
assert.GreaterOrEqual(t, len(response.Data), 2, "Should have multiple tracks")
166+
167+
// Verify tracks are sorted by title ascending
168+
if len(response.Data) >= 2 {
169+
assert.LessOrEqual(t, response.Data[0].Item.Title, response.Data[1].Item.Title,
170+
"Tracks should be sorted by title ascending")
171+
}
172+
173+
// Test sorting by added_date (default)
174+
status, _ = testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=all&sort_method=added_date&sort_direction=desc", &response)
175+
assert.Equal(t, 200, status)
176+
assert.GreaterOrEqual(t, len(response.Data), 2, "Should have multiple tracks")
177+
}
178+
179+
func TestUsersLibraryTracksQuery(t *testing.T) {
180+
app := testAppWithFixtures(t)
181+
user1Id := trashid.MustEncodeHashID(1)
182+
183+
var response struct {
184+
Data []struct {
185+
ItemID int32 `json:"item_id"`
186+
Item struct {
187+
Title string `json:"title"`
188+
} `json:"item"`
189+
} `json:"data"`
190+
}
191+
192+
// Test query filtering by track title
193+
status, _ := testGet(t, app, "/v1/full/users/"+user1Id+"/library/tracks?type=all&query=T1", &response)
194+
assert.Equal(t, 200, status)
195+
assert.GreaterOrEqual(t, len(response.Data), 1, "Should find tracks matching query")
196+
197+
// Verify all results match the query
198+
for _, item := range response.Data {
199+
assert.Contains(t, item.Item.Title, "T1", "All results should match query")
200+
}
201+
}

0 commit comments

Comments
 (0)