Skip to content

Commit e8fca07

Browse files
committed
Add supporters endpoint. GetUsers returns deactivated users.
Python API will return deactivated users in the supporters endpoint... so we do the same... don't filter deactivated users in the get by id.
1 parent 9b34f59 commit e8fca07

9 files changed

Lines changed: 189 additions & 79 deletions

File tree

api/dbv1/full_playlists.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
type FullPlaylist struct {
1111
GetPlaylistsRow
1212

13-
ID string `json:"id"`
14-
Artwork SquareImage `json:"artwork"`
15-
UserID string `json:"user_id"`
16-
User FullUser `json:"user"`
17-
Tracks []FullTrack `json:"tracks"`
13+
ID string `json:"id"`
14+
Artwork *SquareImage `json:"artwork"`
15+
UserID string `json:"user_id"`
16+
User FullUser `json:"user"`
17+
Tracks []FullTrack `json:"tracks"`
1818

1919
FolloweeReposts []*FolloweeRepost `json:"followee_reposts"`
2020
FolloweeFavorites []*FolloweeFavorite `json:"followee_favorites"`
@@ -120,20 +120,20 @@ func (q *Queries) FullPlaylists(ctx context.Context, arg GetPlaylistsParams) ([]
120120
}
121121

122122
type MinPlaylist struct {
123-
ID string `json:"id"`
124-
PlaylistName pgtype.Text `json:"playlist_name"`
125-
PlaylistOwnerID int32 `json:"playlist_owner_id"`
126-
PlaylistID int32 `json:"playlist_id"`
127-
Artwork SquareImage `json:"artwork"`
128-
Description *string `json:"description"`
129-
PlaylistContents interface{} `json:"playlist_contents"`
130-
IsAlbum bool `json:"is_album"`
131-
IsPrivate bool `json:"is_private"`
132-
FavoriteCount int32 `json:"favorite_count"`
133-
RepostCount int32 `json:"repost_count"`
134-
UserID string `json:"user_id"`
135-
User MinUser `json:"user"`
136-
Tracks []MinTrack `json:"tracks"`
123+
ID string `json:"id"`
124+
PlaylistName pgtype.Text `json:"playlist_name"`
125+
PlaylistOwnerID int32 `json:"playlist_owner_id"`
126+
PlaylistID int32 `json:"playlist_id"`
127+
Artwork *SquareImage `json:"artwork"`
128+
Description *string `json:"description"`
129+
PlaylistContents interface{} `json:"playlist_contents"`
130+
IsAlbum bool `json:"is_album"`
131+
IsPrivate bool `json:"is_private"`
132+
FavoriteCount int32 `json:"favorite_count"`
133+
RepostCount int32 `json:"repost_count"`
134+
UserID string `json:"user_id"`
135+
User MinUser `json:"user"`
136+
Tracks []MinTrack `json:"tracks"`
137137
}
138138

139139
func ToMinPlaylist(fullPlaylist FullPlaylist) MinPlaylist {

api/dbv1/full_tracks.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ type FullTracksParams GetTracksParams
1313
type FullTrack struct {
1414
GetTracksRow
1515

16-
Artwork SquareImage `json:"artwork"`
17-
UserID string `json:"user_id"`
18-
User FullUser `json:"user"`
16+
Artwork *SquareImage `json:"artwork"`
17+
UserID string `json:"user_id"`
18+
User FullUser `json:"user"`
1919

2020
FolloweeReposts []*FolloweeRepost `json:"followee_reposts"`
2121
FolloweeFavorites []*FolloweeFavorite `json:"followee_favorites"`
@@ -88,7 +88,7 @@ type MinTrack struct {
8888
ID string `json:"id"`
8989
Title pgtype.Text `json:"title"`
9090
User MinUser `json:"user"`
91-
Artwork SquareImage `json:"artwork"`
91+
Artwork *SquareImage `json:"artwork"`
9292
Duration pgtype.Int4 `json:"duration"`
9393
Description pgtype.Text `json:"description"`
9494
Genre pgtype.Text `json:"genre"`

api/dbv1/full_users.go

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313
type FullUser struct {
1414
GetUsersRow
1515

16-
ArtistPickTrackID *string `json:"artist_pick_track_id"`
17-
ProfilePicture SquareImage `json:"profile_picture"`
18-
CoverPhoto RectangleImage `json:"cover_photo"`
16+
ArtistPickTrackID *string `json:"artist_pick_track_id"`
17+
ProfilePicture *SquareImage `json:"profile_picture"`
18+
CoverPhoto *RectangleImage `json:"cover_photo"`
1919
}
2020

2121
func (q *Queries) FullUsersKeyed(ctx context.Context, arg GetUsersParams) (map[int32]FullUser, error) {
@@ -35,7 +35,7 @@ func (q *Queries) FullUsersKeyed(ctx context.Context, arg GetUsersParams) (map[i
3535
user.ID, _ = trashid.EncodeHashId(int(user.UserID))
3636

3737
// profile picture + cover photo
38-
var coverPhoto RectangleImage
38+
var coverPhoto *RectangleImage
3939
{
4040
cid := ""
4141
if user.CoverPhotoSizes.Valid {
@@ -44,15 +44,17 @@ func (q *Queries) FullUsersKeyed(ctx context.Context, arg GetUsersParams) (map[i
4444
cid = user.CoverPhoto.String
4545
}
4646

47-
// rendezvous for cid
48-
rankedHosts := rendezvous.GlobalHasher.Rank(cid)
49-
first := rankedHosts[0]
50-
rest := rankedHosts[1:3]
51-
52-
coverPhoto = RectangleImage{
53-
X640: fmt.Sprintf("%s/content/%s/640x.jpg", first, cid),
54-
X2000: fmt.Sprintf("%s/content/%s/2000x.jpg", first, cid),
55-
Mirrors: rest,
47+
if cid != "" {
48+
// rendezvous for cid
49+
rankedHosts := rendezvous.GlobalHasher.Rank(cid)
50+
first := rankedHosts[0]
51+
rest := rankedHosts[1:3]
52+
53+
coverPhoto = &RectangleImage{
54+
X640: fmt.Sprintf("%s/content/%s/640x.jpg", first, cid),
55+
X2000: fmt.Sprintf("%s/content/%s/2000x.jpg", first, cid),
56+
Mirrors: rest,
57+
}
5658
}
5759
}
5860

@@ -94,7 +96,7 @@ func (q *Queries) FullUsers(ctx context.Context, arg GetUsersParams) ([]FullUser
9496
return fullUsers, nil
9597
}
9698

97-
func squareImageStruct(maybeCids ...pgtype.Text) SquareImage {
99+
func squareImageStruct(maybeCids ...pgtype.Text) *SquareImage {
98100
cid := ""
99101
for _, m := range maybeCids {
100102
if m.Valid && !strings.HasPrefix(m.String, "{") {
@@ -104,16 +106,15 @@ func squareImageStruct(maybeCids ...pgtype.Text) SquareImage {
104106
}
105107

106108
if cid == "" {
107-
// todo: what to do here?
108-
return SquareImage{}
109+
return nil
109110
}
110111

111112
// rendezvous for cid
112113
rankedHosts := rendezvous.GlobalHasher.Rank(cid)
113114
first := rankedHosts[0]
114115
rest := rankedHosts[1:3]
115116

116-
return SquareImage{
117+
return &SquareImage{
117118
X150x150: fmt.Sprintf("%s/content/%s/150x150.jpg", first, cid),
118119
X480x480: fmt.Sprintf("%s/content/%s/480x480.jpg", first, cid),
119120
X1000x1000: fmt.Sprintf("%s/content/%s/1000x1000.jpg", first, cid),
@@ -122,38 +123,38 @@ func squareImageStruct(maybeCids ...pgtype.Text) SquareImage {
122123
}
123124

124125
type MinUser struct {
125-
ID string `json:"id"`
126-
AlbumCount pgtype.Int8 `json:"album_count"`
127-
ArtistPickTrackID *string `json:"artist_pick_track_id"`
128-
Bio pgtype.Text `json:"bio"`
129-
CoverPhoto RectangleImage `json:"cover_photo"`
130-
FolloweeCount pgtype.Int8 `json:"followee_count"`
131-
FollowerCount pgtype.Int8 `json:"follower_count"`
132-
Handle pgtype.Text `json:"handle"`
133-
IsVerified bool `json:"is_verified"`
134-
TwitterHandle pgtype.Text `json:"twitter_handle"`
135-
InstagramHandle pgtype.Text `json:"instagram_handle"`
136-
TiktokHandle pgtype.Text `json:"tiktok_handle"`
137-
VerifiedWithTwitter pgtype.Bool `json:"verified_with_twitter"`
138-
VerifiedWithInstagram pgtype.Bool `json:"verified_with_instagram"`
139-
VerifiedWithTiktok pgtype.Bool `json:"verified_with_tiktok"`
140-
Website pgtype.Text `json:"website"`
141-
Donation pgtype.Text `json:"donation"`
142-
Location pgtype.Text `json:"location"`
143-
Name pgtype.Text `json:"name"`
144-
PlaylistCount pgtype.Int8 `json:"playlist_count"`
145-
ProfilePicture SquareImage `json:"profile_picture"`
146-
RepostCount pgtype.Int8 `json:"repost_count"`
147-
TrackCount pgtype.Int8 `json:"track_count"`
148-
IsDeactivated bool `json:"is_deactivated"`
149-
IsAvailable bool `json:"is_available"`
150-
ErcWallet pgtype.Text `json:"erc_wallet"`
151-
SplWallet pgtype.Text `json:"spl_wallet"`
152-
SplUsdcPayoutWallet pgtype.Text `json:"spl_usdc_payout_wallet"`
153-
SupporterCount int32 `json:"supporter_count"`
154-
SupportingCount int32 `json:"supporting_count"`
155-
TotalAudioBalance int32 `json:"total_audio_balance"`
156-
Wallet pgtype.Text `json:"wallet"`
126+
ID string `json:"id"`
127+
AlbumCount pgtype.Int8 `json:"album_count"`
128+
ArtistPickTrackID *string `json:"artist_pick_track_id"`
129+
Bio pgtype.Text `json:"bio"`
130+
CoverPhoto *RectangleImage `json:"cover_photo"`
131+
FolloweeCount pgtype.Int8 `json:"followee_count"`
132+
FollowerCount pgtype.Int8 `json:"follower_count"`
133+
Handle pgtype.Text `json:"handle"`
134+
IsVerified bool `json:"is_verified"`
135+
TwitterHandle pgtype.Text `json:"twitter_handle"`
136+
InstagramHandle pgtype.Text `json:"instagram_handle"`
137+
TiktokHandle pgtype.Text `json:"tiktok_handle"`
138+
VerifiedWithTwitter pgtype.Bool `json:"verified_with_twitter"`
139+
VerifiedWithInstagram pgtype.Bool `json:"verified_with_instagram"`
140+
VerifiedWithTiktok pgtype.Bool `json:"verified_with_tiktok"`
141+
Website pgtype.Text `json:"website"`
142+
Donation pgtype.Text `json:"donation"`
143+
Location pgtype.Text `json:"location"`
144+
Name pgtype.Text `json:"name"`
145+
PlaylistCount pgtype.Int8 `json:"playlist_count"`
146+
ProfilePicture *SquareImage `json:"profile_picture"`
147+
RepostCount pgtype.Int8 `json:"repost_count"`
148+
TrackCount pgtype.Int8 `json:"track_count"`
149+
IsDeactivated bool `json:"is_deactivated"`
150+
IsAvailable bool `json:"is_available"`
151+
ErcWallet pgtype.Text `json:"erc_wallet"`
152+
SplWallet pgtype.Text `json:"spl_wallet"`
153+
SplUsdcPayoutWallet pgtype.Text `json:"spl_usdc_payout_wallet"`
154+
SupporterCount int32 `json:"supporter_count"`
155+
SupportingCount int32 `json:"supporting_count"`
156+
TotalAudioBalance int32 `json:"total_audio_balance"`
157+
Wallet pgtype.Text `json:"wallet"`
157158
}
158159

159160
func ToMinUser(fullUser FullUser) MinUser {

api/dbv1/get_users.sql.go

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/dbv1/queries/get_users.sql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ FROM users u
118118
JOIN aggregate_user using (user_id)
119119
LEFT JOIN user_balances using (user_id)
120120
LEFT JOIN user_bank_accounts on u.wallet = user_bank_accounts.ethereum_address
121-
WHERE is_deactivated = false
122-
AND u.user_id = ANY(@ids::int[])
121+
WHERE u.user_id = ANY(@ids::int[])
123122
ORDER BY u.user_id
124123
;

api/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func NewApiServer(config Config) *ApiServer {
139139
g.Get("/users/:userId/mutuals", app.v1UsersMutuals)
140140
g.Get("/users/:userId/reposts", app.v1UsersReposts)
141141
g.Get("/users/:userId/supporting", app.v1UsersSupporting)
142+
g.Get("/users/:userId/supporters", app.v1UsersSupporters)
142143
g.Get("/users/:userId/tracks", app.v1UserTracks)
143144
g.Get("/users/:userId/feed", app.v1UsersFeed)
144145
g.Get("/users/:userId/connected_wallets", app.v1UsersConnectedWallets)

api/server_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func Test200(t *testing.T) {
9191
"/v1/full/users/7eP5n/mutuals",
9292
"/v1/full/users/7eP5n/reposts",
9393
"/v1/full/users/7eP5n/supporting",
94+
"/v1/full/users/7eP5n/supporters",
9495
"/v1/full/users/7eP5n/tracks",
9596
"/v1/full/users/7eP5n/feed",
9697

api/v1_users_supporters.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package api
2+
3+
import (
4+
"bridgerton.audius.co/api/dbv1"
5+
"github.com/gofiber/fiber/v2"
6+
"github.com/jackc/pgx/v5"
7+
)
8+
9+
func (app *ApiServer) v1UsersSupporters(c *fiber.Ctx) error {
10+
myId := c.Locals("myId")
11+
userId := c.Locals("userId").(int)
12+
13+
args := pgx.NamedArgs{
14+
"userId": userId,
15+
}
16+
17+
args["limit"] = c.Query("limit", "20")
18+
args["offset"] = c.Query("offset", "0")
19+
20+
type supportedUser struct {
21+
Rank int `json:"rank" db:"rank"`
22+
SenderUserID int32 `json:"-" db:"sender_user_id"`
23+
ReceiverUserID int32 `json:"-" db:"receiver_user_id"`
24+
Amount string `json:"amount" db:"amount"`
25+
Sender dbv1.FullUser `json:"sender" db:"-"`
26+
}
27+
28+
sql := `
29+
SELECT
30+
sender_user_id,
31+
receiver_user_id,
32+
amount || '0000000000' as amount,
33+
(
34+
SELECT count(*) + 1
35+
FROM aggregate_user_tips b
36+
WHERE b.receiver_user_id = a.receiver_user_id
37+
AND b.amount > a.amount
38+
) as rank
39+
FROM aggregate_user_tips a
40+
-- JOIN users ON a.sender_user_id = user_id
41+
WHERE
42+
receiver_user_id = @userId
43+
-- todo:
44+
-- do the wrong thing here to match python reponse
45+
-- (see comment in v1_users_supporting.go)
46+
-- AND is_deactivated = false
47+
-- AND is_available = true
48+
ORDER BY a.amount DESC, sender_user_id ASC
49+
LIMIT @limit
50+
OFFSET @offset
51+
`
52+
53+
rows, err := app.pool.Query(c.Context(), sql, args)
54+
if err != nil {
55+
return err
56+
}
57+
58+
supported, err := pgx.CollectRows(rows, pgx.RowToStructByName[supportedUser])
59+
if err != nil {
60+
return err
61+
}
62+
63+
userIds := []int32{}
64+
for _, s := range supported {
65+
userIds = append(userIds, s.SenderUserID)
66+
}
67+
userMap, err := app.queries.FullUsersKeyed(c.Context(), dbv1.GetUsersParams{
68+
MyID: myId,
69+
Ids: userIds,
70+
})
71+
if err != nil {
72+
return err
73+
}
74+
75+
for idx, s := range supported {
76+
s.Sender = userMap[s.SenderUserID]
77+
supported[idx] = s
78+
}
79+
80+
if !c.Locals("isFull").(bool) {
81+
// Create a new array with MinUsers
82+
type minSupportedUser struct {
83+
supportedUser
84+
Receiver dbv1.MinUser `json:"receiver"`
85+
}
86+
87+
minSupported := make([]minSupportedUser, len(supported))
88+
for i, user := range supported {
89+
minSupported[i] = minSupportedUser{
90+
supportedUser: user,
91+
Receiver: dbv1.ToMinUser(user.Sender),
92+
}
93+
}
94+
95+
return c.JSON(fiber.Map{
96+
"data": minSupported,
97+
})
98+
}
99+
100+
return c.JSON(fiber.Map{
101+
"data": supported,
102+
})
103+
}

api/v1_users_supporting.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@ func (app *ApiServer) v1UsersSupporting(c *fiber.Ctx) error {
3737
AND b.amount > a.amount
3838
) as rank
3939
FROM aggregate_user_tips a
40-
JOIN users ON a.receiver_user_id = user_id
41-
WHERE sender_user_id = @userId
42-
AND is_deactivated = false
40+
-- JOIN users ON a.receiver_user_id = user_id
41+
WHERE
42+
sender_user_id = @userId
43+
-- todo:
44+
-- these conditions should be here:
45+
-- but python will actually show deactivate / unavailable users
46+
-- so to minimize apidiff, skip the join above and do the wrong thing here
47+
-- AND is_deactivated = false
48+
-- AND is_available = true
4349
ORDER BY a.amount DESC, receiver_user_id ASC
4450
LIMIT @limit
4551
OFFSET @offset

0 commit comments

Comments
 (0)