mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
Add telegram bot fixes (#6281)
This commit is contained in:
parent
f5cd4bf169
commit
4b7ce58fe9
@ -231,6 +231,22 @@ services:
|
||||
resources:
|
||||
limits:
|
||||
memory: 300M
|
||||
# telegram-bot:
|
||||
# image: hardcoreeng/telegram-bot
|
||||
# restart: unless-stopped
|
||||
# environment:
|
||||
# - PORT=4020
|
||||
# - BOT_TOKEN=token
|
||||
# - MONGO_URL=mongodb://mongodb:27017
|
||||
# - MONGO_DB=telegram-bot
|
||||
# - SECRET=secret
|
||||
# - DOMAIN=domain
|
||||
# - ACCOUNTS_URL=http://account:3000
|
||||
# - SERVICE_ID=telegram-bot-service
|
||||
# deploy:
|
||||
# resources:
|
||||
# limits:
|
||||
# memory: 300M
|
||||
volumes:
|
||||
db:
|
||||
files:
|
||||
|
@ -38,5 +38,6 @@ startFront(metricsContext, {
|
||||
POSTHOG_HOST: process.env.POSTHOG_HOST,
|
||||
DESKTOP_UPDATES_URL: process.env.DESKTOP_UPDATES_URL,
|
||||
DESKTOP_UPDATES_CHANNEL: process.env.DESKTOP_UPDATES_CHANNEL,
|
||||
ANALYTICS_COLLECTOR_URL: process.env.ANALYTICS_COLLECTOR_URL
|
||||
ANALYTICS_COLLECTOR_URL: process.env.ANALYTICS_COLLECTOR_URL,
|
||||
TELEGRAM_BOT_URL: process.env.TELEGRAM_BOT_URL
|
||||
})
|
||||
|
@ -343,7 +343,6 @@ export async function getChunterNotificationContent (
|
||||
return {
|
||||
title,
|
||||
body,
|
||||
data: message,
|
||||
intlParams,
|
||||
intlParamsNotLocalized
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ import serverNotification, {
|
||||
getPersonAccount,
|
||||
getPersonAccountById,
|
||||
NOTIFICATION_BODY_SIZE,
|
||||
NOTIFICATION_TITLE_SIZE,
|
||||
PUSH_NOTIFICATION_TITLE_SIZE,
|
||||
ReceiverInfo,
|
||||
SenderInfo
|
||||
} from '@hcengineering/server-notification'
|
||||
@ -373,7 +373,7 @@ async function activityInboxNotificationToText (
|
||||
body = await translate(doc.body, params)
|
||||
}
|
||||
|
||||
return { ...params, title: title.substring(0, NOTIFICATION_TITLE_SIZE), body }
|
||||
return { ...params, title, body }
|
||||
}
|
||||
|
||||
async function commonInboxNotificationToText (
|
||||
@ -461,12 +461,14 @@ export async function createPushFromInbox (
|
||||
_id: Ref<Doc>,
|
||||
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
|
||||
): Promise<Tx | undefined> {
|
||||
const { title, body } = await getTranslatedNotificationContent(data, _class, control)
|
||||
let { title, body } = await getTranslatedNotificationContent(data, _class, control)
|
||||
|
||||
if (title === '' || body === '') {
|
||||
return
|
||||
}
|
||||
|
||||
title = title.slice(0, PUSH_NOTIFICATION_TITLE_SIZE)
|
||||
|
||||
const senderPerson = sender.person
|
||||
const linkProviders = control.modelDb.findAllSync(serverView.mixin.ServerLinkIdProvider, {})
|
||||
const provider = linkProviders.find(({ _id }) => _id === attachedToClass)
|
||||
@ -575,7 +577,7 @@ export async function pushActivityInboxNotifications (
|
||||
activityMessage: ActivityMessage,
|
||||
shouldUpdateTimestamp: boolean
|
||||
): Promise<TxCreateDoc<InboxNotification> | undefined> {
|
||||
const content = await getNotificationContent(originTx, receiver.account, sender, object, control, activityMessage)
|
||||
const content = await getNotificationContent(originTx, receiver.account, sender, object, control)
|
||||
const data: Partial<Data<ActivityInboxNotification>> = {
|
||||
...content,
|
||||
attachedTo: activityMessage._id,
|
||||
@ -606,7 +608,8 @@ export async function applyNotificationProviders (
|
||||
res: Tx[],
|
||||
object: Doc,
|
||||
receiver: ReceiverInfo,
|
||||
sender: SenderInfo
|
||||
sender: SenderInfo,
|
||||
message?: ActivityMessage
|
||||
): Promise<void> {
|
||||
const resources = await control.modelDb.findAll(serverNotification.class.NotificationProviderResources, {})
|
||||
for (const [provider, types] of notifyResult.entries()) {
|
||||
@ -635,7 +638,7 @@ export async function applyNotificationProviders (
|
||||
|
||||
const fn = await getResource(resource.fn)
|
||||
|
||||
const txes = await fn(control, types, object, data, receiver, sender)
|
||||
const txes = await fn(control, types, object, data, receiver, sender, message)
|
||||
if (txes.length > 0) {
|
||||
res.push(...txes)
|
||||
}
|
||||
@ -724,7 +727,8 @@ export async function getNotificationTxes (
|
||||
res,
|
||||
object,
|
||||
receiver,
|
||||
sender
|
||||
sender,
|
||||
message
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -41,7 +41,8 @@ import core, {
|
||||
TxProcessor,
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc,
|
||||
type MeasureContext
|
||||
type MeasureContext,
|
||||
Markup
|
||||
} from '@hcengineering/core'
|
||||
import { getResource, IntlString, translate } from '@hcengineering/platform'
|
||||
import serverNotification, {
|
||||
@ -52,7 +53,7 @@ import serverNotification, {
|
||||
SenderInfo,
|
||||
TextPresenter
|
||||
} from '@hcengineering/server-notification'
|
||||
import { ActivityMessage, DocUpdateMessage } from '@hcengineering/activity'
|
||||
import { DocUpdateMessage } from '@hcengineering/activity'
|
||||
|
||||
import { NotifyResult } from './types'
|
||||
|
||||
@ -347,12 +348,10 @@ async function getFallbackNotificationFullfillment (
|
||||
object: Doc,
|
||||
originTx: TxCUD<Doc>,
|
||||
control: TriggerControl,
|
||||
sender: SenderInfo,
|
||||
message?: ActivityMessage
|
||||
sender: SenderInfo
|
||||
): Promise<NotificationContent> {
|
||||
const title: IntlString = notification.string.CommonNotificationTitle
|
||||
let body: IntlString = notification.string.CommonNotificationBody
|
||||
let data: string | undefined
|
||||
|
||||
const intlParams: Record<string, string | number> = {}
|
||||
const intlParamsNotLocalized: Record<string, IntlString> = {}
|
||||
@ -363,15 +362,6 @@ async function getFallbackNotificationFullfillment (
|
||||
intlParams.title = await textPresenterFunc(object, control)
|
||||
}
|
||||
|
||||
if (message !== undefined) {
|
||||
const dataPresenter = getTextPresenter(message._class, control.hierarchy)
|
||||
|
||||
if (dataPresenter !== undefined) {
|
||||
const textPresenterFunc = await getResource(dataPresenter.presenter)
|
||||
data = await textPresenterFunc(message, control)
|
||||
}
|
||||
}
|
||||
|
||||
const tx = TxProcessor.extractTx(originTx)
|
||||
|
||||
intlParams.senderName = await getSenderName(control, sender)
|
||||
@ -416,7 +406,7 @@ async function getFallbackNotificationFullfillment (
|
||||
}
|
||||
}
|
||||
|
||||
return { title, body, data, intlParams, intlParamsNotLocalized }
|
||||
return { title, body, intlParams, intlParamsNotLocalized }
|
||||
}
|
||||
|
||||
function getNotificationPresenter (_class: Ref<Class<Doc>>, hierarchy: Hierarchy): NotificationPresenter | undefined {
|
||||
@ -428,17 +418,17 @@ export async function getNotificationContent (
|
||||
targetUser: PersonAccount,
|
||||
sender: SenderInfo,
|
||||
object: Doc,
|
||||
control: TriggerControl,
|
||||
message?: ActivityMessage
|
||||
control: TriggerControl
|
||||
): Promise<NotificationContent> {
|
||||
let { title, body, data, intlParams, intlParamsNotLocalized } = await getFallbackNotificationFullfillment(
|
||||
let { title, body, intlParams, intlParamsNotLocalized } = await getFallbackNotificationFullfillment(
|
||||
object,
|
||||
originTx,
|
||||
control,
|
||||
sender,
|
||||
message
|
||||
sender
|
||||
)
|
||||
|
||||
let data: Markup | undefined
|
||||
|
||||
const actualTx = TxProcessor.extractTx(originTx) as TxCUD<Doc>
|
||||
const notificationPresenter = getNotificationPresenter(actualTx.objectClass, control.hierarchy)
|
||||
|
||||
@ -447,7 +437,7 @@ export async function getNotificationContent (
|
||||
const updateParams = await getFuillfillmentParams(object, originTx, targetUser._id, control)
|
||||
title = updateParams.title
|
||||
body = updateParams.body
|
||||
data = updateParams?.data ?? data
|
||||
data = updateParams.data
|
||||
intlParams = {
|
||||
...intlParams,
|
||||
...updateParams.intlParams
|
||||
|
@ -39,6 +39,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/activity": "^0.6.0",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/notification": "^0.6.23",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
} from '@hcengineering/notification'
|
||||
import { Metadata, Plugin, Resource, plugin } from '@hcengineering/platform'
|
||||
import type { TriggerControl, TriggerFunc } from '@hcengineering/server-core'
|
||||
import { ActivityMessage } from '@hcengineering/activity'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -154,7 +155,8 @@ export type NotificationProviderFunc = (
|
||||
object: Doc,
|
||||
data: InboxNotification,
|
||||
receiver: ReceiverInfo,
|
||||
sender: SenderInfo
|
||||
sender: SenderInfo,
|
||||
message?: ActivityMessage
|
||||
) => Promise<Tx[]>
|
||||
|
||||
export interface NotificationProviderResources extends Doc {
|
||||
@ -163,7 +165,7 @@ export interface NotificationProviderResources extends Doc {
|
||||
}
|
||||
|
||||
export const NOTIFICATION_BODY_SIZE = 50
|
||||
export const NOTIFICATION_TITLE_SIZE = 50
|
||||
export const PUSH_NOTIFICATION_TITLE_SIZE = 80
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -40,7 +40,7 @@ import { getTranslatedNotificationContent, getTextPresenter } from '@hcengineeri
|
||||
import { generateToken } from '@hcengineering/server-token'
|
||||
import chunter, { ChatMessage } from '@hcengineering/chunter'
|
||||
import { markupToHTML } from '@hcengineering/text'
|
||||
import activity from '@hcengineering/activity'
|
||||
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -142,10 +142,31 @@ async function getContactChannel (
|
||||
return res?.value ?? ''
|
||||
}
|
||||
|
||||
async function activityMessageToHtml (control: TriggerControl, message: ActivityMessage): Promise<string | undefined> {
|
||||
const { hierarchy } = control
|
||||
if (hierarchy.isDerived(message._class, chunter.class.ChatMessage)) {
|
||||
const chatMessage = message as ChatMessage
|
||||
return markupToHTML(chatMessage.message)
|
||||
} else {
|
||||
const resource = getTextPresenter(message._class, control.hierarchy)
|
||||
|
||||
if (resource !== undefined) {
|
||||
const fn = await getResource(resource.presenter)
|
||||
const textData = await fn(message, control)
|
||||
if (textData !== undefined && textData !== '') {
|
||||
return markupToHTML(textData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function getTranslatedData (
|
||||
data: InboxNotification,
|
||||
doc: Doc,
|
||||
control: TriggerControl
|
||||
control: TriggerControl,
|
||||
message?: ActivityMessage
|
||||
): Promise<{
|
||||
title: string
|
||||
quote: string | undefined
|
||||
@ -156,23 +177,22 @@ async function getTranslatedData (
|
||||
let { title, body } = await getTranslatedNotificationContent(data, data._class, control)
|
||||
let quote: string | undefined
|
||||
|
||||
if (hierarchy.isDerived(doc._class, chunter.class.ChatMessage)) {
|
||||
const chatMessage = doc as ChatMessage
|
||||
title = ''
|
||||
quote = markupToHTML(chatMessage.message)
|
||||
} else if (hierarchy.isDerived(doc._class, activity.class.ActivityMessage)) {
|
||||
const resource = getTextPresenter(doc._class, control.hierarchy)
|
||||
|
||||
if (resource !== undefined) {
|
||||
const fn = await getResource(resource.presenter)
|
||||
const textData = await fn(doc, control)
|
||||
if (textData !== undefined && textData !== '') {
|
||||
title = ''
|
||||
quote = markupToHTML(textData)
|
||||
}
|
||||
if (data.data !== undefined) {
|
||||
body = markupToHTML(data.data)
|
||||
} else if (message !== undefined) {
|
||||
const html = await activityMessageToHtml(control, message)
|
||||
if (html !== undefined) {
|
||||
body = html
|
||||
}
|
||||
}
|
||||
|
||||
if (hierarchy.isDerived(doc._class, activity.class.ActivityMessage)) {
|
||||
const html = await activityMessageToHtml(control, doc as ActivityMessage)
|
||||
if (html !== undefined) {
|
||||
title = ''
|
||||
quote = html
|
||||
}
|
||||
}
|
||||
body = data.data !== undefined ? `${markupToHTML(data.data)}` : body
|
||||
|
||||
return {
|
||||
title,
|
||||
@ -187,7 +207,8 @@ const SendTelegramNotifications: NotificationProviderFunc = async (
|
||||
doc: Doc,
|
||||
data: InboxNotification,
|
||||
receiver: ReceiverInfo,
|
||||
sender: SenderInfo
|
||||
sender: SenderInfo,
|
||||
message?: ActivityMessage
|
||||
): Promise<Tx[]> => {
|
||||
if (types.length === 0) {
|
||||
return []
|
||||
@ -205,7 +226,7 @@ const SendTelegramNotifications: NotificationProviderFunc = async (
|
||||
}
|
||||
|
||||
try {
|
||||
const { title, body, quote } = await getTranslatedData(data, doc, control)
|
||||
const { title, body, quote } = await getTranslatedData(data, doc, control, message)
|
||||
const record: TelegramNotificationRecord = {
|
||||
notificationId: data._id,
|
||||
account: receiver._id,
|
||||
|
@ -13,13 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Context, Telegraf, NarrowedContext } from 'telegraf'
|
||||
import { Update, Message } from 'telegraf/typings/core/types/typegram'
|
||||
import { Context, Telegraf } from 'telegraf'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import telegram from '@hcengineering/telegram'
|
||||
import { htmlToMarkup } from '@hcengineering/text'
|
||||
import { message } from 'telegraf/filters'
|
||||
import { toHTML } from '@telegraf/entity'
|
||||
import { TextMessage } from '@telegraf/entity/types/types'
|
||||
|
||||
import config from './config'
|
||||
import { PlatformWorker } from './worker'
|
||||
@ -91,36 +91,20 @@ async function onConnect (ctx: Context, worker: PlatformWorker): Promise<void> {
|
||||
await ctx.reply(`*${code}*`, { parse_mode: 'MarkdownV2' })
|
||||
}
|
||||
|
||||
type TextMessage = Record<'text', any> & Message.TextMessage
|
||||
|
||||
async function onReply (
|
||||
ctx: NarrowedContext<Context<Update>, Update.MessageUpdate<TextMessage>>,
|
||||
worker: PlatformWorker
|
||||
): Promise<void> {
|
||||
const id = ctx.chat?.id
|
||||
const message = ctx.message
|
||||
|
||||
if (id === undefined || message.reply_to_message === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const replyTo = message.reply_to_message
|
||||
async function onReply (id: number, message: TextMessage, replyTo: number, worker: PlatformWorker): Promise<boolean> {
|
||||
const userRecord = await worker.getUserRecord(id)
|
||||
|
||||
if (userRecord === undefined) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
const notification = await worker.getNotificationRecord(replyTo.message_id, userRecord.email)
|
||||
const notification = await worker.getNotificationRecord(replyTo, userRecord.email)
|
||||
|
||||
if (notification === undefined) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
const isReplied = await worker.reply(notification, htmlToMarkup(toHTML(message)))
|
||||
if (isReplied) {
|
||||
await ctx.react('👍')
|
||||
}
|
||||
return await worker.reply(notification, htmlToMarkup(toHTML(message)))
|
||||
}
|
||||
|
||||
export async function setUpBot (worker: PlatformWorker): Promise<Telegraf> {
|
||||
@ -134,8 +118,20 @@ export async function setUpBot (worker: PlatformWorker): Promise<Telegraf> {
|
||||
bot.command('stop', (ctx) => onStop(ctx, worker))
|
||||
bot.command('connect', (ctx) => onConnect(ctx, worker))
|
||||
|
||||
bot.on(message('text'), async (ctx) => {
|
||||
await onReply(ctx, worker)
|
||||
bot.on(message('reply_to_message'), async (ctx) => {
|
||||
const id = ctx.chat?.id
|
||||
const message = ctx.message
|
||||
|
||||
if (id === undefined || message.reply_to_message === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const replyTo = message.reply_to_message
|
||||
const isReplied = await onReply(id, message as TextMessage, replyTo.message_id, worker)
|
||||
|
||||
if (isReplied) {
|
||||
await ctx.react('👍')
|
||||
}
|
||||
})
|
||||
|
||||
const description = await translate(telegram.string.BotDescription, { app: config.App })
|
||||
|
@ -16,7 +16,6 @@
|
||||
export interface Config {
|
||||
Port: number
|
||||
BotToken: string
|
||||
FrontUrl: string
|
||||
MongoURL: string
|
||||
MongoDB: string
|
||||
ServiceId: string
|
||||
@ -35,7 +34,6 @@ const config: Config = (() => {
|
||||
const params: Partial<Config> = {
|
||||
Port: parseNumber(process.env.PORT) ?? 4020,
|
||||
BotToken: process.env.BOT_TOKEN,
|
||||
FrontUrl: process.env.FRONT_URL,
|
||||
MongoURL: process.env.MONGO_URL,
|
||||
MongoDB: process.env.MONGO_DB,
|
||||
AccountsUrl: process.env.ACCOUNTS_URL,
|
||||
|
@ -36,11 +36,16 @@ export const start = async (): Promise<void> => {
|
||||
const bot = await setUpBot(worker)
|
||||
const app = createServer(bot, worker)
|
||||
|
||||
void bot.launch({ webhook: { domain: config.Domain, port: config.BotPort } }).then(() => {
|
||||
void bot.telegram.getWebhookInfo().then((info) => {
|
||||
ctx.info('Webhook info', info)
|
||||
if (config.Domain === '') {
|
||||
void bot.launch({ dropPendingUpdates: true })
|
||||
} else {
|
||||
void bot.launch({ webhook: { domain: config.Domain, port: config.BotPort }, dropPendingUpdates: true }).then(() => {
|
||||
void bot.telegram.getWebhookInfo().then((info) => {
|
||||
ctx.info('Webhook info', info)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
app.get(`/telegraf/${bot.secretPathComponent()}`, (req, res) => {
|
||||
res.status(200).send()
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user