mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-11 09:51:53 +00:00
Mailbox fixes (#8406)
Signed-off-by: Nikolay Chunosov <Chunosov.N@gmail.com>
This commit is contained in:
parent
b104585c92
commit
a226f9aa0e
@ -12,8 +12,8 @@
|
||||
"webpack": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=development webpack --stats-error-details --progress -w",
|
||||
"devp": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=production CLIENT_TYPE=dev webpack --progress -w",
|
||||
"dev": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=development webpack --progress -w",
|
||||
"start": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=production electron .",
|
||||
"start-dev": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=development electron .",
|
||||
"start": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=production electron --no-sandbox .",
|
||||
"start-dev": "cross-env MODEL_VERSION=$(node ../common/scripts/show_version.js) VERSION=$(node ../common/scripts/show_tag.js) NODE_ENV=development electron --no-sandbox .",
|
||||
"format": "format",
|
||||
"bump": "bump-package-version"
|
||||
},
|
||||
|
@ -89,6 +89,7 @@ import '@hcengineering/lead-assets'
|
||||
import '@hcengineering/login-assets'
|
||||
import '@hcengineering/love-assets'
|
||||
import '@hcengineering/notification-assets'
|
||||
import '@hcengineering/my-space-assets'
|
||||
import '@hcengineering/preference-assets'
|
||||
import '@hcengineering/print-assets'
|
||||
import '@hcengineering/process-assets'
|
||||
@ -361,6 +362,7 @@ export async function configurePlatform (): Promise<void> {
|
||||
addLocation(mySpaceId, () => import(/* webpackChunkName: "card" */ '@hcengineering/my-space-resources'))
|
||||
addLocation(chatId, () => import(/* webpackChunkName: "chat" */ '@hcengineering/chat-resources'))
|
||||
addLocation(inboxId, () => import(/* webpackChunkName: "inbox" */ '@hcengineering/inbox-resources'))
|
||||
addLocation(mailId, () => import(/* webpackChunkName: "card" */ '@hcengineering/mail-resources'))
|
||||
addLocation(processId, () => import(/* webpackChunkName: "process" */ '@hcengineering/process-resources'))
|
||||
|
||||
setMetadata(client.metadata.FilterModel, 'ui')
|
||||
|
@ -124,6 +124,7 @@ import '@hcengineering/view-assets'
|
||||
import '@hcengineering/workbench-assets'
|
||||
import '@hcengineering/chat-assets'
|
||||
import '@hcengineering/inbox-assets'
|
||||
import '@hcengineering/mail-assets'
|
||||
import '@hcengineering/github-assets'
|
||||
|
||||
import { coreId } from '@hcengineering/core'
|
||||
|
@ -93,7 +93,7 @@ export interface AccountClient {
|
||||
findPersonBySocialId: (socialId: PersonId, requireAccount?: boolean) => Promise<PersonUuid | undefined>
|
||||
findSocialIdBySocialKey: (socialKey: string) => Promise<PersonId | undefined>
|
||||
getMailboxOptions: () => Promise<MailboxOptions>
|
||||
createMailbox: (name: string, domain: string) => Promise<void>
|
||||
createMailbox: (name: string, domain: string) => Promise<{ mailbox: string, socialId: PersonId }>
|
||||
getMailboxes: () => Promise<MailboxInfo[]>
|
||||
deleteMailbox: (mailbox: string) => Promise<void>
|
||||
|
||||
@ -653,13 +653,13 @@ class AccountClientImpl implements AccountClient {
|
||||
return await this.rpc(request)
|
||||
}
|
||||
|
||||
async createMailbox (name: string, domain: string): Promise<void> {
|
||||
async createMailbox (name: string, domain: string): Promise<{ mailbox: string, socialId: PersonId }> {
|
||||
const request = {
|
||||
method: 'createMailbox' as const,
|
||||
params: { name, domain }
|
||||
}
|
||||
|
||||
await this.rpc(request)
|
||||
return await this.rpc(request)
|
||||
}
|
||||
|
||||
async getMailboxes (): Promise<MailboxInfo[]> {
|
||||
|
@ -14,12 +14,14 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MailboxOptions } from '@hcengineering/account-client'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import { Dropdown, ListItem, Modal, ModernEditbox, Spinner, themeStore } from '@hcengineering/ui'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getAccountClient } from '../utils'
|
||||
import { IntlString, translateCB } from '@hcengineering/platform'
|
||||
import contact, { getCurrentEmployee, SocialIdentity } from '@hcengineering/contact'
|
||||
import { buildSocialIdString, Ref, SocialIdType } from '@hcengineering/core'
|
||||
|
||||
export let mailboxOptions: MailboxOptions
|
||||
|
||||
@ -39,10 +41,42 @@
|
||||
return n.length >= mailboxOptions.minNameLength && n.length <= mailboxOptions.maxNameLength
|
||||
}
|
||||
|
||||
async function createMailbox (): Promise<void> {
|
||||
const { mailbox, socialId } = await getAccountClient().createMailbox(name, (domain ?? domains[0])._id)
|
||||
console.log('Mailbox created', mailbox, socialId)
|
||||
const currentUser = getCurrentEmployee()
|
||||
const client = getClient()
|
||||
await client.addCollection(
|
||||
contact.class.SocialIdentity,
|
||||
contact.space.Contacts,
|
||||
currentUser,
|
||||
contact.class.Person,
|
||||
'socialIds',
|
||||
{
|
||||
key: buildSocialIdString({ type: SocialIdType.EMAIL, value: mailbox }),
|
||||
type: SocialIdType.EMAIL,
|
||||
value: mailbox,
|
||||
verifiedOn: Date.now()
|
||||
},
|
||||
socialId as any as Ref<SocialIdentity>
|
||||
)
|
||||
await client.addCollection(
|
||||
contact.class.Channel,
|
||||
contact.space.Contacts,
|
||||
currentUser,
|
||||
contact.class.Person,
|
||||
'channels',
|
||||
{
|
||||
provider: contact.channelProvider.Email,
|
||||
value: mailbox
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function save (): Promise<void> {
|
||||
loading = true
|
||||
try {
|
||||
await getAccountClient().createMailbox(name, (domain ?? domains[0])._id)
|
||||
await createMailbox()
|
||||
loading = false
|
||||
dispatch('close', true)
|
||||
} catch (err: any) {
|
||||
|
@ -25,29 +25,19 @@
|
||||
} from '@hcengineering/ui'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { MailboxInfo } from '@hcengineering/account-client'
|
||||
import { MessageBox } from '@hcengineering/presentation'
|
||||
import { getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { getAccountClient } from '../utils'
|
||||
import contact, { getCurrentEmployee } from '@hcengineering/contact'
|
||||
import { buildSocialIdString, SocialIdType } from '@hcengineering/core'
|
||||
|
||||
export let mailbox: MailboxInfo
|
||||
export let mailboxIdx: number
|
||||
export let loadingRequested: () => void
|
||||
export let reloadRequested: () => void
|
||||
|
||||
let opened = false
|
||||
|
||||
function getMenuItems (mailbox: MailboxInfo): (DropdownIntlItem & { action: () => void })[] {
|
||||
return [
|
||||
{
|
||||
id: 'delete',
|
||||
icon: IconDelete,
|
||||
label: setting.string.DeleteMailbox,
|
||||
action: () => {
|
||||
deleteMailbox(mailbox)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function deleteMailbox (mailbox: MailboxInfo): void {
|
||||
function deleteMailboxAction (): void {
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
@ -56,24 +46,71 @@
|
||||
dangerous: true,
|
||||
okLabel: setting.string.Delete,
|
||||
action: async () => {
|
||||
getAccountClient()
|
||||
.deleteMailbox(mailbox.mailbox)
|
||||
.then(() => {
|
||||
reloadRequested()
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error('Failed to delete mailbox', err)
|
||||
})
|
||||
loadingRequested()
|
||||
try {
|
||||
await deleteMailbox()
|
||||
} catch (err) {
|
||||
console.error('Failed to delete mailbox', err)
|
||||
}
|
||||
reloadRequested()
|
||||
}
|
||||
},
|
||||
undefined
|
||||
)
|
||||
}
|
||||
|
||||
const openMailboxMenu = (mailbox: MailboxInfo, ev: MouseEvent): void => {
|
||||
async function deleteMailbox (): Promise<void> {
|
||||
await getAccountClient().deleteMailbox(mailbox.mailbox)
|
||||
const client = getClient()
|
||||
const currentUser = getCurrentEmployee()
|
||||
const socialIds = await client.findAll(contact.class.SocialIdentity, {
|
||||
attachedTo: currentUser,
|
||||
type: SocialIdType.EMAIL,
|
||||
value: mailbox.mailbox
|
||||
})
|
||||
for (const socialId of socialIds) {
|
||||
const value = `${socialId.value}#${socialId._id}`
|
||||
await client.updateCollection(
|
||||
socialId._class,
|
||||
socialId.space,
|
||||
socialId._id,
|
||||
socialId.attachedTo,
|
||||
socialId.attachedToClass,
|
||||
socialId.collection,
|
||||
{
|
||||
value,
|
||||
key: buildSocialIdString({ type: SocialIdType.EMAIL, value })
|
||||
}
|
||||
)
|
||||
}
|
||||
const channels = await client.findAll(contact.class.Channel, {
|
||||
attachedTo: currentUser,
|
||||
provider: contact.channelProvider.Email,
|
||||
value: mailbox.mailbox
|
||||
})
|
||||
for (const channel of channels) {
|
||||
await client.removeCollection(
|
||||
channel._class,
|
||||
channel.space,
|
||||
channel._id,
|
||||
channel.attachedTo,
|
||||
channel.attachedToClass,
|
||||
channel.collection
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const openMailboxMenu = (ev: MouseEvent): void => {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
const items = getMenuItems(mailbox)
|
||||
const items: (DropdownIntlItem & { action: () => void })[] = [
|
||||
{
|
||||
id: 'delete',
|
||||
icon: IconDelete,
|
||||
label: setting.string.DeleteMailbox,
|
||||
action: deleteMailboxAction
|
||||
}
|
||||
]
|
||||
showPopup(ModernPopup, { items }, eventToHTMLElement(ev), (result) => {
|
||||
items.find((it) => it.id === result)?.action()
|
||||
opened = false
|
||||
@ -94,9 +131,7 @@
|
||||
pressed={opened}
|
||||
inheritColor
|
||||
hasMenu
|
||||
on:click={(ev) => {
|
||||
openMailboxMenu(mailbox, ev)
|
||||
}}
|
||||
on:click={openMailboxMenu}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -119,7 +119,14 @@
|
||||
{:else}
|
||||
<Scroller>
|
||||
{#each mailboxes as mailbox, i}
|
||||
<MailboxItem {mailbox} mailboxIdx={i} reloadRequested={loadMailboxes} />
|
||||
<MailboxItem
|
||||
{mailbox}
|
||||
mailboxIdx={i}
|
||||
reloadRequested={loadMailboxes}
|
||||
loadingRequested={() => {
|
||||
boxesLoading = true
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</Scroller>
|
||||
{/if}
|
||||
|
@ -2032,7 +2032,7 @@ async function createMailbox (
|
||||
name: string
|
||||
domain: string
|
||||
}
|
||||
): Promise<void> {
|
||||
): Promise<{ mailbox: string, socialId: PersonId }> {
|
||||
const { account } = decodeTokenVerbose(ctx, token)
|
||||
const { name, domain } = params
|
||||
const normalizedName = cleanEmail(name)
|
||||
@ -2060,7 +2060,14 @@ async function createMailbox (
|
||||
|
||||
await db.mailbox.insertOne({ accountUuid: account, mailbox })
|
||||
await db.mailboxSecret.insertOne({ mailbox, secret: generatePassword() })
|
||||
await db.socialId.insertOne({ personUuid: account, type: SocialIdType.EMAIL, value: mailbox })
|
||||
const socialId: PersonId = await db.socialId.insertOne({
|
||||
personUuid: account,
|
||||
type: SocialIdType.EMAIL,
|
||||
value: mailbox,
|
||||
verifiedOn: Date.now()
|
||||
})
|
||||
ctx.info('Mailbox created', { mailbox, account, socialId })
|
||||
return { mailbox, socialId }
|
||||
}
|
||||
|
||||
async function getMailboxes (
|
||||
@ -2081,15 +2088,33 @@ async function deleteMailbox (
|
||||
params: { mailbox: string }
|
||||
): Promise<void> {
|
||||
const { account } = decodeTokenVerbose(ctx, token)
|
||||
const { mailbox } = params
|
||||
const mailbox = cleanEmail(params.mailbox)
|
||||
|
||||
if (!isEmail(mailbox)) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.MailboxError, { reason: 'invalid-name' }))
|
||||
}
|
||||
|
||||
const mb = await db.mailbox.findOne({ mailbox, accountUuid: account })
|
||||
if (mb == null) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.MailboxError, { reason: 'mailbox-not-found' }))
|
||||
}
|
||||
|
||||
await db.mailbox.deleteMany({ mailbox })
|
||||
await db.mailboxSecret.deleteMany({ mailbox })
|
||||
await db.mailbox.deleteMany({ mailbox })
|
||||
await releaseSocialId(db, account, SocialIdType.EMAIL, mailbox)
|
||||
ctx.info('Mailbox deleted', { mailbox, account })
|
||||
}
|
||||
|
||||
async function releaseSocialId (
|
||||
db: AccountDB,
|
||||
personUuid: PersonUuid,
|
||||
type: SocialIdType,
|
||||
value: string
|
||||
): Promise<void> {
|
||||
const socialIds = await db.socialId.find({ personUuid, type, value })
|
||||
for (const socialId of socialIds) {
|
||||
await db.socialId.updateOne({ _id: socialId._id }, { value: `${socialId.value}#${socialId._id}` })
|
||||
}
|
||||
}
|
||||
|
||||
export type AccountMethods =
|
||||
|
@ -22,6 +22,7 @@ interface Config {
|
||||
accountsUrl: string
|
||||
workspaceUrl: string
|
||||
ignoredAddresses: string[]
|
||||
hookToken?: string
|
||||
}
|
||||
|
||||
const config: Config = {
|
||||
@ -34,7 +35,8 @@ const config: Config = {
|
||||
}
|
||||
throw Error('WORKSPACE_URL env var is not set')
|
||||
})(),
|
||||
ignoredAddresses: process.env.IGNORED_ADDRESSES?.split(',') ?? []
|
||||
ignoredAddresses: process.env.IGNORED_ADDRESSES?.split(',') ?? [],
|
||||
hookToken: process.env.HOOK_TOKEN
|
||||
}
|
||||
|
||||
export default config
|
||||
|
@ -36,6 +36,13 @@ interface MtaMessage {
|
||||
|
||||
export async function handleMtaHook (req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
if (config.hookToken !== undefined) {
|
||||
const token = req.headers['x-hook-token']
|
||||
if (token !== config.hookToken) {
|
||||
throw new Error('Invalid hook token')
|
||||
}
|
||||
}
|
||||
|
||||
const mta: MtaMessage = req.body
|
||||
|
||||
const from = { address: mta.envelope.from.address, name: '' }
|
||||
@ -119,5 +126,31 @@ async function getContent (mta: MtaMessage): Promise<string> {
|
||||
function extractContactName (fromHeader: string): string {
|
||||
// Match name part that appears before an email in angle brackets
|
||||
const nameMatch = fromHeader.match(/^\s*"?([^"<]+?)"?\s*<.+?>/)
|
||||
return nameMatch?.[1].trim() ?? ''
|
||||
const name = nameMatch?.[1].trim() ?? ''
|
||||
if (name.length > 0) {
|
||||
return decodeMimeWord(name)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function decodeMimeWord (text: string): string {
|
||||
return text.replace(/=\?([^?]+)\?([BQ])\?([^?]+)\?=/gi, (match, charset, encoding, content) => {
|
||||
try {
|
||||
if (encoding.toUpperCase() === 'B') {
|
||||
// Base64 encoding
|
||||
const buffer = Buffer.from(content, 'base64')
|
||||
return buffer.toString(charset as BufferEncoding)
|
||||
} else if (encoding.toUpperCase() === 'Q') {
|
||||
// Quoted-printable encoding
|
||||
const decoded = content
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/=([0-9A-F]{2})/gi, (_: any, hex: string) => String.fromCharCode(parseInt(hex, 16)))
|
||||
return Buffer.from(decoded).toString(charset as BufferEncoding)
|
||||
}
|
||||
return match
|
||||
} catch (error) {
|
||||
console.warn('Failed to decode encoded word:', match, error)
|
||||
return match
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ async function main (): Promise<void> {
|
||||
|
||||
const server = app.listen(config.port, () => {
|
||||
console.log(`server started on port ${config.port}`)
|
||||
console.log({ ...config, secret: '(stripped)' })
|
||||
console.log({ ...config, secret: '(stripped)', hookToken: '(stripped)' })
|
||||
})
|
||||
|
||||
const shutdown = (): void => {
|
||||
|
@ -29,7 +29,7 @@ import chunter from '@hcengineering/chunter'
|
||||
import contact, { PersonSpace } from '@hcengineering/contact'
|
||||
import mail from '@hcengineering/mail'
|
||||
import config from './config'
|
||||
import { ensureGlobalPerson } from './person'
|
||||
import { ensureGlobalPerson, ensureLocalPerson } from './person'
|
||||
|
||||
function generateToken (): string {
|
||||
return encode(
|
||||
@ -61,6 +61,21 @@ export async function createMessages (
|
||||
console.error(`[${mailId}] Unable to create message without a proper FROM`)
|
||||
return
|
||||
}
|
||||
try {
|
||||
await ensureLocalPerson(
|
||||
client,
|
||||
mailId,
|
||||
fromPerson.uuid,
|
||||
fromPerson.socialId,
|
||||
from.address,
|
||||
fromPerson.firstName,
|
||||
fromPerson.lastName
|
||||
)
|
||||
} catch (err) {
|
||||
console.error(`[${mailId}] Failed to ensure local FROM person`, err)
|
||||
console.error(`[${mailId}] Unable to create message without a proper FROM`)
|
||||
return
|
||||
}
|
||||
|
||||
const toPersons: { address: string, uuid: PersonUuid, socialId: PersonId }[] = []
|
||||
for (const to of tos) {
|
||||
@ -68,6 +83,20 @@ export async function createMessages (
|
||||
if (toPerson === undefined) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
await ensureLocalPerson(
|
||||
client,
|
||||
mailId,
|
||||
toPerson.uuid,
|
||||
toPerson.socialId,
|
||||
to.address,
|
||||
toPerson.firstName,
|
||||
toPerson.lastName
|
||||
)
|
||||
} catch (err) {
|
||||
console.error(`[${mailId}] Failed to ensure local TO person, skip`, err)
|
||||
continue
|
||||
}
|
||||
toPersons.push({ address: to.address, ...toPerson })
|
||||
}
|
||||
if (toPersons.length === 0) {
|
||||
|
@ -12,26 +12,34 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import { buildSocialIdString, generateId, PersonId, PersonUuid, SocialIdType, TxOperations } from '@hcengineering/core'
|
||||
import contact, { AvatarType, combineName } from '@hcengineering/contact'
|
||||
import {
|
||||
buildSocialIdString,
|
||||
generateId,
|
||||
PersonId,
|
||||
PersonUuid,
|
||||
Ref,
|
||||
SocialIdType,
|
||||
TxOperations
|
||||
} from '@hcengineering/core'
|
||||
import contact, { AvatarType, combineName, SocialIdentity } from '@hcengineering/contact'
|
||||
import { AccountClient } from '@hcengineering/account-client'
|
||||
|
||||
export async function ensureGlobalPerson (
|
||||
client: AccountClient,
|
||||
mailId: string,
|
||||
contact: { address: string, name: string }
|
||||
): Promise<{ socialId: PersonId, uuid: PersonUuid } | undefined> {
|
||||
): Promise<{ socialId: PersonId, uuid: PersonUuid, firstName: string, lastName: string } | undefined> {
|
||||
const [firstName, lastName] = contact.name.split(' ')
|
||||
const socialKey = buildSocialIdString({ type: SocialIdType.EMAIL, value: contact.address })
|
||||
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 }
|
||||
return { socialId, uuid, firstName, lastName }
|
||||
}
|
||||
const [firstName, lastName] = contact.name.split(' ')
|
||||
try {
|
||||
const globalPerson = await client.ensurePerson(SocialIdType.EMAIL, contact.address, firstName, lastName)
|
||||
return globalPerson
|
||||
console.log(`[${mailId}] Created global person for ${contact.address}: ${globalPerson.uuid}`)
|
||||
return { ...globalPerson, firstName, lastName }
|
||||
} catch (err) {
|
||||
console.error(`[${mailId}] Failed to create global person for ${contact.address}`, err)
|
||||
}
|
||||
@ -40,21 +48,14 @@ export async function ensureGlobalPerson (
|
||||
|
||||
export async function ensureLocalPerson (
|
||||
client: TxOperations,
|
||||
mailId: string,
|
||||
personUuid: PersonUuid,
|
||||
socialId: PersonId,
|
||||
personId: PersonId,
|
||||
email: string,
|
||||
firstName: string,
|
||||
lastName: string
|
||||
): Promise<void> {
|
||||
let person = await client.findOne(
|
||||
contact.class.Person,
|
||||
{
|
||||
personUuid
|
||||
},
|
||||
{
|
||||
projection: { name: 1 }
|
||||
}
|
||||
)
|
||||
let person = await client.findOne(contact.class.Person, { personUuid })
|
||||
if (person === undefined) {
|
||||
const newPersonId = await client.createDoc(
|
||||
contact.class.Person,
|
||||
@ -69,7 +70,16 @@ export async function ensureLocalPerson (
|
||||
person = await client.findOne(contact.class.Person, { _id: newPersonId })
|
||||
if (person === undefined) {
|
||||
throw new Error(`Failed to create local person for ${personUuid}`)
|
||||
} else {
|
||||
console.log(`[${mailId}] Created local person for ${personUuid}: ${person._id}`)
|
||||
}
|
||||
}
|
||||
const socialId = await client.findOne(contact.class.SocialIdentity, {
|
||||
attachedTo: person._id,
|
||||
type: SocialIdType.EMAIL,
|
||||
value: email
|
||||
})
|
||||
if (socialId === undefined) {
|
||||
await client.addCollection(
|
||||
contact.class.SocialIdentity,
|
||||
contact.space.Contacts,
|
||||
@ -77,12 +87,13 @@ export async function ensureLocalPerson (
|
||||
contact.class.Person,
|
||||
'socialIds',
|
||||
{
|
||||
key: socialId,
|
||||
key: buildSocialIdString({ type: SocialIdType.EMAIL, value: email }),
|
||||
type: SocialIdType.EMAIL,
|
||||
value: email
|
||||
},
|
||||
generateId()
|
||||
personId as any as Ref<SocialIdentity>
|
||||
)
|
||||
console.log(`[${mailId}] Created local socialId for ${personUuid}: ${email}`)
|
||||
}
|
||||
const channel = await client.findOne(contact.class.Channel, {
|
||||
attachedTo: person._id,
|
||||
@ -103,5 +114,6 @@ export async function ensureLocalPerson (
|
||||
},
|
||||
generateId()
|
||||
)
|
||||
console.log(`[${mailId}] Created channel for ${personUuid}: ${email}`)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user