Compare commits
6 Commits
main
...
hotfix/bot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57da275534 | ||
|
|
5f1ad4028c | ||
|
|
5671ad5b02 | ||
|
|
a2bbcbb107 | ||
|
|
97ee81561b | ||
|
|
16889db3b4 |
82
apps/bot/src/bot/conversations/add-contact.ts
Normal file
82
apps/bot/src/bot/conversations/add-contact.ts
Normal file
@ -0,0 +1,82 @@
|
||||
/* eslint-disable id-length */
|
||||
import { type Context } from '@/bot/context';
|
||||
import { KEYBOARD_REMOVE, KEYBOARD_SHARE_BOT, KEYBOARD_SHARE_PHONE } from '@/config/keyboards';
|
||||
import { isCustomerMaster } from '@/utils/customer';
|
||||
import { isValidPhoneNumber, normalizePhoneNumber } from '@/utils/phone';
|
||||
import { type Conversation } from '@grammyjs/conversations';
|
||||
import { CustomersService } from '@repo/graphql/api/customers';
|
||||
import { RegistrationService } from '@repo/graphql/api/registration';
|
||||
|
||||
export async function addContact(conversation: Conversation<Context, Context>, ctx: Context) {
|
||||
// Проверяем, что пользователь является мастером
|
||||
const telegramId = ctx.from?.id;
|
||||
if (!telegramId) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('err-generic')));
|
||||
}
|
||||
|
||||
const customerService = new CustomersService({ telegramId });
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
|
||||
if (!customer) {
|
||||
return ctx.reply(
|
||||
await conversation.external(({ t }) => t('msg-need-phone')),
|
||||
KEYBOARD_SHARE_PHONE,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isCustomerMaster(customer)) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-not-master')));
|
||||
}
|
||||
|
||||
// Просим отправить контакт клиента
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-send-client-contact')));
|
||||
|
||||
// Ждем любое сообщение от пользователя
|
||||
const waitCtx = await conversation.wait();
|
||||
|
||||
// Проверяем, что отправлен контакт
|
||||
if (!waitCtx.message?.contact) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-send-contact')));
|
||||
}
|
||||
|
||||
const { contact } = waitCtx.message;
|
||||
const name = `${contact.first_name || ''} ${contact.last_name || ''}`.trim();
|
||||
const phone = normalizePhoneNumber(contact.phone_number);
|
||||
|
||||
// Проверяем валидность номера телефона
|
||||
if (!isValidPhoneNumber(phone)) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-invalid-phone')));
|
||||
}
|
||||
|
||||
try {
|
||||
// Проверяем, есть ли клиент с таким номером
|
||||
const { customer: existingCustomer } = await customerService.getCustomer({ phone });
|
||||
let documentId = existingCustomer?.documentId;
|
||||
|
||||
// Если клиента нет, создаём нового
|
||||
if (!documentId) {
|
||||
const registrationService = new RegistrationService();
|
||||
const createCustomerResult = await registrationService.createCustomer({ name, phone });
|
||||
|
||||
documentId = createCustomerResult?.createCustomer?.documentId;
|
||||
if (!documentId) throw new Error('Клиент не создан');
|
||||
}
|
||||
|
||||
// Добавляем текущего мастера к клиенту
|
||||
const masters = [customer.documentId];
|
||||
await customerService.addMasters({ data: { masters }, documentId });
|
||||
|
||||
// Отправляем подтверждения и инструкции
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-contact-added', { name })));
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-contact-forward')));
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-share-bot')), KEYBOARD_SHARE_BOT);
|
||||
} catch (error) {
|
||||
await ctx.reply(
|
||||
await conversation.external(({ t }) => t('err-with-details', { error: String(error) })),
|
||||
);
|
||||
} finally {
|
||||
await ctx.reply(await conversation.external(({ t }) => t('commands-list')), KEYBOARD_REMOVE);
|
||||
}
|
||||
|
||||
return ctx.reply(await conversation.external(({ t }) => t('err-generic')), KEYBOARD_REMOVE);
|
||||
}
|
||||
1
apps/bot/src/bot/conversations/index.ts
Normal file
1
apps/bot/src/bot/conversations/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './add-contact';
|
||||
@ -1,99 +1,11 @@
|
||||
/* eslint-disable id-length */
|
||||
import { type Context } from '@/bot/context';
|
||||
import { logHandle } from '@/bot/helpers/logging';
|
||||
import { KEYBOARD_REMOVE, KEYBOARD_SHARE_BOT, KEYBOARD_SHARE_PHONE } from '@/config/keyboards';
|
||||
import { isCustomerMaster } from '@/utils/customer';
|
||||
import { isValidPhoneNumber, normalizePhoneNumber } from '@/utils/phone';
|
||||
import { type Conversation, createConversation } from '@grammyjs/conversations';
|
||||
import { CustomersService } from '@repo/graphql/api/customers';
|
||||
import { RegistrationService } from '@repo/graphql/api/registration';
|
||||
import { Composer } from 'grammy';
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType('private');
|
||||
|
||||
async function addContact(conversation: Conversation<Context, Context>, ctx: Context) {
|
||||
// Проверяем, что пользователь является мастером
|
||||
const telegramId = ctx.from?.id;
|
||||
if (!telegramId) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('err-generic')));
|
||||
}
|
||||
|
||||
const customerService = new CustomersService({ telegramId });
|
||||
const { customer } = await customerService.getCustomer({ telegramId });
|
||||
|
||||
if (!customer) {
|
||||
return ctx.reply(
|
||||
await conversation.external(({ t }) => t('msg-need-phone')),
|
||||
KEYBOARD_SHARE_PHONE,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isCustomerMaster(customer)) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-not-master')));
|
||||
}
|
||||
|
||||
// Просим отправить контакт клиента
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-send-client-contact')));
|
||||
|
||||
// Ждем любое сообщение от пользователя
|
||||
const waitCtx = await conversation.wait();
|
||||
|
||||
// Проверяем команду отмены
|
||||
if (waitCtx.message?.text === '/cancel') {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-cancel')));
|
||||
}
|
||||
|
||||
// Проверяем, что отправлен контакт
|
||||
if (!waitCtx.message?.contact) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-send-contact')));
|
||||
}
|
||||
|
||||
const { contact } = waitCtx.message;
|
||||
const name = `${contact.first_name || ''} ${contact.last_name || ''}`.trim();
|
||||
const phone = normalizePhoneNumber(contact.phone_number);
|
||||
|
||||
// Проверяем валидность номера телефона
|
||||
if (!isValidPhoneNumber(phone)) {
|
||||
return ctx.reply(await conversation.external(({ t }) => t('msg-invalid-phone')));
|
||||
}
|
||||
|
||||
try {
|
||||
// Проверяем, есть ли клиент с таким номером
|
||||
const { customer: existingCustomer } = await customerService.getCustomer({ phone });
|
||||
let documentId = existingCustomer?.documentId;
|
||||
|
||||
// Если клиента нет, создаём нового
|
||||
if (!documentId) {
|
||||
const registrationService = new RegistrationService();
|
||||
const createCustomerResult = await registrationService.createCustomer({ name, phone });
|
||||
|
||||
documentId = createCustomerResult?.createCustomer?.documentId;
|
||||
if (!documentId) throw new Error('Клиент не создан');
|
||||
}
|
||||
|
||||
// Добавляем текущего мастера к клиенту
|
||||
const masters = [customer.documentId];
|
||||
await customerService.addMasters({ data: { masters }, documentId });
|
||||
|
||||
// Отправляем подтверждения и инструкции
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-contact-added', { name })));
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-contact-forward')));
|
||||
await ctx.reply(await conversation.external(({ t }) => t('msg-share-bot')), KEYBOARD_SHARE_BOT);
|
||||
} catch (error) {
|
||||
await ctx.reply(
|
||||
await conversation.external(({ t }) => t('err-with-details', { error: String(error) })),
|
||||
);
|
||||
} finally {
|
||||
await ctx.reply(await conversation.external(({ t }) => t('commands-list')), KEYBOARD_REMOVE);
|
||||
}
|
||||
|
||||
return ctx.reply(await conversation.external(({ t }) => t('err-generic')), KEYBOARD_REMOVE);
|
||||
}
|
||||
|
||||
feature.use(createConversation(addContact));
|
||||
|
||||
feature.command('addcontact', logHandle('command-add-contact'), async (ctx) => {
|
||||
await ctx.conversation.enter('addContact');
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { type Context } from './context';
|
||||
import * as conversations from './conversations';
|
||||
import * as features from './features';
|
||||
import { unhandledFeature } from './features/unhandled';
|
||||
import { errorHandler } from './handlers/errors';
|
||||
@ -7,10 +8,9 @@ import * as middlewares from './middlewares';
|
||||
import { setCommands } from './settings/commands';
|
||||
import { setInfo } from './settings/info';
|
||||
import { env } from '@/config/env';
|
||||
import { logger } from '@/utils/logger';
|
||||
import { getRedisInstance } from '@/utils/redis';
|
||||
import { autoChatAction } from '@grammyjs/auto-chat-action';
|
||||
import { conversations } from '@grammyjs/conversations';
|
||||
import { createConversation, conversations as grammyConversations } from '@grammyjs/conversations';
|
||||
import { hydrate } from '@grammyjs/hydrate';
|
||||
import { limit } from '@grammyjs/ratelimiter';
|
||||
import { Bot } from 'grammy';
|
||||
@ -38,14 +38,14 @@ export function createBot({ token }: Parameters_) {
|
||||
}),
|
||||
);
|
||||
|
||||
bot.use(async (context, next) => {
|
||||
context.logger = logger.child({
|
||||
update_id: context.update.update_id,
|
||||
});
|
||||
await next();
|
||||
bot.use(grammyConversations()).command('cancel', async (ctx) => {
|
||||
await ctx.conversation.exitAll();
|
||||
await ctx.reply(ctx.t('msg-cancel'));
|
||||
});
|
||||
|
||||
bot.use(conversations());
|
||||
for (const conversation of Object.values(conversations)) {
|
||||
bot.use(createConversation(conversation));
|
||||
}
|
||||
|
||||
setInfo(bot);
|
||||
setCommands(bot);
|
||||
|
||||
@ -7,7 +7,7 @@ export default defineConfig({
|
||||
external: ['telegraf', 'zod'],
|
||||
format: 'cjs',
|
||||
loader: { '.json': 'copy' },
|
||||
minify: true,
|
||||
minify: false,
|
||||
noExternal: ['@repo'],
|
||||
outDir: './dist',
|
||||
sourcemap: false,
|
||||
|
||||
@ -53,11 +53,7 @@ export class BaseService {
|
||||
|
||||
const customer = result.data.customers.at(0);
|
||||
|
||||
if (!customer) {
|
||||
throw new Error(BASE_ERRORS.NOT_FOUND_CUSTOMER);
|
||||
}
|
||||
|
||||
if (isCustomerBanned(customer)) {
|
||||
if (customer && isCustomerBanned(customer)) {
|
||||
throw new Error(ERRORS.NO_PERMISSION);
|
||||
}
|
||||
|
||||
|
||||
@ -20,10 +20,6 @@ export class RegistrationService {
|
||||
}
|
||||
|
||||
async getCustomer(variables: VariablesOf<typeof GQL.GetCustomerDocument>) {
|
||||
if (variables.telegramId) {
|
||||
await this.checkBanStatus(variables.telegramId);
|
||||
}
|
||||
|
||||
const { query } = await getClientWithToken();
|
||||
|
||||
const result = await query({
|
||||
@ -66,21 +62,4 @@ export class RegistrationService {
|
||||
|
||||
return mutationResult.data;
|
||||
}
|
||||
|
||||
private async checkBanStatus(telegramId: number) {
|
||||
const { query } = await getClientWithToken();
|
||||
|
||||
const result = await query({
|
||||
query: GQL.GetCustomerDocument,
|
||||
variables: { telegramId },
|
||||
});
|
||||
|
||||
const customer = result.data.customers.at(0);
|
||||
|
||||
if (customer && isCustomerBanned(customer)) {
|
||||
throw new Error(ERRORS.NO_PERMISSION);
|
||||
}
|
||||
|
||||
return { customer };
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user