Add logs on notify request (#6295)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-08-09 08:46:30 +04:00 committed by GitHub
parent d7b974b106
commit 5975a4a135
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 22 deletions

View File

@ -55,6 +55,8 @@
}, },
"dependencies": { "dependencies": {
"@hcengineering/activity": "^0.6.0", "@hcengineering/activity": "^0.6.0",
"@hcengineering/analytics": "^0.6.0",
"@hcengineering/analytics-service": "^0.6.0",
"@hcengineering/chunter": "^0.6.20", "@hcengineering/chunter": "^0.6.20",
"@hcengineering/client": "^0.6.18", "@hcengineering/client": "^0.6.18",
"@hcengineering/client-resources": "^0.6.27", "@hcengineering/client-resources": "^0.6.27",

View File

@ -26,6 +26,7 @@ export interface Config {
OtpTimeToLiveSec: number OtpTimeToLiveSec: number
OtpRetryDelaySec: number OtpRetryDelaySec: number
AccountsUrl: string AccountsUrl: string
SentryDSN: string
} }
const parseNumber = (str: string | undefined): number | undefined => (str !== undefined ? Number(str) : undefined) const parseNumber = (str: string | undefined): number | undefined => (str !== undefined ? Number(str) : undefined)
@ -39,12 +40,13 @@ const config: Config = (() => {
AccountsUrl: process.env.ACCOUNTS_URL, AccountsUrl: process.env.ACCOUNTS_URL,
ServiceId: process.env.SERVICE_ID, ServiceId: process.env.SERVICE_ID,
Secret: process.env.SECRET, Secret: process.env.SECRET,
Domain: process.env.DOMAIN, Domain: process.env.DOMAIN ?? '',
BotPort: parseNumber(process.env.BOT_PORT) ?? 8443, BotPort: parseNumber(process.env.BOT_PORT) ?? 8443,
// TODO: later we should get this title from branding map // TODO: later we should get this title from branding map
App: process.env.APP ?? 'Huly', App: process.env.APP ?? 'Huly',
OtpTimeToLiveSec: parseNumber(process.env.OTP_TIME_TO_LIVE_SEC) ?? 60, OtpTimeToLiveSec: parseNumber(process.env.OTP_TIME_TO_LIVE_SEC) ?? 60,
OtpRetryDelaySec: parseNumber(process.env.OTP_RETRY_DELAY_SEC) ?? 60 OtpRetryDelaySec: parseNumber(process.env.OTP_RETRY_DELAY_SEC) ?? 60,
SentryDSN: process.env.SENTRY_DSN ?? ''
} }
const missingEnv = (Object.keys(params) as Array<keyof Config>).filter((key) => params[key] === undefined) const missingEnv = (Object.keys(params) as Array<keyof Config>).filter((key) => params[key] === undefined)

View File

@ -86,6 +86,7 @@ const handleRequest = async (
const token = extractToken(req.headers) const token = extractToken(req.headers)
await fn(req, res, token, next) await fn(req, res, token, next)
} catch (err: unknown) { } catch (err: unknown) {
console.error('Error during extract token', err)
next(err) next(err)
} }
} }
@ -94,7 +95,7 @@ const wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, n
void handleRequest(fn, req, res, next) void handleRequest(fn, req, res, next)
} }
export function createServer (bot: Telegraf, worker: PlatformWorker): Express { export function createServer (bot: Telegraf, worker: PlatformWorker, ctx: MeasureContext): Express {
const limiter = new Limiter() const limiter = new Limiter()
const app = express() const app = express()
@ -174,28 +175,32 @@ export function createServer (bot: Telegraf, worker: PlatformWorker): Express {
app.post( app.post(
'/notify', '/notify',
wrapRequest(async (req, res, token) => { wrapRequest(async (req, res, token) => {
ctx.info('Received notification', { email: token.email })
if (req.body == null || !Array.isArray(req.body)) { if (req.body == null || !Array.isArray(req.body)) {
ctx.error('Invalid request body', { body: req.body, email: token.email })
throw new ApiError(400) throw new ApiError(400)
} }
const notificationRecords = req.body as TelegramNotificationRecord[] const notificationRecords = req.body as TelegramNotificationRecord[]
const usersRecords = await worker.getUsersRecords() const userRecord = await worker.getUserRecordByEmail(token.email)
if (userRecord === undefined) {
ctx.error('User not found', { email: token.email })
throw new ApiError(404)
}
for (const notificationRecord of notificationRecords) { for (const notificationRecord of notificationRecords) {
const userRecord = usersRecords.find((record) => record.email === token.email) void limiter.add(userRecord.telegramId, async () => {
if (userRecord !== undefined) { const formattedMessage = toTelegramHtml(notificationRecord)
void limiter.add(userRecord.telegramId, async () => { const message = await bot.telegram.sendMessage(userRecord.telegramId, formattedMessage, {
const formattedMessage = toTelegramHtml(notificationRecord) parse_mode: 'HTML'
const message = await bot.telegram.sendMessage(userRecord.telegramId, formattedMessage, {
parse_mode: 'HTML'
})
await worker.addNotificationRecord({
notificationId: notificationRecord.notificationId,
email: userRecord.email,
workspace: notificationRecord.workspace,
telegramId: message.message_id
})
}) })
} await worker.addNotificationRecord({
notificationId: notificationRecord.notificationId,
email: userRecord.email,
workspace: notificationRecord.workspace,
telegramId: message.message_id
})
})
} }
res.status(200) res.status(200)

View File

@ -13,10 +13,13 @@
// limitations under the License. // limitations under the License.
// //
import { MeasureMetricsContext } from '@hcengineering/core' import { MeasureMetricsContext, newMetrics } from '@hcengineering/core'
import { setMetadata } from '@hcengineering/platform' import { setMetadata } from '@hcengineering/platform'
import serverToken from '@hcengineering/server-token' import serverToken from '@hcengineering/server-token'
import serverClient from '@hcengineering/server-client' import serverClient from '@hcengineering/server-client'
import { SplitLogger, configureAnalytics } from '@hcengineering/analytics-service'
import { Analytics } from '@hcengineering/analytics'
import { join } from 'path'
import config from './config' import config from './config'
import { createServer, listen } from './server' import { createServer, listen } from './server'
@ -24,17 +27,29 @@ import { setUpBot } from './bot'
import { PlatformWorker } from './worker' import { PlatformWorker } from './worker'
import { registerLoaders } from './loaders' import { registerLoaders } from './loaders'
const ctx = new MeasureMetricsContext(
'telegram-bot-service',
{},
{},
newMetrics(),
new SplitLogger('telegram-bot-service', {
root: join(process.cwd(), 'logs'),
enableConsole: (process.env.ENABLE_CONSOLE ?? 'true') === 'true'
})
)
configureAnalytics(config.SentryDSN, config)
Analytics.setTag('application', 'telegram-bot-service')
export const start = async (): Promise<void> => { export const start = async (): Promise<void> => {
setMetadata(serverToken.metadata.Secret, config.Secret) setMetadata(serverToken.metadata.Secret, config.Secret)
setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl)
setMetadata(serverClient.metadata.UserAgent, config.ServiceId) setMetadata(serverClient.metadata.UserAgent, config.ServiceId)
registerLoaders() registerLoaders()
const ctx = new MeasureMetricsContext('telegram-bot', {})
const worker = await PlatformWorker.create() const worker = await PlatformWorker.create()
const bot = await setUpBot(worker) const bot = await setUpBot(worker)
const app = createServer(bot, worker) const app = createServer(bot, worker, ctx)
if (config.Domain === '') { if (config.Domain === '') {
void bot.launch({ dropPendingUpdates: true }) void bot.launch({ dropPendingUpdates: true })