Fix email notifications

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina Fefelova 2025-05-16 20:50:20 +04:00
parent 845ec007bf
commit d84955b67c
No known key found for this signature in database
GPG Key ID: 750D35EF042F0690
4 changed files with 133 additions and 49 deletions

View File

@ -45,4 +45,13 @@ export function createModel (builder: Builder): void {
builder.mixin(gmail.ids.EmailNotification, notification.class.NotificationType, serverNotification.mixin.TypeMatch, {
func: serverGmail.function.IsIncomingMessageTypeMatch
})
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverGmail.trigger.NotificationsHandler,
isAsync: true,
txMatch: {
_class: core.class.TxCreateDoc,
objectClass: notification.class.InboxNotification
}
})
}

View File

@ -44,6 +44,7 @@
"@hcengineering/gmail": "^0.6.22",
"@hcengineering/notification": "^0.6.23",
"@hcengineering/platform": "^0.6.11",
"@hcengineering/server-contact": "^0.6.1",
"@hcengineering/server-core": "^0.6.1",
"@hcengineering/server-notification": "^0.6.1",
"@hcengineering/server-notification-resources": "^0.6.0"

View File

@ -14,7 +14,7 @@
//
/* eslint-disable @typescript-eslint/no-unused-vars */
import contact, { Channel, formatName, Person } from '@hcengineering/contact'
import {
import core, {
PersonId,
Class,
concatLink,
@ -27,16 +27,27 @@ import {
Ref,
Tx,
TxCreateDoc,
TxProcessor
TxProcessor,
groupByArray,
SocialIdType
} from '@hcengineering/core'
import gmail, { Message } from '@hcengineering/gmail'
import { TriggerControl } from '@hcengineering/server-core'
import { NotificationType, InboxNotification } from '@hcengineering/notification'
import serverNotification, { ReceiverInfo, SenderInfo } from '@hcengineering/server-notification'
import { getContentByTemplate } from '@hcengineering/server-notification-resources'
import notification, {
NotificationType,
InboxNotification,
ActivityInboxNotification,
MentionInboxNotification
} from '@hcengineering/notification'
import serverNotification from '@hcengineering/server-notification'
import {
AvailableProvidersCache,
AvailableProvidersCacheKey,
getContentByTemplate
} from '@hcengineering/server-notification-resources'
import { getMetadata } from '@hcengineering/platform'
import { ActivityMessage } from '@hcengineering/activity'
import aiBot from '@hcengineering/ai-bot'
import activity, { ActivityMessage } from '@hcengineering/activity'
import { getEmployeeByAcc, getPerson } from '@hcengineering/server-contact'
/**
* @public
@ -139,50 +150,112 @@ export async function sendEmailNotification (
async function notifyByEmail (
control: TriggerControl,
type: Ref<NotificationType>,
doc: Doc | undefined,
sender: SenderInfo,
receiver: ReceiverInfo,
doc: Doc,
sender: Person | undefined,
senderSocialId: PersonId,
email: string,
data: InboxNotification,
message?: ActivityMessage
message: ActivityMessage
): Promise<void> {
// TODO: FIXME
// const account = receiver.account
// if (account === undefined) {
// return
// }
// const senderPerson = sender.person
// const senderName = senderPerson !== undefined ? formatName(senderPerson.name, control.branding?.lastNameFirst) : ''
// const content = await getContentByTemplate(doc, senderName, type, control, '', data, message)
// if (content !== undefined) {
// await sendEmailNotification(control.ctx, content.text, content.html, content.subject, account.email)
// }
let senderName = sender !== undefined ? formatName(sender.name, control.branding?.lastNameFirst) : ''
if (senderName === '' && senderSocialId === core.account.System) {
senderName = 'System'
}
const content = await getContentByTemplate(doc, senderName, type, control, '', data, message)
if (content !== undefined) {
await sendEmailNotification(control.ctx, content.text, content.html, content.subject, email)
}
}
const SendEmailNotifications = async (
control: TriggerControl,
types: NotificationType[],
object: Doc,
data: InboxNotification,
receiver: ReceiverInfo,
sender: SenderInfo,
message?: ActivityMessage
): Promise<Tx[]> => {
// TODO: FIXME
// if (types.length === 0) {
// return []
// }
async function getNotificationMessages (
notifications: InboxNotification[],
control: TriggerControl
): Promise<ActivityMessage[]> {
const { hierarchy } = control
const ids: Ref<ActivityMessage>[] = []
for (const n of notifications) {
if (hierarchy.isDerived(n._class, notification.class.ActivityInboxNotification)) {
const activityNotification = n as ActivityInboxNotification
ids.push(activityNotification.attachedTo)
} else if (hierarchy.isDerived(n._class, notification.class.MentionInboxNotification)) {
const mentionNotification = n as MentionInboxNotification
if (hierarchy.isDerived(mentionNotification.mentionedInClass, activity.class.ActivityMessage)) {
ids.push(mentionNotification.mentionedIn as Ref<ActivityMessage>)
}
}
}
// if (
// !receiver.person.active ||
// receiver.account._id === core.account.System ||
// receiver.account._id === aiBot.account.AIBot
// ) {
// return []
// }
if (ids.length === 0) return []
// for (const type of types) {
// await notifyByEmail(control, type._id, object, sender, receiver, data, message)
// }
return await control.findAll(control.ctx, activity.class.ActivityMessage, { _id: { $in: ids } })
}
async function processEmailNotifications (control: TriggerControl, notifications: InboxNotification[]): Promise<void> {
if (notifications.length === 0) return
const docId = notifications[0].objectId
const docClass = notifications[0].objectClass
const doc = (await control.findAll(control.ctx, docClass, { _id: docId }))[0]
if (doc === undefined) return
const messages = await getNotificationMessages(notifications, control)
const { hierarchy } = control
const senders = new Map<PersonId, Person>()
for (const n of notifications) {
const type = (n.types ?? [])[0]
if (type === undefined) continue
let message: ActivityMessage | undefined
if (hierarchy.isDerived(n._class, notification.class.ActivityInboxNotification)) {
const activityNotification = n as ActivityInboxNotification
message = messages.find((m) => m._id === activityNotification.attachedTo)
} else if (hierarchy.isDerived(n._class, notification.class.MentionInboxNotification)) {
const mentionNotification = n as MentionInboxNotification
if (hierarchy.isDerived(mentionNotification.mentionedInClass, activity.class.ActivityMessage)) {
message = messages.find((m) => m._id === mentionNotification.mentionedIn)
}
}
if (message === undefined) continue
const employee = await getEmployeeByAcc(control, n.user)
if (employee === undefined) continue
const emails = await control.findAll(control.ctx, contact.class.SocialIdentity, {
attachedTo: employee._id,
type: { $in: [SocialIdType.EMAIL, SocialIdType.GOOGLE] },
verifiedOn: { $gt: 0 }
})
if (emails.length === 0) continue
const senderSocialId = message.createdBy ?? message.modifiedBy
const sender = senders.get(senderSocialId) ?? (await getPerson(control, senderSocialId))
if (sender != null) {
senders.set(senderSocialId, sender)
}
await notifyByEmail(control, type, doc, sender, senderSocialId, emails[0].value, n, message)
}
}
async function NotificationsHandler (txes: TxCreateDoc<InboxNotification>[], control: TriggerControl): Promise<Tx[]> {
const availableProviders: AvailableProvidersCache = control.contextCache.get(AvailableProvidersCacheKey) ?? new Map()
const all: InboxNotification[] = txes
.map((tx) => TxProcessor.createDoc2Doc(tx))
.filter(
(it) => availableProviders.get(it._id)?.find((p) => p === gmail.providers.EmailNotificationProvider) !== undefined
)
if (all.length === 0) {
return []
}
const notificationsByDocId = groupByArray(all, (n) => n.objectId)
await Promise.all(
Array.from(notificationsByDocId.entries()).map(([docId, notifications]) =>
processEmailNotifications(control, notifications)
)
)
return []
}
@ -190,11 +263,11 @@ const SendEmailNotifications = async (
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnMessageCreate
OnMessageCreate,
NotificationsHandler
},
function: {
IsIncomingMessageTypeMatch,
FindMessages,
SendEmailNotifications
FindMessages
}
})

View File

@ -29,7 +29,8 @@ export const serverGmailId = 'server-gmail' as Plugin
*/
export default plugin(serverGmailId, {
trigger: {
OnMessageCreate: '' as Resource<TriggerFunc>
OnMessageCreate: '' as Resource<TriggerFunc>,
NotificationsHandler: '' as Resource<TriggerFunc>
},
function: {
IsIncomingMessageTypeMatch: '' as TypeMatchFunc,