mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-25 01:39:53 +00:00
Calendar event triggers (#6761)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
2f0223faad
commit
41a228387a
models/server-calendar/src
plugins/calendar-resources/src/components
server-plugins
services/calendar/pod-calendar/src
@ -41,6 +41,13 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverCalendar.trigger.OnEvent,
|
||||
txMatch: {
|
||||
'tx.objectClass': calendar.class.Event
|
||||
}
|
||||
})
|
||||
|
||||
builder.mixin<Class<Doc>, ObjectDDParticipant>(
|
||||
core.class.Doc,
|
||||
core.class.Class,
|
||||
|
@ -211,6 +211,7 @@
|
||||
focusIndex={10007}
|
||||
kind={'indented'}
|
||||
showButtons={false}
|
||||
readonly={readOnly}
|
||||
placeholder={calendar.string.Description}
|
||||
bind:content={description}
|
||||
/>
|
||||
|
@ -13,10 +13,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import calendar, { Calendar, Event } from '@hcengineering/calendar'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import {
|
||||
import calendar, { Calendar, Event, ExternalCalendar } from '@hcengineering/calendar'
|
||||
import contactPlugin, { Contact, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Class,
|
||||
Data,
|
||||
Doc,
|
||||
DocumentQuery,
|
||||
FindOptions,
|
||||
@ -25,7 +26,10 @@ import {
|
||||
Ref,
|
||||
Tx,
|
||||
TxCreateDoc,
|
||||
TxProcessor
|
||||
TxCUD,
|
||||
TxProcessor,
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc
|
||||
} from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { TriggerControl } from '@hcengineering/server-core'
|
||||
@ -98,6 +102,170 @@ export async function OnPersonAccountCreate (tx: Tx, control: TriggerControl): P
|
||||
return [res]
|
||||
}
|
||||
|
||||
function getCalendar (calendars: Calendar[], person: Ref<PersonAccount>): Ref<Calendar> | undefined {
|
||||
const filtered = calendars.filter((c) => (c.createdBy ?? c.modifiedBy) === person)
|
||||
const defaultExternal = filtered.find((c) => (c as ExternalCalendar).default)
|
||||
if (defaultExternal !== undefined) return defaultExternal._id
|
||||
return filtered[0]?._id
|
||||
}
|
||||
|
||||
function getEventPerson (current: Event, calendars: Calendar[], control: TriggerControl): Ref<Contact> | undefined {
|
||||
const calendar = calendars.find((c) => c._id === current.calendar)
|
||||
if (calendar === undefined) return
|
||||
const accId = (current.createdBy ?? current.modifiedBy) as Ref<PersonAccount>
|
||||
const acc = control.modelDb.findAllSync(contactPlugin.class.PersonAccount, { _id: accId })[0]
|
||||
if (acc === undefined) return
|
||||
return acc.person
|
||||
}
|
||||
|
||||
async function OnEvent (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const ctx = TxProcessor.extractTx(tx) as TxCUD<Event>
|
||||
if (ctx._class === core.class.TxCreateDoc) {
|
||||
return await onEventCreate(ctx as TxCreateDoc<Event>, control)
|
||||
} else if (ctx._class === core.class.TxUpdateDoc) {
|
||||
return await onEventUpdate(ctx as TxUpdateDoc<Event>, control)
|
||||
} else if (ctx._class === core.class.TxRemoveDoc) {
|
||||
return await onRemoveEvent(ctx as TxRemoveDoc<Event>, control)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
async function onEventUpdate (ctx: TxUpdateDoc<Event>, control: TriggerControl): Promise<Tx[]> {
|
||||
const ops = ctx.operations
|
||||
const { visibility, ...otherOps } = ops
|
||||
if (Object.keys(otherOps).length === 0) return []
|
||||
const event = (await control.findAll(control.ctx, calendar.class.Event, { _id: ctx.objectId }, { limit: 1 }))[0]
|
||||
if (event === undefined) return []
|
||||
if (event.access !== 'owner') return []
|
||||
const events = await control.findAll(control.ctx, calendar.class.Event, { eventId: event.eventId })
|
||||
const res: Tx[] = []
|
||||
const newParticipants = new Set<Ref<Contact>>(event.participants)
|
||||
const calendars = await control.findAll(control.ctx, calendar.class.Calendar, { hidden: false })
|
||||
for (const ev of events) {
|
||||
if (ev._id === event._id) continue
|
||||
const person = getEventPerson(ev, calendars, control)
|
||||
if (person === undefined || !event.participants.includes(person)) {
|
||||
const innerTx = control.txFactory.createTxRemoveDoc(ev._class, ev.space, ev._id)
|
||||
const outerTx = control.txFactory.createTxCollectionCUD(
|
||||
ev.attachedToClass,
|
||||
ev.attachedTo,
|
||||
ev.space,
|
||||
ev.collection,
|
||||
innerTx
|
||||
)
|
||||
res.push(outerTx)
|
||||
} else {
|
||||
newParticipants.delete(person)
|
||||
const innerTx = control.txFactory.createTxUpdateDoc(ev._class, ev.space, ev._id, { ...otherOps })
|
||||
const outerTx = control.txFactory.createTxCollectionCUD(
|
||||
ev.attachedToClass,
|
||||
ev.attachedTo,
|
||||
ev.space,
|
||||
ev.collection,
|
||||
innerTx
|
||||
)
|
||||
res.push(outerTx)
|
||||
}
|
||||
}
|
||||
if (newParticipants.size === 0) return res
|
||||
const newPartTxs = await eventForNewParticipants(event, newParticipants, calendars, control)
|
||||
return res.concat(newPartTxs)
|
||||
}
|
||||
|
||||
async function eventForNewParticipants (
|
||||
event: Event,
|
||||
newParticipants: Set<Ref<Person>>,
|
||||
calendars: Calendar[],
|
||||
control: TriggerControl
|
||||
): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
const accounts = await control.findAll(control.ctx, contactPlugin.class.PersonAccount, {
|
||||
person: { $in: event.participants }
|
||||
})
|
||||
const access = 'reader'
|
||||
const { _class, space, attachedTo, attachedToClass, collection, ...attr } = event
|
||||
const data = attr as any as Data<Event>
|
||||
for (const part of newParticipants) {
|
||||
const acc = accounts.find((a) => a.person === part)
|
||||
if (acc === undefined) continue
|
||||
if (acc._id === (event.createdBy ?? event.modifiedBy)) continue
|
||||
const calendar = getCalendar(calendars, acc._id)
|
||||
if (calendar === undefined) continue
|
||||
const innerTx = control.txFactory.createTxCreateDoc(
|
||||
_class,
|
||||
space,
|
||||
{ ...data, calendar, access },
|
||||
undefined,
|
||||
undefined,
|
||||
acc._id
|
||||
)
|
||||
const outerTx = control.txFactory.createTxCollectionCUD(
|
||||
attachedToClass,
|
||||
attachedTo,
|
||||
space,
|
||||
collection,
|
||||
innerTx,
|
||||
undefined,
|
||||
acc._id
|
||||
)
|
||||
res.push(outerTx)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async function onEventCreate (ctx: TxCreateDoc<Event>, control: TriggerControl): Promise<Tx[]> {
|
||||
const event = TxProcessor.createDoc2Doc(ctx)
|
||||
if (event.access !== 'owner') return []
|
||||
const res: Tx[] = []
|
||||
const { _class, space, attachedTo, attachedToClass, collection, ...attr } = event
|
||||
const data = attr as any as Data<Event>
|
||||
const calendars = await control.findAll(control.ctx, calendar.class.Calendar, { hidden: false })
|
||||
const accounts = await control.findAll(control.ctx, contactPlugin.class.PersonAccount, {
|
||||
person: { $in: event.participants }
|
||||
})
|
||||
const access = 'reader'
|
||||
for (const part of event.participants) {
|
||||
const acc = accounts.find((a) => a.person === part)
|
||||
if (acc === undefined) continue
|
||||
if (acc._id === (event.createdBy ?? event.modifiedBy)) continue
|
||||
const calendar = getCalendar(calendars, acc._id)
|
||||
if (calendar === undefined) continue
|
||||
const innerTx = control.txFactory.createTxCreateDoc(
|
||||
_class,
|
||||
space,
|
||||
{ ...data, calendar, access },
|
||||
undefined,
|
||||
undefined,
|
||||
acc._id
|
||||
)
|
||||
const outerTx = control.txFactory.createTxCollectionCUD(
|
||||
attachedToClass,
|
||||
attachedTo,
|
||||
space,
|
||||
collection,
|
||||
innerTx,
|
||||
undefined,
|
||||
acc._id
|
||||
)
|
||||
res.push(outerTx)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async function onRemoveEvent (ctx: TxRemoveDoc<Event>, control: TriggerControl): Promise<Tx[]> {
|
||||
const removed = control.removedMap.get(ctx.objectId) as Event
|
||||
const res: Tx[] = []
|
||||
if (removed !== undefined) {
|
||||
if (removed.access !== 'owner') return []
|
||||
const current = await control.findAll(control.ctx, calendar.class.Event, { eventId: removed.eventId })
|
||||
for (const cur of current) {
|
||||
res.push(control.txFactory.createTxRemoveDoc(cur._class, cur.space, cur._id))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
function: {
|
||||
@ -106,6 +274,7 @@ export default async () => ({
|
||||
FindReminders
|
||||
},
|
||||
trigger: {
|
||||
OnPersonAccountCreate
|
||||
OnPersonAccountCreate,
|
||||
OnEvent
|
||||
}
|
||||
})
|
||||
|
@ -34,6 +34,7 @@ export default plugin(serverCalendarId, {
|
||||
FindReminders: '' as Resource<ObjectDDParticipantFunc>
|
||||
},
|
||||
trigger: {
|
||||
OnPersonAccountCreate: '' as Resource<TriggerFunc>
|
||||
OnPersonAccountCreate: '' as Resource<TriggerFunc>,
|
||||
OnEvent: '' as Resource<TriggerFunc>
|
||||
}
|
||||
})
|
||||
|
@ -235,7 +235,7 @@ export class WorkspaceClient {
|
||||
return
|
||||
}
|
||||
case core.class.TxUpdateDoc: {
|
||||
await this.txUpdateEvent(actualTx as TxUpdateDoc<Doc>)
|
||||
await this.txUpdateEvent(actualTx as TxUpdateDoc<Event>)
|
||||
return
|
||||
}
|
||||
case core.class.TxRemoveDoc: {
|
||||
@ -249,6 +249,7 @@ export class WorkspaceClient {
|
||||
const hierarhy = this.client.getHierarchy()
|
||||
if (hierarhy.isDerived(tx.objectClass, calendar.class.Event)) {
|
||||
const doc = TxProcessor.createDoc2Doc(tx as TxCreateDoc<Event>)
|
||||
if (doc.access !== 'owner') return
|
||||
const client = this.getCalendarClientByCalendar(doc.calendar as Ref<ExternalCalendar>)
|
||||
if (client === undefined) {
|
||||
return
|
||||
@ -296,23 +297,24 @@ export class WorkspaceClient {
|
||||
}
|
||||
}
|
||||
|
||||
private async txUpdateEvent (tx: TxUpdateDoc<Doc>): Promise<void> {
|
||||
private async txUpdateEvent (tx: TxUpdateDoc<Event>): Promise<void> {
|
||||
const hierarhy = this.client.getHierarchy()
|
||||
if (hierarhy.isDerived(tx.objectClass, calendar.class.Event)) {
|
||||
if (tx.operations.space !== undefined) {
|
||||
await this.handleMove(tx as TxUpdateDoc<Event>)
|
||||
if (tx.operations.calendar !== undefined) {
|
||||
await this.handleMove(tx)
|
||||
return
|
||||
}
|
||||
const event = await this.client.findOne(calendar.class.Event, { _id: (tx as TxUpdateDoc<Event>).objectId })
|
||||
const event = await this.client.findOne(calendar.class.Event, { _id: tx.objectId })
|
||||
if (event === undefined) {
|
||||
return
|
||||
}
|
||||
if (event.access !== 'owner' && event.access !== 'writer') return
|
||||
const client = this.getCalendarClientByCalendar(event.calendar as Ref<ExternalCalendar>)
|
||||
if (client === undefined) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await client.updateEvent(event, tx as TxUpdateDoc<Event>)
|
||||
await client.updateEvent(event, tx)
|
||||
await this.updateSyncTime()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
@ -328,6 +330,7 @@ export class WorkspaceClient {
|
||||
})
|
||||
const ev = TxProcessor.buildDoc2Doc<Event>(txes.map((tx) => TxProcessor.extractTx(tx)))
|
||||
if (ev === undefined) return
|
||||
if (ev.access !== 'owner' && ev.access !== 'writer') return
|
||||
const client = this.getCalendarClientByCalendar(ev?.calendar as Ref<ExternalCalendar>)
|
||||
if (client === undefined) {
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user