mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-18 06:13:52 +00:00
parent
ee57808311
commit
9b27f289cd
@ -17,6 +17,9 @@
|
||||
import activity from '@hcengineering/activity'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import {
|
||||
DOMAIN_MODEL,
|
||||
Hierarchy,
|
||||
IndexKind,
|
||||
type Account,
|
||||
type AttachedDoc,
|
||||
type Class,
|
||||
@ -24,26 +27,22 @@ import {
|
||||
type Data,
|
||||
type Doc,
|
||||
type Domain,
|
||||
DOMAIN_MODEL,
|
||||
Hierarchy,
|
||||
IndexKind,
|
||||
type Ref,
|
||||
type Timestamp,
|
||||
type Tx,
|
||||
type TxCUD
|
||||
} from '@hcengineering/core'
|
||||
import { ArrOf, type Builder, Index, Mixin, Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model'
|
||||
import { ArrOf, Index, Mixin, Model, Prop, TypeRef, TypeString, UX, type Builder } from '@hcengineering/model'
|
||||
import core, { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import view, { createAction } from '@hcengineering/model-view'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
import {
|
||||
type DocUpdates,
|
||||
notificationId,
|
||||
type DocUpdateTx,
|
||||
type EmailNotification,
|
||||
type DocUpdates,
|
||||
type Notification,
|
||||
type NotificationGroup,
|
||||
notificationId,
|
||||
type NotificationObjectPresenter,
|
||||
type NotificationPreferencesGroup,
|
||||
type NotificationPreview,
|
||||
@ -76,29 +75,6 @@ export class TNotification extends TAttachedDoc implements Notification {
|
||||
type!: Ref<NotificationType>
|
||||
}
|
||||
|
||||
@Model(notification.class.EmailNotification, core.class.Doc, DOMAIN_NOTIFICATION)
|
||||
export class TEmaiNotification extends TDoc implements EmailNotification {
|
||||
@Prop(TypeString(), 'Sender' as IntlString)
|
||||
sender!: string
|
||||
|
||||
@Prop(ArrOf(TypeString()), 'Receivers' as IntlString)
|
||||
receivers!: string[]
|
||||
|
||||
@Prop(TypeString(), 'Subject' as IntlString)
|
||||
subject!: string
|
||||
|
||||
@Prop(TypeString(), 'Text' as IntlString)
|
||||
text!: string
|
||||
|
||||
@Prop(TypeString(), 'Html' as IntlString)
|
||||
html?: string
|
||||
|
||||
@Prop(TypeString(), 'Status' as IntlString)
|
||||
status!: 'new' | 'sent' | 'error'
|
||||
|
||||
error?: string
|
||||
}
|
||||
|
||||
@Model(notification.class.NotificationType, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TNotificationType extends TDoc implements NotificationType {
|
||||
generated!: boolean
|
||||
@ -182,7 +158,6 @@ export class TDocUpdates extends TDoc implements DocUpdates {
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(
|
||||
TNotification,
|
||||
TEmaiNotification,
|
||||
TNotificationType,
|
||||
TNotificationProvider,
|
||||
TNotificationSetting,
|
||||
|
@ -29,10 +29,10 @@ import {
|
||||
} from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { Preference } from '@hcengineering/preference'
|
||||
import { IntegrationType } from '@hcengineering/setting'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import { Writable } from './types'
|
||||
import { Preference } from '@hcengineering/preference'
|
||||
export * from './types'
|
||||
|
||||
/**
|
||||
@ -45,19 +45,6 @@ export interface Notification extends AttachedDoc {
|
||||
type: Ref<NotificationType>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EmailNotification extends Doc {
|
||||
sender: string
|
||||
receivers: string[]
|
||||
subject: string
|
||||
text: string
|
||||
html?: string
|
||||
status: 'new' | 'sent' | 'error'
|
||||
error?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -238,7 +225,6 @@ const notification = plugin(notificationId, {
|
||||
},
|
||||
class: {
|
||||
Notification: '' as Ref<Class<Notification>>,
|
||||
EmailNotification: '' as Ref<Class<EmailNotification>>,
|
||||
NotificationType: '' as Ref<Class<NotificationType>>,
|
||||
NotificationProvider: '' as Ref<Class<NotificationProvider>>,
|
||||
NotificationSetting: '' as Ref<Class<NotificationSetting>>,
|
||||
|
@ -20,6 +20,7 @@ import serverCore from '@hcengineering/server-core'
|
||||
import serverToken from '@hcengineering/server-token'
|
||||
import { serverFactories } from '@hcengineering/server-ws'
|
||||
import { start } from '.'
|
||||
import serverNotification from '@hcengineering/server-notification'
|
||||
|
||||
const serverPort = parseInt(process.env.SERVER_PORT ?? '3333')
|
||||
|
||||
@ -81,8 +82,11 @@ if (frontUrl === undefined) {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const sesUrl = process.env.SES_URL
|
||||
|
||||
setMetadata(serverCore.metadata.FrontUrl, frontUrl)
|
||||
setMetadata(serverToken.metadata.Secret, serverSecret)
|
||||
setMetadata(serverNotification.metadata.SesUrl, sesUrl ?? '')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
console.log(
|
||||
|
@ -40,7 +40,7 @@ import notification, { NotificationType } from '@hcengineering/notification'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { TriggerControl } from '@hcengineering/server-core'
|
||||
import { getEmployee, getPersonAccountById } from '@hcengineering/server-notification'
|
||||
import { getContent, isAllowed } from '@hcengineering/server-notification-resources'
|
||||
import { getContent, isAllowed, sendEmailNotification } from '@hcengineering/server-notification-resources'
|
||||
|
||||
async function getOldDepartment (
|
||||
currentTx: TxMixin<Employee, Staff> | TxUpdateDoc<Employee>,
|
||||
@ -221,13 +221,13 @@ export async function OnEmployeeDeactivate (tx: Tx, control: TriggerControl): Pr
|
||||
)
|
||||
}
|
||||
|
||||
async function getEmailNotification (
|
||||
async function sendEmailNotifications (
|
||||
control: TriggerControl,
|
||||
sender: PersonAccount,
|
||||
doc: Request | PublicHoliday,
|
||||
space: Ref<Department>,
|
||||
type: Ref<NotificationType>
|
||||
): Promise<Tx[]> {
|
||||
): Promise<void> {
|
||||
const contacts = new Set<Ref<Contact>>()
|
||||
const departments = await buildHierarchy(space, control)
|
||||
for (const department of departments) {
|
||||
@ -257,25 +257,11 @@ async function getEmailNotification (
|
||||
|
||||
const senderName = senderPerson !== undefined ? formatName(senderPerson.name) : ''
|
||||
const content = await getContent(doc, senderName, type, control, '')
|
||||
if (content === undefined) return []
|
||||
if (content === undefined) return
|
||||
|
||||
const res: Tx[] = []
|
||||
for (const channel of channels) {
|
||||
const tx = control.txFactory.createTxCreateDoc(
|
||||
notification.class.EmailNotification,
|
||||
notification.space.Notifications,
|
||||
{
|
||||
status: 'new',
|
||||
sender: senderName,
|
||||
receivers: [channel.value],
|
||||
subject: content.subject,
|
||||
text: content.text,
|
||||
html: content.html
|
||||
}
|
||||
)
|
||||
res.push(tx)
|
||||
await sendEmailNotification(content.text, content.html, content.subject, channel.value)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
@ -289,13 +275,14 @@ export async function OnRequestCreate (tx: Tx, control: TriggerControl): Promise
|
||||
|
||||
const request = TxProcessor.createDoc2Doc(ctx)
|
||||
|
||||
return await getEmailNotification(
|
||||
await sendEmailNotifications(
|
||||
control,
|
||||
sender,
|
||||
request,
|
||||
ctx.objectSpace as Ref<Department>,
|
||||
hr.ids.CreateRequestNotification
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
@ -310,13 +297,14 @@ export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise
|
||||
const request = (await control.findAll(hr.class.Request, { _id: ctx.objectId }))[0] as Request
|
||||
if (request === undefined) return []
|
||||
|
||||
return await getEmailNotification(
|
||||
await sendEmailNotifications(
|
||||
control,
|
||||
sender,
|
||||
request,
|
||||
ctx.objectSpace as Ref<Department>,
|
||||
hr.ids.UpdateRequestNotification
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,13 +319,14 @@ export async function OnRequestRemove (tx: Tx, control: TriggerControl): Promise
|
||||
const request = control.removedMap.get(ctx.objectId) as Request
|
||||
if (request === undefined) return []
|
||||
|
||||
return await getEmailNotification(
|
||||
await sendEmailNotifications(
|
||||
control,
|
||||
sender,
|
||||
request,
|
||||
ctx.objectSpace as Ref<Department>,
|
||||
hr.ids.RemoveRequestNotification
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,13 +377,14 @@ export async function OnPublicHolidayCreate (tx: Tx, control: TriggerControl): P
|
||||
if (employee === undefined) return []
|
||||
|
||||
const publicHoliday = TxProcessor.createDoc2Doc(ctx)
|
||||
return await getEmailNotification(
|
||||
await sendEmailNotifications(
|
||||
control,
|
||||
sender,
|
||||
publicHoliday,
|
||||
publicHoliday.department,
|
||||
hr.ids.CreatePublicHolidayNotification
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,25 +38,24 @@ import core, {
|
||||
TxProcessor,
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc,
|
||||
generateId,
|
||||
concatLink,
|
||||
matchQuery
|
||||
} from '@hcengineering/core'
|
||||
import notification, {
|
||||
ClassCollaborators,
|
||||
Collaborators,
|
||||
DocUpdates,
|
||||
DocUpdateTx,
|
||||
EmailNotification,
|
||||
DocUpdates,
|
||||
NotificationProvider,
|
||||
NotificationType
|
||||
} from '@hcengineering/notification'
|
||||
import { IntlString, getResource } from '@hcengineering/platform'
|
||||
import { IntlString, getMetadata, getResource } from '@hcengineering/platform'
|
||||
import type { TriggerControl } from '@hcengineering/server-core'
|
||||
import serverNotification, {
|
||||
HTMLPresenter,
|
||||
NotificationPresenter,
|
||||
TextPresenter,
|
||||
getEmployee,
|
||||
NotificationPresenter,
|
||||
getPersonAccount,
|
||||
getPersonAccountById
|
||||
} from '@hcengineering/server-notification'
|
||||
@ -222,15 +221,14 @@ export async function getContent (
|
||||
}
|
||||
}
|
||||
|
||||
async function createEmailNotificationTxes (
|
||||
async function notifyByEmail (
|
||||
control: TriggerControl,
|
||||
tx: Tx,
|
||||
type: Ref<NotificationType>,
|
||||
doc: Doc | undefined,
|
||||
senderId: Ref<PersonAccount>,
|
||||
receiverId: Ref<PersonAccount>,
|
||||
data: string = ''
|
||||
): Promise<Tx | undefined> {
|
||||
): Promise<void> {
|
||||
const sender = (await control.modelDb.findAll(contact.class.PersonAccount, { _id: senderId }))[0]
|
||||
|
||||
const receiver = (await control.modelDb.findAll(contact.class.PersonAccount, { _id: receiverId }))[0]
|
||||
@ -238,42 +236,43 @@ async function createEmailNotificationTxes (
|
||||
let senderName = ''
|
||||
|
||||
if (sender !== undefined) {
|
||||
const senderPerson = (await control.modelDb.findAll(contact.class.Person, { _id: sender.person }))[0]
|
||||
const senderPerson = (await control.findAll(contact.class.Person, { _id: sender.person }))[0]
|
||||
senderName = senderPerson !== undefined ? formatName(senderPerson.name) : ''
|
||||
}
|
||||
|
||||
const content = await getContent(doc, senderName, type, control, data)
|
||||
|
||||
if (content !== undefined) {
|
||||
return await getEmailNotificationTx(tx, senderName, content.text, content.html, content.subject, receiver)
|
||||
await sendEmailNotification(content.text, content.html, content.subject, receiver.email)
|
||||
}
|
||||
}
|
||||
|
||||
async function getEmailNotificationTx (
|
||||
tx: Tx,
|
||||
sender: string,
|
||||
export async function sendEmailNotification (
|
||||
text: string,
|
||||
html: string,
|
||||
subject: string,
|
||||
receiver: PersonAccount
|
||||
): Promise<TxCreateDoc<EmailNotification> | undefined> {
|
||||
return {
|
||||
_id: generateId(),
|
||||
objectId: generateId(),
|
||||
_class: core.class.TxCreateDoc,
|
||||
space: core.space.DerivedTx,
|
||||
objectClass: notification.class.EmailNotification,
|
||||
objectSpace: notification.space.Notifications,
|
||||
modifiedOn: tx.modifiedOn,
|
||||
modifiedBy: tx.modifiedBy,
|
||||
attributes: {
|
||||
status: 'new',
|
||||
sender,
|
||||
receivers: [receiver.email],
|
||||
subject,
|
||||
text,
|
||||
html
|
||||
receiver: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
const sesURL = getMetadata(serverNotification.metadata.SesUrl)
|
||||
if (sesURL === undefined || sesURL === '') {
|
||||
console.log('Please provide email service url to enable email confirmations.')
|
||||
return
|
||||
}
|
||||
await fetch(concatLink(sesURL, '/send'), {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text,
|
||||
html,
|
||||
subject,
|
||||
to: [receiver]
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
console.log('Could not send email notification', err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,17 +599,13 @@ async function getNotificationTxes (
|
||||
const emp = await getEmployee(acc.person as Ref<Employee>, control)
|
||||
if (emp?.active === true) {
|
||||
for (const type of allowed.emails) {
|
||||
const emailTx = await createEmailNotificationTxes(
|
||||
await notifyByEmail(
|
||||
control,
|
||||
originTx,
|
||||
type._id,
|
||||
object,
|
||||
originTx.modifiedBy as Ref<PersonAccount>,
|
||||
target as Ref<PersonAccount>
|
||||
)
|
||||
if (emailTx !== undefined) {
|
||||
res.push(emailTx)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
@ -17,7 +17,7 @@
|
||||
import contact, { Employee, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { Account, Class, Doc, Mixin, Ref, Tx, TxCUD } from '@hcengineering/core'
|
||||
import { NotificationType, NotificationContent } from '@hcengineering/notification'
|
||||
import { Plugin, Resource, plugin } from '@hcengineering/platform'
|
||||
import { Metadata, Plugin, Resource, plugin } from '@hcengineering/platform'
|
||||
import type { TriggerControl, TriggerFunc } from '@hcengineering/server-core'
|
||||
|
||||
/**
|
||||
@ -133,6 +133,9 @@ export interface NotificationPresenter extends Class<Doc> {
|
||||
* @public
|
||||
*/
|
||||
export default plugin(serverNotificationId, {
|
||||
metadata: {
|
||||
SesUrl: '' as Metadata<string>
|
||||
},
|
||||
mixin: {
|
||||
HTMLPresenter: '' as Ref<Mixin<HTMLPresenter>>,
|
||||
TextPresenter: '' as Ref<Mixin<TextPresenter>>,
|
||||
|
@ -407,6 +407,7 @@ async function sendConfirmation (productId: string, account: Account): Promise<v
|
||||
const sesURL = getMetadata(accountPlugin.metadata.SES_URL)
|
||||
if (sesURL === undefined || sesURL === '') {
|
||||
console.info('Please provide email service url to enable email confirmations.')
|
||||
return
|
||||
}
|
||||
const front = getMetadata(accountPlugin.metadata.FrontURL)
|
||||
if (front === undefined || front === '') {
|
||||
@ -443,21 +444,19 @@ async function sendConfirmation (productId: string, account: Account): Promise<v
|
||||
subject = 'Confirm your email address to sign up for ezQMS'
|
||||
}
|
||||
|
||||
if (sesURL !== undefined) {
|
||||
const to = account.email
|
||||
await fetch(concatLink(sesURL, '/send'), {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text,
|
||||
html,
|
||||
subject,
|
||||
to
|
||||
})
|
||||
const to = account.email
|
||||
await fetch(concatLink(sesURL, '/send'), {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text,
|
||||
html,
|
||||
subject,
|
||||
to
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -475,7 +474,16 @@ export async function signUpJoin (
|
||||
console.log(`signup join:${email} ${first} ${last}`)
|
||||
const invite = await getInvite(db, inviteId)
|
||||
const workspace = await checkInvite(invite, email)
|
||||
await createAcc(db, productId, email, password, first, last, invite?.emailMask === email)
|
||||
const sesURL = getMetadata(accountPlugin.metadata.SES_URL)
|
||||
await createAcc(
|
||||
db,
|
||||
productId,
|
||||
email,
|
||||
password,
|
||||
first,
|
||||
last,
|
||||
invite?.emailMask === email || sesURL === undefined || sesURL === ''
|
||||
)
|
||||
await assignWorkspace(db, productId, email, workspace.name)
|
||||
|
||||
const token = (await login(db, productId, email, password)).token
|
||||
@ -540,7 +548,8 @@ export async function createAccount (
|
||||
first: string,
|
||||
last: string
|
||||
): Promise<LoginInfo> {
|
||||
const account = await createAcc(db, productId, email, password, first, last, false)
|
||||
const sesURL = getMetadata(accountPlugin.metadata.SES_URL)
|
||||
const account = await createAcc(db, productId, email, password, first, last, sesURL === undefined || sesURL === '')
|
||||
|
||||
const result = {
|
||||
endpoint: getEndpoint(),
|
||||
|
Loading…
Reference in New Issue
Block a user