Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-05-06 23:45:59 +06:00 committed by GitHub
parent 50ad39d037
commit 03cb718c72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 212 additions and 23 deletions

View File

@ -24,9 +24,9 @@ import type {
Person,
Persons
} from '@anticrm/contact'
import type { Domain, Ref } from '@anticrm/core'
import type { Domain, Ref, Timestamp } from '@anticrm/core'
import { DOMAIN_MODEL, IndexKind } from '@anticrm/core'
import { Builder, Collection, Index, Model, Prop, TypeRef, TypeString, UX } from '@anticrm/model'
import { Builder, Collection, Index, Model, Prop, TypeRef, TypeString, TypeTimestamp, UX } from '@anticrm/model'
import attachment from '@anticrm/model-attachment'
import chunter from '@anticrm/model-chunter'
import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@anticrm/model-core'
@ -70,7 +70,7 @@ export class TContact extends TDoc implements Contact {
}
@Model(contact.class.Channel, core.class.AttachedDoc, DOMAIN_CHANNEL)
@UX(contact.string.Channel, contact.icon.Person, undefined, 'modifiedOn')
@UX(contact.string.Channel, contact.icon.Person, undefined, 'lastMessage')
export class TChannel extends TAttachedDoc implements Channel {
@Prop(TypeRef(contact.class.ChannelProvider), contact.string.ChannelProvider)
provider!: Ref<ChannelProvider>
@ -80,6 +80,9 @@ export class TChannel extends TAttachedDoc implements Channel {
value!: string
items?: number
@Prop(TypeTimestamp(), core.string.Modified)
lastMessage?: Timestamp
}
@Model(contact.class.Person, contact.class.Contact)

View File

@ -30,6 +30,7 @@
"@anticrm/core": "~0.6.16",
"@anticrm/platform": "~0.6.6",
"@anticrm/model-core": "~0.6.0",
"@anticrm/contact": "~0.6.5",
"@anticrm/model-contact": "~0.6.1",
"@anticrm/gmail": "~0.6.0",
"@anticrm/gmail-resources": "~0.6.0",

View File

@ -1,6 +1,5 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
// Copyright © 2022 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
@ -15,12 +14,13 @@
//
import activity from '@anticrm/activity'
import { Domain, IndexKind, Timestamp, Type } from '@anticrm/core'
import { Channel } from '@anticrm/contact'
import { Class, Domain, IndexKind, Ref, Timestamp, Type } from '@anticrm/core'
import type { Message, NewMessage, SharedMessage, SharedMessages } from '@anticrm/gmail'
import { ArrOf, Builder, Collection, Index, Model, Prop, TypeBoolean, TypeString, TypeTimestamp } from '@anticrm/model'
import contact from '@anticrm/model-contact'
import core, { TDoc, TAttachedDoc } from '@anticrm/model-core'
import attachment from '@anticrm/model-attachment'
import contact from '@anticrm/model-contact'
import core, { TAttachedDoc, TDoc } from '@anticrm/model-core'
import setting from '@anticrm/setting'
import gmail from './plugin'
@ -32,6 +32,9 @@ function TypeSharedMessage (): Type<SharedMessage> {
@Model(gmail.class.Message, core.class.AttachedDoc, DOMAIN_GMAIL)
export class TMessage extends TAttachedDoc implements Message {
declare attachedTo: Ref<Channel>
declare attachedToClass: Ref<Class<Channel>>
@Prop(TypeString(), gmail.string.MessageID)
messageId!: string

View File

@ -29,4 +29,8 @@ export function createModel (builder: Builder): void {
collectDocs: serverGmail.function.FindMessages
}
)
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverGmail.trigger.OnMessageCreate
})
}

View File

@ -29,4 +29,8 @@ export function createModel (builder: Builder): void {
collectDocs: serverTelegram.function.FindMessages
}
)
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverTelegram.trigger.OnMessageCreate
})
}

View File

@ -32,6 +32,7 @@
"@anticrm/model-core": "~0.6.0",
"@anticrm/model-attachment": "~0.6.0",
"@anticrm/model-contact": "~0.6.1",
"@anticrm/contact": "~0.6.5",
"@anticrm/telegram": "~0.6.2",
"@anticrm/telegram-resources": "~0.6.0",
"@anticrm/setting": "~0.6.1",

View File

@ -24,9 +24,10 @@ import type {
SharedTelegramMessage,
SharedTelegramMessages
} from '@anticrm/telegram'
import { Domain, IndexKind, Timestamp, Type } from '@anticrm/core'
import { Class, Domain, IndexKind, Ref, Timestamp, Type } from '@anticrm/core'
import setting from '@anticrm/setting'
import activity from '@anticrm/activity'
import { Channel } from '@anticrm/contact'
import attachment from '@anticrm/model-attachment'
export const DOMAIN_TELEGRAM = 'telegram' as Domain
@ -37,6 +38,9 @@ function TypeSharedMessage (): Type<SharedTelegramMessage> {
@Model(telegram.class.Message, core.class.AttachedDoc, DOMAIN_TELEGRAM)
export class TTelegramMessage extends TAttachedDoc implements TelegramMessage {
declare attachedTo: Ref<Channel>
declare attachedToClass: Ref<Class<Channel>>
@Prop(TypeString(), telegram.string.Content)
@Index(IndexKind.FullText)
content!: string

View File

@ -13,9 +13,31 @@
// limitations under the License.
//
import core, { TxOperations } from '@anticrm/core'
import core, { SortingOrder, TxOperations } from '@anticrm/core'
import telegram from './plugin'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
import contact from '@anticrm/model-contact'
async function updateChannlLastMessage (client: TxOperations): Promise<void> {
const channels = await client.findAll(contact.class.Channel, {
provider: contact.channelProvider.Telegram
})
const targets = channels.filter((p) => p.lastMessage === undefined)
for (const channel of targets) {
const lastMessage = await client.findOne(
telegram.class.Message,
{
attachedTo: channel._id
},
{ sort: { sendOn: SortingOrder.Descending } }
)
if (lastMessage !== undefined) {
await client.updateDoc(channel._class, channel.space, channel._id, {
lastMessage: lastMessage.sendOn
})
}
}
}
export const telegramOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {},
@ -38,5 +60,7 @@ export const telegramOperation: MigrateOperation = {
telegram.space.Telegram
)
}
await updateChannlLastMessage(tx)
}
}

View File

@ -73,8 +73,9 @@
}
function isNew (item: Channel, lastViews: Map<Ref<Doc>, Timestamp>): boolean {
if (item.lastMessage === undefined) return false
const lastView = (item as Channel)._id !== undefined ? lastViews.get((item as Channel)._id) : undefined
return lastView ? lastView < item.modifiedOn : (item.items ?? 0) > 0
return lastView ? lastView < item.lastMessage : (item.items ?? 0) > 0
}
async function update (value: AttachedData<Channel>[] | Channel | null, lastViews: Map<Ref<Doc>, Timestamp>) {

View File

@ -65,8 +65,9 @@
}
function isNew (item: Channel, lastViews: Map<Ref<Doc>, Timestamp>): boolean {
if (item.lastMessage === undefined) return false
const lastView = (item as Channel)._id !== undefined ? lastViews.get((item as Channel)._id) : undefined
return lastView ? lastView < item.modifiedOn : (item.items ?? 0) > 0
return lastView ? lastView < item.lastMessage : (item.items ?? 0) > 0
}
async function update (value: AttachedData<Channel>[] | Channel | null, lastViews: Map<Ref<Doc>, Timestamp>) {

View File

@ -24,6 +24,7 @@ import {
FindResult,
Ref,
Space,
Timestamp,
UXObject
} from '@anticrm/core'
import type { Asset, Plugin } from '@anticrm/platform'
@ -56,6 +57,7 @@ export interface Channel extends AttachedDoc {
provider: Ref<ChannelProvider>
value: string
items?: number
lastMessage?: Timestamp
}
/**

View File

@ -18,11 +18,14 @@ import type { Plugin } from '@anticrm/platform'
import type { Doc, Ref, Class, Space, AttachedDoc, Timestamp } from '@anticrm/core'
import type { AnyComponent } from '@anticrm/ui'
import type { IntegrationType, Handler } from '@anticrm/setting'
import { Channel } from '@anticrm/contact'
/**
* @public
*/
export interface Message extends BaseMessage, AttachedDoc {
attachedTo: Ref<Channel>
attachedToClass: Ref<Class<Channel>>
messageId: string
from: string
textContent: string

View File

@ -18,6 +18,7 @@ import type { Plugin } from '@anticrm/platform'
import type { Doc, Ref, Class, Space, AttachedDoc, Timestamp } from '@anticrm/core'
import type { AnyComponent } from '@anticrm/ui'
import type { IntegrationType, Handler } from '@anticrm/setting'
import { Channel } from '@anticrm/contact'
/**
* @public
@ -31,6 +32,9 @@ export interface BaseTelegramMessage extends Doc {
* @public
*/
export interface TelegramMessage extends BaseTelegramMessage, AttachedDoc {
attachedTo: Ref<Channel>
attachedToClass: Ref<Class<Channel>>
incoming: boolean
sendOn: Timestamp

View File

@ -14,8 +14,38 @@
//
import contact, { Channel } from '@anticrm/contact'
import gmail from '@anticrm/gmail'
import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core'
import core, {
AttachedDoc,
Class,
Doc,
DocumentQuery,
FindOptions,
FindResult,
Hierarchy,
Ref,
Tx,
TxCollectionCUD,
TxCreateDoc,
TxProcessor
} from '@anticrm/core'
import gmail, { Message } from '@anticrm/gmail'
import { TriggerControl } from '@anticrm/server-core'
const extractTx = (tx: Tx): Tx => {
if (tx._class === core.class.TxCollectionCUD) {
const ctx = tx as TxCollectionCUD<Doc, AttachedDoc>
if (ctx.tx._class === core.class.TxCreateDoc) {
const create = ctx.tx as TxCreateDoc<AttachedDoc>
create.attributes.attachedTo = ctx.objectId
create.attributes.attachedToClass = ctx.objectClass
create.attributes.collection = ctx.collection
return create
}
return ctx.tx
}
return tx
}
/**
* @public
@ -33,13 +63,45 @@ export async function FindMessages (
if (channel.provider !== contact.channelProvider.Email) {
return []
}
const messages = await findAll(gmail.class.Message, { attachedTo: doc._id })
const newMessages = await findAll(gmail.class.NewMessage, { attachedTo: doc._id })
const messages = await findAll(gmail.class.Message, { attachedTo: channel._id })
const newMessages = await findAll(gmail.class.NewMessage, { attachedTo: channel._id })
return [...messages, ...newMessages]
}
/**
* @public
*/
export async function OnMessageCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
const actualTx = extractTx(tx)
if (actualTx._class !== core.class.TxCreateDoc) {
return []
}
const createTx = tx as TxCreateDoc<Message>
if (!control.hierarchy.isDerived(createTx.objectClass, gmail.class.Message)) {
return []
}
const message = TxProcessor.createDoc2Doc<Message>(createTx)
const channel = (await control.findAll(contact.class.Channel, { _id: message.attachedTo }, { limit: 1 }))[0]
if (channel === undefined) {
return []
}
if (channel.lastMessage === undefined || channel.lastMessage < message.sendOn) {
const tx = control.txFactory.createTxUpdateDoc(channel._class, channel.space, channel._id, {
lastMessage: message.sendOn
})
return [tx]
}
return []
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnMessageCreate
},
function: {
FindMessages
}

View File

@ -28,6 +28,7 @@
},
"dependencies": {
"@anticrm/core": "~0.6.16",
"@anticrm/platform": "~0.6.6"
"@anticrm/platform": "~0.6.6",
"@anticrm/server-core": "~0.6.1"
}
}

View File

@ -17,6 +17,7 @@
import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core'
import type { Plugin, Resource } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import { TriggerFunc } from '@anticrm/server-core'
/**
* @public
@ -27,6 +28,9 @@ export const serverGmailId = 'server-gmail' as Plugin
* @public
*/
export default plugin(serverGmailId, {
trigger: {
OnMessageCreate: '' as Resource<TriggerFunc>
},
function: {
FindMessages: '' as Resource<
(

View File

@ -32,7 +32,7 @@ const extractTx = (tx: Tx): Tx => {
create.attributes.collection = ctx.collection
return create
}
return ctx
return ctx.tx
}
return tx

View File

@ -14,8 +14,38 @@
//
import contact, { Channel } from '@anticrm/contact'
import telegram from '@anticrm/telegram'
import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core'
import core, {
AttachedDoc,
Class,
Doc,
DocumentQuery,
FindOptions,
FindResult,
Hierarchy,
Ref,
Tx,
TxCollectionCUD,
TxCreateDoc,
TxProcessor
} from '@anticrm/core'
import { TriggerControl } from '@anticrm/server-core'
import telegram, { TelegramMessage } from '@anticrm/telegram'
const extractTx = (tx: Tx): Tx => {
if (tx._class === core.class.TxCollectionCUD) {
const ctx = tx as TxCollectionCUD<Doc, AttachedDoc>
if (ctx.tx._class === core.class.TxCreateDoc) {
const create = ctx.tx as TxCreateDoc<AttachedDoc>
create.attributes.attachedTo = ctx.objectId
create.attributes.attachedToClass = ctx.objectClass
create.attributes.collection = ctx.collection
return create
}
return ctx.tx
}
return tx
}
/**
* @public
@ -33,13 +63,45 @@ export async function FindMessages (
if (channel.provider !== contact.channelProvider.Telegram) {
return []
}
const messages = await findAll(telegram.class.Message, { attachedTo: doc._id })
const newMessages = await findAll(telegram.class.NewMessage, { attachedTo: doc._id })
const messages = await findAll(telegram.class.Message, { attachedTo: channel._id })
const newMessages = await findAll(telegram.class.NewMessage, { attachedTo: channel._id })
return [...messages, ...newMessages]
}
/**
* @public
*/
export async function OnMessageCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
const actualTx = extractTx(tx)
if (actualTx._class !== core.class.TxCreateDoc) {
return []
}
const createTx = tx as TxCreateDoc<TelegramMessage>
if (!control.hierarchy.isDerived(createTx.objectClass, telegram.class.Message)) {
return []
}
const message = TxProcessor.createDoc2Doc<TelegramMessage>(createTx)
const channel = (await control.findAll(contact.class.Channel, { _id: message.attachedTo }, { limit: 1 }))[0]
if (channel === undefined) {
return []
}
if (channel.lastMessage === undefined || channel.lastMessage < message.sendOn) {
const tx = control.txFactory.createTxUpdateDoc(channel._class, channel.space, channel._id, {
lastMessage: message.sendOn
})
return [tx]
}
return []
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnMessageCreate
},
function: {
FindMessages
}

View File

@ -28,6 +28,7 @@
},
"dependencies": {
"@anticrm/core": "~0.6.16",
"@anticrm/platform": "~0.6.6"
"@anticrm/platform": "~0.6.6",
"@anticrm/server-core": "~0.6.1"
}
}

View File

@ -17,6 +17,7 @@
import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core'
import type { Plugin, Resource } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import { TriggerFunc } from '@anticrm/server-core'
/**
* @public
@ -27,6 +28,9 @@ export const serverTelegramId = 'server-telegram' as Plugin
* @public
*/
export default plugin(serverTelegramId, {
trigger: {
OnMessageCreate: '' as Resource<TriggerFunc>
},
function: {
FindMessages: '' as Resource<
(