Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions api/swagger/swagger-v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8282,6 +8282,8 @@ paths:
- track_added_to_purchased_album
- request_manager
- approve_manager_request
- track_collaborator_invite
- track_collaborator_accept
- claimable_reward
- comment
- comment_thread
Expand Down Expand Up @@ -17078,6 +17080,7 @@ components:
- $ref: "#/components/schemas/usdc_purchase_buyer_notification"
- $ref: "#/components/schemas/request_manager_notification"
- $ref: "#/components/schemas/approve_manager_request_notification"
- $ref: "#/components/schemas/track_collaborator_notification"
- $ref: "#/components/schemas/trending_notification"
- $ref: "#/components/schemas/trending_playlist_notification"
- $ref: "#/components/schemas/trending_underground_notification"
Expand Down Expand Up @@ -17125,6 +17128,8 @@ components:
usdc_purchase_buyer: "#/components/schemas/usdc_purchase_buyer_notification"
request_manager: "#/components/schemas/request_manager_notification"
approve_manager_request: "#/components/schemas/approve_manager_request_notification"
track_collaborator_invite: "#/components/schemas/track_collaborator_notification"
track_collaborator_accept: "#/components/schemas/track_collaborator_notification"
trending: "#/components/schemas/trending_notification"
trending_playlist: "#/components/schemas/trending_playlist_notification"
trending_underground: "#/components/schemas/trending_underground_notification"
Expand Down Expand Up @@ -17412,6 +17417,29 @@ components:
type: array
items:
$ref: "#/components/schemas/approve_manager_request_notification_action"
track_collaborator_notification:
required:
- actions
- group_id
- is_seen
- type
type: object
properties:
type:
type: string
enum:
- track_collaborator_invite
- track_collaborator_accept
group_id:
type: string
is_seen:
type: boolean
seen_at:
type: integer
actions:
type: array
items:
$ref: "#/components/schemas/track_collaborator_notification_action"
fan_remix_contest_ended_notification_action:
required:
- data
Expand Down Expand Up @@ -17493,6 +17521,22 @@ components:
type: integer
data:
$ref: "#/components/schemas/approve_manager_request_notification_action_data"
track_collaborator_notification_action:
required:
- data
- specifier
- timestamp
- type
type: object
properties:
specifier:
type: string
type:
type: string
timestamp:
type: integer
data:
$ref: "#/components/schemas/track_collaborator_notification_action_data"
comment_mention_notification:
required:
- actions
Expand Down Expand Up @@ -18658,6 +18702,26 @@ components:
type: string
grantee_address:
type: string
track_collaborator_notification_action_data:
required:
- collaborator_user_id
- inviter_user_id
- track_id
type: object
properties:
track_id:
type: string
inviter_user_id:
type: string
collaborator_user_id:
type: string
status:
type: string
description: Current collaborator invite status at response time.
enum:
- pending
- accepted
- rejected
save_of_repost_notification_action:
required:
- data
Expand Down
21 changes: 16 additions & 5 deletions api/v1_notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,17 @@ SELECT
n.group_id AS group_id,
json_agg(
json_build_object(
'type', type,
'specifier', specifier,
'timestamp', EXTRACT(EPOCH FROM timestamp),
'data', data
'type', n.type,
'specifier', n.specifier,
'timestamp', EXTRACT(EPOCH FROM n.timestamp),
'data',
CASE
WHEN n.type = 'track_collaborator_invite' AND tc.status IS NOT NULL
THEN jsonb_set(n.data, '{status}', to_jsonb(tc.status), true)
ELSE n.data
END
)
ORDER BY timestamp DESC
ORDER BY n.timestamp DESC
)::jsonb AS actions,
CASE
-- If seen at is not null, we were able to match a window between seen events
Expand Down Expand Up @@ -113,6 +118,12 @@ LEFT JOIN playlists p ON
n.data ? 'playlist_id' AND
p.playlist_id = (n.data->>'playlist_id')::integer AND
p.is_current = true
LEFT JOIN track_collaborators tc ON
n.type = 'track_collaborator_invite' AND
n.data ? 'track_id' AND
n.data ? 'collaborator_user_id' AND
tc.track_id = (n.data->>'track_id')::integer AND
tc.collaborator_user_id = (n.data->>'collaborator_user_id')::integer
WHERE
(ARRAY[@user_id] && n.user_ids)
AND (n.type = ANY(@types) OR @types IS NULL)
Expand Down
60 changes: 55 additions & 5 deletions api/v1_notifications_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package api

import (
"context"
"strconv"
"testing"
"time"

"api.audius.co/database"
"api.audius.co/trashid"
Expand Down Expand Up @@ -463,10 +465,59 @@ func TestV1Notifications_AnnouncementRequiresUserIdInUserIds(t *testing.T) {
assert.Equal(t, 200, status)

jsonAssert(t, body, map[string]any{
"data.notifications.#": 1,
"data.notifications.0.type": "announcement",
"data.notifications.0.group_id": "announcement:target-user-1",
"data.notifications.0.actions.0.data.title": "For user 1",
"data.notifications.#": 1,
"data.notifications.0.type": "announcement",
"data.notifications.0.group_id": "announcement:target-user-1",
"data.notifications.0.actions.0.data.title": "For user 1",
})
}

func TestV1Notifications_TrackCollaboratorInviteIncludesCurrentStatus(t *testing.T) {
app := emptyTestApp(t)
ctx := context.Background()

const trackID = 700
const collaboratorUserID = 1
const inviterUserID = 500

invitedAt := time.Now()
_, err := app.pool.Replicas[0].Exec(ctx, `
INSERT INTO track_collaborators (
track_id,
collaborator_user_id,
invited_by,
status,
created_at,
updated_at,
txhash
)
VALUES ($1, $2, $3, 'pending', $4, $4, 'invite-tx')
`, trackID, collaboratorUserID, inviterUserID, invitedAt)
assert.NoError(t, err)

_, err = app.pool.Replicas[0].Exec(ctx, `
UPDATE track_collaborators
SET status = 'accepted', updated_at = $3
WHERE track_id = $1 AND collaborator_user_id = $2
`, trackID, collaboratorUserID, invitedAt.Add(time.Second))
assert.NoError(t, err)

status, body := testGet(
t,
app,
"/v1/notifications/"+
trashid.MustEncodeHashID(collaboratorUserID)+
"?types=track_collaborator_invite",
)
assert.Equal(t, 200, status)

jsonAssert(t, body, map[string]any{
"data.notifications.#": 1,
"data.notifications.0.type": "track_collaborator_invite",
"data.notifications.0.actions.0.data.track_id": trashid.MustEncodeHashID(trackID),
"data.notifications.0.actions.0.data.collaborator_user_id": trashid.MustEncodeHashID(collaboratorUserID),
"data.notifications.0.actions.0.data.inviter_user_id": trashid.MustEncodeHashID(inviterUserID),
"data.notifications.0.actions.0.data.status": "accepted",
})
}

Expand Down Expand Up @@ -582,4 +633,3 @@ func TestV1Notifications_RelatedEntities(t *testing.T) {
assert.Contains(t, gotUserIds, trashid.MustEncodeHashID(saver),
"saver must appear in related.users")
}

Loading