Better name for the save newsletter service

This commit is contained in:
Jackson Harper 2022-03-02 19:45:28 -08:00
parent d66c114a7d
commit 9206230659
3 changed files with 147 additions and 144 deletions

View file

@ -1,43 +1,13 @@
import express from 'express'
import {
createPubSubClient,
readPushSubscription,
} from '../../datalayer/pubsub'
import {
getNewsletterEmail,
updateConfirmationCode,
} from '../../services/newsletters'
import {
SaveContext,
saveEmail,
SaveEmailInput,
} from '../../services/save_email'
import { initModels } from '../../server'
import { kx } from '../../datalayer/knex_config'
import { analytics } from '../../utils/analytics'
import { env } from '../../env'
import { sendMulticastPushNotifications } from '../../utils/sendNotification'
import { getDeviceTokensByUserId } from '../../services/user_device_tokens'
import { messaging } from 'firebase-admin'
import { ContentReader } from '../../generated/graphql'
import { UserDeviceToken } from '../../entity/user_device_tokens'
import { UserArticleData } from '../../datalayer/links/model'
import { ArticleData } from '../../datalayer/article/model'
import MulticastMessage = messaging.MulticastMessage
import { readPushSubscription } from '../../datalayer/pubsub'
import { updateConfirmationCode } from '../../services/newsletters'
import { saveNewsletterEmail } from '../../services/save_newsletter_email'
interface SetConfirmationCodeMessage {
emailAddress: string
confirmationCode: string
}
interface NewsletterMessage {
email: string
content: string
url: string
title: string
author: string
}
export function newsletterServiceRouter() {
const router = express.Router()
@ -111,7 +81,7 @@ export function newsletterServiceRouter() {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const data: NewsletterMessage = JSON.parse(message)
const data = JSON.parse(message)
if (
!('email' in data) ||
@ -124,79 +94,15 @@ export function newsletterServiceRouter() {
return
}
// get user from newsletter email
const newsletterEmail = await getNewsletterEmail(data.email)
if (!newsletterEmail) {
console.log('newsletter email not found', data.email)
res.status(200).send('Not Found')
return
}
analytics.track({
userId: newsletterEmail.user.id,
event: 'newsletter_email_received',
properties: {
url: data.url,
title: data.title,
author: data.author,
env: env.server.apiEnv,
},
})
const ctx: SaveContext = {
models: initModels(kx, false),
pubsub: createPubSubClient(),
}
const input: SaveEmailInput = {
url: data.url,
originalContent: data.content,
title: data.title,
author: data.author,
}
const result = await saveEmail(ctx, newsletterEmail.user.id, input)
const result = await saveNewsletterEmail(data)
if (!result) {
console.log('newsletter not created:', input)
res.status(200).send(result)
console.log('Error createing newsletter link from data', data)
res.status(500).send('Error creating newsletter link')
return
}
// send push notification
const deviceTokens = await getDeviceTokensByUserId(
newsletterEmail.user.id
)
if (!deviceTokens) {
console.log('Device tokens not set:', newsletterEmail.user.id)
res.status(200).send('Device token Not Found')
return
}
const link = await ctx.models.userArticle.getForUser(
newsletterEmail.user.id,
result.articleId
)
if (!link) {
console.log(
'Newsletter link not found:',
newsletterEmail.user.id,
result.articleId
)
res.status(200).send(result)
return
}
if (deviceTokens.length) {
const multicastMessage = messageForLink(link, deviceTokens)
await sendMulticastPushNotifications(
newsletterEmail.user.id,
multicastMessage,
'newsletter'
)
}
// We always send 200 if it was a valid message
// because we don't want the
res.status(200).send('newsletter created')
} catch (e) {
console.log(e)
@ -211,43 +117,3 @@ export function newsletterServiceRouter() {
return router
}
const messageForLink = (
link: ArticleData & UserArticleData,
deviceTokens: UserDeviceToken[]
): MulticastMessage => {
let title = '📫 - An article was added to your Omnivore Inbox'
if (link.author) {
title = `📫 - ${link.author} has published a new article`
}
const pushData = !link
? undefined
: {
link: Buffer.from(
JSON.stringify({
id: link.id,
url: link.url,
slug: link.slug,
title: link.title,
image: link.image,
author: link.author,
isArchived: link.isArchived,
contentReader: ContentReader.Web,
readingProgressPercent: link.articleReadingProgress,
readingProgressAnchorIndex: link.articleReadingProgressAnchorIndex,
})
).toString('base64'),
}
return {
notification: {
title: title,
body: link.title,
imageUrl: link.image || undefined,
},
data: pushData,
tokens: deviceTokens.map((token) => token.token),
}
}

View file

@ -0,0 +1,137 @@
import { MulticastMessage } from 'firebase-admin/messaging'
import { ArticleData } from '../datalayer/article/model'
import { kx } from '../datalayer/knex_config'
import { UserArticleData } from '../datalayer/links/model'
import { createPubSubClient } from '../datalayer/pubsub'
import { UserDeviceToken } from '../entity/user_device_tokens'
import { env } from '../env'
import { ContentReader } from '../generated/graphql'
import { initModels } from '../server'
import { analytics } from '../utils/analytics'
import { sendMulticastPushNotifications } from '../utils/sendNotification'
import { getNewsletterEmail } from './newsletters'
import { SaveContext, saveEmail, SaveEmailInput } from './save_email'
import { getDeviceTokensByUserId } from './user_device_tokens'
interface NewsletterMessage {
email: string
content: string
url: string
title: string
author: string
}
// Returns true if the link was created successfully. Can still fail to
// send the push but that is ok and we wont retry in that case.
export const saveNewsletterEmail = async (
data: NewsletterMessage
): Promise<boolean> => {
// get user from newsletter email
const newsletterEmail = await getNewsletterEmail(data.email)
if (!newsletterEmail) {
console.log('newsletter email not found', data.email)
return false
}
analytics.track({
userId: newsletterEmail.user.id,
event: 'newsletter_email_received',
properties: {
url: data.url,
title: data.title,
author: data.author,
env: env.server.apiEnv,
},
})
const ctx: SaveContext = {
models: initModels(kx, false),
pubsub: createPubSubClient(),
}
const input: SaveEmailInput = {
url: data.url,
originalContent: data.content,
title: data.title,
author: data.author,
}
const result = await saveEmail(ctx, newsletterEmail.user.id, input)
if (!result) {
console.log('newsletter not created:', input)
return false
}
// send push notification
const deviceTokens = await getDeviceTokensByUserId(newsletterEmail.user.id)
if (!deviceTokens) {
console.log('Device tokens not set:', newsletterEmail.user.id)
return true
}
const link = await ctx.models.userArticle.getForUser(
newsletterEmail.user.id,
result.articleId
)
if (!link) {
console.log(
'Newsletter link not found:',
newsletterEmail.user.id,
result.articleId
)
return true
}
if (deviceTokens.length) {
const multicastMessage = messageForLink(link, deviceTokens)
await sendMulticastPushNotifications(
newsletterEmail.user.id,
multicastMessage,
'newsletter'
)
}
return true
}
const messageForLink = (
link: ArticleData & UserArticleData,
deviceTokens: UserDeviceToken[]
): MulticastMessage => {
let title = '📫 - An article was added to your Omnivore Inbox'
if (link.author) {
title = `📫 - ${link.author} has published a new article`
}
const pushData = !link
? undefined
: {
link: Buffer.from(
JSON.stringify({
id: link.id,
url: link.url,
slug: link.slug,
title: link.title,
image: link.image,
author: link.author,
isArchived: link.isArchived,
contentReader: ContentReader.Web,
readingProgressPercent: link.articleReadingProgress,
readingProgressAnchorIndex: link.articleReadingProgressAnchorIndex,
})
).toString('base64'),
}
return {
notification: {
title: title,
body: link.title,
imageUrl: link.image || undefined,
},
data: pushData,
tokens: deviceTokens.map((token) => token.token),
}
}

View file

@ -397,4 +397,4 @@ export const isProbablyNewsletter = (dom: DOMWindow): boolean => {
}
return false
};
}