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
41 changes: 41 additions & 0 deletions packages/common/src/adapters/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,47 @@ export const notificationFromSDK = (
}
}
default:
// Types below may arrive before the SDK is regenerated
{
const n = notification as unknown as {
type: string
actions: typeof notification.actions
}
if (n.type === 'remix_contest_update') {
const data = n.actions[0].data as unknown as Record<string, string>
return {
type: NotificationType.RemixContestUpdate,
eventId: HashId.parse(data.eventId ?? data.event_id),
entityId: HashId.parse(data.entityId ?? data.entity_id),
entityUserId: HashId.parse(
data.entityUserId ?? data.entity_user_id
),
commentId: HashId.parse(data.commentId ?? data.comment_id),
userIds: [],
entityType: Entity.Track,
...formatBaseNotification(notification)
}
}
if (n.type === 'fan_remix_contest_submission') {
const data = n.actions[0].data as unknown as Record<string, string>
return {
type: NotificationType.FanRemixContestSubmission,
eventId: HashId.parse(data.eventId ?? data.event_id),
entityId: HashId.parse(data.entityId ?? data.entity_id),
entityUserId: HashId.parse(
data.entityUserId ?? data.entity_user_id
),
submissionTrackId: HashId.parse(
data.submissionTrackId ?? data.submission_track_id
),
userIds: [
HashId.parse(data.submitterUserId ?? data.submitter_user_id)
].filter(removeNullable),
entityType: Entity.Track,
...formatBaseNotification(notification)
}
}
}
return undefined
}
}
24 changes: 24 additions & 0 deletions packages/common/src/store/notifications/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export enum NotificationType {
FanRemixContestEnded = 'FanRemixContestEnded',
FanRemixContestEndingSoon = 'FanRemixContestEndingSoon',
FanRemixContestWinnersSelected = 'FanRemixContestWinnersSelected',
RemixContestUpdate = 'RemixContestUpdate',
FanRemixContestSubmission = 'FanRemixContestSubmission',
Tastemaker = 'Tastemaker',
TrendingTrack = 'TrendingTrack',
TrendingUnderground = 'TrendingUnderground',
Expand Down Expand Up @@ -612,6 +614,26 @@ export type FanRemixContestWinnersSelectedNotification = BaseNotification & {
entityType: Entity.Track
}

export type RemixContestUpdateNotification = BaseNotification & {
type: NotificationType.RemixContestUpdate
eventId: ID
entityId: ID
entityUserId: ID
commentId: ID
userIds: ID[]
entityType: Entity.Track
}

export type FanRemixContestSubmissionNotification = BaseNotification & {
type: NotificationType.FanRemixContestSubmission
eventId: ID
entityId: ID
entityUserId: ID
submissionTrackId: ID
userIds: ID[]
entityType: Entity.Track
}

export type ArtistRemixContestEndingSoonNotification = BaseNotification & {
type: NotificationType.ArtistRemixContestEndingSoon
entityId: ID
Expand Down Expand Up @@ -665,6 +687,8 @@ export type Notification =
| ArtistRemixContestEndedNotification
| FanRemixContestEndedNotification
| FanRemixContestWinnersSelectedNotification
| RemixContestUpdateNotification
| FanRemixContestSubmissionNotification
| ArtistRemixContestEndingSoonNotification
| ArtistRemixContestSubmissionsNotification
| FanClubTextPostNotification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ def test_create_event_comment_by_owner_is_post_update(app, mocker):
assert recipient_ids == [2, 3]
for notif in update_notifs:
assert notif.data["event_id"] == 100
assert notif.data["event_user_id"] == 1
assert notif.data["entity_id"] == 1
assert notif.data["entity_user_id"] == 1
assert notif.data["comment_id"] == 500


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ def create_comment(params: ManageEntityParameters):
event_follower_user_ids = {
row[0] for row in event_follower_rows if row[0] != entity_user_id
}
event_row = (
params.session.query(Event)
.filter(Event.event_id == stored_entity_id)
.first()
)
contest_track_id = event_row.entity_id if event_row else None
for recipient_id in event_follower_user_ids:
event_update_notification = Notification(
blocknumber=params.block_number,
Expand All @@ -399,7 +405,8 @@ def create_comment(params: ManageEntityParameters):
),
data={
"event_id": stored_entity_id,
"event_user_id": entity_user_id,
"entity_id": contest_track_id,
"entity_user_id": entity_user_id,
"comment_id": comment_id,
},
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime, timezone
from typing import Dict, List, Union

from sqlalchemy import desc
from sqlalchemy import desc, or_
from sqlalchemy.orm.session import Session
from sqlalchemy.sql import null

Expand All @@ -15,11 +15,16 @@
)
from src.models.tracks.remix import Remix
from src.models.tracks.stem import Stem
from src.models.events.event import Event, EventType
from src.models.tracks.track import Track
from src.models.tracks.track_download import TrackDownload
from src.models.tracks.track_price_history import TrackPriceHistory
from src.models.tracks.track_route import TrackRoute
from src.models.users.usdc_purchase import PurchaseAccessType
from src.models.social.subscription import (
SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription,
)
from src.models.users.user import User
from src.tasks.entity_manager.utils import (
CHARACTER_LIMIT_DESCRIPTION,
Expand Down Expand Up @@ -595,6 +600,62 @@ def create_remix_contest_notification_helper(
)


def auto_subscribe_to_contest_on_submission(
params: ManageEntityParameters, track_record: Track
) -> None:
if track_record.stem_of is not None or not track_record.remix_of:
return
parent_ids = get_remix_parent_track_ids(params.metadata)
if not parent_ids:
return
parent_track_id = parent_ids[0]
now = params.block_datetime
event = (
params.session.query(Event)
.filter(
Event.event_type == EventType.remix_contest,
Event.entity_id == parent_track_id,
Event.is_deleted == False,
)
.filter(or_(Event.end_date == None, Event.end_date > now))
.first()
)
if not event:
return
uploader_id = track_record.owner_id
if uploader_id == event.user_id:
return
existing = (
params.session.query(Subscription)
.filter(
Subscription.subscriber_id == uploader_id,
Subscription.user_id == event.event_id,
Subscription.entity_type == SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription.is_current == True,
Subscription.is_delete == False,
)
.first()
)
if existing:
return
# Synthetic tx: unique per (contest, upload tx) so reindexing stays idempotent
sub_tx = f"auto_e{event.event_id}_{params.txhash}"[:200]
params.session.add(
Subscription(
blockhash=params.event_blockhash,
blocknumber=params.block_number,
created_at=params.block_datetime,
txhash=sub_tx,
user_id=event.event_id,
subscriber_id=uploader_id,
is_current=True,
is_delete=False,
entity_type=SUBSCRIPTION_EVENT_ENTITY_TYPE,
entity_id=event.event_id,
)
)


def create_track(params: ManageEntityParameters):
handle = get_handle(params)
validate_track_tx(params)
Expand Down Expand Up @@ -634,6 +695,8 @@ def create_track(params: ManageEntityParameters):
params.challenge_bus, params.block_number, params.block_datetime, track_record
)

auto_subscribe_to_contest_on_submission(params, track_record)

params.add_record(track_id, track_record)


Expand Down
28 changes: 27 additions & 1 deletion packages/discovery-provider/src/tasks/entity_manager/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
from src.models.social.repost import Repost
from src.models.social.save import Save
from src.models.social.share import Share
from src.models.social.subscription import Subscription
from src.models.social.subscription import (
SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription,
)
from src.models.tracks.track import Track
from src.models.tracks.track_route import TrackRoute
from src.models.users.associated_wallet import AssociatedWallet
Expand Down Expand Up @@ -670,6 +673,24 @@ def safe_add_notification(session: Session, notification: Notification):
session.add(notification)


def get_remix_contest_event_subscriber_user_ids(session: Session, event: Event) -> List[int]:
"""
user_id on `subscriptions` is the event_id for Event subscriptions
(see subscription row shape for entity_type = 'Event').
"""
rows = (
session.query(Subscription.subscriber_id)
.filter(
Subscription.user_id == event.event_id,
Subscription.entity_type == SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription.is_current == True,
Subscription.is_delete == False,
)
.all()
)
return [r[0] for r in rows]


def create_remix_contest_notification(
session: Session,
track: Track,
Expand Down Expand Up @@ -722,11 +743,16 @@ def create_remix_contest_notification(
.all()
)

contest_follower_user_ids = get_remix_contest_event_subscriber_user_ids(
session, remix_contest_event
)

# Combine and deduplicate user IDs
user_ids = list(
set(
[user_id for (user_id,) in follower_user_ids]
+ [user_id for (user_id,) in save_user_ids]
+ contest_follower_user_ids
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

from src.models.events.event import Event, EventType
from src.models.notifications.notification import Notification
from src.models.social.follow import Follow
from src.models.social.save import Save, SaveType
from src.models.social.subscription import (
SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription,
)
from src.models.tracks.track import Track
from src.utils.structured_logger import StructuredLogger

Expand Down Expand Up @@ -47,7 +53,55 @@ def create_fan_remix_contest_ended_notifications(session, now=None):
.all()
)
remixer_user_ids = {row[0] for row in remixers}
for user_id in remixer_user_ids:
event_follower_user_ids = {
row[0]
for row in (
session.query(Subscription.subscriber_id)
.filter(
Subscription.user_id == event.event_id,
Subscription.entity_type == SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription.is_current == True,
Subscription.is_delete == False,
)
.all()
)
}
# Followers of the contest host artist
host_follower_user_ids = {
row[0]
for row in (
session.query(Follow.follower_user_id)
.filter(
Follow.followee_user_id == event.user_id,
Follow.is_current == True,
Follow.is_delete == False,
)
.all()
)
}
# Users who favorited the parent contest track
favoriter_user_ids = {
row[0]
for row in (
session.query(Save.user_id)
.filter(
Save.save_item_id == contest_track_id,
Save.save_type == SaveType.track,
Save.is_current == True,
Save.is_delete == False,
)
.all()
)
}
notified_user_ids = (
remixer_user_ids
| event_follower_user_ids
| host_follower_user_ids
| favoriter_user_ids
)
# Exclude the contest host — they have artist_remix_contest_ended.
notified_user_ids.discard(event.user_id)
for user_id in notified_user_ids:
group_id = get_fan_remix_contest_ended_group_id(event.event_id)
parent_track = (
session.query(Track)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
from src.models.notifications.notification import Notification
from src.models.social.follow import Follow
from src.models.social.save import Save, SaveType
from src.models.social.subscription import (
SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription,
)
from src.models.tracks.track import Track
from src.utils.structured_logger import StructuredLogger

Expand Down Expand Up @@ -71,7 +75,22 @@ def create_fan_remix_contest_ending_soon_notifications(session, now=None):
)
.all()
)
notified_user_ids = follower_user_ids | favoriter_user_ids
event_follower_user_ids = set(
row[0]
for row in session.query(Subscription.subscriber_id)
.filter(
Subscription.user_id == event.event_id,
Subscription.entity_type == SUBSCRIPTION_EVENT_ENTITY_TYPE,
Subscription.is_current == True,
Subscription.is_delete == False,
)
.all()
)
notified_user_ids = (
follower_user_ids | favoriter_user_ids | event_follower_user_ids
)
# Exclude the contest host — they have artist_remix_contest_ending_soon.
notified_user_ids.discard(event.user_id)
parent_track_owner_id = parent_track.owner_id if parent_track else None
group_id = get_fan_remix_contest_ending_soon_group_id(event.event_id)
for user_id in notified_user_ids:
Expand Down
Loading
Loading