diff --git a/packages/discovery-provider/plugins/notifications/src/email/notifications/index.ts b/packages/discovery-provider/plugins/notifications/src/email/notifications/index.ts index 74fda06d8f5..c40be9fa8a7 100644 --- a/packages/discovery-provider/plugins/notifications/src/email/notifications/index.ts +++ b/packages/discovery-provider/plugins/notifications/src/email/notifications/index.ts @@ -171,6 +171,13 @@ const getNotifications = async ( userIds: string[], remoteConfig: RemoteConfig ): Promise => { + if (!remoteConfig) { + logger.warn( + 'RemoteConfig not provided to getNotifications, returning empty array' + ) + return [] + } + // NOTE: Temp while testing DM notifs on staging const appNotificationsResp = await dnDb.raw(appNotificationsSql, { start_offset: startOffset, @@ -314,6 +321,13 @@ export async function processEmailNotifications( remoteConfig: RemoteConfig ) { try { + if (!remoteConfig) { + logger.warn( + 'RemoteConfig not provided to processEmailNotifications, using default values' + ) + return + } + const now = moment.utc() let days = 1 if (frequency == 'weekly') { diff --git a/packages/discovery-provider/plugins/notifications/src/email/notifications/renderEmail.ts b/packages/discovery-provider/plugins/notifications/src/email/notifications/renderEmail.ts index bce1173b8d8..bfcea618027 100644 --- a/packages/discovery-provider/plugins/notifications/src/email/notifications/renderEmail.ts +++ b/packages/discovery-provider/plugins/notifications/src/email/notifications/renderEmail.ts @@ -12,6 +12,7 @@ import { mapNotifications } from '../../processNotifications/mappers/mapNotifica import { BaseNotification } from '../../processNotifications/mappers/base' import { EmailFrequency } from '../../processNotifications/mappers/userNotificationSettings' import { getContentNode } from '../../utils/env' +import { formatImageUrl } from '../../utils/format' type RenderEmailProps = { userId: number @@ -35,7 +36,6 @@ type UserResource = { handle: string profile_picture_sizes: string profile_picture: string - creator_node_endpoint: string } type TrackResource = { track_id: number @@ -44,7 +44,6 @@ type TrackResource = { cover_art: string cover_art_sizes: string stream_conditions: object - creator_node_endpoint: string slug: string ownerName: string ownerCreatorNodeEndpoint: string @@ -55,7 +54,6 @@ type PlaylistResource = { is_album: boolean playlist_image_multihash: string playlist_image_sizes_multihash: string - creator_node_endpoint: string slug: string ownerName: string ownerCreatorNodeEndpoint: string @@ -87,38 +85,30 @@ const DEFAULT_TRACK_COVER_ART_URL = '' const DEFAULT_PLAYLIST_IMAGE_IRL = '' const getUserProfileUrl = (user: UserResource) => { - let profilePictureUrl = DEFAULT_PROFILE_IMG - const contentNode = getContentNode() if (user.profile_picture_sizes) { - profilePictureUrl = `${contentNode}/content/${user.profile_picture_sizes}/1000x1000.jpg` + return formatImageUrl(user.profile_picture_sizes, 1000) } else if (user.profile_picture) { - profilePictureUrl = `${contentNode}/content/${user.profile_picture}` + return `${getContentNode()}/content/${user.profile_picture}` } - return profilePictureUrl + return DEFAULT_PROFILE_IMG } const getTrackCoverArt = (track: TrackResource) => { - const contentNodes = track.creator_node_endpoint.split(',') - const primaryEndpoint = contentNodes[0] - let coverArtUrl = DEFAULT_TRACK_COVER_ART_URL if (track.cover_art_sizes) { - coverArtUrl = `${primaryEndpoint}/ipfs/${track.cover_art_sizes}/1000x1000.jpg` + return formatImageUrl(track.cover_art_sizes, 1000) } else if (track.cover_art) { - coverArtUrl = `${primaryEndpoint}/ipfs/${track.cover_art}` + return `${getContentNode()}/content/${track.cover_art}` } - return coverArtUrl + return DEFAULT_TRACK_COVER_ART_URL } const getPlaylistImage = (playlist: PlaylistResource) => { - const contentNodes = playlist.creator_node_endpoint.split(',') - const primaryEndpoint = contentNodes[0] - let playlistImageUrl = DEFAULT_PLAYLIST_IMAGE_IRL if (playlist.playlist_image_sizes_multihash) { - playlistImageUrl = `${primaryEndpoint}/ipfs/${playlist.playlist_image_sizes_multihash}/1000x1000.jpg` + return formatImageUrl(playlist.playlist_image_sizes_multihash, 1000) } else if (playlist.playlist_image_multihash) { - playlistImageUrl = `${primaryEndpoint}/ipfs/${playlist.playlist_image_multihash}` + return `${getContentNode()}/content/${playlist.playlist_image_multihash}` } - return playlistImageUrl + return DEFAULT_PLAYLIST_IMAGE_IRL } export const fetchResources = async ( @@ -135,8 +125,7 @@ export const fetchResources = async ( 'users.tiktok_handle as tikTokHandle', 'users.name', 'users.profile_picture_sizes', - 'users.profile_picture', - 'users.creator_node_endpoint' + 'users.profile_picture' ) .from('users') .whereIn('user_id', Array.from(ids.users)) @@ -158,7 +147,6 @@ export const fetchResources = async ( 'tracks.cover_art_sizes', 'tracks.stream_conditions', { ownerName: 'users.name' }, - 'users.creator_node_endpoint', 'track_routes.slug' ) .from('tracks') @@ -184,7 +172,6 @@ export const fetchResources = async ( 'playlists.playlist_image_sizes_multihash', 'playlists.playlist_image_multihash', { ownerName: 'users.name' }, - 'users.creator_node_endpoint', 'playlist_routes.slug' ) .from('playlists') diff --git a/packages/discovery-provider/plugins/notifications/src/main.ts b/packages/discovery-provider/plugins/notifications/src/main.ts index cc27fbad132..d26e4664abd 100644 --- a/packages/discovery-provider/plugins/notifications/src/main.ts +++ b/packages/discovery-provider/plugins/notifications/src/main.ts @@ -101,6 +101,13 @@ export class Processor { } getIsScheduledEmailEnabled() { + if (!this.remoteConfig) { + logger.warn( + 'RemoteConfig not initialized, defaulting to disabled scheduled emails' + ) + return false + } + const isEnabled = this.remoteConfig.getFeatureVariableEnabled( NotificationsEmailPlugin, EmailPluginMappings.Scheduled @@ -111,6 +118,13 @@ export class Processor { } getIsBrowserPushEnabled(): boolean { + if (!this.remoteConfig) { + logger.warn( + 'RemoteConfig not initialized, defaulting to disabled browser push' + ) + return false + } + const isEnabled = this.remoteConfig.getFeatureVariableEnabled( BrowserPushPlugin, BrowserPluginMappings.Enabled @@ -179,7 +193,9 @@ export class Processor { } close = async () => { - this.remoteConfig.close() + if (this.remoteConfig) { + this.remoteConfig.close() + } await this.listener?.close() await this.notificationSeenListener?.close() await this.discoveryDB?.destroy() diff --git a/packages/discovery-provider/plugins/notifications/src/processNotifications/indexAppNotifications.ts b/packages/discovery-provider/plugins/notifications/src/processNotifications/indexAppNotifications.ts index 24ff0bed751..7aefd164b35 100644 --- a/packages/discovery-provider/plugins/notifications/src/processNotifications/indexAppNotifications.ts +++ b/packages/discovery-provider/plugins/notifications/src/processNotifications/indexAppNotifications.ts @@ -114,9 +114,20 @@ export class AppNotificationsProcessor { this.dnDB = dnDB this.identityDB = identityDB this.remoteConfig = remoteConfig + + if (!this.remoteConfig) { + logger.warn('AppNotificationsProcessor initialized without remoteConfig') + } } getIsPushNotificationEnabled(type: string) { + if (!this.remoteConfig) { + logger.warn( + 'RemoteConfig not initialized, defaulting to disabled push notifications' + ) + return false + } + const mappingVariable = notificationTypeMapping[type] // If there is no remote variable, do no push - it must be explicitly enabled if (!mappingVariable) return false @@ -130,6 +141,13 @@ export class AppNotificationsProcessor { } getIsLiveEmailEnabled() { + if (!this.remoteConfig) { + logger.warn( + 'RemoteConfig not initialized, defaulting to disabled live emails' + ) + return false + } + const isEnabled = this.remoteConfig.getFeatureVariableEnabled( NotificationsEmailPlugin, EmailPluginMappings.Live @@ -140,6 +158,13 @@ export class AppNotificationsProcessor { } getIsBrowserPushEnabled(): boolean { + if (!this.remoteConfig) { + logger.warn( + 'RemoteConfig not initialized, defaulting to disabled browser push' + ) + return false + } + const isEnabled = this.remoteConfig.getFeatureVariableEnabled( BrowserPushPlugin, BrowserPluginMappings.Enabled diff --git a/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/challengeReward.ts b/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/challengeReward.ts index c15d070e2ac..0e7d2096759 100644 --- a/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/challengeReward.ts +++ b/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/challengeReward.ts @@ -86,17 +86,30 @@ export class ChallengeReward extends BaseNotification { } getPushBodyText() { + // Check if the challenge ID exists in our map + const challengeInfo = this.challengeInfoMap[this.challengeId] + if (!challengeInfo) { + return `You've earned ${ + this.amount / AUDIO_DIVISOR + } $AUDIO for completing this challenge!` + } + if (this.challengeId === 'rd') { - return `You’ve received ${ - this.challengeInfoMap[this.challengeId].amount - } $AUDIO for being referred! Invite your friends to join to earn more!` + const amount = 'amount' in challengeInfo ? challengeInfo.amount : 1 + return `You've received ${amount} $AUDIO for being referred! Invite your friends to join to earn more!` } else if (this.challengeId === 'o') { - return `You’ve earned ${ + return `You've earned ${ this.amount / AUDIO_DIVISOR } $AUDIO for completing this challenge!` } - return `You’ve earned ${ - this.challengeInfoMap[this.challengeId].amount + + // Check if amount exists on challengeInfo + if ('amount' in challengeInfo && challengeInfo.amount) { + return `You've earned ${challengeInfo.amount} $AUDIO for completing this challenge!` + } + + return `You've earned ${ + this.amount / AUDIO_DIVISOR } $AUDIO for completing this challenge!` } @@ -134,7 +147,16 @@ export class ChallengeReward extends BaseNotification { [this.receiverUserId] ) - const title = this.challengeInfoMap[this.challengeId].title + // Check if the challenge ID exists in our map, provide fallback if not + const challengeInfo = this.challengeInfoMap[this.challengeId] + if (!challengeInfo) { + console.warn( + `Unknown challenge ID: ${this.challengeId}, skipping notification` + ) + return + } + + const title = challengeInfo.title const body = this.getPushBodyText() await sendBrowserNotification( isBrowserPushEnabled, diff --git a/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/rewardInCooldown.ts b/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/rewardInCooldown.ts index 82d665e3c19..258f4903775 100644 --- a/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/rewardInCooldown.ts +++ b/packages/discovery-provider/plugins/notifications/src/processNotifications/mappers/rewardInCooldown.ts @@ -125,6 +125,13 @@ export class RewardInCooldown extends BaseNotification { [user.user_id] ) const challengeMessage = challengeMessages[this.challengeId] + if (!challengeMessage) { + logger.error( + `Unknown challenge ID: ${this.challengeId}, skipping notification` + ) + return + } + await sendTransactionalEmail({ email: userNotificationSettings.getUserEmail(user.user_id), html: email({ @@ -137,7 +144,7 @@ export class RewardInCooldown extends BaseNotification { challengeDescription: challengeMessage.description, challengeImage: challengeMessage.imageUrl }), - subject: 'Congratulations! 🏆 You’ve earned a reward!' + subject: "Congratulations! 🏆 You've earned a reward!" }) } } diff --git a/packages/discovery-provider/plugins/notifications/src/types/notifications.ts b/packages/discovery-provider/plugins/notifications/src/types/notifications.ts index 45250296c01..348d53146b6 100644 --- a/packages/discovery-provider/plugins/notifications/src/types/notifications.ts +++ b/packages/discovery-provider/plugins/notifications/src/types/notifications.ts @@ -39,7 +39,6 @@ export type EmailUser = { name: string profile_picture_sizes: string profile_picture: string - creator_node_endpoint: string imageUrl: string }