mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Better name for the save newsletter service
This commit is contained in:
parent
d66c114a7d
commit
9206230659
3 changed files with 147 additions and 144 deletions
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
137
packages/api/src/services/save_newsletter_email.ts
Normal file
137
packages/api/src/services/save_newsletter_email.ts
Normal 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),
|
||||
}
|
||||
}
|
||||
|
|
@ -397,4 +397,4 @@ export const isProbablyNewsletter = (dom: DOMWindow): boolean => {
|
|||
}
|
||||
|
||||
return false
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue