mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #1025 from omnivore-app/fix/save-from-email
Add support to the case when from address is in Name <address> format
This commit is contained in:
commit
e68f34b7be
9 changed files with 49 additions and 23 deletions
|
|
@ -36,6 +36,7 @@
|
|||
"@sentry/integrations": "^6.19.1",
|
||||
"@sentry/node": "^5.26.0",
|
||||
"@sentry/tracing": "^5.26.0",
|
||||
"addressparser": "^1.0.1",
|
||||
"analytics-node": "^6.0.0",
|
||||
"apollo-datasource": "^3.3.1",
|
||||
"apollo-server-express": "^3.6.3",
|
||||
|
|
@ -87,6 +88,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/register": "^7.14.5",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||
"@types/addressparser": "^1.0.1",
|
||||
"@types/analytics-node": "^3.1.7",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/chai": "^4.2.18",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
getTitleFromEmailSubject,
|
||||
isProbablyArticle,
|
||||
isProbablyNewsletter,
|
||||
parseEmailAddress,
|
||||
} from '../../utils/parser'
|
||||
import { saveNewsletterEmail } from '../../services/save_newsletter_email'
|
||||
import { saveEmail } from '../../services/save_email'
|
||||
|
|
@ -75,6 +76,7 @@ export function emailsServiceRouter() {
|
|||
}
|
||||
const user = newsletterEmail.user
|
||||
const ctx = { pubsub: createPubSubClient(), uid: user.id }
|
||||
const parsedFrom = parseEmailAddress(data.from)
|
||||
|
||||
if (await isProbablyNewsletter(data.html)) {
|
||||
logger.info('handling as newsletter', data)
|
||||
|
|
@ -83,7 +85,7 @@ export function emailsServiceRouter() {
|
|||
email: data.to,
|
||||
title: data.subject,
|
||||
content: data.html,
|
||||
author: data.from,
|
||||
author: parsedFrom.name,
|
||||
url: (await findNewsletterUrl(data.html)) || generateUniqueUrl(),
|
||||
unsubMailTo: data.unsubMailTo,
|
||||
unsubHttpUrl: data.unsubHttpUrl,
|
||||
|
|
@ -95,11 +97,11 @@ export function emailsServiceRouter() {
|
|||
return
|
||||
}
|
||||
|
||||
if (await isProbablyArticle(data.from, data.subject)) {
|
||||
if (await isProbablyArticle(parsedFrom.address, data.subject)) {
|
||||
logger.info('handling as article', data)
|
||||
await saveEmail(ctx, {
|
||||
title: getTitleFromEmailSubject(data.subject),
|
||||
author: data.from,
|
||||
author: parsedFrom.name,
|
||||
url: generateUniqueUrl(),
|
||||
originalContent: data.html,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { getRepository } from '../entity/utils'
|
|||
import { User } from '../entity/user'
|
||||
import { ILike } from 'typeorm'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import addressparser from 'addressparser'
|
||||
|
||||
const logger = buildLogger('utils.parse')
|
||||
|
||||
|
|
@ -567,3 +568,14 @@ export const getTitleFromEmailSubject = (subject: string) => {
|
|||
const title = subject.replace(ARTICLE_PREFIX, '')
|
||||
return title.trim()
|
||||
}
|
||||
|
||||
export const parseEmailAddress = (from: string): addressparser.EmailAddress => {
|
||||
// get author name from email
|
||||
// e.g. 'Jackson Harper from Omnivore App <jacksonh@substack.com>'
|
||||
// or 'Mike Allen <mike@axios.com>'
|
||||
const parsed = addressparser(from)
|
||||
if (parsed.length > 0) {
|
||||
return parsed[0]
|
||||
}
|
||||
return { name: '', address: from }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const deleteTestUser = async (name: string) => {
|
|||
await AppDataSource.createQueryBuilder()
|
||||
.delete()
|
||||
.from(User)
|
||||
.where({ email: `${name}@fake.com` })
|
||||
.where({ email: `${name}@omnivore.app` })
|
||||
.execute()
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ export const createTestUser = async (
|
|||
const [newUser] = await createUser({
|
||||
provider: 'GOOGLE',
|
||||
sourceUserId: 'fake-user-id-' + name,
|
||||
email: `${name}@fake.com`,
|
||||
email: `${name}@omnivore.app`,
|
||||
username: name,
|
||||
bio: `i am ${name}`,
|
||||
name: name,
|
||||
|
|
@ -93,7 +93,7 @@ export const createUserWithoutProfile = async (name: string): Promise<User> => {
|
|||
return getRepository(User).save({
|
||||
source: 'GOOGLE',
|
||||
sourceUserId: 'fake-user-id-' + name,
|
||||
email: `${name}@fake.com`,
|
||||
email: `${name}@omnivore.app`,
|
||||
name: name,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ describe('Newsletters API', () => {
|
|||
// create test newsletter emails
|
||||
const newsletterEmail1 = await createTestNewsletterEmail(
|
||||
user,
|
||||
'Test_email_address_1@fake-email.com'
|
||||
'Test_email_address_1@omnivore.app'
|
||||
)
|
||||
const newsletterEmail2 = await createTestNewsletterEmail(
|
||||
user,
|
||||
'Test_email_address_2@fake-email.com'
|
||||
'Test_email_address_2@omnivore.app'
|
||||
)
|
||||
newsletterEmails = [newsletterEmail1, newsletterEmail2]
|
||||
})
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ describe('auth router', () => {
|
|||
before(() => {
|
||||
password = validPassword
|
||||
username = 'Some_username'
|
||||
email = `${username}@fake.com`
|
||||
email = `${username}@omnivore.app`
|
||||
name = 'Some name'
|
||||
})
|
||||
|
||||
|
|
@ -397,9 +397,7 @@ describe('auth router', () => {
|
|||
|
||||
it('redirects to forgot-password page with success message', async () => {
|
||||
const res = await emailResetPasswordReq(email).expect(302)
|
||||
expect(res.header.location).to.endWith(
|
||||
'/auth/reset-sent'
|
||||
)
|
||||
expect(res.header.location).to.endWith('/auth/reset-sent')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -434,9 +432,7 @@ describe('auth router', () => {
|
|||
|
||||
it('redirects to email-login page with error code PENDING_VERIFICATION', async () => {
|
||||
const res = await emailResetPasswordReq(email).expect(302)
|
||||
expect(res.header.location).to.endWith(
|
||||
'/auth/reset-sent'
|
||||
)
|
||||
expect(res.header.location).to.endWith('/auth/reset-sent')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -448,9 +444,7 @@ describe('auth router', () => {
|
|||
|
||||
it('redirects to forgot-password page with error code USER_NOT_FOUND', async () => {
|
||||
const res = await emailResetPasswordReq(email).expect(302)
|
||||
expect(res.header.location).to.endWith(
|
||||
'/auth/reset-sent'
|
||||
)
|
||||
expect(res.header.location).to.endWith('/auth/reset-sent')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -501,9 +495,7 @@ describe('auth router', () => {
|
|||
const res = await resetPasswordRequest(token, 'new_password').expect(
|
||||
302
|
||||
)
|
||||
expect(res.header.location).to.contain(
|
||||
'/api/client/auth?tok'
|
||||
)
|
||||
expect(res.header.location).to.contain('/api/client/auth?tok')
|
||||
})
|
||||
|
||||
it('resets password', async () => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { getPageById } from '../../src/elastic/pages'
|
|||
|
||||
describe('PDF attachments Router', () => {
|
||||
const username = 'fakeUser'
|
||||
const newsletterEmail = 'fakeEmail@fake-email.com'
|
||||
const newsletterEmail = 'fakeEmail@omnivore.app'
|
||||
|
||||
let user: User
|
||||
let authToken: string
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
getTitleFromEmailSubject,
|
||||
isProbablyArticle,
|
||||
isProbablyNewsletter,
|
||||
parseEmailAddress,
|
||||
parsePageMetadata,
|
||||
parsePreparedContent,
|
||||
} from '../../src/utils/parser'
|
||||
|
|
@ -179,3 +180,20 @@ describe('getTitleFromEmailSubject', () => {
|
|||
expect(getTitleFromEmailSubject(subject)).to.eql(title)
|
||||
})
|
||||
})
|
||||
|
||||
describe('parseEmailAddress', () => {
|
||||
it('returns the name and address when in name <address> format', () => {
|
||||
const name = 'test name'
|
||||
const address = 'tester@omnivore.app'
|
||||
const parsed = parseEmailAddress(`${name} <${address}>`)
|
||||
expect(parsed.name).to.eql(name)
|
||||
expect(parsed.address).to.eql(address)
|
||||
})
|
||||
|
||||
it('returns the address when in address format', () => {
|
||||
const address = 'tester@omnivore.app'
|
||||
const parsed = parseEmailAddress(address)
|
||||
expect(parsed.name).to.eql('')
|
||||
expect(parsed.address).to.eql(address)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8682,7 +8682,7 @@ address@^1.0.1:
|
|||
addressparser@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"
|
||||
integrity sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=
|
||||
integrity sha512-aQX7AISOMM7HFE0iZ3+YnD07oIeJqWGVnJ+ZIKaBZAk03ftmVYVqsGas/rbXKR21n4D/hKCSHypvcyOkds/xzg==
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.1"
|
||||
|
|
|
|||
Loading…
Reference in a new issue