Add notifications middleware to do not send updates for all users (#6714)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-09-24 22:12:00 +04:00 committed by GitHub
parent f1da8ff9b1
commit 0da0d6e80a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 112 additions and 9 deletions

View File

@ -27,7 +27,6 @@ import {
type Data,
type Doc,
type DocumentQuery,
type Domain,
type IndexingConfiguration,
type Markup,
type Ref,
@ -56,6 +55,9 @@ import view, { createAction, template } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import {
notificationId,
DOMAIN_USER_NOTIFY,
DOMAIN_NOTIFICATION,
DOMAIN_DOC_NOTIFY,
type ActivityInboxNotification,
type ActivityNotificationViewlet,
type BaseNotificationType,
@ -86,16 +88,10 @@ import { type AnyComponent, type Location } from '@hcengineering/ui/src/types'
import notification from './plugin'
export { notificationId } from '@hcengineering/notification'
export { notificationId, DOMAIN_USER_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_DOC_NOTIFY } from '@hcengineering/notification'
export { notificationOperation } from './migration'
export { notification as default }
export const DOMAIN_NOTIFICATION = 'notification' as Domain
export const DOMAIN_DOC_NOTIFY = 'notification-dnc' as Domain
export const DOMAIN_USER_NOTIFY = 'notification-user' as Domain
@Model(notification.class.BrowserNotification, core.class.Doc, DOMAIN_USER_NOTIFY)
export class TBrowserNotification extends TDoc implements BrowserNotification {
senderId?: Ref<Account> | undefined

View File

@ -20,6 +20,7 @@ import {
Class,
Doc,
DocumentQuery,
type Domain,
IdMap,
Markup,
Mixin,
@ -42,6 +43,10 @@ import { Readable, Writable } from './types'
export * from './types'
export const DOMAIN_NOTIFICATION = 'notification' as Domain
export const DOMAIN_DOC_NOTIFY = 'notification-dnc' as Domain
export const DOMAIN_USER_NOTIFY = 'notification-user' as Domain
/**
* @public
*/

View File

@ -31,6 +31,7 @@ import type { TriggerControl, TriggerFunc } from '@hcengineering/server-core'
* @public
*/
export const serverNotificationId = 'server-notification' as Plugin
export { DOMAIN_USER_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_DOC_NOTIFY } from '@hcengineering/notification'
/**
* @public

View File

@ -41,6 +41,7 @@
"@hcengineering/platform": "^0.6.11",
"@hcengineering/server-core": "^0.6.1",
"@hcengineering/server-preference": "^0.6.0",
"@hcengineering/server-notification": "^0.6.1",
"@hcengineering/query": "^0.6.12",
"fast-equals": "^5.0.1"
}

View File

@ -33,3 +33,4 @@ export * from './spacePermissions'
export * from './spaceSecurity'
export * from './triggers'
export * from './txPush'
export * from './notifications'

View File

@ -0,0 +1,97 @@
//
// Copyright © 2024 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.
//
import core, {
Doc,
MeasureContext,
Tx,
TxCUD,
TxProcessor,
systemAccountEmail,
type SessionData,
TxApplyIf
} from '@hcengineering/core'
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
import { BaseMiddleware, Middleware, TxMiddlewareResult, type PipelineContext } from '@hcengineering/server-core'
import { DOMAIN_USER_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_DOC_NOTIFY } from '@hcengineering/server-notification'
/**
* @public
*/
export class NotificationsMiddleware extends BaseMiddleware implements Middleware {
private readonly targetDomains = [DOMAIN_USER_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_DOC_NOTIFY]
private constructor (context: PipelineContext, next?: Middleware) {
super(context, next)
}
static async create (
ctx: MeasureContext,
context: PipelineContext,
next: Middleware | undefined
): Promise<NotificationsMiddleware> {
return new NotificationsMiddleware(context, next)
}
isTargetDomain (tx: Tx): boolean {
if (TxProcessor.isExtendsCUD(tx._class)) {
const txCUD = tx as TxCUD<Doc>
const domain = this.context.hierarchy.getDomain(txCUD.objectClass)
return this.targetDomains.includes(domain)
}
return false
}
processTx (ctx: MeasureContext<SessionData>, tx: Tx): void {
let target: string[] | undefined
if (this.isTargetDomain(tx)) {
const account = ctx.contextData.account._id
if (account !== tx.modifiedBy && account !== core.account.System) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
}
const modifiedByAccount = ctx.contextData.getAccount(tx.modifiedBy)
target = [ctx.contextData.userEmail, systemAccountEmail]
if (modifiedByAccount !== undefined && !target.includes(modifiedByAccount.email)) {
target.push(modifiedByAccount.email)
}
ctx.contextData.broadcast.targets['checkDomain' + account] = (tx) => {
if (this.isTargetDomain(tx)) {
return target
}
}
}
}
tx (ctx: MeasureContext<SessionData>, txes: Tx[]): Promise<TxMiddlewareResult> {
for (const tx of txes) {
if (this.context.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) {
for (const ttx of (tx as TxApplyIf).txes) {
this.processTx(ctx, ttx)
}
} else {
this.processTx(ctx, tx)
}
}
return this.provideTx(ctx, txes)
}
isAvailable (ctx: MeasureContext<SessionData>, doc: Doc): boolean {
const domain = this.context.hierarchy.getDomain(doc._class)
if (!this.targetDomains.includes(domain)) return true
const account = ctx.contextData.account._id
return doc.createdBy === account || account === core.account.System
}
}

View File

@ -33,7 +33,8 @@ import {
SpacePermissionsMiddleware,
SpaceSecurityMiddleware,
TriggersMiddleware,
TxMiddleware
TxMiddleware,
NotificationsMiddleware
} from '@hcengineering/middleware'
import { createMongoAdapter, createMongoTxAdapter } from '@hcengineering/mongo'
import { createPostgresAdapter, createPostgresTxAdapter } from '@hcengineering/postgres'
@ -121,6 +122,7 @@ export function createServerPipeline (
LookupMiddleware.create,
ModifiedMiddleware.create,
PrivateMiddleware.create,
NotificationsMiddleware.create,
(ctx: MeasureContext, context: PipelineContext, next?: Middleware) =>
SpaceSecurityMiddleware.create(opt.adapterSecurity ?? false, ctx, context, next),
SpacePermissionsMiddleware.create,