diff --git a/api/dbv1/get_playlist_ids_by_permalink.sql.go b/api/dbv1/get_playlist_ids_by_permalink.sql.go new file mode 100644 index 00000000..8d251d07 --- /dev/null +++ b/api/dbv1/get_playlist_ids_by_permalink.sql.go @@ -0,0 +1,62 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: get_playlist_ids_by_permalink.sql + +package dbv1 + +import ( + "context" +) + +const getPlaylistIdsByPermalink = `-- name: GetPlaylistIdsByPermalink :many +WITH lower_handles AS ( + SELECT LOWER(h) AS handle + FROM unnest($2::text[]) AS h +), +lower_permalinks AS ( + SELECT LOWER(p) AS permalink + FROM unnest($3::text[]) AS p +) +SELECT pr.playlist_id +FROM playlist_routes pr +JOIN users u ON u.user_id = pr.owner_id +JOIN lower_handles lh + ON u.handle_lc = lh.handle +WHERE pr.slug = ANY($1::text[]) + -- in case of conflicts across users + AND ( + CONCAT('/', u.handle_lc, '/playlist/', LOWER(pr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ) + OR CONCAT('/', u.handle_lc, '/album/', LOWER(pr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ) + ) +` + +type GetPlaylistIdsByPermalinkParams struct { + Slugs []string `json:"slugs"` + Handles []string `json:"handles"` + Permalinks []string `json:"permalinks"` +} + +func (q *Queries) GetPlaylistIdsByPermalink(ctx context.Context, arg GetPlaylistIdsByPermalinkParams) ([]int32, error) { + rows, err := q.db.Query(ctx, getPlaylistIdsByPermalink, arg.Slugs, arg.Handles, arg.Permalinks) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int32 + for rows.Next() { + var playlist_id int32 + if err := rows.Scan(&playlist_id); err != nil { + return nil, err + } + items = append(items, playlist_id) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/api/dbv1/get_track_ids_by_permalink.sql.go b/api/dbv1/get_track_ids_by_permalink.sql.go index 4bc37253..63ffc33e 100644 --- a/api/dbv1/get_track_ids_by_permalink.sql.go +++ b/api/dbv1/get_track_ids_by_permalink.sql.go @@ -10,22 +10,34 @@ import ( ) const getTrackIdsByPermalink = `-- name: GetTrackIdsByPermalink :many -SELECT track_id -FROM track_routes -JOIN users ON users.user_id = track_routes.owner_id -WHERE handle_lc = ANY($1::text[]) - AND slug = ANY($2::text[]) - AND CONCAT(handle_lc, '/', slug) = ANY($3::text[]) -- in case of conflicts across users +WITH lower_handles AS ( + SELECT LOWER(h) AS handle + FROM unnest($2::text[]) AS h +), +lower_permalinks AS ( + SELECT LOWER(p) AS permalink + FROM unnest($3::text[]) AS p +) +SELECT tr.track_id +FROM track_routes tr +JOIN users u ON u.user_id = tr.owner_id +JOIN lower_handles lh + ON u.handle_lc = lh.handle +WHERE tr.slug = ANY($1::text[]) + -- in case of conflicts across usAers + AND CONCAT('/', u.handle_lc, '/', LOWER(tr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ) ` type GetTrackIdsByPermalinkParams struct { - Handles []string `json:"handles"` Slugs []string `json:"slugs"` + Handles []string `json:"handles"` Permalinks []string `json:"permalinks"` } func (q *Queries) GetTrackIdsByPermalink(ctx context.Context, arg GetTrackIdsByPermalinkParams) ([]int32, error) { - rows, err := q.db.Query(ctx, getTrackIdsByPermalink, arg.Handles, arg.Slugs, arg.Permalinks) + rows, err := q.db.Query(ctx, getTrackIdsByPermalink, arg.Slugs, arg.Handles, arg.Permalinks) if err != nil { return nil, err } diff --git a/api/dbv1/get_user_for_handle.sql.go b/api/dbv1/get_user_for_handle.sql.go new file mode 100644 index 00000000..34ce3368 --- /dev/null +++ b/api/dbv1/get_user_for_handle.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: get_user_for_handle.sql + +package dbv1 + +import ( + "context" + + "bridgerton.audius.co/trashid" +) + +const getUserForHandle = `-- name: GetUserForHandle :one +SELECT user_id FROM users +WHERE + handle_lc = lower($1) +ORDER BY created_at ASC +LIMIT 1 +` + +func (q *Queries) GetUserForHandle(ctx context.Context, handle string) (trashid.HashId, error) { + row := q.db.QueryRow(ctx, getUserForHandle, handle) + var user_id trashid.HashId + err := row.Scan(&user_id) + return user_id, err +} diff --git a/api/dbv1/queries/get_playlist_ids_by_permalink.sql b/api/dbv1/queries/get_playlist_ids_by_permalink.sql new file mode 100644 index 00000000..97ec026e --- /dev/null +++ b/api/dbv1/queries/get_playlist_ids_by_permalink.sql @@ -0,0 +1,24 @@ +-- name: GetPlaylistIdsByPermalink :many +WITH lower_handles AS ( + SELECT LOWER(h) AS handle + FROM unnest(@handles::text[]) AS h +), +lower_permalinks AS ( + SELECT LOWER(p) AS permalink + FROM unnest(@permalinks::text[]) AS p +) +SELECT pr.playlist_id +FROM playlist_routes pr +JOIN users u ON u.user_id = pr.owner_id +JOIN lower_handles lh + ON u.handle_lc = lh.handle +WHERE pr.slug = ANY(@slugs::text[]) + -- in case of conflicts across users + AND ( + CONCAT('/', u.handle_lc, '/playlist/', LOWER(pr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ) + OR CONCAT('/', u.handle_lc, '/album/', LOWER(pr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ) + ); diff --git a/api/dbv1/queries/get_track_ids_by_permalink.sql b/api/dbv1/queries/get_track_ids_by_permalink.sql index 91afb0ed..05f9d8eb 100644 --- a/api/dbv1/queries/get_track_ids_by_permalink.sql +++ b/api/dbv1/queries/get_track_ids_by_permalink.sql @@ -1,8 +1,19 @@ -- name: GetTrackIdsByPermalink :many -SELECT track_id -FROM track_routes -JOIN users ON users.user_id = track_routes.owner_id -WHERE handle_lc = ANY(@handles::text[]) - AND slug = ANY(@slugs::text[]) - AND CONCAT(handle_lc, '/', slug) = ANY(@permalinks::text[]) -- in case of conflicts across users -; \ No newline at end of file +WITH lower_handles AS ( + SELECT LOWER(h) AS handle + FROM unnest(@handles::text[]) AS h +), +lower_permalinks AS ( + SELECT LOWER(p) AS permalink + FROM unnest(@permalinks::text[]) AS p +) +SELECT tr.track_id +FROM track_routes tr +JOIN users u ON u.user_id = tr.owner_id +JOIN lower_handles lh + ON u.handle_lc = lh.handle +WHERE tr.slug = ANY(@slugs::text[]) + -- in case of conflicts across usAers + AND CONCAT('/', u.handle_lc, '/', LOWER(tr.slug)) = ANY( + SELECT permalink FROM lower_permalinks + ); diff --git a/api/dbv1/queries/get_user_for_handle.sql b/api/dbv1/queries/get_user_for_handle.sql new file mode 100644 index 00000000..64f4d39e --- /dev/null +++ b/api/dbv1/queries/get_user_for_handle.sql @@ -0,0 +1,6 @@ +-- name: GetUserForHandle :one +SELECT user_id FROM users +WHERE + handle_lc = lower(@handle) +ORDER BY created_at ASC +LIMIT 1; diff --git a/api/fixture_test.go b/api/fixture_test.go index f743a607..919e6280 100644 --- a/api/fixture_test.go +++ b/api/fixture_test.go @@ -162,6 +162,30 @@ var ( "txhash": "tx123", } + trackRouteBaseRow = map[string]any{ + "slug": nil, + "title_slug": nil, + "collision_id": nil, + "owner_id": nil, + "track_id": nil, + "is_current": true, + "blockhash": "block_abc123", + "blocknumber": 101, + "txhash": "tx123", + } + + playlistRouteBaseRow = map[string]any{ + "slug": nil, + "title_slug": nil, + "collision_id": nil, + "owner_id": nil, + "playlist_id": nil, + "is_current": true, + "blockhash": "block_abc123", + "blocknumber": 101, + "txhash": "tx123", + } + commentBaseRow = map[string]any{ "entity_type": "Track", "created_at": time.Now(), diff --git a/api/resolve_middleware.go b/api/resolve_middleware.go index fa1b1e7e..916e0fb9 100644 --- a/api/resolve_middleware.go +++ b/api/resolve_middleware.go @@ -14,6 +14,10 @@ func (app *ApiServer) isFullMiddleware(c *fiber.Ctx) error { return c.Next() } +func (app *ApiServer) getIsFull(c *fiber.Ctx) bool { + return c.Locals("isFull").(bool) +} + // will set myId if valid, defaults to 0 func (app *ApiServer) resolveMyIdMiddleware(c *fiber.Ctx) error { myId, _ := trashid.DecodeHashId(c.Query("user_id")) diff --git a/api/server.go b/api/server.go index 07e9c8db..446eb47c 100644 --- a/api/server.go +++ b/api/server.go @@ -250,6 +250,9 @@ func NewApiServer(config config.Config) *ApiServer { // Rewards g.Get("/rewards/claim", app.v1ClaimRewards) + // Resolve + g.Get("/resolve", app.v1Resolve) + // Comments g.Get("/comments/unclaimed_id", app.v1CommentsUnclaimedId) } @@ -316,11 +319,12 @@ func (app *ApiServer) resolveUserHandleToId(handle string) (int32, error) { if hit, ok := app.resolveHandleCache.Get(handle); ok { return hit, nil } - var userId int32 - sql := `select user_id from users where handle_lc = lower($1)` - err := app.pool.QueryRow(context.Background(), sql, handle).Scan(&userId) - app.resolveHandleCache.Set(handle, userId) - return userId, err + user_id, err := app.queries.GetUserForHandle(context.Background(), handle) + if err != nil { + return 0, err + } + app.resolveHandleCache.Set(handle, int32(user_id)) + return int32(user_id), nil } func (as *ApiServer) Serve() { diff --git a/api/server_test.go b/api/server_test.go index c9667c49..b2eaed1d 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -78,7 +78,8 @@ func TestMain(m *testing.M) { insertFixtures("associated_wallets", connectedWalletsBaseRow, "testdata/connected_wallets_fixtures.csv") insertFixtures("aggregate_user_tips", aggregateUserTipsBaseRow, "testdata/aggregate_user_tips_fixtures.csv") insertFixtures("usdc_purchases", usdcPurchaseBaseRow, "testdata/usdc_purchases_fixtures.csv") - insertFixtures("track_routes", map[string]any{}, "testdata/track_routes_fixtures.csv") + insertFixtures("track_routes", trackRouteBaseRow, "testdata/track_routes_fixtures.csv") + insertFixtures("playlist_routes", playlistRouteBaseRow, "testdata/playlist_routes_fixtures.csv") insertFixtures("grants", grantBaseRow, "testdata/grants_fixtures.csv") insertFixtures("comments", commentBaseRow, "testdata/comment_fixtures.csv") insertFixtures("comment_threads", map[string]any{}, "testdata/comment_thread_fixtures.csv") diff --git a/api/testdata/playlist_fixtures.csv b/api/testdata/playlist_fixtures.csv index 08cee516..2aab6f9f 100644 --- a/api/testdata/playlist_fixtures.csv +++ b/api/testdata/playlist_fixtures.csv @@ -3,3 +3,5 @@ playlist_id,playlist_name,playlist_owner_id,is_album,playlist_contents,stream_co 2,Follow Gated Stream,3,t,"{}","{""follow_user_id"": 3}" 3,SecondAlbum,1,t,"{""track_ids"": [{""time"": 1722451644, ""track"": 200, ""metadata_time"": 1722451644},{""time"": 1722451644, ""track"": -1, ""metadata_time"": 1722451644},{""time"": 1722451644, ""track"": 300, ""metadata_time"": 1722451644}]}", 4,Purchase Gated Stream,3,t,"{}","{""usdc_purchase"": {""price"": 135, ""splits"": [{""user_id"": 3, ""percentage"": 100.0}]}}" +500,playlist by permalink,7,f,, +501,album by permalink,8,t,, \ No newline at end of file diff --git a/api/testdata/playlist_routes_fixtures.csv b/api/testdata/playlist_routes_fixtures.csv new file mode 100644 index 00000000..facf6bde --- /dev/null +++ b/api/testdata/playlist_routes_fixtures.csv @@ -0,0 +1,3 @@ +slug,title_slug,collision_id,owner_id,playlist_id +playlist-by-permalink,playlist-by-permalink,0,7,500 +album-by-permalink,album-by-permalink,0,8,501 \ No newline at end of file diff --git a/api/testdata/track_routes_fixtures.csv b/api/testdata/track_routes_fixtures.csv index 0c50a94c..4a01b2df 100644 --- a/api/testdata/track_routes_fixtures.csv +++ b/api/testdata/track_routes_fixtures.csv @@ -1,2 +1,2 @@ -"slug","title_slug","collision_id","owner_id","track_id","is_current","blockhash","blocknumber","txhash" -"track-by-permalink","track-by-permalink",0,6,500,TRUE,"0x24f1465e4bd8803b79b2cbcfad695363a640623053563ffd20fdeaf4656a7b89",23200013,"0x76dcea2bf98e56f683b95a071f5c87405a864eea87243920e60cbc7b96ad565b" +slug,title_slug,collision_id,owner_id,track_id +track-by-permalink,track-by-permalink,0,6,500 diff --git a/api/testdata/user_fixtures.csv b/api/testdata/user_fixtures.csv index 44130ce3..e9e0c32a 100644 --- a/api/testdata/user_fixtures.csv +++ b/api/testdata/user_fixtures.csv @@ -5,6 +5,8 @@ user_id,handle,handle_lc,is_deactivated,wallet,playlist_library 4,accesstester,accesstester,f,0x34567890abcdef12, 5,guyintrending,guyintrending,f,0x34567890abcdef13, 6,TracksByPermalink,tracksbypermalink,f,0xffffffffff, +7,PlaylistsByPermalink,playlistsbypermalink,f,0xffffffffff, +8,AlbumsByPermalink,albumsbypermalink,f,0xffffffffff, 91,badguy,badguy,t,0x4567890abcdef123, 100,authtest1,authtest1,f,0x681c616ae836ceca1effe00bd07f2fdbf9a082bc, 101,authtest2,authtest2,f,0xc451c1f8943b575158310552b41230c61844a1c1, diff --git a/api/v1_playlists.go b/api/v1_playlists.go index b5b2eda4..836a270e 100644 --- a/api/v1_playlists.go +++ b/api/v1_playlists.go @@ -9,6 +9,31 @@ func (app *ApiServer) v1playlists(c *fiber.Ctx) error { myId := app.getMyId(c) ids := decodeIdList(c) + // Add permalink ID mappings + permalinks := queryMutli(c, "permalink") + if len(permalinks) > 0 { + handles := make([]string, len(permalinks)) + slugs := make([]string, len(permalinks)) + for i, permalink := range permalinks { + if match := playlistURLRegex.FindStringSubmatch(permalink); match != nil { + handles[i] = match[1] + slugs[i] = match[3] + permalinks[i] = permalink + } else { + return fiber.NewError(fiber.StatusBadRequest, "Invalid permalink: "+permalinks[i]) + } + } + newIds, err := app.queries.GetPlaylistIdsByPermalink(c.Context(), dbv1.GetPlaylistIdsByPermalinkParams{ + Handles: handles, + Slugs: slugs, + Permalinks: permalinks, + }) + if err != nil { + return err + } + ids = append(ids, newIds...) + } + playlists, err := app.queries.FullPlaylists(c.Context(), dbv1.GetPlaylistsParams{ MyID: myId, Ids: ids, diff --git a/api/v1_playlists_test.go b/api/v1_playlists_test.go index 9568dc65..bb8dc2e2 100644 --- a/api/v1_playlists_test.go +++ b/api/v1_playlists_test.go @@ -4,7 +4,6 @@ import ( "testing" "bridgerton.audius.co/api/dbv1" - "bridgerton.audius.co/trashid" "github.com/stretchr/testify/assert" ) @@ -13,11 +12,39 @@ func TestPlaylistsEndpoint(t *testing.T) { Data []dbv1.FullPlaylist } - status, _ := testGet(t, "/v1/full/playlists?id=7eP5n", &resp) + status, body := testGet(t, "/v1/full/playlists?id=7eP5n", &resp) assert.Equal(t, 200, status) - pl := resp.Data[0] - assert.Equal(t, pl.ID, "7eP5n") - assert.Len(t, pl.Tracks, 2) - assert.Equal(t, trashid.HashId(2), pl.Tracks[0].User.ID) + jsonAssert(t, body, map[string]string{ + "data.0.id": "7eP5n", + "data.0.playlist_name": "First", + }) +} + +func TestPlaylistsEndpointWithPlaylistPermalink(t *testing.T) { + var resp struct { + Data []dbv1.FullPlaylist + } + + status, body := testGet(t, "/v1/full/playlists?permalink=/PlaylistsByPermalink/playlist/playlist-by-permalink", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.0.id": "eYake", + "data.0.playlist_name": "playlist by permalink", + }) +} + +func TestPlaylistsEndpointWithAlbumPermalink(t *testing.T) { + var resp struct { + Data []dbv1.FullPlaylist + } + + status, body := testGet(t, "/v1/full/playlists?permalink=/AlbumsByPermalink/album/album-by-permalink", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.0.id": "ePVXL", + "data.0.playlist_name": "album by permalink", + }) } diff --git a/api/v1_resolve.go b/api/v1_resolve.go new file mode 100644 index 00000000..714a5ae5 --- /dev/null +++ b/api/v1_resolve.go @@ -0,0 +1,106 @@ +package api + +import ( + "net/url" + "regexp" + "strings" + + "bridgerton.audius.co/api/dbv1" + "bridgerton.audius.co/trashid" + "github.com/gofiber/fiber/v2" +) + +var ( + trackURLRegex = regexp.MustCompile(`^/(?P[^/]*)/(?P[^/]*)$`) + playlistURLRegex = regexp.MustCompile(`/(?P[^/]*)/(?Pplaylist|album)/(?P[^/]*)$`) + userURLRegex = regexp.MustCompile(`^/(?P[^/]*)$`) +) + +func (app *ApiServer) v1Resolve(c *fiber.Ctx) error { + isFull := app.getIsFull(c) + urlStr := c.Query("url") + if urlStr == "" { + return fiber.NewError(fiber.StatusBadRequest, "Missing url parameter") + } + + parsedURL, err := url.Parse(urlStr) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid URL") + } + + // Strip out any preceding protocol & domain + path := parsedURL.Path + + // Try to match track URL + if match := trackURLRegex.FindStringSubmatch(path); match != nil { + handle := strings.ToLower(match[1]) + slug := match[2] + + trackIds, err := app.queries.GetTrackIdsByPermalink(c.Context(), dbv1.GetTrackIdsByPermalinkParams{ + Handles: []string{handle}, + Slugs: []string{slug}, + Permalinks: []string{path}, + }) + if err != nil || len(trackIds) == 0 { + return fiber.NewError(fiber.StatusNotFound, "Track not found") + } + + trackId, err := trashid.EncodeHashId(int(trackIds[0])) + if err != nil { + return err + } + + if isFull { + return c.Redirect("/v1/full/tracks/"+trackId, fiber.StatusFound) + } + return c.Redirect("/v1/tracks/"+trackId, fiber.StatusFound) + } + + // Try to match playlist URL + if match := playlistURLRegex.FindStringSubmatch(path); match != nil { + handle := strings.ToLower(match[1]) + slug := match[3] + + playlistIds, err := app.queries.GetPlaylistIdsByPermalink(c.Context(), dbv1.GetPlaylistIdsByPermalinkParams{ + Handles: []string{handle}, + Slugs: []string{slug}, + Permalinks: []string{path}, + }) + if err != nil || len(playlistIds) == 0 { + return fiber.NewError(fiber.StatusNotFound, "Playlist not found") + } + + playlistId, err := trashid.EncodeHashId(int(playlistIds[0])) + if err != nil { + return err + } + + if isFull { + return c.Redirect("/v1/full/playlists/"+playlistId, fiber.StatusFound) + } + return c.Redirect("/v1/playlists/"+playlistId, fiber.StatusFound) + } + + // Try to match user URL + if match := userURLRegex.FindStringSubmatch(path); match != nil { + handle := strings.ToLower(match[1]) + + rawUserId, err := app.queries.GetUserForHandle(c.Context(), handle) + + if err != nil { + return fiber.NewError(fiber.StatusNotFound, "User not found") + } + + userId, err := trashid.EncodeHashId(int(rawUserId)) + if err != nil { + return err + } + + if isFull { + return c.Redirect("/v1/full/users/"+userId, fiber.StatusFound) + } + return c.Redirect("/v1/users/"+userId, fiber.StatusFound) + } + + return fiber.NewError(fiber.StatusNotFound, "URL not found") +} diff --git a/api/v1_resolve_test.go b/api/v1_resolve_test.go new file mode 100644 index 00000000..14c116c8 --- /dev/null +++ b/api/v1_resolve_test.go @@ -0,0 +1,45 @@ +package api + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResolveTrackURL(t *testing.T) { + // Test successful track resolution + status, _ := testGet(t, "/v1/resolve?url=https://audius.co/TracksByPermalink/track-by-permalink") + assert.Equal(t, 302, status) + + // Test failed track resolution + status, _ = testGet(t, "/v1/resolve?url=https://audius.co/nonexistent/track") + assert.Equal(t, 404, status) + status, _ = testGet(t, "/v1/resolve?url=invalid-url") + assert.Equal(t, 404, status) + status, _ = testGet(t, "/v1/resolve") + assert.Equal(t, 400, status) +} + +func TestResolvePlaylistURL(t *testing.T) { + // Test successful playlist resolution + status, _ := testGet(t, "/v1/resolve?url=https://audius.co/PlaylistsByPermalink/playlist/playlist-by-permalink") + assert.Equal(t, 302, status) + + // Test successful album resolution + status, _ = testGet(t, "/v1/resolve?url=https://audius.co/AlbumsByPermalink/album/album-by-permalink") + assert.Equal(t, 302, status) + + // Test failed playlist resolution + status, _ = testGet(t, "/v1/resolve?url=https://audius.co/nonexistent/playlist/playlist") + assert.Equal(t, 404, status) +} + +func TestResolveUserURL(t *testing.T) { + // Test successful user resolution + status, _ := testGet(t, "/v1/resolve?url=https://audius.co/rayjacobson") + assert.Equal(t, 302, status) + + // Test failed user resolution + status, _ = testGet(t, "/v1/resolve?url=https://audius.co/nonexistentuser") + assert.Equal(t, 404, status) +} diff --git a/api/v1_tracks.go b/api/v1_tracks.go index af2de91a..092fe812 100644 --- a/api/v1_tracks.go +++ b/api/v1_tracks.go @@ -1,8 +1,6 @@ package api import ( - "strings" - "bridgerton.audius.co/api/dbv1" "bridgerton.audius.co/trashid" "github.com/gofiber/fiber/v2" @@ -18,13 +16,13 @@ func (app *ApiServer) v1Tracks(c *fiber.Ctx) error { handles := make([]string, len(permalinks)) slugs := make([]string, len(permalinks)) for i, permalink := range permalinks { - permalinks[i] = strings.ToLower(strings.TrimPrefix(permalink, "/")) - splits := strings.Split(permalinks[i], "/") - if len(splits) != 2 { + if match := trackURLRegex.FindStringSubmatch(permalink); match != nil { + handles[i] = match[1] + slugs[i] = match[2] + permalinks[i] = permalink + } else { return fiber.NewError(fiber.StatusBadRequest, "Invalid permalink: "+permalink) } - handles[i] = splits[0] - slugs[i] = splits[1] } newIds, err := app.queries.GetTrackIdsByPermalink(c.Context(), dbv1.GetTrackIdsByPermalinkParams{ Handles: handles, diff --git a/api/v1_tracks_test.go b/api/v1_tracks_test.go index d83328c0..3992bd16 100644 --- a/api/v1_tracks_test.go +++ b/api/v1_tracks_test.go @@ -7,6 +7,20 @@ import ( "github.com/stretchr/testify/assert" ) +func TestTracksEndpoint(t *testing.T) { + var resp struct { + Data []dbv1.FullTrack + } + + status, body := testGet(t, "/v1/full/tracks?id=eYZmn", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.0.id": "eYZmn", + "data.0.title": "T1", + }) +} + func TestGetTracksByPermalink(t *testing.T) { var tracksResponse struct { Data []dbv1.FullTrack diff --git a/api/v1_user.go b/api/v1_user.go index c4c0de11..ba59cf4a 100644 --- a/api/v1_user.go +++ b/api/v1_user.go @@ -25,7 +25,7 @@ func (app *ApiServer) v1User(c *fiber.Ctx) error { // full returns an array // non-full returns an object // wild - if c.Locals("isFull").(bool) { + if app.getIsFull(c) { return v1UsersResponse(c, users) } return v1UserResponse(c, users[0]) diff --git a/api/v1_users_handle_test.go b/api/v1_users_handle_test.go new file mode 100644 index 00000000..d874420f --- /dev/null +++ b/api/v1_users_handle_test.go @@ -0,0 +1,21 @@ +package api + +import ( + "testing" + + "bridgerton.audius.co/api/dbv1" + "github.com/stretchr/testify/assert" +) + +func TestGetUsersHandle(t *testing.T) { + var accountResponse struct { + Data dbv1.FullAccount + } + status, body := testGet(t, "/v1/users/handle/rayjacobson", &accountResponse) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.id": "7eP5n", + "data.handle": "rayjacobson", + }) +} diff --git a/api/v1_users_supporters.go b/api/v1_users_supporters.go index 447cb0a2..fe9fa879 100644 --- a/api/v1_users_supporters.go +++ b/api/v1_users_supporters.go @@ -77,7 +77,7 @@ func (app *ApiServer) v1UsersSupporters(c *fiber.Ctx) error { supported[idx] = s } - if !c.Locals("isFull").(bool) { + if !app.getIsFull(c) { // Create a new array with MinUsers type minSupportedUser struct { supportedUser diff --git a/api/v1_users_supporting.go b/api/v1_users_supporting.go index faee5f77..ca496738 100644 --- a/api/v1_users_supporting.go +++ b/api/v1_users_supporting.go @@ -83,7 +83,7 @@ func (app *ApiServer) v1UsersSupporting(c *fiber.Ctx) error { supported[idx] = s } - if !c.Locals("isFull").(bool) { + if !app.getIsFull(c) { // Create a new array with MinUsers type minSupportedUser struct { supportedUser