feat(bot): add session management and user tracking
- Implement Prisma storage adapter for Telegram session management - Add middleware to upsert Telegram user data - Extend TelegramUser model with additional fields - Add db:push command to turbo.json and package.json - Extend Prisma client with exists helper method
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
import { serve } from '@hono/node-server';
|
||||
import { config } from './config';
|
||||
import { Bot, webhookCallback } from 'grammy';
|
||||
import { Bot, session, webhookCallback } from 'grammy';
|
||||
import { Hono } from 'hono';
|
||||
import { logger } from '@repo/logger';
|
||||
import { PrismaStorageAdapter } from './session-storage';
|
||||
import { BotContext } from './types';
|
||||
import { upsertUser } from './middlewares/upsert-user';
|
||||
|
||||
const bot = new Bot(config.BOT_TOKEN);
|
||||
const bot = new Bot<BotContext>(config.BOT_TOKEN);
|
||||
const storage = new PrismaStorageAdapter();
|
||||
|
||||
bot.command('start', (ctx) => ctx.reply('Привет, мир'));
|
||||
bot.use(session({ storage, initial: () => ({}) }));
|
||||
bot.use(upsertUser);
|
||||
|
||||
bot.command('start', async (ctx) => {
|
||||
const session = await ctx.session;
|
||||
await ctx.reply('Привет, ' + JSON.stringify(session));
|
||||
});
|
||||
|
||||
if (config.MODE === 'webhook') {
|
||||
logger.info('Starting in webhook mode...');
|
||||
|
||||
30
apps/bot/src/middlewares/upsert-user.ts
Normal file
30
apps/bot/src/middlewares/upsert-user.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { MiddlewareFn } from 'grammy';
|
||||
import { BotContext } from '../types';
|
||||
import { Prisma, prisma } from '@repo/db';
|
||||
|
||||
export const upsertUser: MiddlewareFn<BotContext> = async (ctx, next) => {
|
||||
const telegramId = ctx.from?.id.toString();
|
||||
|
||||
if (!telegramId) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const payload: Prisma.TelegramUserUncheckedCreateInput = {
|
||||
id: telegramId,
|
||||
username: ctx.from?.username,
|
||||
firstName: ctx.from?.first_name,
|
||||
lastName: ctx.from?.last_name,
|
||||
languageCode: ctx.from?.language_code,
|
||||
isPremium: ctx.from?.is_premium,
|
||||
};
|
||||
|
||||
await prisma.telegramUser.upsert({
|
||||
where: {
|
||||
id: telegramId,
|
||||
},
|
||||
create: payload,
|
||||
update: payload,
|
||||
});
|
||||
|
||||
return next();
|
||||
};
|
||||
37
apps/bot/src/session-storage.ts
Normal file
37
apps/bot/src/session-storage.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { prisma } from '@repo/db';
|
||||
import { StorageAdapter } from 'grammy';
|
||||
|
||||
export class PrismaStorageAdapter<T extends object>
|
||||
implements StorageAdapter<T>
|
||||
{
|
||||
async read(key: string): Promise<T | undefined> {
|
||||
return prisma.telegramSession
|
||||
.findUnique({
|
||||
where: {
|
||||
id: key,
|
||||
},
|
||||
})
|
||||
.then((session) => (session?.data as T) || undefined);
|
||||
}
|
||||
async write(key: string, data: T): Promise<void> {
|
||||
console.log('write', data);
|
||||
await prisma.telegramSession.upsert({
|
||||
where: {
|
||||
id: key,
|
||||
},
|
||||
create: {
|
||||
id: key,
|
||||
data,
|
||||
},
|
||||
update: {
|
||||
data,
|
||||
},
|
||||
});
|
||||
}
|
||||
async delete(key: string): Promise<void> {
|
||||
await prisma.telegramSession.delete({ where: { id: key } });
|
||||
}
|
||||
async has(key: string): Promise<boolean> {
|
||||
return prisma.telegramSession.exists({ id: key });
|
||||
}
|
||||
}
|
||||
5
apps/bot/src/types.ts
Normal file
5
apps/bot/src/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Context, LazySessionFlavor } from 'grammy';
|
||||
|
||||
// config your session data
|
||||
export type SessionData = { };
|
||||
export type BotContext = Context & LazySessionFlavor<SessionData>;
|
||||
Reference in New Issue
Block a user