Mail hook adjustments (#8385)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions

Signed-off-by: Nikolay Chunosov <Chunosov.N@gmail.com>
This commit is contained in:
Chunosov 2025-03-31 11:00:30 +07:00 committed by GitHub
parent 1d1593d77d
commit fca71b6a93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 43 additions and 24 deletions

View File

@ -643,7 +643,8 @@ export class PostgresAccountDB implements AccountDB {
this.getV2Migration2(),
this.getV2Migration3(),
this.getV3Migration(),
this.getV4Migration()
this.getV4Migration(),
this.getV4Migration1()
]
}
@ -878,4 +879,14 @@ export class PostgresAccountDB implements AccountDB {
`
]
}
private getV4Migration1 (): [string, string] {
return [
'account_db_v4_remove_mailbox_account_fk',
`
ALTER TABLE ${this.ns}.mailbox
DROP CONSTRAINT IF EXISTS mailbox_account_fk;
`
]
}
}

View File

@ -21,6 +21,7 @@ interface Config {
secret: string
accountsUrl: string
workspaceUrl: string
ignoredAddresses: string[]
}
const config: Config = {
@ -32,7 +33,8 @@ const config: Config = {
return process.env.WORKSPACE_URL
}
throw Error('WORKSPACE_URL env var is not set')
})()
})(),
ignoredAddresses: process.env.IGNORED_ADDRESSES?.split(',') ?? []
}
export default config

View File

@ -17,6 +17,7 @@ import { readEml, ReadedEmlJson } from 'eml-parse-js'
import { Request, Response } from 'express'
import { htmlToMarkup } from '@hcengineering/text-html'
import { createMessages } from './message'
import config from './config'
interface MtaMessage {
envelope: {
@ -38,6 +39,10 @@ export async function handleMtaHook (req: Request, res: Response): Promise<void>
const mta: MtaMessage = req.body
const from = { address: mta.envelope.from.address, name: '' }
if (config.ignoredAddresses.includes(from.address)) {
console.log(`Ignoring message from ${from.address}`)
return
}
const fromHeader = mta.message.headers.find((header) => header[0] === 'From')?.[1]
if (fromHeader !== undefined) {
from.name = extractContactName(fromHeader)

View File

@ -18,8 +18,8 @@ import {
type Ref,
type TxOperations,
generateId,
PersonUuid,
RateLimiter,
SocialIdType,
systemAccountUuid
} from '@hcengineering/core'
import { getClient as getAccountClient } from '@hcengineering/account-client'
@ -56,40 +56,40 @@ export async function createMessages (
const transactorUrl = wsInfo.endpoint.replace('ws://', 'http://').replace('wss://', 'https://')
const client = await createRestTxOperations(transactorUrl, wsInfo.workspace, wsInfo.token)
const fromPersonId = await ensureGlobalPerson(accountClient, mailId, from)
if (fromPersonId === undefined) {
const fromPerson = await ensureGlobalPerson(accountClient, mailId, from)
if (fromPerson === undefined) {
console.error(`[${mailId}] Unable to create message without a proper FROM`)
return
}
const toPersons: { address: string, socialId: PersonId }[] = []
const toPersons: { address: string, uuid: PersonUuid, socialId: PersonId }[] = []
for (const to of tos) {
const toPersonId = await ensureGlobalPerson(accountClient, mailId, to)
if (toPersonId === undefined) {
const toPerson = await ensureGlobalPerson(accountClient, mailId, to)
if (toPerson === undefined) {
continue
}
toPersons.push({ address: to.address, socialId: toPersonId })
toPersons.push({ address: to.address, ...toPerson })
}
if (toPersons.length === 0) {
console.error(`[${mailId}] Unable to create message without a proper TO`)
return
}
const modifiedBy = fromPersonId
const participants = [fromPersonId, ...toPersons.map((p) => p.socialId)]
const modifiedBy = fromPerson.socialId
const participants = [fromPerson.socialId, ...toPersons.map((p) => p.socialId)]
try {
const spaces = await getPersonSpaces(client, mailId, fromPersonId, from.address)
const spaces = await getPersonSpaces(client, mailId, fromPerson.uuid, from.address)
if (spaces.length > 0) {
await saveMessageToSpaces(client, mailId, spaces, participants, modifiedBy, subject, content, inReplyTo)
}
} catch (err) {
console.error(`[${mailId}] Failed to save message to personal spaces of ${fromPersonId} (${from.address})`, err)
console.error(`[${mailId}] Failed to save message to personal spaces of ${fromPerson.uuid} (${from.address})`, err)
}
for (const to of toPersons) {
try {
const spaces = await getPersonSpaces(client, mailId, to.socialId, to.address)
const spaces = await getPersonSpaces(client, mailId, to.uuid, to.address)
if (spaces.length > 0) {
await saveMessageToSpaces(client, mailId, spaces, participants, modifiedBy, subject, content, inReplyTo)
}
@ -102,14 +102,14 @@ export async function createMessages (
async function getPersonSpaces (
client: TxOperations,
mailId: string,
personId: PersonId,
personUuid: PersonUuid,
email: string
): Promise<PersonSpace[]> {
const socialIdents = await client.findAll(contact.class.SocialIdentity, { type: SocialIdType.EMAIL, value: email })
const personRefs = socialIdents.map((socialId) => socialId.attachedTo)
const persons = await client.findAll(contact.class.Person, { personUuid }, { projection: { _id: 1 } })
const personRefs = persons.map((p) => p._id)
const spaces = await client.findAll(contact.class.PersonSpace, { person: { $in: personRefs } })
if (spaces.length === 0) {
console.log(`[${mailId}] No personal space found for ${personId} (${email}), skip`)
console.log(`[${mailId}] No personal space found for ${personUuid} (${email}), skip`)
}
return spaces
}

View File

@ -20,17 +20,18 @@ export async function ensureGlobalPerson (
client: AccountClient,
mailId: string,
contact: { address: string, name: string }
): Promise<PersonId | undefined> {
): Promise<{ socialId: PersonId, uuid: PersonUuid } | undefined> {
const socialKey = buildSocialIdString({ type: SocialIdType.EMAIL, value: contact.address })
const personId = await client.findSocialIdBySocialKey(socialKey)
if (personId !== undefined) {
console.log(`[${mailId}] Found global person for ${contact.address}: ${personId}`)
return personId
const socialId = await client.findSocialIdBySocialKey(socialKey)
const uuid = await client.findPersonBySocialKey(socialKey)
if (socialId !== undefined && uuid !== undefined) {
console.log(`[${mailId}] Found global person for ${contact.address}: ${uuid}`)
return { socialId, uuid }
}
const [firstName, lastName] = contact.name.split(' ')
try {
const globalPerson = await client.ensurePerson(SocialIdType.EMAIL, contact.address, firstName, lastName)
return globalPerson.socialId
return globalPerson
} catch (err) {
console.error(`[${mailId}] Failed to create global person for ${contact.address}`, err)
}