Skip to content

Commit

Permalink
Fix email notifications (#6328)
Browse files Browse the repository at this point in the history
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
  • Loading branch information
kristina-fefelova authored Aug 13, 2024
1 parent cc7240c commit 071551c
Show file tree
Hide file tree
Showing 17 changed files with 134 additions and 37 deletions.
4 changes: 2 additions & 2 deletions models/chunter/src/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ export function defineNotifications (builder: Builder): void {
defaultEnabled: false,
group: chunter.ids.ChunterNotificationGroup,
templates: {
textTemplate: '{body}',
htmlTemplate: '<p>{body}</p>',
textTemplate: '{sender} replied to {doc}:\n\n{message}',
htmlTemplate: '<p><b>{sender}</b> replied to {doc}:</p><p>{message}</p><p>{link}</p>',
subjectTemplate: '{title}'
}
},
Expand Down
4 changes: 2 additions & 2 deletions models/notification/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,8 @@ export function createModel (builder: Builder): void {
group: notification.ids.NotificationGroup,
defaultEnabled: true,
templates: {
textTemplate: '{sender} mentioned you in {doc} {message}',
htmlTemplate: '<p>{sender}</b> mentioned you in {doc}</p> {message}',
textTemplate: '{sender} mentioned you in {doc}: {message}',
htmlTemplate: '<p><b>{sender}</b> mentioned you in {doc}:</p> <p>{message}</p> <p>{link}</p>',
subjectTemplate: 'You were mentioned in {doc}'
}
},
Expand Down
4 changes: 4 additions & 0 deletions models/server-chunter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export function createModel (builder: Builder): void {
presenter: serverChunter.function.ChatMessageTextPresenter
})

builder.mixin(chunter.class.ChatMessage, core.class.Class, serverNotification.mixin.HTMLPresenter, {
presenter: serverChunter.function.ChatMessageTextPresenter
})

builder.mixin<Class<Doc>, ObjectDDParticipant>(
chunter.class.ChatMessage,
core.class.Class,
Expand Down
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"CommonNotificationCollectionRemoved": "{senderName} removed {collection}",
"Sound": "Sound",
"SoundNotificationsDescription": "Receive sound notifications for events.",
"NoAccessToObject": "You no longer have access to this object"
"NoAccessToObject": "You no longer have access to this object",
"ViewIn": "View in {app}"
}
}
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"SoundNotificationsDescription": "Reciba notificaciones de sonido para eventos.",
"CommonNotificationCollectionAdded": "{senderName} añadió {collection}",
"CommonNotificationCollectionRemoved": "{senderName} eliminó {collection}",
"NoAccessToObject": "Ya no tienes acceso a este objeto"
"NoAccessToObject": "Ya no tienes acceso a este objeto",
"ViewIn": "Ver en {app}"
}
}
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"SoundNotificationsDescription": "Recevez des notifications sonores pour les événements.",
"CommonNotificationCollectionAdded": "{senderName} a ajouté {collection}",
"CommonNotificationCollectionRemoved": "{senderName} a supprimé {collection}",
"NoAccessToObject": "Vous n'avez plus accès à cet objet"
"NoAccessToObject": "Vous n'avez plus accès à cet objet",
"ViewIn": "Voir dans {app}"
}
}
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"SoundNotificationsDescription": "Receba notificações sonoras para eventos.",
"CommonNotificationCollectionAdded": "{senderName} adicionou {collection}",
"CommonNotificationCollectionRemoved": "{senderName} removeu {collection}",
"NoAccessToObject": "Você não tem mais acesso a este objeto"
"NoAccessToObject": "Você não tem mais acesso a este objeto",
"ViewIn": "Ver em {app}"
}
}
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"SoundNotificationsDescription": "Получайте звуковые уведомления о событиях.",
"CommonNotificationCollectionAdded": "{senderName} добавил {collection}",
"CommonNotificationCollectionRemoved": "{senderName} удалил {collection}",
"NoAccessToObject": "У вас больше нет доступа к этому объекту"
"NoAccessToObject": "У вас больше нет доступа к этому объекту",
"ViewIn": "Посмотреть в {app}"
}
}
3 changes: 2 additions & 1 deletion plugins/notification-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"SoundNotificationsDescription": "接收事件的声音通知。",
"CommonNotificationCollectionAdded": "{senderName} 添加了 {collection}",
"CommonNotificationCollectionRemoved": "{senderName} 移除了 {collection}",
"NoAccessToObject": "您不再可以访问此对象"
"NoAccessToObject": "您不再可以访问此对象",
"ViewIn": "在 {app} 中查看"
}
}
31 changes: 24 additions & 7 deletions plugins/notification-resources/src/components/inbox/Inbox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<script lang="ts">
import activity, { ActivityMessage } from '@hcengineering/activity'
import chunter from '@hcengineering/chunter'
import { getCurrentAccount, groupByArray, IdMap, Ref, SortingOrder, Space } from '@hcengineering/core'
import { Doc, getCurrentAccount, groupByArray, IdMap, Ref, SortingOrder, Space } from '@hcengineering/core'
import { DocNotifyContext, InboxNotification, notificationId } from '@hcengineering/notification'
import { ActionContext, createQuery, getClient } from '@hcengineering/presentation'
import {
Expand All @@ -31,7 +31,8 @@
Separator,
TabItem,
TabList,
closePanel
closePanel,
getCurrentLocation
} from '@hcengineering/ui'
import view, { decodeObjectURI } from '@hcengineering/view'
import { parseLinkId } from '@hcengineering/view-resources'
Expand Down Expand Up @@ -143,11 +144,23 @@
$: filteredData = filterData(filter, selectedTabId, inboxData, $contextByIdStore)
locationStore.subscribe((newLocation) => {
void syncLocation(newLocation)
const unsubscribeLoc = locationStore.subscribe((newLocation) => {
void syncLocation(newLocation, $contextByDocStore)
})
async function syncLocation (newLocation: Location): Promise<void> {
let isContextsLoaded = false
const unsubscribeContexts = contextByDocStore.subscribe((docs) => {
if (selectedContext !== undefined || docs.size === 0 || isContextsLoaded) {
return
}
const loc = getCurrentLocation()
void syncLocation(loc, docs)
isContextsLoaded = true
})
async function syncLocation (newLocation: Location, contextByDoc: Map<Ref<Doc>, DocNotifyContext>): Promise<void> {
const loc = await resolveLocation(newLocation)
if (loc?.loc.path[2] !== notificationId) {
return
Expand All @@ -161,7 +174,7 @@
const [id, _class] = decodeObjectURI(loc?.loc.path[3] ?? '')
const _id = await parseLinkId(linkProviders, id, _class)
const context = _id ? $contextByDocStore.get(_id) : undefined
const context = _id ? contextByDoc.get(_id) : undefined
selectedContextId = context?._id
Expand Down Expand Up @@ -357,7 +370,11 @@
}
]
$: $deviceInfo.replacedPanel = replacedPanel
onDestroy(() => ($deviceInfo.replacedPanel = undefined))
onDestroy(() => {
$deviceInfo.replacedPanel = undefined
unsubscribeLoc()
unsubscribeContexts()
})
</script>

<ActionContext
Expand Down
3 changes: 2 additions & 1 deletion plugins/notification/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ const notification = plugin(notificationId, {
CommonNotificationCollectionRemoved: '' as IntlString,
SoundNotificationsDescription: '' as IntlString,
Sound: '' as IntlString,
NoAccessToObject: '' as IntlString
NoAccessToObject: '' as IntlString,
ViewIn: '' as IntlString
},
function: {
Notify: '' as Resource<NotifyFunc>,
Expand Down
7 changes: 6 additions & 1 deletion server-plugins/chunter-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {
getDocCollaborators,
getMixinTx
} from '@hcengineering/server-notification-resources'
import { markupToText, stripTags } from '@hcengineering/text'
import { markupToHTML, markupToText, stripTags } from '@hcengineering/text'
import { workbenchId } from '@hcengineering/workbench'

import { NOTIFICATION_BODY_SIZE } from '@hcengineering/server-notification'
Expand Down Expand Up @@ -91,6 +91,10 @@ export async function ChatMessageTextPresenter (doc: ChatMessage): Promise<strin
return markupToText(doc.message)
}

export async function ChatMessageHtmlPresenter (doc: ChatMessage): Promise<string> {
return markupToHTML(doc.message)
}

/**
* @public
*/
Expand Down Expand Up @@ -580,6 +584,7 @@ export default async () => ({
ChannelTextPresenter: channelTextPresenter,
ChunterNotificationContentProvider: getChunterNotificationContent,
ChatMessageTextPresenter,
ChatMessageHtmlPresenter,
JoinChannelTypeMatch
}
})
1 change: 1 addition & 0 deletions server-plugins/chunter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default plugin(serverChunterId, {
ChannelTextPresenter: '' as Resource<Presenter>,
ChunterNotificationContentProvider: '' as Resource<NotificationContentProvider>,
ChatMessageTextPresenter: '' as Resource<Presenter>,
ChatMessageHtmlPresenter: '' as Resource<Presenter>,
JoinChannelTypeMatch: '' as TypeMatchFunc
}
})
8 changes: 5 additions & 3 deletions server-plugins/gmail-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@
"@types/jest": "^29.5.5"
},
"dependencies": {
"@hcengineering/activity": "^0.6.0",
"@hcengineering/contact": "^0.6.24",
"@hcengineering/core": "^0.6.32",
"@hcengineering/gmail": "^0.6.22",
"@hcengineering/notification": "^0.6.23",
"@hcengineering/platform": "^0.6.11",
"@hcengineering/server-core": "^0.6.1",
"@hcengineering/server-notification": "^0.6.1",
"@hcengineering/server-notification-resources": "^0.6.0",
"@hcengineering/notification": "^0.6.23",
"@hcengineering/contact": "^0.6.24",
"@hcengineering/gmail": "^0.6.22"
"@hcengineering/text": "^0.6.5"
}
}
12 changes: 7 additions & 5 deletions server-plugins/gmail-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import serverNotification, {
} from '@hcengineering/server-notification'
import { getContentByTemplate } from '@hcengineering/server-notification-resources'
import { getMetadata } from '@hcengineering/platform'
import { ActivityMessage } from '@hcengineering/activity'

/**
* @public
Expand Down Expand Up @@ -134,7 +135,8 @@ async function notifyByEmail (
doc: Doc | undefined,
sender: SenderInfo,
receiver: ReceiverInfo,
data: InboxNotification
data: InboxNotification,
message?: ActivityMessage
): Promise<void> {
const account = receiver.account

Expand All @@ -145,8 +147,7 @@ async function notifyByEmail (
const senderPerson = sender.person
const senderName = senderPerson !== undefined ? formatName(senderPerson.name, control.branding?.lastNameFirst) : ''

const content = await getContentByTemplate(doc, senderName, type, control, '', data)

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)
}
Expand All @@ -158,7 +159,8 @@ const SendEmailNotifications: NotificationProviderFunc = async (
object: Doc,
data: InboxNotification,
receiver: ReceiverInfo,
sender: SenderInfo
sender: SenderInfo,
message?: ActivityMessage
): Promise<Tx[]> => {
if (types.length === 0) {
return []
Expand All @@ -169,7 +171,7 @@ const SendEmailNotifications: NotificationProviderFunc = async (
}

for (const type of types) {
await notifyByEmail(control, type._id, object, sender, receiver, data)
await notifyByEmail(control, type._id, object, sender, receiver, data, message)
}

return []
Expand Down
40 changes: 32 additions & 8 deletions server-plugins/notification-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ import serverNotification, {
SenderInfo
} from '@hcengineering/server-notification'
import serverView from '@hcengineering/server-view'
import { stripTags } from '@hcengineering/text'
import { markupToText, stripTags } from '@hcengineering/text'
import { encodeObjectURI } from '@hcengineering/view'
import { workbenchId } from '@hcengineering/workbench'
import webpush, { WebPushError } from 'web-push'
Expand All @@ -91,13 +91,15 @@ import {
createPushCollaboratorsTx,
getHTMLPresenter,
getNotificationContent,
getNotificationLink,
getTextPresenter,
getUsersInfo,
isAllowed,
isMixinTx,
isShouldNotifyTx,
isUserEmployeeInFieldValue,
isUserInFieldValue,
messageToMarkup,
replaceAll,
toReceiverInfo,
updateNotifyContextsSpace
Expand Down Expand Up @@ -212,19 +214,33 @@ export async function getContentByTemplate (
type: Ref<BaseNotificationType>,
control: TriggerControl,
data: string,
notificationData?: InboxNotification
notificationData?: InboxNotification,
message?: ActivityMessage
): Promise<Content | undefined> {
if (doc === undefined) return
const notificationType = control.modelDb.getObject(type)
if (notificationType.templates === undefined) return

const textPart = await getTextPart(doc, control)
if (textPart === undefined) return
const params =
const params: Record<string, string> =
notificationData !== undefined
? await getTranslatedNotificationContent(notificationData, notificationData._class, control)
: {}

if (message !== undefined) {
const markup = await messageToMarkup(control, message)
params.message = markup !== undefined ? markupToText(markup) : params.message ?? ''
} else if (params.message === undefined) {
params.message = params.body ?? ''
}

const link = await getNotificationLink(control, doc, message?._id)
const app = control.branding?.title ?? 'Huly'
const linkText = await translate(notification.string.ViewIn, { app })

params.link = `<a href='${link}'>${linkText}</a>`

const text = fillTemplate(notificationType.templates.textTemplate, sender, textPart, data, params)
const htmlPart = await getHtmlPart(doc, control)
const html = fillTemplate(notificationType.templates.htmlTemplate, sender, htmlPart ?? textPart, data, params)
Expand Down Expand Up @@ -838,16 +854,24 @@ export async function createCollabDocInfo (
return res
}

const notifyContexts = await control.findAllCtx(ctx, notification.class.DocNotifyContext, { objectId: object._id })

await updateContextsTimestamp(notifyContexts, originTx.modifiedOn, control, originTx.modifiedBy)
await removeContexts(notifyContexts, unsubscribe, control)

const docMessages = activityMessages.filter((message) => message.attachedTo === object._id)

if (docMessages.length === 0) {
if (unsubscribe.length > 0) {
const notifyContexts = await control.findAllCtx(ctx, notification.class.DocNotifyContext, {
objectId: object._id,
user: { $in: unsubscribe }
})
await removeContexts(notifyContexts, unsubscribe, control)
}

return res
}

const notifyContexts = await control.findAllCtx(ctx, notification.class.DocNotifyContext, { objectId: object._id })
await removeContexts(notifyContexts, unsubscribe, control)
await updateContextsTimestamp(notifyContexts, originTx.modifiedOn, control, originTx.modifiedBy)

const targets = new Set(collaborators)

// user is not collaborator of himself, but we should notify user of changes related to users account (mentions, comments etc)
Expand Down
Loading

0 comments on commit 071551c

Please sign in to comment.