Send emails for new comments on markets you commented on or created.
This commit is contained in:
parent
a6657a28fd
commit
7522b6af3c
|
@ -28,6 +28,7 @@ export type PrivateUser = {
|
|||
|
||||
email?: string
|
||||
unsubscribedFromResolutionEmails?: boolean
|
||||
unsubscribedFromCommentEmails?: boolean
|
||||
initialDeviceToken?: string
|
||||
initialIpAddress?: string
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import _ = require('lodash')
|
||||
import { getProbability } from '../../common/calculate'
|
||||
import { Comment } from '../../common/comment'
|
||||
import { Contract } from '../../common/contract'
|
||||
import { CREATOR_FEE } from '../../common/fees'
|
||||
import { PrivateUser, User } from '../../common/user'
|
||||
import { formatMoney, formatPercent } from '../../common/util/format'
|
||||
import { sendTemplateEmail, sendTextEmail } from './send-email'
|
||||
import { getPrivateUser, getUser } from './utils'
|
||||
import { getPrivateUser, getUser, isProd } from './utils'
|
||||
|
||||
type market_resolved_template = {
|
||||
userId: string
|
||||
|
@ -138,3 +139,48 @@ export const sendMarketCloseEmail = async (
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const sendNewCommentEmail = async (
|
||||
userId: string,
|
||||
commentCreator: User,
|
||||
comment: Comment,
|
||||
contract: Contract
|
||||
) => {
|
||||
const privateUser = await getPrivateUser(userId)
|
||||
if (
|
||||
!privateUser ||
|
||||
privateUser.unsubscribedFromCommentEmails ||
|
||||
!privateUser.email
|
||||
)
|
||||
return
|
||||
|
||||
const user = await getUser(userId)
|
||||
if (!user) return
|
||||
|
||||
const { question, creatorUsername, slug } = contract
|
||||
const marketUrl = `https://manifold.markets/${creatorUsername}/${slug}`
|
||||
|
||||
const unsubscribeUrl = `https://us-central1-${
|
||||
isProd ? 'mantic-markets' : 'dev-mantic-markets'
|
||||
}.cloudfunctions.net/unsubscribe?id=${userId}&type=market-comment`
|
||||
|
||||
const { name: commentorName, avatarUrl: commentorAvatarUrl } = commentCreator
|
||||
const { text } = comment
|
||||
|
||||
const subject = `Comment on ${question}`
|
||||
const from = `${commentorName} <info@manifold.markets>`
|
||||
|
||||
await sendTemplateEmail(
|
||||
privateUser.email,
|
||||
subject,
|
||||
'market-comment',
|
||||
{
|
||||
commentorName,
|
||||
commentorAvatarUrl: commentorAvatarUrl ?? '',
|
||||
comment: text,
|
||||
marketUrl,
|
||||
unsubscribeUrl,
|
||||
},
|
||||
{ from }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ export * from './create-contract'
|
|||
export * from './create-user'
|
||||
export * from './create-fold'
|
||||
export * from './create-answer'
|
||||
export * from './on-create-comment'
|
||||
export * from './on-fold-follow'
|
||||
export * from './on-fold-delete'
|
||||
export * from './unsubscribe'
|
||||
|
|
40
functions/src/on-create-comment.ts
Normal file
40
functions/src/on-create-comment.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
import * as _ from 'lodash'
|
||||
|
||||
import { getContract, getUser, getValues } from './utils'
|
||||
import { Comment } from '../../common/comment'
|
||||
import { sendNewCommentEmail } from './emails'
|
||||
|
||||
const firestore = admin.firestore()
|
||||
|
||||
export const onCreateComment = functions.firestore
|
||||
.document('contracts/{contractId}/comments/{commentId}')
|
||||
.onCreate(async (change, context) => {
|
||||
const { contractId } = context.params as {
|
||||
contractId: string
|
||||
}
|
||||
|
||||
const contract = await getContract(contractId)
|
||||
if (!contract) return
|
||||
|
||||
const comment = change.data() as Comment
|
||||
|
||||
const commentCreator = await getUser(comment.userId)
|
||||
if (!commentCreator) return
|
||||
|
||||
const comments = await getValues<Comment>(
|
||||
firestore.collection('contracts').doc(contractId).collection('comments')
|
||||
)
|
||||
|
||||
const recipientUserIds = _.uniq([
|
||||
contract.creatorId,
|
||||
...comments.map((comment) => comment.userId),
|
||||
]).filter((id) => id !== comment.userId)
|
||||
|
||||
await Promise.all(
|
||||
recipientUserIds.map((userId) =>
|
||||
sendNewCommentEmail(userId, commentCreator, comment, contract)
|
||||
)
|
||||
)
|
||||
})
|
|
@ -24,10 +24,11 @@ export const sendTemplateEmail = (
|
|||
to: string,
|
||||
subject: string,
|
||||
templateId: string,
|
||||
templateData: Record<string, string>
|
||||
templateData: Record<string, string>,
|
||||
options?: { from: string }
|
||||
) => {
|
||||
const data = {
|
||||
from: 'Manifold Markets <info@manifold.markets>',
|
||||
from: options?.from ?? 'Manifold Markets <info@manifold.markets>',
|
||||
to,
|
||||
subject,
|
||||
template: templateId,
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as functions from 'firebase-functions'
|
|||
import * as admin from 'firebase-admin'
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import { payUser } from './utils'
|
||||
import { isProd, payUser } from './utils'
|
||||
|
||||
export type StripeTransaction = {
|
||||
userId: string
|
||||
|
@ -18,8 +18,7 @@ const stripe = new Stripe(functions.config().stripe.apikey, {
|
|||
})
|
||||
|
||||
// manage at https://dashboard.stripe.com/test/products?active=true
|
||||
const manticDollarStripePrice =
|
||||
admin.instanceId().app.options.projectId === 'mantic-markets'
|
||||
const manticDollarStripePrice = isProd
|
||||
? {
|
||||
500: 'price_1KFQXcGdoFKoCJW770gTNBrm',
|
||||
1000: 'price_1KFQp1GdoFKoCJW7Iu0dsF65',
|
||||
|
|
|
@ -1,30 +1,36 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
import * as _ from 'lodash'
|
||||
import { getPrivateUser } from './utils'
|
||||
import { getUser } from './utils'
|
||||
import { PrivateUser } from '../../common/user'
|
||||
|
||||
export const unsubscribe = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onRequest(async (req, res) => {
|
||||
let id = req.query.id as string
|
||||
if (!id) return
|
||||
const { id, type } = req.query as { id: string; type: string }
|
||||
if (!id || !type) return
|
||||
|
||||
let privateUser = await getPrivateUser(id)
|
||||
const user = await getUser(id)
|
||||
|
||||
if (privateUser) {
|
||||
let { username } = privateUser
|
||||
if (user) {
|
||||
const { name } = user
|
||||
|
||||
const update: Partial<PrivateUser> = {
|
||||
unsubscribedFromResolutionEmails: true,
|
||||
unsubscribedFromResolutionEmails: type === 'market-resolve',
|
||||
unsubscribedFromCommentEmails: type === 'market-comment',
|
||||
}
|
||||
|
||||
await firestore.collection('private-users').doc(id).update(update)
|
||||
|
||||
if (type === 'market-resolve')
|
||||
res.send(
|
||||
username +
|
||||
', you have been unsubscribed from market resolution emails on Manifold Markets.'
|
||||
`${name}, you have been unsubscribed from market resolution emails on Manifold Markets.`
|
||||
)
|
||||
else if (type === 'market-comment')
|
||||
res.send(
|
||||
`${name}, you have been unsubscribed from market comment emails on Manifold Markets.`
|
||||
)
|
||||
else res.send(`${name}, you have been unsubscribed.`)
|
||||
} else {
|
||||
res.send('This user is not currently subscribed or does not exist.')
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ import * as admin from 'firebase-admin'
|
|||
import { Contract } from '../../common/contract'
|
||||
import { PrivateUser, User } from '../../common/user'
|
||||
|
||||
export const isProd =
|
||||
admin.instanceId().app.options.projectId === 'mantic-markets'
|
||||
|
||||
export const getValue = async <T>(collection: string, doc: string) => {
|
||||
const snap = await admin.firestore().collection(collection).doc(doc).get()
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user