mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-24 01:07:50 +00:00
Browser notification (#2178)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
643544c4cb
commit
7653c1cf83
@ -6,6 +6,7 @@ Core:
|
|||||||
|
|
||||||
- Allow to leave workspace
|
- Allow to leave workspace
|
||||||
- Allow to kick employee
|
- Allow to kick employee
|
||||||
|
- Browser notifications
|
||||||
- Allow to create employee
|
- Allow to create employee
|
||||||
|
|
||||||
HR:
|
HR:
|
||||||
|
@ -51,6 +51,10 @@ export class TNotification extends TAttachedDoc implements Notification {
|
|||||||
|
|
||||||
@Prop(TypeString(), 'Status' as IntlString)
|
@Prop(TypeString(), 'Status' as IntlString)
|
||||||
status!: NotificationStatus
|
status!: NotificationStatus
|
||||||
|
|
||||||
|
text!: string
|
||||||
|
|
||||||
|
type!: Ref<NotificationType>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(notification.class.EmailNotification, core.class.Doc, DOMAIN_NOTIFICATION)
|
@Model(notification.class.EmailNotification, core.class.Doc, DOMAIN_NOTIFICATION)
|
||||||
@ -137,6 +141,16 @@ export function createModel (builder: Builder): void {
|
|||||||
notification.ids.PlatformNotification
|
notification.ids.PlatformNotification
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
notification.class.NotificationProvider,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
label: notification.string.BrowserNotification,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
notification.ids.BrowserNotification
|
||||||
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
notification.class.NotificationProvider,
|
notification.class.NotificationProvider,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
|
@ -13,9 +13,56 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import core, { DOMAIN_TX, Ref, TxCreateDoc, TxOperations } from '@anticrm/core'
|
||||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
||||||
|
import notification, { Notification, NotificationType } from '@anticrm/notification'
|
||||||
|
import { DOMAIN_NOTIFICATION } from '.'
|
||||||
|
|
||||||
|
async function fillNotificationText (client: MigrationClient): Promise<void> {
|
||||||
|
await client.update(
|
||||||
|
DOMAIN_NOTIFICATION,
|
||||||
|
{ _class: notification.class.Notification, text: { $exists: false } },
|
||||||
|
{
|
||||||
|
text: ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await client.update(
|
||||||
|
DOMAIN_TX,
|
||||||
|
{
|
||||||
|
_class: core.class.TxCreateDoc,
|
||||||
|
objectClass: notification.class.Notification,
|
||||||
|
'attributes.text': { $exists: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'attributes.text': ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fillNotificationType (client: MigrationUpgradeClient): Promise<void> {
|
||||||
|
const notifications = await client.findAll(notification.class.Notification, { type: { $exists: false } })
|
||||||
|
const txOp = new TxOperations(client, core.account.System)
|
||||||
|
const promises = notifications.map(async (doc) => {
|
||||||
|
const tx = await client.findOne(core.class.TxCUD, { _id: doc.tx })
|
||||||
|
if (tx === undefined) return
|
||||||
|
const type =
|
||||||
|
tx._class === core.class.TxMixin
|
||||||
|
? ('calendar:ids:ReminderNotification' as Ref<NotificationType>)
|
||||||
|
: notification.ids.MentionNotification
|
||||||
|
const objectTx = txOp.update(doc, { type })
|
||||||
|
const ctx = await client.findOne<TxCreateDoc<Notification>>(core.class.TxCreateDoc, { objectId: doc._id })
|
||||||
|
if (ctx === undefined) return await objectTx
|
||||||
|
const updateTx = txOp.update(ctx, { 'attributes.type': type } as any)
|
||||||
|
return await Promise.all([objectTx, updateTx])
|
||||||
|
})
|
||||||
|
await Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
export const notificationOperation: MigrateOperation = {
|
export const notificationOperation: MigrateOperation = {
|
||||||
async migrate (client: MigrationClient): Promise<void> {},
|
async migrate (client: MigrationClient): Promise<void> {
|
||||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {}
|
await fillNotificationText(client)
|
||||||
|
},
|
||||||
|
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||||
|
await fillNotificationType(client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export default mergeIds(notificationId, notification, {
|
|||||||
LastView: '' as IntlString,
|
LastView: '' as IntlString,
|
||||||
MentionNotification: '' as IntlString,
|
MentionNotification: '' as IntlString,
|
||||||
PlatformNotification: '' as IntlString,
|
PlatformNotification: '' as IntlString,
|
||||||
|
BrowserNotification: '' as IntlString,
|
||||||
EmailNotification: '' as IntlString
|
EmailNotification: '' as IntlString
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"EmailNotification": "by email",
|
"EmailNotification": "by email",
|
||||||
"PlatformNotification": "in platform",
|
"PlatformNotification": "in platform",
|
||||||
"Track": "Track",
|
"Track": "Track",
|
||||||
"DontTrack": "Don't track"
|
"DontTrack": "Don't track",
|
||||||
|
"BrowserNotification": "in browser"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@
|
|||||||
"EmailNotification": "по email",
|
"EmailNotification": "по email",
|
||||||
"PlatformNotification": "в системе",
|
"PlatformNotification": "в системе",
|
||||||
"Track": "Отслеживать",
|
"Track": "Отслеживать",
|
||||||
"DontTrack": "Не отслеживать"
|
"DontTrack": "Не отслеживать",
|
||||||
|
"BrowserNotification": "в браузере"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import contact, { EmployeeAccount } from '@anticrm/contact'
|
||||||
|
import { Doc, getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||||
|
import {
|
||||||
|
Notification as PlatformNotification,
|
||||||
|
NotificationProvider,
|
||||||
|
NotificationSetting,
|
||||||
|
NotificationStatus,
|
||||||
|
NotificationType
|
||||||
|
} from '@anticrm/notification'
|
||||||
|
import { createQuery } from '@anticrm/presentation'
|
||||||
|
import notification from '../plugin'
|
||||||
|
import { NotificationClientImpl } from '../utils'
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
const settingQuery = createQuery()
|
||||||
|
const providersQuery = createQuery()
|
||||||
|
const accountId = getCurrentAccount()._id
|
||||||
|
const space = accountId as string as Ref<Space>
|
||||||
|
const notificationClient = NotificationClientImpl.getClient()
|
||||||
|
const lastViews = notificationClient.getLastViews()
|
||||||
|
const lastViewId: Ref<Doc> = ((getCurrentAccount() as EmployeeAccount).employee + 'notification') as Ref<Doc>
|
||||||
|
|
||||||
|
let settingsReceived = false
|
||||||
|
let settings: Map<Ref<NotificationType>, NotificationSetting> = new Map<Ref<NotificationType>, NotificationSetting>()
|
||||||
|
let provider: NotificationProvider | undefined
|
||||||
|
|
||||||
|
const enabled = 'Notification' in window && Notification.permission !== 'denied'
|
||||||
|
|
||||||
|
$: enabled &&
|
||||||
|
providersQuery.query(
|
||||||
|
notification.class.NotificationProvider,
|
||||||
|
{ _id: notification.ids.BrowserNotification },
|
||||||
|
(res) => {
|
||||||
|
provider = res[0]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$: enabled &&
|
||||||
|
settingQuery.query(
|
||||||
|
notification.class.NotificationSetting,
|
||||||
|
{
|
||||||
|
space
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
settings = new Map(
|
||||||
|
res.map((setting) => {
|
||||||
|
return [setting.type, setting]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
settingsReceived = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$: enabled &&
|
||||||
|
settingsReceived &&
|
||||||
|
provider !== undefined &&
|
||||||
|
query.query(
|
||||||
|
notification.class.Notification,
|
||||||
|
{
|
||||||
|
attachedTo: (getCurrentAccount() as EmployeeAccount).employee,
|
||||||
|
status: NotificationStatus.New
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
process(res)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
async function process (notifications: PlatformNotification[]): Promise<void> {
|
||||||
|
for (const notification of notifications) {
|
||||||
|
await tryNotify(notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryNotify (notification: PlatformNotification): Promise<void> {
|
||||||
|
const text = notification.text.replace(/<[^>]*>/g, '').trim()
|
||||||
|
if (text === '') return
|
||||||
|
const setting = settings.get(notification.type)
|
||||||
|
const enabled = setting?.enabled ?? provider?.default
|
||||||
|
if (!enabled) return
|
||||||
|
if (setting?.modifiedOn ?? notification.modifiedOn < 0) return
|
||||||
|
if (Notification.permission === 'granted') {
|
||||||
|
await notify(text, notification)
|
||||||
|
} else if (Notification.permission !== 'denied') {
|
||||||
|
const permission = await Notification.requestPermission()
|
||||||
|
if (permission === 'granted') {
|
||||||
|
await notify(text, notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function notify (text: string, notification: PlatformNotification): Promise<void> {
|
||||||
|
const lastView = $lastViews.get(lastViewId)
|
||||||
|
if (lastView ?? notification.modifiedOn > 0) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
new Notification(text, { tag: notification._id })
|
||||||
|
await notificationClient.updateLastView(
|
||||||
|
lastViewId,
|
||||||
|
contact.class.Employee,
|
||||||
|
notification.modifiedOn,
|
||||||
|
lastView === undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -26,6 +26,8 @@
|
|||||||
const client = getClient()
|
const client = getClient()
|
||||||
const space = accountId as string as Ref<Space>
|
const space = accountId as string as Ref<Space>
|
||||||
|
|
||||||
|
let disabled = true
|
||||||
|
|
||||||
let types: NotificationType[] = []
|
let types: NotificationType[] = []
|
||||||
let providers: NotificationProvider[] = []
|
let providers: NotificationProvider[] = []
|
||||||
let settings: Map<Ref<NotificationType>, Map<Ref<NotificationProvider>, NotificationSetting>> = new Map<
|
let settings: Map<Ref<NotificationType>, Map<Ref<NotificationProvider>, NotificationSetting>> = new Map<
|
||||||
@ -67,6 +69,7 @@
|
|||||||
} else {
|
} else {
|
||||||
current.enabled = value
|
current.enabled = value
|
||||||
}
|
}
|
||||||
|
disabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSetting (
|
function getSetting (
|
||||||
@ -92,6 +95,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function save (): Promise<void> {
|
async function save (): Promise<void> {
|
||||||
|
disabled = true
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<any>[] = []
|
||||||
for (const type of settings.values()) {
|
for (const type of settings.values()) {
|
||||||
for (const setting of type.values()) {
|
for (const setting of type.values()) {
|
||||||
@ -107,7 +111,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(promises)
|
try {
|
||||||
|
await Promise.all(promises)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: column = providers.length + 1
|
$: column = providers.length + 1
|
||||||
@ -152,6 +160,7 @@
|
|||||||
<div class="flex-row-reverse">
|
<div class="flex-row-reverse">
|
||||||
<Button
|
<Button
|
||||||
label={presentation.string.Save}
|
label={presentation.string.Save}
|
||||||
|
{disabled}
|
||||||
kind={'primary'}
|
kind={'primary'}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
save()
|
save()
|
||||||
|
@ -23,6 +23,8 @@ import { NotificationClientImpl } from './utils'
|
|||||||
|
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
|
|
||||||
|
export { default as BrowserNotificatator } from './components/BrowserNotificatator.svelte'
|
||||||
|
|
||||||
export default async (): Promise<Resources> => ({
|
export default async (): Promise<Resources> => ({
|
||||||
component: {
|
component: {
|
||||||
NotificationsPopup,
|
NotificationsPopup,
|
||||||
|
@ -33,6 +33,8 @@ export interface LastView extends AttachedDoc {
|
|||||||
export interface Notification extends AttachedDoc {
|
export interface Notification extends AttachedDoc {
|
||||||
tx: Ref<TxCUD<Doc>>
|
tx: Ref<TxCUD<Doc>>
|
||||||
status: NotificationStatus
|
status: NotificationStatus
|
||||||
|
text: string
|
||||||
|
type: Ref<NotificationType>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,6 +139,7 @@ const notification = plugin(notificationId, {
|
|||||||
ids: {
|
ids: {
|
||||||
MentionNotification: '' as Ref<NotificationType>,
|
MentionNotification: '' as Ref<NotificationType>,
|
||||||
PlatformNotification: '' as Ref<NotificationProvider>,
|
PlatformNotification: '' as Ref<NotificationProvider>,
|
||||||
|
BrowserNotification: '' as Ref<NotificationProvider>,
|
||||||
EmailNotification: '' as Ref<NotificationProvider>,
|
EmailNotification: '' as Ref<NotificationProvider>,
|
||||||
NotificationSettings: '' as Ref<Doc>
|
NotificationSettings: '' as Ref<Doc>
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||||
import core, { Class, Client, Doc, getCurrentAccount, Ref, Space } from '@anticrm/core'
|
import core, { Class, Client, Doc, getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||||
import notification, { NotificationStatus } from '@anticrm/notification'
|
import notification, { NotificationStatus } from '@anticrm/notification'
|
||||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
import { NotificationClientImpl, BrowserNotificatator } from '@anticrm/notification-resources'
|
||||||
import { getMetadata, getResource, IntlString } from '@anticrm/platform'
|
import { getMetadata, getResource, IntlString } from '@anticrm/platform'
|
||||||
import { Avatar, createQuery, setClient } from '@anticrm/presentation'
|
import { Avatar, createQuery, setClient } from '@anticrm/presentation'
|
||||||
import {
|
import {
|
||||||
@ -119,9 +119,6 @@
|
|||||||
},
|
},
|
||||||
(res) => {
|
(res) => {
|
||||||
hasNotification = res.length > 0
|
hasNotification = res.length > 0
|
||||||
},
|
|
||||||
{
|
|
||||||
limit: 1
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -517,6 +514,7 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Popup>
|
</Popup>
|
||||||
<DatePickerPopup />
|
<DatePickerPopup />
|
||||||
|
<BrowserNotificatator />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex-col-center justify-center h-full flex-grow">
|
<div class="flex-col-center justify-center h-full flex-grow">
|
||||||
<h1><Label label={workbench.string.AccountDisabled} /></h1>
|
<h1><Label label={workbench.string.AccountDisabled} /></h1>
|
||||||
|
@ -34,7 +34,12 @@ import core, {
|
|||||||
TxCUD,
|
TxCUD,
|
||||||
TxProcessor
|
TxProcessor
|
||||||
} from '@anticrm/core'
|
} from '@anticrm/core'
|
||||||
import notification, { EmailNotification, Notification, NotificationStatus } from '@anticrm/notification'
|
import notification, {
|
||||||
|
EmailNotification,
|
||||||
|
Notification,
|
||||||
|
NotificationProvider,
|
||||||
|
NotificationStatus
|
||||||
|
} from '@anticrm/notification'
|
||||||
import { getResource } from '@anticrm/platform'
|
import { getResource } from '@anticrm/platform'
|
||||||
import type { TriggerControl } from '@anticrm/server-core'
|
import type { TriggerControl } from '@anticrm/server-core'
|
||||||
import { extractTx } from '@anticrm/server-core'
|
import { extractTx } from '@anticrm/server-core'
|
||||||
@ -46,33 +51,52 @@ import view, { HTMLPresenter, TextPresenter } from '@anticrm/view'
|
|||||||
*/
|
*/
|
||||||
export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||||
const hierarchy = control.hierarchy
|
const hierarchy = control.hierarchy
|
||||||
if (tx._class !== core.class.TxCollectionCUD) {
|
const ptx = tx as TxCollectionCUD<Doc, Backlink>
|
||||||
return []
|
|
||||||
|
if (!checkTx(ptx, hierarchy)) return []
|
||||||
|
|
||||||
|
const result: Tx[] = []
|
||||||
|
|
||||||
|
const receiver = await getReceiver(ptx, control)
|
||||||
|
if (receiver === undefined) return []
|
||||||
|
const sender = await getSender(ptx, control)
|
||||||
|
const backlink = getBacklink(ptx)
|
||||||
|
const doc = await getBacklinkDoc(backlink, control)
|
||||||
|
const textPart = doc !== undefined ? await getTextPart(doc, hierarchy) : undefined
|
||||||
|
const htmlPart = doc !== undefined ? await getHtmlPart(doc, hierarchy) : undefined
|
||||||
|
|
||||||
|
const createNotificationTx = await getPlatformNotificationTx(ptx, backlink, textPart, sender)
|
||||||
|
|
||||||
|
if (createNotificationTx !== undefined) {
|
||||||
|
result.push(createNotificationTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ptx = tx as TxCollectionCUD<Doc, Backlink>
|
if (
|
||||||
|
sender !== undefined &&
|
||||||
|
textPart !== undefined &&
|
||||||
|
(await isAllowed(control, receiver, notification.ids.EmailNotification))
|
||||||
|
) {
|
||||||
|
const emailTx = await getEmailTx(ptx, backlink, sender, textPart, htmlPart, receiver)
|
||||||
|
if (emailTx !== undefined) {
|
||||||
|
result.push(emailTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTx (ptx: TxCollectionCUD<Doc, Backlink>, hierarchy: Hierarchy): boolean {
|
||||||
|
if (ptx._class !== core.class.TxCollectionCUD) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
ptx.tx._class !== core.class.TxCreateDoc ||
|
ptx.tx._class !== core.class.TxCreateDoc ||
|
||||||
!hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink) ||
|
!hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink) ||
|
||||||
!hierarchy.isDerived(ptx.objectClass, contact.class.Employee)
|
!hierarchy.isDerived(ptx.objectClass, contact.class.Employee)
|
||||||
) {
|
) {
|
||||||
return []
|
return false
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
const result: Tx[] = []
|
|
||||||
|
|
||||||
const createNotificationTx = await getPlatformNotificationTx(ptx, control)
|
|
||||||
|
|
||||||
if (createNotificationTx !== undefined) {
|
|
||||||
result.push(createNotificationTx)
|
|
||||||
}
|
|
||||||
|
|
||||||
const emailTx = await getEmailTx(ptx, control)
|
|
||||||
if (emailTx !== undefined) {
|
|
||||||
result.push(emailTx)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUpdateLastViewTxes (
|
async function getUpdateLastViewTxes (
|
||||||
@ -170,11 +194,11 @@ export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise<
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPlatformNotificationTx (
|
async function getReceiver (
|
||||||
ptx: TxCollectionCUD<Doc, Backlink>,
|
ptx: TxCollectionCUD<Doc, Backlink>,
|
||||||
control: TriggerControl
|
control: TriggerControl
|
||||||
): Promise<TxCollectionCUD<Doc, Notification> | undefined> {
|
): Promise<EmployeeAccount | undefined> {
|
||||||
const attached = (
|
return (
|
||||||
await control.modelDb.findAll(
|
await control.modelDb.findAll(
|
||||||
contact.class.EmployeeAccount,
|
contact.class.EmployeeAccount,
|
||||||
{
|
{
|
||||||
@ -183,29 +207,42 @@ async function getPlatformNotificationTx (
|
|||||||
{ limit: 1 }
|
{ limit: 1 }
|
||||||
)
|
)
|
||||||
)[0]
|
)[0]
|
||||||
if (attached === undefined) return
|
}
|
||||||
|
|
||||||
|
async function isAllowed (
|
||||||
|
control: TriggerControl,
|
||||||
|
receiver: EmployeeAccount,
|
||||||
|
providerId: Ref<NotificationProvider>
|
||||||
|
): Promise<boolean> {
|
||||||
const setting = (
|
const setting = (
|
||||||
await control.findAll(
|
await control.findAll(
|
||||||
notification.class.NotificationSetting,
|
notification.class.NotificationSetting,
|
||||||
{
|
{
|
||||||
provider: notification.ids.PlatformNotification,
|
provider: providerId,
|
||||||
type: notification.ids.MentionNotification,
|
type: notification.ids.MentionNotification,
|
||||||
space: attached._id as unknown as Ref<Space>
|
space: receiver._id as unknown as Ref<Space>
|
||||||
},
|
},
|
||||||
{ limit: 1 }
|
{ limit: 1 }
|
||||||
)
|
)
|
||||||
)[0]
|
)[0]
|
||||||
if (setting === undefined) {
|
if (setting !== undefined) {
|
||||||
const provider = (
|
return setting.enabled
|
||||||
await control.modelDb.findAll(notification.class.NotificationProvider, {
|
|
||||||
_id: notification.ids.PlatformNotification
|
|
||||||
})
|
|
||||||
)[0]
|
|
||||||
if (provider === undefined) return
|
|
||||||
if (!provider.default) return
|
|
||||||
}
|
}
|
||||||
|
const provider = (
|
||||||
|
await control.modelDb.findAll(notification.class.NotificationProvider, {
|
||||||
|
_id: providerId
|
||||||
|
})
|
||||||
|
)[0]
|
||||||
|
if (provider === undefined) return false
|
||||||
|
return provider.default
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPlatformNotificationTx (
|
||||||
|
ptx: TxCollectionCUD<Doc, Backlink>,
|
||||||
|
backlink: Backlink,
|
||||||
|
textPart: string | undefined,
|
||||||
|
sender: string | undefined
|
||||||
|
): Promise<TxCollectionCUD<Doc, Notification> | undefined> {
|
||||||
const createTx: TxCreateDoc<Notification> = {
|
const createTx: TxCreateDoc<Notification> = {
|
||||||
objectClass: notification.class.Notification,
|
objectClass: notification.class.Notification,
|
||||||
objectSpace: notification.space.Notifications,
|
objectSpace: notification.space.Notifications,
|
||||||
@ -217,10 +254,16 @@ async function getPlatformNotificationTx (
|
|||||||
_class: core.class.TxCreateDoc,
|
_class: core.class.TxCreateDoc,
|
||||||
attributes: {
|
attributes: {
|
||||||
tx: ptx._id,
|
tx: ptx._id,
|
||||||
status: NotificationStatus.New
|
status: NotificationStatus.New,
|
||||||
|
type: notification.ids.MentionNotification
|
||||||
} as unknown as Data<Notification>
|
} as unknown as Data<Notification>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sender !== undefined && textPart !== undefined) {
|
||||||
|
const text = `${sender} mentioned you in ${textPart} ${backlink.message}`
|
||||||
|
createTx.attributes.text = text
|
||||||
|
}
|
||||||
|
|
||||||
const createNotificationTx: TxCollectionCUD<Doc, Notification> = {
|
const createNotificationTx: TxCollectionCUD<Doc, Notification> = {
|
||||||
...ptx,
|
...ptx,
|
||||||
_id: generateId(),
|
_id: generateId(),
|
||||||
@ -231,12 +274,35 @@ async function getPlatformNotificationTx (
|
|||||||
return createNotificationTx
|
return createNotificationTx
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEmailTx (
|
function getBacklink (ptx: TxCollectionCUD<Doc, Backlink>): Backlink {
|
||||||
ptx: TxCollectionCUD<Doc, Backlink>,
|
return TxProcessor.createDoc2Doc(ptx.tx as TxCreateDoc<Backlink>)
|
||||||
control: TriggerControl
|
}
|
||||||
): Promise<TxCreateDoc<EmailNotification> | undefined> {
|
|
||||||
const hierarchy = control.hierarchy
|
async function getBacklinkDoc (backlink: Backlink, control: TriggerControl): Promise<Doc | undefined> {
|
||||||
const backlink = TxProcessor.createDoc2Doc(ptx.tx as TxCreateDoc<Backlink>)
|
return (
|
||||||
|
await control.findAll(
|
||||||
|
backlink.backlinkClass,
|
||||||
|
{
|
||||||
|
_id: backlink.backlinkId
|
||||||
|
},
|
||||||
|
{ limit: 1 }
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getTextPart (doc: Doc, hierarchy: Hierarchy): Promise<string | undefined> {
|
||||||
|
const TextPresenter = getTextPresenter(doc._class, hierarchy)
|
||||||
|
if (TextPresenter === undefined) return
|
||||||
|
return (await getResource(TextPresenter.presenter))(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHtmlPart (doc: Doc, hierarchy: Hierarchy): Promise<string | undefined> {
|
||||||
|
const HTMLPresenter = getHTMLPresenter(doc._class, hierarchy)
|
||||||
|
const htmlPart = HTMLPresenter !== undefined ? (await getResource(HTMLPresenter.presenter))(doc) : undefined
|
||||||
|
return htmlPart
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSender (ptx: TxCollectionCUD<Doc, Backlink>, control: TriggerControl): Promise<string | undefined> {
|
||||||
const account = (
|
const account = (
|
||||||
await control.modelDb.findAll(
|
await control.modelDb.findAll(
|
||||||
contact.class.EmployeeAccount,
|
contact.class.EmployeeAccount,
|
||||||
@ -248,57 +314,17 @@ async function getEmailTx (
|
|||||||
)[0]
|
)[0]
|
||||||
if (account === undefined) return undefined
|
if (account === undefined) return undefined
|
||||||
|
|
||||||
const sender = formatName(account.name)
|
return formatName(account.name)
|
||||||
const attached = (
|
}
|
||||||
await control.modelDb.findAll(
|
|
||||||
contact.class.EmployeeAccount,
|
|
||||||
{
|
|
||||||
employee: ptx.objectId as Ref<Employee>
|
|
||||||
},
|
|
||||||
{ limit: 1 }
|
|
||||||
)
|
|
||||||
)[0]
|
|
||||||
if (attached === undefined) return undefined
|
|
||||||
|
|
||||||
const setting = (
|
async function getEmailTx (
|
||||||
await control.findAll(
|
ptx: TxCollectionCUD<Doc, Backlink>,
|
||||||
notification.class.NotificationSetting,
|
backlink: Backlink,
|
||||||
{
|
sender: string,
|
||||||
provider: notification.ids.EmailNotification,
|
textPart: string,
|
||||||
type: notification.ids.MentionNotification,
|
htmlPart: string | undefined,
|
||||||
space: attached._id as unknown as Ref<Space>
|
receiver: EmployeeAccount
|
||||||
},
|
): Promise<TxCreateDoc<EmailNotification> | undefined> {
|
||||||
{ limit: 1 }
|
|
||||||
)
|
|
||||||
)[0]
|
|
||||||
if (setting === undefined) {
|
|
||||||
const provider = (
|
|
||||||
await control.modelDb.findAll(notification.class.NotificationProvider, {
|
|
||||||
_id: notification.ids.PlatformNotification
|
|
||||||
})
|
|
||||||
)[0]
|
|
||||||
if (provider === undefined) return
|
|
||||||
if (!provider.default) return
|
|
||||||
}
|
|
||||||
|
|
||||||
const receiver = attached.email
|
|
||||||
const doc = (
|
|
||||||
await control.findAll(
|
|
||||||
backlink.backlinkClass,
|
|
||||||
{
|
|
||||||
_id: backlink.backlinkId
|
|
||||||
},
|
|
||||||
{ limit: 1 }
|
|
||||||
)
|
|
||||||
)[0]
|
|
||||||
if (doc === undefined) return undefined
|
|
||||||
|
|
||||||
const TextPresenter = getTextPresenter(doc._class, hierarchy)
|
|
||||||
if (TextPresenter === undefined) return
|
|
||||||
|
|
||||||
const HTMLPresenter = getHTMLPresenter(doc._class, hierarchy)
|
|
||||||
const htmlPart = HTMLPresenter !== undefined ? (await getResource(HTMLPresenter.presenter))(doc) : undefined
|
|
||||||
const textPart = (await getResource(TextPresenter.presenter))(doc)
|
|
||||||
const html = `<p><b>${sender}</b> mentioned you in ${htmlPart !== undefined ? htmlPart : textPart}</p> ${
|
const html = `<p><b>${sender}</b> mentioned you in ${htmlPart !== undefined ? htmlPart : textPart}</p> ${
|
||||||
backlink.message
|
backlink.message
|
||||||
}`
|
}`
|
||||||
@ -315,7 +341,7 @@ async function getEmailTx (
|
|||||||
attributes: {
|
attributes: {
|
||||||
status: 'new',
|
status: 'new',
|
||||||
sender,
|
sender,
|
||||||
receivers: [receiver],
|
receivers: [receiver.email],
|
||||||
subject: `You was mentioned in ${textPart}`,
|
subject: `You was mentioned in ${textPart}`,
|
||||||
text,
|
text,
|
||||||
html
|
html
|
||||||
|
Loading…
Reference in New Issue
Block a user