Better error handling for notification destinations
This commit is contained in:
parent
a310963952
commit
dea65a4ba0
|
@ -178,6 +178,8 @@ export const getNotificationDestinationsForUser = (
|
||||||
reason: notification_reason_types | notification_preference
|
reason: notification_reason_types | notification_preference
|
||||||
) => {
|
) => {
|
||||||
const notificationSettings = privateUser.notificationPreferences
|
const notificationSettings = privateUser.notificationPreferences
|
||||||
|
const unsubscribeEndpoint = getFunctionUrl('unsubscribe')
|
||||||
|
try {
|
||||||
let destinations
|
let destinations
|
||||||
let subscriptionType: notification_preference | undefined
|
let subscriptionType: notification_preference | undefined
|
||||||
if (Object.keys(notificationSettings).includes(reason)) {
|
if (Object.keys(notificationSettings).includes(reason)) {
|
||||||
|
@ -198,11 +200,22 @@ export const getNotificationDestinationsForUser = (
|
||||||
const optedOutOfBrowser =
|
const optedOutOfBrowser =
|
||||||
optOutOfAllSettings.includes('browser') &&
|
optOutOfAllSettings.includes('browser') &&
|
||||||
subscriptionType !== 'your_contract_closed'
|
subscriptionType !== 'your_contract_closed'
|
||||||
const unsubscribeEndpoint = getFunctionUrl('unsubscribe')
|
|
||||||
return {
|
return {
|
||||||
sendToEmail: destinations.includes('email') && !optedOutOfEmail,
|
sendToEmail: destinations.includes('email') && !optedOutOfEmail,
|
||||||
sendToBrowser: destinations.includes('browser') && !optedOutOfBrowser,
|
sendToBrowser: destinations.includes('browser') && !optedOutOfBrowser,
|
||||||
unsubscribeUrl: `${unsubscribeEndpoint}?id=${privateUser.id}&type=${subscriptionType}`,
|
unsubscribeUrl: `${unsubscribeEndpoint}?id=${privateUser.id}&type=${subscriptionType}`,
|
||||||
urlToManageThisNotification: `${DOMAIN}/notifications?tab=settings§ion=${subscriptionType}`,
|
urlToManageThisNotification: `${DOMAIN}/notifications?tab=settings§ion=${subscriptionType}`,
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fail safely
|
||||||
|
console.log(
|
||||||
|
`couldn't get notification destinations for type ${reason} for user ${privateUser.id}`
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
sendToEmail: false,
|
||||||
|
sendToBrowser: false,
|
||||||
|
unsubscribeUrl: '',
|
||||||
|
urlToManageThisNotification: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { getValueFromBucket } from '../../common/calculate-dpm'
|
||||||
import { formatNumericProbability } from '../../common/pseudo-numeric'
|
import { formatNumericProbability } from '../../common/pseudo-numeric'
|
||||||
|
|
||||||
import { sendTemplateEmail, sendTextEmail } from './send-email'
|
import { sendTemplateEmail, sendTextEmail } from './send-email'
|
||||||
import { contractUrl, getUser } from './utils'
|
import { contractUrl, getUser, log } from './utils'
|
||||||
import { buildCardUrl, getOpenGraphProps } from '../../common/contract-details'
|
import { buildCardUrl, getOpenGraphProps } from '../../common/contract-details'
|
||||||
import { notification_reason_types } from '../../common/notification'
|
import { notification_reason_types } from '../../common/notification'
|
||||||
import { Dictionary } from 'lodash'
|
import { Dictionary } from 'lodash'
|
||||||
|
@ -212,20 +212,16 @@ export const sendOneWeekBonusEmail = async (
|
||||||
user: User,
|
user: User,
|
||||||
privateUser: PrivateUser
|
privateUser: PrivateUser
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (!privateUser || !privateUser.email) return
|
||||||
!privateUser ||
|
|
||||||
!privateUser.email ||
|
|
||||||
!privateUser.notificationPreferences.onboarding_flow.includes('email')
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const { name } = user
|
const { name } = user
|
||||||
const firstName = name.split(' ')[0]
|
const firstName = name.split(' ')[0]
|
||||||
|
|
||||||
const { unsubscribeUrl } = getNotificationDestinationsForUser(
|
const { unsubscribeUrl, sendToEmail } = getNotificationDestinationsForUser(
|
||||||
privateUser,
|
privateUser,
|
||||||
'onboarding_flow'
|
'onboarding_flow'
|
||||||
)
|
)
|
||||||
|
if (!sendToEmail) return
|
||||||
|
|
||||||
return await sendTemplateEmail(
|
return await sendTemplateEmail(
|
||||||
privateUser.email,
|
privateUser.email,
|
||||||
|
@ -247,19 +243,15 @@ export const sendCreatorGuideEmail = async (
|
||||||
privateUser: PrivateUser,
|
privateUser: PrivateUser,
|
||||||
sendTime: string
|
sendTime: string
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (!privateUser || !privateUser.email) return
|
||||||
!privateUser ||
|
|
||||||
!privateUser.email ||
|
|
||||||
!privateUser.notificationPreferences.onboarding_flow.includes('email')
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const { name } = user
|
const { name } = user
|
||||||
const firstName = name.split(' ')[0]
|
const firstName = name.split(' ')[0]
|
||||||
const { unsubscribeUrl } = getNotificationDestinationsForUser(
|
const { unsubscribeUrl, sendToEmail } = getNotificationDestinationsForUser(
|
||||||
privateUser,
|
privateUser,
|
||||||
'onboarding_flow'
|
'onboarding_flow'
|
||||||
)
|
)
|
||||||
|
if (!sendToEmail) return
|
||||||
return await sendTemplateEmail(
|
return await sendTemplateEmail(
|
||||||
privateUser.email,
|
privateUser.email,
|
||||||
'Create your own prediction market',
|
'Create your own prediction market',
|
||||||
|
@ -279,22 +271,16 @@ export const sendThankYouEmail = async (
|
||||||
user: User,
|
user: User,
|
||||||
privateUser: PrivateUser
|
privateUser: PrivateUser
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (!privateUser || !privateUser.email) return
|
||||||
!privateUser ||
|
|
||||||
!privateUser.email ||
|
|
||||||
!privateUser.notificationPreferences.thank_you_for_purchases.includes(
|
|
||||||
'email'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const { name } = user
|
const { name } = user
|
||||||
const firstName = name.split(' ')[0]
|
const firstName = name.split(' ')[0]
|
||||||
const { unsubscribeUrl } = getNotificationDestinationsForUser(
|
const { unsubscribeUrl, sendToEmail } = getNotificationDestinationsForUser(
|
||||||
privateUser,
|
privateUser,
|
||||||
'thank_you_for_purchases'
|
'thank_you_for_purchases'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!sendToEmail) return
|
||||||
return await sendTemplateEmail(
|
return await sendTemplateEmail(
|
||||||
privateUser.email,
|
privateUser.email,
|
||||||
'Thanks for your Manifold purchase',
|
'Thanks for your Manifold purchase',
|
||||||
|
@ -466,17 +452,13 @@ export const sendInterestingMarketsEmail = async (
|
||||||
contractsToSend: Contract[],
|
contractsToSend: Contract[],
|
||||||
deliveryTime?: string
|
deliveryTime?: string
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (!privateUser || !privateUser.email) return
|
||||||
!privateUser ||
|
|
||||||
!privateUser.email ||
|
|
||||||
!privateUser.notificationPreferences.trending_markets.includes('email')
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const { unsubscribeUrl } = getNotificationDestinationsForUser(
|
const { unsubscribeUrl, sendToEmail } = getNotificationDestinationsForUser(
|
||||||
privateUser,
|
privateUser,
|
||||||
'trending_markets'
|
'trending_markets'
|
||||||
)
|
)
|
||||||
|
if (!sendToEmail) return
|
||||||
|
|
||||||
const { name } = user
|
const { name } = user
|
||||||
const firstName = name.split(' ')[0]
|
const firstName = name.split(' ')[0]
|
||||||
|
@ -620,18 +602,15 @@ export const sendWeeklyPortfolioUpdateEmail = async (
|
||||||
investments: PerContractInvestmentsData[],
|
investments: PerContractInvestmentsData[],
|
||||||
overallPerformance: OverallPerformanceData
|
overallPerformance: OverallPerformanceData
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (!privateUser || !privateUser.email) return
|
||||||
!privateUser ||
|
|
||||||
!privateUser.email ||
|
|
||||||
!privateUser.notificationPreferences.profit_loss_updates.includes('email')
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const { unsubscribeUrl } = getNotificationDestinationsForUser(
|
const { unsubscribeUrl, sendToEmail } = getNotificationDestinationsForUser(
|
||||||
privateUser,
|
privateUser,
|
||||||
'profit_loss_updates'
|
'profit_loss_updates'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!sendToEmail) return
|
||||||
|
|
||||||
const { name } = user
|
const { name } = user
|
||||||
const firstName = name.split(' ')[0]
|
const firstName = name.split(' ')[0]
|
||||||
const templateData: Record<string, string> = {
|
const templateData: Record<string, string> = {
|
||||||
|
@ -656,4 +635,5 @@ export const sendWeeklyPortfolioUpdateEmail = async (
|
||||||
: 'portfolio-update',
|
: 'portfolio-update',
|
||||||
templateData
|
templateData
|
||||||
)
|
)
|
||||||
|
log('Sent portfolio update email to', privateUser.email)
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,13 +112,12 @@ export async function sendPortfolioUpdateEmailsToAllUsers() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
log('Found', contractsUsersBetOn.length, 'contracts')
|
|
||||||
let count = 0
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
privateUsersToSendEmailsTo.map(async (privateUser) => {
|
privateUsersToSendEmailsTo.map(async (privateUser) => {
|
||||||
const user = await getUser(privateUser.id)
|
const user = await getUser(privateUser.id)
|
||||||
// Don't send to a user unless they're over 5 days old
|
// Don't send to a user unless they're over 5 days old
|
||||||
if (!user || user.createdTime > Date.now() - 5 * DAY_MS) return
|
if (!user || user.createdTime > Date.now() - 5 * DAY_MS)
|
||||||
|
return await setEmailFlagAsSent(privateUser.id)
|
||||||
const userBets = usersBets[privateUser.id] as Bet[]
|
const userBets = usersBets[privateUser.id] as Bet[]
|
||||||
const contractsUserBetOn = contractsUsersBetOn.filter((contract) =>
|
const contractsUserBetOn = contractsUsersBetOn.filter((contract) =>
|
||||||
userBets.some((bet) => bet.contractId === contract.id)
|
userBets.some((bet) => bet.contractId === contract.id)
|
||||||
|
@ -219,13 +218,6 @@ export async function sendPortfolioUpdateEmailsToAllUsers() {
|
||||||
(differences) => Math.abs(differences.profit)
|
(differences) => Math.abs(differences.profit)
|
||||||
).reverse()
|
).reverse()
|
||||||
|
|
||||||
log(
|
|
||||||
'Found',
|
|
||||||
investmentValueDifferences.length,
|
|
||||||
'investment differences for user',
|
|
||||||
privateUser.id
|
|
||||||
)
|
|
||||||
|
|
||||||
const [winningInvestments, losingInvestments] = partition(
|
const [winningInvestments, losingInvestments] = partition(
|
||||||
investmentValueDifferences.filter(
|
investmentValueDifferences.filter(
|
||||||
(diff) => diff.pastValue > 0.01 && Math.abs(diff.profit) > 1
|
(diff) => diff.pastValue > 0.01 && Math.abs(diff.profit) > 1
|
||||||
|
@ -245,29 +237,28 @@ export async function sendPortfolioUpdateEmailsToAllUsers() {
|
||||||
usersToContractsCreated[privateUser.id].length === 0
|
usersToContractsCreated[privateUser.id].length === 0
|
||||||
) {
|
) {
|
||||||
log(
|
log(
|
||||||
'No bets in last week, no market movers, no markets created. Not sending an email.'
|
`No bets in last week, no market movers, no markets created. Not sending an email to ${privateUser.email} .`
|
||||||
)
|
)
|
||||||
await firestore.collection('private-users').doc(privateUser.id).update({
|
return await setEmailFlagAsSent(privateUser.id)
|
||||||
weeklyPortfolioUpdateEmailSent: true,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
// Set the flag beforehand just to be safe
|
||||||
|
await setEmailFlagAsSent(privateUser.id)
|
||||||
await sendWeeklyPortfolioUpdateEmail(
|
await sendWeeklyPortfolioUpdateEmail(
|
||||||
user,
|
user,
|
||||||
privateUser,
|
privateUser,
|
||||||
topInvestments.concat(worstInvestments) as PerContractInvestmentsData[],
|
topInvestments.concat(worstInvestments) as PerContractInvestmentsData[],
|
||||||
performanceData
|
performanceData
|
||||||
)
|
)
|
||||||
await firestore.collection('private-users').doc(privateUser.id).update({
|
|
||||||
weeklyPortfolioUpdateEmailSent: true,
|
|
||||||
})
|
|
||||||
log('Sent weekly portfolio update email to', privateUser.email)
|
|
||||||
count++
|
|
||||||
log('sent out emails to users:', count)
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setEmailFlagAsSent(privateUserId: string) {
|
||||||
|
await firestore.collection('private-users').doc(privateUserId).update({
|
||||||
|
weeklyPortfolioUpdateEmailSent: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export type PerContractInvestmentsData = {
|
export type PerContractInvestmentsData = {
|
||||||
questionTitle: string
|
questionTitle: string
|
||||||
questionUrl: string
|
questionUrl: string
|
||||||
|
|
Loading…
Reference in New Issue
Block a user