diff --git a/dev/prod/package.json b/dev/prod/package.json index 56d49b5dc8..c09fdeadfb 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -99,7 +99,7 @@ "@hcengineering/server-attachment-resources": "~0.6.0", "@hcengineering/server-contact": "~0.6.1", "@hcengineering/server-contact-resources": "~0.6.0", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-notification-resources": "~0.6.0", "@hcengineering/server-setting": "~0.6.0", "@hcengineering/server-setting-resources": "~0.6.0", diff --git a/dev/tool/package.json b/dev/tool/package.json index a290a9b172..3679283ac6 100644 --- a/dev/tool/package.json +++ b/dev/tool/package.json @@ -77,7 +77,7 @@ "@hcengineering/attachment": "~0.6.1", "@hcengineering/server-contact": "~0.6.1", "@hcengineering/server-contact-resources": "~0.6.0", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-notification-resources": "~0.6.0", "@hcengineering/server-setting": "~0.6.0", "@hcengineering/server-setting-resources": "~0.6.0", diff --git a/models/calendar/src/index.ts b/models/calendar/src/index.ts index 7002680404..13a3d10029 100644 --- a/models/calendar/src/index.ts +++ b/models/calendar/src/index.ts @@ -128,7 +128,10 @@ export function createModel (builder: Builder): void { notification.class.NotificationType, core.space.Model, { - label: calendar.string.Reminder + label: calendar.string.Reminder, + textTemplate: 'Reminder: {doc}', + htmlTemplate: 'Reminder: {doc}', + subjectTemplate: 'Reminder: {doc}' }, calendar.ids.ReminderNotification ) diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index 82e812eb80..f6ad84ed6c 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -81,6 +81,9 @@ export class TEmaiNotification extends TDoc implements EmailNotification { @Model(notification.class.NotificationType, core.class.Doc, DOMAIN_MODEL) export class TNotificationType extends TDoc implements NotificationType { label!: IntlString + textTemplate!: string + htmlTemplate!: string + subjectTemplate!: string } @Model(notification.class.NotificationProvider, core.class.Doc, DOMAIN_MODEL) @@ -126,7 +129,10 @@ export function createModel (builder: Builder): void { notification.class.NotificationType, core.space.Model, { - label: notification.string.MentionNotification + label: notification.string.MentionNotification, + textTemplate: '{sender} mentioned you in {doc} {data}', + htmlTemplate: '

{sender} mentioned you in {doc}

{data}', + subjectTemplate: 'You was mentioned in {doc}' }, notification.ids.MentionNotification ) diff --git a/models/server-chunter/package.json b/models/server-chunter/package.json index f846572a60..7d25169dbf 100644 --- a/models/server-chunter/package.json +++ b/models/server-chunter/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-chunter": "~0.6.0", "@hcengineering/server-core": "~0.6.1", "@hcengineering/chunter": "~0.6.1", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-chunter/src/index.ts b/models/server-chunter/src/index.ts index 7ae70822e3..c610b21902 100644 --- a/models/server-chunter/src/index.ts +++ b/models/server-chunter/src/index.ts @@ -17,16 +17,16 @@ import { Builder } from '@hcengineering/model' import core, { Class, Doc } from '@hcengineering/core' import chunter from '@hcengineering/chunter' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core' import serverChunter from '@hcengineering/server-chunter' export function createModel (builder: Builder): void { - builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(chunter.class.Channel, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverChunter.function.ChannelHTMLPresenter }) - builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(chunter.class.Channel, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverChunter.function.ChannelTextPresenter }) diff --git a/models/server-contact/package.json b/models/server-contact/package.json index 35c578c152..384860384f 100644 --- a/models/server-contact/package.json +++ b/models/server-contact/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-contact": "~0.6.1", "@hcengineering/server-core": "~0.6.1", "@hcengineering/contact": "~0.6.5", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-contact/src/index.ts b/models/server-contact/src/index.ts index 4c4f5abb6d..14062ad286 100644 --- a/models/server-contact/src/index.ts +++ b/models/server-contact/src/index.ts @@ -19,23 +19,23 @@ import { Builder } from '@hcengineering/model' import serverCore from '@hcengineering/server-core' import core from '@hcengineering/core' import contact from '@hcengineering/contact' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' import serverContact from '@hcengineering/server-contact' export function createModel (builder: Builder): void { - builder.mixin(contact.class.Person, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(contact.class.Person, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverContact.function.PersonHTMLPresenter }) - builder.mixin(contact.class.Person, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(contact.class.Person, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverContact.function.PersonTextPresenter }) - builder.mixin(contact.class.Organization, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(contact.class.Organization, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverContact.function.OrganizationHTMLPresenter }) - builder.mixin(contact.class.Organization, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(contact.class.Organization, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverContact.function.OrganizationTextPresenter }) diff --git a/models/server-inventory/package.json b/models/server-inventory/package.json index 74b6b2369c..a46fa655b5 100644 --- a/models/server-inventory/package.json +++ b/models/server-inventory/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-inventory": "~0.6.0", "@hcengineering/server-core": "~0.6.1", "@hcengineering/inventory": "~0.6.0", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-inventory/src/index.ts b/models/server-inventory/src/index.ts index 93f0749075..4838c2503b 100644 --- a/models/server-inventory/src/index.ts +++ b/models/server-inventory/src/index.ts @@ -18,14 +18,14 @@ import { Builder } from '@hcengineering/model' import core from '@hcengineering/core' import inventory from '@hcengineering/inventory' import serverInventory from '@hcengineering/server-inventory' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' export function createModel (builder: Builder): void { - builder.mixin(inventory.class.Product, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(inventory.class.Product, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverInventory.function.ProductHTMLPresenter }) - builder.mixin(inventory.class.Product, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(inventory.class.Product, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverInventory.function.ProductTextPresenter }) } diff --git a/models/server-lead/package.json b/models/server-lead/package.json index 2f1b493914..c0e240cd4b 100644 --- a/models/server-lead/package.json +++ b/models/server-lead/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-lead": "~0.6.0", "@hcengineering/server-core": "~0.6.1", "@hcengineering/lead": "~0.6.0", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-lead/src/index.ts b/models/server-lead/src/index.ts index 155b333ff2..c4bc5ac9d7 100644 --- a/models/server-lead/src/index.ts +++ b/models/server-lead/src/index.ts @@ -17,16 +17,16 @@ import { Builder } from '@hcengineering/model' import core from '@hcengineering/core' import lead from '@hcengineering/lead' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' import serverLead from '@hcengineering/server-lead' import serverCore from '@hcengineering/server-core' export function createModel (builder: Builder): void { - builder.mixin(lead.class.Lead, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(lead.class.Lead, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverLead.function.LeadHTMLPresenter }) - builder.mixin(lead.class.Lead, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(lead.class.Lead, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverLead.function.LeadTextPresenter }) diff --git a/models/server-notification/package.json b/models/server-notification/package.json index 7598151f05..a0f217176c 100644 --- a/models/server-notification/package.json +++ b/models/server-notification/package.json @@ -27,8 +27,9 @@ "dependencies": { "@hcengineering/core": "^0.6.17", "@hcengineering/model": "~0.6.0", + "@hcengineering/model-core": "~0.6.0", "@hcengineering/platform": "^0.6.7", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-core": "~0.6.1" } } diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index cd1ff70591..af8f1d3307 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -14,13 +14,27 @@ // limitations under the License. // -import { Builder } from '@hcengineering/model' +import { Builder, Mixin } from '@hcengineering/model' import serverCore from '@hcengineering/server-core' import core from '@hcengineering/core' -import serverNotification from '@hcengineering/server-notification' +import serverNotification, { HTMLPresenter, TextPresenter, Presenter } from '@hcengineering/server-notification' +import { Resource } from '@hcengineering/platform' +import { TClass } from '@hcengineering/model-core' + +@Mixin(serverNotification.mixin.HTMLPresenter, core.class.Class) +export class THTMLPresenter extends TClass implements HTMLPresenter { + presenter!: Resource +} + +@Mixin(serverNotification.mixin.TextPresenter, core.class.Class) +export class TTextPresenter extends TClass implements TextPresenter { + presenter!: Resource +} export function createModel (builder: Builder): void { + builder.createModel(THTMLPresenter, TTextPresenter) + builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverNotification.trigger.OnBacklinkCreate }) diff --git a/models/server-recruit/package.json b/models/server-recruit/package.json index c881a74a3f..7d40d8c45a 100644 --- a/models/server-recruit/package.json +++ b/models/server-recruit/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-recruit": "~0.6.0", "@hcengineering/server-core": "~0.6.1", "@hcengineering/recruit": "~0.6.3", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-recruit/src/index.ts b/models/server-recruit/src/index.ts index a2064fa34a..24d460208b 100644 --- a/models/server-recruit/src/index.ts +++ b/models/server-recruit/src/index.ts @@ -17,24 +17,24 @@ import { Builder } from '@hcengineering/model' import core from '@hcengineering/core' import recruit from '@hcengineering/recruit' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' import serverRecruit from '@hcengineering/server-recruit' import serverCore from '@hcengineering/server-core' export function createModel (builder: Builder): void { - builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(recruit.class.Applicant, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverRecruit.function.ApplicationHTMLPresenter }) - builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(recruit.class.Applicant, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverRecruit.function.ApplicationTextPresenter }) - builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(recruit.class.Vacancy, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverRecruit.function.VacancyHTMLPresenter }) - builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(recruit.class.Vacancy, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverRecruit.function.VacancyTextPresenter }) diff --git a/models/server-task/package.json b/models/server-task/package.json index d53ed036ef..14438275c3 100644 --- a/models/server-task/package.json +++ b/models/server-task/package.json @@ -31,6 +31,6 @@ "@hcengineering/server-task": "~0.6.0", "@hcengineering/server-core": "~0.6.1", "@hcengineering/task": "~0.6.0", - "@hcengineering/view": "^0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/models/server-task/src/index.ts b/models/server-task/src/index.ts index b3cdf4ddf9..83f9d3a798 100644 --- a/models/server-task/src/index.ts +++ b/models/server-task/src/index.ts @@ -18,14 +18,14 @@ import { Builder } from '@hcengineering/model' import core from '@hcengineering/core' import serverTask from '@hcengineering/server-task' import task from '@hcengineering/task' -import view from '@hcengineering/view' +import serverNotification from '@hcengineering/server-notification' export function createModel (builder: Builder): void { - builder.mixin(task.class.Issue, core.class.Class, view.mixin.HTMLPresenter, { + builder.mixin(task.class.Issue, core.class.Class, serverNotification.mixin.HTMLPresenter, { presenter: serverTask.function.IssueHTMLPresenter }) - builder.mixin(task.class.Issue, core.class.Class, view.mixin.TextPresenter, { + builder.mixin(task.class.Issue, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverTask.function.IssueTextPresenter }) } diff --git a/models/server-tracker/package.json b/models/server-tracker/package.json index 7844644011..894d26b7b6 100644 --- a/models/server-tracker/package.json +++ b/models/server-tracker/package.json @@ -27,7 +27,9 @@ "dependencies": { "@hcengineering/core": "^0.6.17", "@hcengineering/model": "~0.6.0", + "@hcengineering/tracker": "^0.6.1", "@hcengineering/server-core": "~0.6.1", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-tracker": "~0.6.0" } } diff --git a/models/server-tracker/src/index.ts b/models/server-tracker/src/index.ts index 4523f1b118..f7cffca933 100644 --- a/models/server-tracker/src/index.ts +++ b/models/server-tracker/src/index.ts @@ -17,8 +17,18 @@ import { Builder } from '@hcengineering/model' import core from '@hcengineering/core' import serverCore from '@hcengineering/server-core' import serverTracker from '@hcengineering/server-tracker' +import tracker from '@hcengineering/tracker' +import serverNotification from '@hcengineering/server-notification' export function createModel (builder: Builder): void { + builder.mixin(tracker.class.Issue, core.class.Class, serverNotification.mixin.HTMLPresenter, { + presenter: serverTracker.function.IssueHTMLPresenter + }) + + builder.mixin(tracker.class.Issue, core.class.Class, serverNotification.mixin.TextPresenter, { + presenter: serverTracker.function.IssueTextPresenter + }) + builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverTracker.trigger.OnIssueUpdate }) diff --git a/models/task/src/index.ts b/models/task/src/index.ts index 63abe3609c..0628f4a8f7 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -581,7 +581,10 @@ export function createModel (builder: Builder): void { notification.class.NotificationType, core.space.Model, { - label: task.string.Assigned + label: task.string.Assigned, + textTemplate: '{doc} was assigned to you by {sender}', + htmlTemplate: '

{doc} was assigned to you by {sender}

', + subjectTemplate: '{doc} was assigned to you' }, task.ids.AssigneedNotification ) diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 21670cd506..f2927c0312 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -17,6 +17,7 @@ import type { Class, Client, Data, Doc, DocumentQuery, Ref, Space } from '@hceng import { DOMAIN_MODEL } from '@hcengineering/core' import { Builder, Mixin, Model } from '@hcengineering/model' import core, { TClass, TDoc } from '@hcengineering/model-core' +import preference, { TPreference } from '@hcengineering/model-preference' import type { Asset, IntlString, Resource, Status } from '@hcengineering/platform' import type { AnyComponent } from '@hcengineering/ui' import type { @@ -32,7 +33,6 @@ import type { CollectionPresenter, Filter, FilterMode, - HTMLPresenter, IgnoreActions, InlineAttributEditor, KeyBinding, @@ -46,7 +46,6 @@ import type { PreviewPresenter, SpaceHeader, SpaceName, - TextPresenter, ViewAction, ViewActionInput, ViewContext, @@ -54,7 +53,6 @@ import type { ViewletDescriptor, ViewletPreference } from '@hcengineering/view' -import preference, { TPreference } from '@hcengineering/model-preference' import view from './plugin' export { viewOperation } from './migration' @@ -223,16 +221,6 @@ export class TIgnoreActions extends TClass implements IgnoreActions { actions!: Ref[] } -@Mixin(view.mixin.HTMLPresenter, core.class.Class) -export class THTMLPresenter extends TClass implements HTMLPresenter { - presenter!: Resource<(doc: Doc) => string> -} - -@Mixin(view.mixin.TextPresenter, core.class.Class) -export class TTextPresenter extends TClass implements TextPresenter { - presenter!: Resource<(doc: Doc) => string> -} - @Mixin(view.mixin.PreviewPresenter, core.class.Class) export class TPreviewPresenter extends TClass implements PreviewPresenter { presenter!: AnyComponent @@ -291,10 +279,8 @@ export function createModel (builder: Builder): void { TObjectFactory, TObjectTitle, TObjectEditorHeader, - THTMLPresenter, TSpaceHeader, TSpaceName, - TTextPresenter, TIgnoreActions, TPreviewPresenter, TLinkPresenter, diff --git a/plugins/notification/src/index.ts b/plugins/notification/src/index.ts index d7b052f8ec..1b98f8d5fe 100644 --- a/plugins/notification/src/index.ts +++ b/plugins/notification/src/index.ts @@ -29,6 +29,15 @@ export interface LastView extends AttachedDoc { user: Ref } +/** + * @public + */ +export interface NotificationAction { + component: AnyComponent + objectId: Ref + objectClass: Ref> +} + /** * @public */ @@ -39,11 +48,7 @@ export interface Notification extends AttachedDoc { type: Ref // Defined to open particular item if required. - action?: { - component: AnyComponent - objectId: Ref - objectClass: Ref> - } + action?: NotificationAction } /** @@ -72,6 +77,9 @@ export enum NotificationStatus { */ export interface NotificationType extends Doc { label: IntlString + textTemplate: string + htmlTemplate: string + subjectTemplate: string } /** diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index ab1077b422..d8fa737a54 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -306,20 +306,6 @@ export interface IgnoreActions extends Class { actions: Ref[] } -/** - * @public - */ -export interface HTMLPresenter extends Class { - presenter: Resource<(doc: Doc) => string> -} - -/** - * @public - */ -export interface TextPresenter extends Class { - presenter: Resource<(doc: Doc) => string> -} - /** * @public */ @@ -420,8 +406,6 @@ const view = plugin(viewId, { SpaceHeader: '' as Ref>, SpaceName: '' as Ref>, IgnoreActions: '' as Ref>, - HTMLPresenter: '' as Ref>, - TextPresenter: '' as Ref>, PreviewPresenter: '' as Ref> }, class: { diff --git a/products/tracker/package.json b/products/tracker/package.json index 3094dd1192..d112704582 100644 --- a/products/tracker/package.json +++ b/products/tracker/package.json @@ -90,7 +90,7 @@ "@hcengineering/server-attachment-resources": "~0.6.0", "@hcengineering/server-contact": "~0.6.1", "@hcengineering/server-contact-resources": "~0.6.0", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-notification-resources": "~0.6.0", "@hcengineering/server-setting": "~0.6.0", "@hcengineering/server-setting-resources": "~0.6.0", diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts index 292785b43c..4f8e3d54e5 100644 --- a/server-plugins/chunter-resources/src/index.ts +++ b/server-plugins/chunter-resources/src/index.ts @@ -38,16 +38,16 @@ import { workbenchId } from '@hcengineering/workbench' /** * @public */ -export function channelHTMLPresenter (doc: Doc): string { +export async function channelHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const channel = doc as ChunterSpace const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${channel.name}` + return `${channel.name}` } /** * @public */ -export function channelTextPresenter (doc: Doc): string { +export async function channelTextPresenter (doc: Doc): Promise { const channel = doc as ChunterSpace return `${channel.name}` } diff --git a/server-plugins/chunter/package.json b/server-plugins/chunter/package.json index ba5b7ff4ab..445c56fc78 100644 --- a/server-plugins/chunter/package.json +++ b/server-plugins/chunter/package.json @@ -27,6 +27,7 @@ "typescript": "^4.3.5" }, "dependencies": { + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1" diff --git a/server-plugins/chunter/src/index.ts b/server-plugins/chunter/src/index.ts index aaf9e6a9f8..182e80e139 100644 --- a/server-plugins/chunter/src/index.ts +++ b/server-plugins/chunter/src/index.ts @@ -17,6 +17,7 @@ import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } fr import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import { TriggerFunc } from '@hcengineering/server-core' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -42,7 +43,7 @@ export default plugin(serverChunterId, { ) => Promise> ) => Promise >, - ChannelHTMLPresenter: '' as Resource<(doc: Doc) => string>, - ChannelTextPresenter: '' as Resource<(doc: Doc) => string> + ChannelHTMLPresenter: '' as Resource, + ChannelTextPresenter: '' as Resource } }) diff --git a/server-plugins/contact-resources/src/index.ts b/server-plugins/contact-resources/src/index.ts index 2a9d2157a4..5c714c0bc7 100644 --- a/server-plugins/contact-resources/src/index.ts +++ b/server-plugins/contact-resources/src/index.ts @@ -67,10 +67,10 @@ export async function OnContactDelete (tx: Tx, { findAll, hierarchy, storageFx } /** * @public */ -export function personHTMLPresenter (doc: Doc): string { +export function personHTMLPresenter (doc: Doc, control: TriggerControl): string { const person = doc as Person const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${formatName(person.name)}` } @@ -86,10 +86,10 @@ export function personTextPresenter (doc: Doc): string { /** * @public */ -export function organizationHTMLPresenter (doc: Doc): string { +export function organizationHTMLPresenter (doc: Doc, control: TriggerControl): string { const organization = doc as Organization const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${organization.name}` + return `${organization.name}` } /** diff --git a/server-plugins/contact/package.json b/server-plugins/contact/package.json index 3159ffd323..6558479f2e 100644 --- a/server-plugins/contact/package.json +++ b/server-plugins/contact/package.json @@ -27,7 +27,7 @@ "typescript": "^4.3.5" }, "dependencies": { - "@hcengineering/core": "^0.6.17", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1" } diff --git a/server-plugins/contact/src/index.ts b/server-plugins/contact/src/index.ts index 8f92bc63d0..c77f65a798 100644 --- a/server-plugins/contact/src/index.ts +++ b/server-plugins/contact/src/index.ts @@ -17,7 +17,7 @@ import type { Resource, Plugin } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import type { TriggerFunc } from '@hcengineering/server-core' -import { Doc } from '@hcengineering/core' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -32,9 +32,9 @@ export default plugin(serverContactId, { OnContactDelete: '' as Resource }, function: { - PersonHTMLPresenter: '' as Resource<(doc: Doc) => string>, - PersonTextPresenter: '' as Resource<(doc: Doc) => string>, - OrganizationHTMLPresenter: '' as Resource<(doc: Doc) => string>, - OrganizationTextPresenter: '' as Resource<(doc: Doc) => string> + PersonHTMLPresenter: '' as Resource, + PersonTextPresenter: '' as Resource, + OrganizationHTMLPresenter: '' as Resource, + OrganizationTextPresenter: '' as Resource } }) diff --git a/server-plugins/inventory-resources/package.json b/server-plugins/inventory-resources/package.json index e8859787f8..5af3e97e24 100644 --- a/server-plugins/inventory-resources/package.json +++ b/server-plugins/inventory-resources/package.json @@ -29,7 +29,7 @@ "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/inventory": "~0.6.0", "@hcengineering/view": "^0.6.1", "@hcengineering/login": "~0.6.1", diff --git a/server-plugins/inventory-resources/src/index.ts b/server-plugins/inventory-resources/src/index.ts index ed4d36d2cc..8205012ecc 100644 --- a/server-plugins/inventory-resources/src/index.ts +++ b/server-plugins/inventory-resources/src/index.ts @@ -17,22 +17,23 @@ import { Doc } from '@hcengineering/core' import { inventoryId, Product } from '@hcengineering/inventory' import login from '@hcengineering/login' import { getMetadata } from '@hcengineering/platform' +import { TriggerControl } from '@hcengineering/server-core' import view from '@hcengineering/view' import { workbenchId } from '@hcengineering/workbench' /** * @public */ -export function productHTMLPresenter (doc: Doc): string { +export async function productHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const product = doc as Product const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${product.name}` + return `${product.name}` } /** * @public */ -export function productTextPresenter (doc: Doc): string { +export async function productTextPresenter (doc: Doc): Promise { const product = doc as Product return `${product.name}` } diff --git a/server-plugins/inventory/package.json b/server-plugins/inventory/package.json index 7d096fb3a0..bce25396ba 100644 --- a/server-plugins/inventory/package.json +++ b/server-plugins/inventory/package.json @@ -27,8 +27,7 @@ "typescript": "^4.3.5" }, "dependencies": { - "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", - "@hcengineering/server-core": "~0.6.1" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/server-plugins/inventory/src/index.ts b/server-plugins/inventory/src/index.ts index d9defc2650..128057ea45 100644 --- a/server-plugins/inventory/src/index.ts +++ b/server-plugins/inventory/src/index.ts @@ -13,9 +13,9 @@ // limitations under the License. // -import { Doc } from '@hcengineering/core' import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -27,7 +27,7 @@ export const serverInventoryId = 'server-inventory' as Plugin */ export default plugin(serverInventoryId, { function: { - ProductHTMLPresenter: '' as Resource<(doc: Doc) => string>, - ProductTextPresenter: '' as Resource<(doc: Doc) => string> + ProductHTMLPresenter: '' as Resource, + ProductTextPresenter: '' as Resource } }) diff --git a/server-plugins/lead-resources/src/index.ts b/server-plugins/lead-resources/src/index.ts index a3a5132c87..8f9fadcf4d 100644 --- a/server-plugins/lead-resources/src/index.ts +++ b/server-plugins/lead-resources/src/index.ts @@ -34,16 +34,16 @@ import { addAssigneeNotification } from '@hcengineering/server-task-resources' /** * @public */ -export function leadHTMLPresenter (doc: Doc): string { +export async function leadHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const lead = doc as Lead const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${lead.title}` + return `${lead.title}` } /** * @public */ -export function leadTextPresenter (doc: Doc): string { +export async function leadTextPresenter (doc: Doc): Promise { const lead = doc as Lead return `LEAD-${lead.number}` } @@ -77,7 +77,6 @@ async function handleLeadCreate (control: TriggerControl, cud: TxCUD, res: control, res, leadValue, - leadTextPresenter(leadValue), leadValue.assignee, tx as TxCollectionCUD ) @@ -96,7 +95,6 @@ async function handleLeadUpdate (control: TriggerControl, cud: TxCUD, res: control, res, leadValue, - leadTextPresenter(leadValue), leadValue.assignee, tx as TxCollectionCUD ) diff --git a/server-plugins/lead/package.json b/server-plugins/lead/package.json index faa4d03734..f43ad3ecfa 100644 --- a/server-plugins/lead/package.json +++ b/server-plugins/lead/package.json @@ -27,10 +27,8 @@ "typescript": "^4.3.5" }, "dependencies": { - "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1", - "@hcengineering/contact": "~0.6.5", - "@hcengineering/server-task-resources": "~0.6.0" + "@hcengineering/server-notification": "^0.6.0" } } diff --git a/server-plugins/lead/src/index.ts b/server-plugins/lead/src/index.ts index 2f176f0ec4..012f541c8d 100644 --- a/server-plugins/lead/src/index.ts +++ b/server-plugins/lead/src/index.ts @@ -13,10 +13,10 @@ // limitations under the License. // -import { Doc } from '@hcengineering/core' import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import { TriggerFunc } from '@hcengineering/server-core' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -28,8 +28,8 @@ export const serverLeadId = 'server-lead' as Plugin */ export default plugin(serverLeadId, { function: { - LeadHTMLPresenter: '' as Resource<(doc: Doc) => string>, - LeadTextPresenter: '' as Resource<(doc: Doc) => string> + LeadHTMLPresenter: '' as Resource, + LeadTextPresenter: '' as Resource }, trigger: { OnLeadUpdate: '' as Resource diff --git a/server-plugins/notification-resources/package.json b/server-plugins/notification-resources/package.json index b33b288616..412a0987df 100644 --- a/server-plugins/notification-resources/package.json +++ b/server-plugins/notification-resources/package.json @@ -29,7 +29,7 @@ "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/notification": "~0.6.0", "@hcengineering/chunter": "~0.6.1", "@hcengineering/view": "^0.6.1", diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts index d75c865571..b9c0d35ee2 100644 --- a/server-plugins/notification-resources/src/index.ts +++ b/server-plugins/notification-resources/src/index.ts @@ -36,14 +36,24 @@ import core, { } from '@hcengineering/core' import notification, { EmailNotification, + NotificationAction, Notification, NotificationProvider, - NotificationStatus + NotificationStatus, + NotificationType } from '@hcengineering/notification' import { getResource } from '@hcengineering/platform' import type { TriggerControl } from '@hcengineering/server-core' -import { createLastViewTx, getUpdateLastViewTx } from '@hcengineering/server-notification' -import view, { HTMLPresenter, TextPresenter } from '@hcengineering/view' +import serverNotification, { + HTMLPresenter, + TextPresenter, + createLastViewTx, + getEmployeeAccount, + getEmployeeAccountById, + getUpdateLastViewTx +} from '@hcengineering/server-notification' +import { replaceAll } from './utils' +import { Content } from './types' /** * @public @@ -54,33 +64,21 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis if (!checkTx(ptx, hierarchy)) return [] - const result: Tx[] = [] - - const receiver = await getReceiver(ptx, control) + const receiver = await getEmployeeAccount(ptx.objectId as Ref, control) if (receiver === undefined) return [] - const sender = await getSender(ptx, control) + const sender = await getEmployeeAccountById(ptx.modifiedBy, control) + if (sender === undefined) return [] 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) - } - - 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 + return await createNotificationTxes( + control, + ptx, + notification.ids.MentionNotification, + doc, + sender, + receiver, + backlink.message + ) } function checkTx (ptx: TxCollectionCUD, hierarchy: Hierarchy): boolean { @@ -98,6 +96,202 @@ function checkTx (ptx: TxCollectionCUD, hierarchy: Hierarchy): bo return true } +async function isAllowed ( + control: TriggerControl, + receiver: EmployeeAccount, + providerId: Ref +): Promise { + const setting = ( + await control.findAll( + notification.class.NotificationSetting, + { + provider: providerId, + type: notification.ids.MentionNotification, + space: receiver._id as unknown as Ref + }, + { limit: 1 } + ) + )[0] + if (setting !== undefined) { + return setting.enabled + } + const provider = ( + await control.modelDb.findAll(notification.class.NotificationProvider, { + _id: providerId + }) + )[0] + if (provider === undefined) return false + return provider.default +} + +async function getTextPart (doc: Doc, control: TriggerControl): Promise { + const TextPresenter = getTextPresenter(doc._class, control.hierarchy) + if (TextPresenter === undefined) return + return await ( + await getResource(TextPresenter.presenter) + )(doc, control) +} + +async function getHtmlPart (doc: Doc, control: TriggerControl): Promise { + const HTMLPresenter = getHTMLPresenter(doc._class, control.hierarchy) + const htmlPart = + HTMLPresenter !== undefined ? await (await getResource(HTMLPresenter.presenter))(doc, control) : undefined + return htmlPart +} + +function getHTMLPresenter (_class: Ref>, hierarchy: Hierarchy): HTMLPresenter | undefined { + let clazz: Ref> | undefined = _class + while (clazz !== undefined) { + const _class = hierarchy.getClass(clazz) + const presenter = hierarchy.as(_class, serverNotification.mixin.HTMLPresenter) + if (presenter.presenter != null) return presenter + clazz = _class.extends + } +} + +function getTextPresenter (_class: Ref>, hierarchy: Hierarchy): TextPresenter | undefined { + let clazz: Ref> | undefined = _class + while (clazz !== undefined) { + const _class = hierarchy.getClass(clazz) + const presenter = hierarchy.as(_class, serverNotification.mixin.TextPresenter) + if (presenter.presenter != null) return presenter + clazz = _class.extends + } +} + +function fillTemplate (template: string, sender: string, doc: string, data: string): string { + let res = replaceAll(template, '{sender}', sender) + res = replaceAll(res, '{doc}', doc) + res = replaceAll(res, '{data}', data) + return res +} + +async function getContent ( + doc: Doc | undefined, + sender: string, + type: Ref, + control: TriggerControl, + data: string +): Promise { + if (doc === undefined) return + const notificationType = control.modelDb.getObject(type) + + const textPart = await getTextPart(doc, control) + if (textPart === undefined) return + const text = fillTemplate(notificationType.textTemplate, sender, textPart, data) + const htmlPart = await getHtmlPart(doc, control) + const html = fillTemplate(notificationType.htmlTemplate, sender, htmlPart ?? textPart, data) + const subject = fillTemplate(notificationType.subjectTemplate, sender, textPart, data) + return { + text, + html, + subject + } +} + +/** + * @public + */ +export async function createNotificationTxes ( + control: TriggerControl, + ptx: TxCollectionCUD, + type: Ref, + doc: Doc | undefined, + sender: EmployeeAccount, + receiver: EmployeeAccount, + data: string = '', + action?: NotificationAction +): Promise { + const res: Tx[] = [] + + const senderName = formatName(sender.name) + + const content = await getContent(doc, senderName, type, control, data) + + if (await isAllowed(control, receiver, notification.ids.PlatformNotification)) { + const createNotificationTx = await getPlatformNotificationTx(ptx, type, content?.text, action) + + res.push(createNotificationTx) + } + + if (content !== undefined && (await isAllowed(control, receiver, notification.ids.EmailNotification))) { + const emailTx = await getEmailNotificationTx(ptx, senderName, content.text, content.html, content.subject, receiver) + if (emailTx !== undefined) { + res.push(emailTx) + } + } + + return res +} + +async function getPlatformNotificationTx ( + ptx: TxCollectionCUD, + type: Ref, + text?: string, + action?: NotificationAction +): Promise> { + const createTx: TxCreateDoc = { + objectClass: notification.class.Notification, + objectSpace: notification.space.Notifications, + objectId: generateId(), + modifiedOn: ptx.modifiedOn, + modifiedBy: ptx.modifiedBy, + space: ptx.space, + _id: generateId(), + _class: core.class.TxCreateDoc, + attributes: { + tx: ptx._id, + status: NotificationStatus.New, + type + } as unknown as Data + } + + if (text !== undefined) { + createTx.attributes.text = text + } + + if (action !== undefined) { + createTx.attributes.action = action + } + + const createNotificationTx: TxCollectionCUD = { + ...ptx, + _id: generateId(), + collection: 'notifications', + tx: createTx + } + + return createNotificationTx +} + +async function getEmailNotificationTx ( + ptx: TxCollectionCUD, + sender: string, + text: string, + html: string, + subject: string, + receiver: EmployeeAccount +): Promise | undefined> { + return { + _id: generateId(), + objectId: generateId(), + _class: core.class.TxCreateDoc, + space: core.space.DerivedTx, + objectClass: notification.class.EmailNotification, + objectSpace: notification.space.Notifications, + modifiedOn: ptx.modifiedOn, + modifiedBy: ptx.modifiedBy, + attributes: { + status: 'new', + sender, + receivers: [receiver.email], + subject, + text, + html + } + } +} + async function getUpdateLastViewTxes ( doc: Doc, _id: Ref, @@ -197,86 +391,6 @@ export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise< return result } -async function getReceiver ( - ptx: TxCollectionCUD, - control: TriggerControl -): Promise { - return ( - await control.modelDb.findAll( - contact.class.EmployeeAccount, - { - employee: ptx.objectId as Ref - }, - { limit: 1 } - ) - )[0] -} - -async function isAllowed ( - control: TriggerControl, - receiver: EmployeeAccount, - providerId: Ref -): Promise { - const setting = ( - await control.findAll( - notification.class.NotificationSetting, - { - provider: providerId, - type: notification.ids.MentionNotification, - space: receiver._id as unknown as Ref - }, - { limit: 1 } - ) - )[0] - if (setting !== undefined) { - return setting.enabled - } - 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, - backlink: Backlink, - textPart: string | undefined, - sender: string | undefined -): Promise | undefined> { - const createTx: TxCreateDoc = { - objectClass: notification.class.Notification, - objectSpace: notification.space.Notifications, - objectId: generateId(), - modifiedOn: ptx.modifiedOn, - modifiedBy: ptx.modifiedBy, - space: ptx.space, - _id: generateId(), - _class: core.class.TxCreateDoc, - attributes: { - tx: ptx._id, - status: NotificationStatus.New, - type: notification.ids.MentionNotification - } as unknown as Data - } - - if (sender !== undefined && textPart !== undefined) { - const text = `${sender} mentioned you in ${textPart} ${backlink.message}` - createTx.attributes.text = text - } - - const createNotificationTx: TxCollectionCUD = { - ...ptx, - _id: generateId(), - collection: 'notifications', - tx: createTx - } - - return createNotificationTx -} - function getBacklink (ptx: TxCollectionCUD): Backlink { return TxProcessor.createDoc2Doc(ptx.tx as TxCreateDoc) } @@ -293,85 +407,6 @@ async function getBacklinkDoc (backlink: Backlink, control: TriggerControl): Pro )[0] } -async function getTextPart (doc: Doc, hierarchy: Hierarchy): Promise { - const TextPresenter = getTextPresenter(doc._class, hierarchy) - if (TextPresenter === undefined) return - return (await getResource(TextPresenter.presenter))(doc) -} - -async function getHtmlPart (doc: Doc, hierarchy: Hierarchy): Promise { - const HTMLPresenter = getHTMLPresenter(doc._class, hierarchy) - const htmlPart = HTMLPresenter !== undefined ? (await getResource(HTMLPresenter.presenter))(doc) : undefined - return htmlPart -} - -async function getSender (ptx: TxCollectionCUD, control: TriggerControl): Promise { - const account = ( - await control.modelDb.findAll( - contact.class.EmployeeAccount, - { - _id: ptx.modifiedBy as Ref - }, - { limit: 1 } - ) - )[0] - if (account === undefined) return undefined - - return formatName(account.name) -} - -async function getEmailTx ( - ptx: TxCollectionCUD, - backlink: Backlink, - sender: string, - textPart: string, - htmlPart: string | undefined, - receiver: EmployeeAccount -): Promise | undefined> { - const html = `

${sender} mentioned you in ${htmlPart !== undefined ? htmlPart : textPart}

${ - backlink.message - }` - const text = `${sender} mentioned you in ${textPart}` - return { - _id: generateId(), - objectId: generateId(), - _class: core.class.TxCreateDoc, - space: core.space.DerivedTx, - objectClass: notification.class.EmailNotification, - objectSpace: notification.space.Notifications, - modifiedOn: ptx.modifiedOn, - modifiedBy: ptx.modifiedBy, - attributes: { - status: 'new', - sender, - receivers: [receiver.email], - subject: `You was mentioned in ${textPart}`, - text, - html - } - } -} - -function getHTMLPresenter (_class: Ref>, hierarchy: Hierarchy): HTMLPresenter | undefined { - let clazz: Ref> | undefined = _class - while (clazz !== undefined) { - const _class = hierarchy.getClass(clazz) - const presenter = hierarchy.as(_class, view.mixin.HTMLPresenter) - if (presenter.presenter != null) return presenter - clazz = _class.extends - } -} - -function getTextPresenter (_class: Ref>, hierarchy: Hierarchy): TextPresenter | undefined { - let clazz: Ref> | undefined = _class - while (clazz !== undefined) { - const _class = hierarchy.getClass(clazz) - const presenter = hierarchy.as(_class, view.mixin.TextPresenter) - if (presenter.presenter != null) return presenter - clazz = _class.extends - } -} - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export default async () => ({ trigger: { diff --git a/server-plugins/notification-resources/src/types.ts b/server-plugins/notification-resources/src/types.ts new file mode 100644 index 0000000000..5863a769ed --- /dev/null +++ b/server-plugins/notification-resources/src/types.ts @@ -0,0 +1,5 @@ +export interface Content { + text: string + html: string + subject: string +} diff --git a/server-plugins/notification-resources/src/utils.ts b/server-plugins/notification-resources/src/utils.ts new file mode 100644 index 0000000000..d84158364c --- /dev/null +++ b/server-plugins/notification-resources/src/utils.ts @@ -0,0 +1,7 @@ +function escapeRegExp (str: string): string { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + +export function replaceAll (str: string, find: string, replace: string): string { + return str.replace(new RegExp(escapeRegExp(find), 'g'), replace) +} diff --git a/server-plugins/notification/package.json b/server-plugins/notification/package.json index 560688c831..6537dc2853 100644 --- a/server-plugins/notification/package.json +++ b/server-plugins/notification/package.json @@ -30,6 +30,7 @@ "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/notification": "~0.6.0", - "@hcengineering/server-core": "~0.6.1" + "@hcengineering/server-core": "~0.6.1", + "@hcengineering/contact": "~0.6.5" } } diff --git a/server-plugins/notification/src/index.ts b/server-plugins/notification/src/index.ts index b5c0d6bac2..a75123f9e2 100644 --- a/server-plugins/notification/src/index.ts +++ b/server-plugins/notification/src/index.ts @@ -14,11 +14,11 @@ // limitations under the License. // -import core, { Account, Class, Doc, Ref, TxCreateDoc, TxFactory, TxUpdateDoc } from '@hcengineering/core' -import type { Resource, Plugin } from '@hcengineering/platform' -import { plugin } from '@hcengineering/platform' -import type { TriggerControl, TriggerFunc } from '@hcengineering/server-core' +import contact, { Employee, EmployeeAccount } from '@hcengineering/contact' +import core, { Account, Class, Doc, Mixin, Ref, TxCreateDoc, TxFactory, TxUpdateDoc } from '@hcengineering/core' import notification, { LastView } from '@hcengineering/notification' +import { Plugin, plugin, Resource } from '@hcengineering/platform' +import type { TriggerControl, TriggerFunc } from '@hcengineering/server-core' /** * @public @@ -69,6 +69,60 @@ export async function getUpdateLastViewTx ( } } +/** + * @public + */ +export async function getEmployeeAccount ( + employee: Ref, + control: TriggerControl +): Promise { + const account = ( + await control.modelDb.findAll( + contact.class.EmployeeAccount, + { + employee: employee + }, + { limit: 1 } + ) + )[0] + return account +} + +/** + * @public + */ +export async function getEmployeeAccountById ( + _id: Ref, + control: TriggerControl +): Promise { + const account = ( + await control.modelDb.findAll( + contact.class.EmployeeAccount, + { + _id: _id as Ref + }, + { limit: 1 } + ) + )[0] + return account +} + +/** + * @public + */ +export async function getEmployee (employee: Ref, control: TriggerControl): Promise { + const account = ( + await control.findAll( + contact.class.Employee, + { + _id: employee + }, + { limit: 1 } + ) + )[0] + return account +} + /** * @public */ @@ -103,10 +157,33 @@ export async function createLastViewTx ( } } +/** + * @public + */ +export type Presenter = (doc: Doc, control: TriggerControl) => Promise + +/** + * @public + */ +export interface HTMLPresenter extends Class { + presenter: Resource +} + +/** + * @public + */ +export interface TextPresenter extends Class { + presenter: Resource +} + /** * @public */ export default plugin(serverNotificationId, { + mixin: { + HTMLPresenter: '' as Ref>, + TextPresenter: '' as Ref> + }, trigger: { OnBacklinkCreate: '' as Resource, UpdateLastView: '' as Resource diff --git a/server-plugins/recruit-resources/src/index.ts b/server-plugins/recruit-resources/src/index.ts index 522ad7d15d..10b8fc4323 100644 --- a/server-plugins/recruit-resources/src/index.ts +++ b/server-plugins/recruit-resources/src/index.ts @@ -36,16 +36,16 @@ import { workbenchId } from '@hcengineering/workbench' /** * @public */ -export function vacancyHTMLPresenter (doc: Doc): string { +export async function vacancyHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const vacancy = doc as Vacancy const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${vacancy.name}` + return `${vacancy.name}` } /** * @public */ -export function vacancyTextPresenter (doc: Doc): string { +export async function vacancyTextPresenter (doc: Doc): Promise { const vacancy = doc as Vacancy return `${vacancy.name}` } @@ -53,16 +53,16 @@ export function vacancyTextPresenter (doc: Doc): string { /** * @public */ -export function applicationHTMLPresenter (doc: Doc): string { +export async function applicationHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const applicant = doc as Applicant const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `APP-${applicant.number}` + return `APP-${applicant.number}` } /** * @public */ -export function applicationTextPresenter (doc: Doc): string { +export async function applicationTextPresenter (doc: Doc): Promise { const applicant = doc as Applicant return `APP-${applicant.number}` } @@ -185,7 +185,6 @@ async function handleApplicantUpdate (control: TriggerControl, cud: TxCUD, control, res, applicant, - applicationTextPresenter(applicant), applicant.assignee, tx as TxCollectionCUD ) @@ -203,7 +202,6 @@ async function handleApplicantCreate (control: TriggerControl, cud: TxCUD, control, res, applicant, - applicationTextPresenter(applicant), applicant.assignee, tx as TxCollectionCUD ) diff --git a/server-plugins/recruit/package.json b/server-plugins/recruit/package.json index 7b2e99c5c8..3073b69de1 100644 --- a/server-plugins/recruit/package.json +++ b/server-plugins/recruit/package.json @@ -27,8 +27,8 @@ "typescript": "^4.3.5" }, "dependencies": { - "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-core": "~0.6.1" } } diff --git a/server-plugins/recruit/src/index.ts b/server-plugins/recruit/src/index.ts index b90ede6a16..443764a6f3 100644 --- a/server-plugins/recruit/src/index.ts +++ b/server-plugins/recruit/src/index.ts @@ -13,10 +13,10 @@ // limitations under the License. // -import type { Resource, Plugin } from '@hcengineering/platform' +import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import { Doc } from '@hcengineering/core' import { TriggerFunc } from '@hcengineering/server-core' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -28,10 +28,10 @@ export const serverRecruitId = 'server-recruit' as Plugin */ export default plugin(serverRecruitId, { function: { - ApplicationHTMLPresenter: '' as Resource<(doc: Doc) => string>, - ApplicationTextPresenter: '' as Resource<(doc: Doc) => string>, - VacancyHTMLPresenter: '' as Resource<(doc: Doc) => string>, - VacancyTextPresenter: '' as Resource<(doc: Doc) => string> + ApplicationHTMLPresenter: '' as Resource, + ApplicationTextPresenter: '' as Resource, + VacancyHTMLPresenter: '' as Resource, + VacancyTextPresenter: '' as Resource }, trigger: { OnRecruitUpdate: '' as Resource diff --git a/server-plugins/task-resources/package.json b/server-plugins/task-resources/package.json index 9dd42bd8b6..74c0bda169 100644 --- a/server-plugins/task-resources/package.json +++ b/server-plugins/task-resources/package.json @@ -29,7 +29,8 @@ "@hcengineering/core": "^0.6.17", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", + "@hcengineering/server-notification-resources": "~0.6.0", "@hcengineering/task": "~0.6.0", "@hcengineering/view": "^0.6.1", "@hcengineering/login": "~0.6.1", diff --git a/server-plugins/task-resources/src/index.ts b/server-plugins/task-resources/src/index.ts index 3a378fcb8c..6174de5433 100644 --- a/server-plugins/task-resources/src/index.ts +++ b/server-plugins/task-resources/src/index.ts @@ -13,25 +13,19 @@ // limitations under the License. // -import contact, { Employee, EmployeeAccount, formatName } from '@hcengineering/contact' -import core, { - Account, - AttachedDoc, - Data, - Doc, - generateId, - Ref, - Tx, - TxCollectionCUD, - TxCreateDoc, - TxProcessor, - TxUpdateDoc -} from '@hcengineering/core' +import { Employee } from '@hcengineering/contact' +import core, { AttachedDoc, Doc, Ref, Tx, TxCollectionCUD, TxProcessor, TxUpdateDoc } from '@hcengineering/core' import login from '@hcengineering/login' -import notification, { Notification, NotificationStatus } from '@hcengineering/notification' +import { NotificationAction } from '@hcengineering/notification' import { getMetadata, Resource } from '@hcengineering/platform' import { TriggerControl } from '@hcengineering/server-core' -import { getUpdateLastViewTx } from '@hcengineering/server-notification' +import { + getEmployee, + getEmployeeAccount, + getEmployeeAccountById, + getUpdateLastViewTx +} from '@hcengineering/server-notification' +import { createNotificationTxes } from '@hcengineering/server-notification-resources' import task, { Issue, Task, taskId } from '@hcengineering/task' import view from '@hcengineering/view' import { workbenchId } from '@hcengineering/workbench' @@ -39,52 +33,20 @@ import { workbenchId } from '@hcengineering/workbench' /** * @public */ -export function issueHTMLPresenter (doc: Doc): string { +export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const issue = doc as Issue const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `Task-${issue.number}` + return `Task-${issue.number}` } /** * @public */ -export function issueTextPresenter (doc: Doc): string { +export async function issueTextPresenter (doc: Doc): Promise { const issue = doc as Issue return `Task-${issue.number}` } -/** - * @public - */ -export async function getEmployeeAccount ( - employee: Ref, - control: TriggerControl -): Promise { - const account = ( - await control.modelDb.findAll( - contact.class.EmployeeAccount, - { - _id: employee as Ref - }, - { limit: 1 } - ) - )[0] - return account -} - -async function getEmployee (employee: Ref, control: TriggerControl): Promise { - const account = ( - await control.findAll( - contact.class.Employee, - { - _id: employee - }, - { limit: 1 } - ) - )[0] - return account -} - /** * @public */ @@ -92,12 +54,11 @@ export async function addAssigneeNotification ( control: TriggerControl, res: Tx[], issue: Doc, - issueName: string, assignee: Ref, ptx: TxCollectionCUD, component?: Resource ): Promise { - const sender = await getEmployeeAccount(ptx.modifiedBy, control) + const sender = await getEmployeeAccountById(ptx.modifiedBy, control) if (sender === undefined) { return } @@ -107,29 +68,30 @@ export async function addAssigneeNotification ( return } - const createTx: TxCreateDoc = { - objectClass: notification.class.Notification, - objectSpace: notification.space.Notifications, - objectId: generateId(), - modifiedOn: ptx.modifiedOn, - modifiedBy: ptx.modifiedBy, - space: ptx.space, - _id: generateId(), - _class: core.class.TxCreateDoc, - attributes: { - tx: ptx._id, - status: NotificationStatus.New, - type: task.ids.AssigneedNotification, - text: `${issueName} was assigned to you by ${formatName(sender.name)}`, - action: { - component: component ?? view.component.EditDoc, - objectId: issue._id, - objectClass: issue._class - } - } as unknown as Data + const receiver = await getEmployeeAccount(assignee, control) + if (receiver === undefined) { + return } - res.push(control.txFactory.createTxCollectionCUD(target._class, target._id, target.space, 'notifications', createTx)) + // eslint-disable-next-line + const action: NotificationAction = { + component: component ?? view.component.EditDoc, + objectId: issue._id, + objectClass: issue._class + } as NotificationAction + + const result = await createNotificationTxes( + control, + ptx, + task.ids.AssigneedNotification, + issue, + sender, + receiver, + undefined, + action + ) + + res.push(...result) } /** diff --git a/server-plugins/task/package.json b/server-plugins/task/package.json index 845bb5c551..e008194fb8 100644 --- a/server-plugins/task/package.json +++ b/server-plugins/task/package.json @@ -27,7 +27,7 @@ "typescript": "^4.3.5" }, "dependencies": { - "@hcengineering/core": "^0.6.17", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/platform": "^0.6.7", "@hcengineering/server-core": "~0.6.1" } diff --git a/server-plugins/task/src/index.ts b/server-plugins/task/src/index.ts index c0e939b078..7a6c5d24c9 100644 --- a/server-plugins/task/src/index.ts +++ b/server-plugins/task/src/index.ts @@ -13,9 +13,9 @@ // limitations under the License. // -import { Doc } from '@hcengineering/core' import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -27,7 +27,7 @@ export const serverTaskId = 'server-task' as Plugin */ export default plugin(serverTaskId, { function: { - IssueHTMLPresenter: '' as Resource<(doc: Doc) => string>, - IssueTextPresenter: '' as Resource<(doc: Doc) => string> + IssueHTMLPresenter: '' as Resource, + IssueTextPresenter: '' as Resource } }) diff --git a/server-plugins/tracker-resources/package.json b/server-plugins/tracker-resources/package.json index ed300e8d17..019eebf399 100644 --- a/server-plugins/tracker-resources/package.json +++ b/server-plugins/tracker-resources/package.json @@ -33,6 +33,9 @@ "@hcengineering/contact": "~0.6.5", "@hcengineering/notification": "~0.6.0", "@hcengineering/task": "~0.6.0", + "@hcengineering/view": "^0.6.1", + "@hcengineering/login": "~0.6.1", + "@hcengineering/workbench": "~0.6.1", "@hcengineering/server-task-resources": "~0.6.0" } } diff --git a/server-plugins/tracker-resources/src/index.ts b/server-plugins/tracker-resources/src/index.ts index e0d6d0e81c..28c6b21e14 100644 --- a/server-plugins/tracker-resources/src/index.ts +++ b/server-plugins/tracker-resources/src/index.ts @@ -16,6 +16,7 @@ import { Employee } from '@hcengineering/contact' import core, { AttachedDoc, + Doc, DocumentUpdate, Ref, Space, @@ -28,10 +29,13 @@ import core, { TxUpdateDoc, WithLookup } from '@hcengineering/core' +import login from '@hcengineering/login' +import { workbenchId } from '@hcengineering/workbench' +import { getMetadata } from '@hcengineering/platform' import { Resource } from '@hcengineering/platform/lib/platform' import { TriggerControl } from '@hcengineering/server-core' import { addAssigneeNotification } from '@hcengineering/server-task-resources' -import tracker, { Issue, IssueParentInfo, TimeSpendReport } from '@hcengineering/tracker' +import tracker, { Issue, IssueParentInfo, TimeSpendReport, trackerId } from '@hcengineering/tracker' async function updateSubIssues ( updateTx: TxUpdateDoc, @@ -46,6 +50,29 @@ async function updateSubIssues ( }) } +/** + * @public + */ +export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Promise { + const issue = doc as Issue + const team = (await control.findAll(tracker.class.Team, { _id: issue.space })).shift() + const issueName = `${team?.identifier ?? '?'}-${issue.number}` + + const front = getMetadata(login.metadata.FrontUrl) ?? '' + return `${issueName}` +} + +/** + * @public + */ +export async function issueTextPresenter (doc: Doc, control: TriggerControl): Promise { + const issue = doc as Issue + const team = (await control.findAll(tracker.class.Team, { _id: issue.space })).shift() + const issueName = `${team?.identifier ?? '?'}-${issue.number}` + + return issueName +} + /** * @public */ @@ -56,14 +83,10 @@ export async function addTrackerAssigneeNotification ( assignee: Ref, ptx: TxCollectionCUD ): Promise { - const team = (await control.findAll(tracker.class.Team, { _id: issue.space })).shift() - const issueName = `${team?.identifier ?? '?'}-${issue.number}` - await addAssigneeNotification( control, res, issue, - issueName, assignee, ptx, tracker.component.EditIssue as unknown as Resource @@ -142,6 +165,10 @@ export async function OnIssueUpdate (tx: Tx, control: TriggerControl): Promise ({ + function: { + IssueHTMLPresenter: issueHTMLPresenter, + IssueTextPresenter: issueTextPresenter + }, trigger: { OnIssueUpdate } diff --git a/server-plugins/tracker/package.json b/server-plugins/tracker/package.json index b3c6282bbf..109fd6a1d7 100644 --- a/server-plugins/tracker/package.json +++ b/server-plugins/tracker/package.json @@ -28,6 +28,7 @@ }, "dependencies": { "@hcengineering/platform": "^0.6.7", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-core": "~0.6.1" } } diff --git a/server-plugins/tracker/src/index.ts b/server-plugins/tracker/src/index.ts index bd27098bbb..8714079166 100644 --- a/server-plugins/tracker/src/index.ts +++ b/server-plugins/tracker/src/index.ts @@ -16,6 +16,7 @@ import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import { TriggerFunc } from '@hcengineering/server-core' +import { Presenter } from '@hcengineering/server-notification' /** * @public @@ -26,6 +27,10 @@ export const serverTrackerId = 'server-tracker' as Plugin * @public */ export default plugin(serverTrackerId, { + function: { + IssueHTMLPresenter: '' as Resource, + IssueTextPresenter: '' as Resource + }, trigger: { OnIssueUpdate: '' as Resource } diff --git a/server/core/src/storage.ts b/server/core/src/storage.ts index 84ed20b1bd..683a9756db 100644 --- a/server/core/src/storage.ts +++ b/server/core/src/storage.ts @@ -408,6 +408,7 @@ class TServerStorage implements ServerStorage { ...(await ctx.with('process-move', { _class }, () => this.processMove(ctx, tx))), ...(await ctx.with('process-triggers', {}, (ctx) => this.triggers.apply(tx.modifiedBy, tx, { + workspace: this.workspace, fx: triggerFx.fx, fulltextFx: (f) => triggerFx.fx(() => f(this.fulltextAdapter)), storageFx: (f) => { diff --git a/server/core/src/types.ts b/server/core/src/types.ts index 4d1d41fa7b..14066b6902 100644 --- a/server/core/src/types.ts +++ b/server/core/src/types.ts @@ -98,6 +98,7 @@ export interface Pipeline extends LowLevelStorage { * @public */ export interface TriggerControl { + workspace: string txFactory: TxFactory findAll: Storage['findAll'] hierarchy: Hierarchy diff --git a/server/server/package.json b/server/server/package.json index 06dbdd277a..6f7f459a41 100644 --- a/server/server/package.json +++ b/server/server/package.json @@ -49,7 +49,7 @@ "minio": "^7.0.26", "@hcengineering/server-contact": "~0.6.1", "@hcengineering/server-contact-resources": "~0.6.0", - "@hcengineering/server-notification": "~0.6.0", + "@hcengineering/server-notification": "^0.6.0", "@hcengineering/server-notification-resources": "~0.6.0", "@hcengineering/server-setting": "~0.6.0", "@hcengineering/server-setting-resources": "~0.6.0",