Mohammed Foud commited on
Commit
7ed0bf2
·
1 Parent(s): 9c3af50
src/bots/handlers/commandHandlers.ts CHANGED
@@ -31,8 +31,9 @@ export const setupCommandHandlers = (bot: any) => {
31
  const handleStartCommand = (ctx: BotContext) => {
32
  const name = ctx.from?.first_name || "عزيزي المستخدم";
33
  const telegramId = ctx.from?.id;
 
34
 
35
- if (telegramId && authService.isUserLoggedIn(telegramId)) {
36
  return {
37
  message: messageManager.getMessage('start_welcome_back').replace('{name}', name),
38
  options: getLoggedInMenuKeyboard()
@@ -113,6 +114,7 @@ const handleBalanceCommand = async (ctx: BotContext) => {
113
 
114
  const handleHistoryCommand = async (ctx: BotContext) => {
115
  const telegramId = ctx.from?.id;
 
116
 
117
  if (!telegramId) {
118
  return {
@@ -121,7 +123,7 @@ const handleHistoryCommand = async (ctx: BotContext) => {
121
  };
122
  }
123
 
124
- if (!authService.isUserLoggedIn(telegramId)) {
125
  return {
126
  message: messageManager.getMessage('history_auth_required'),
127
  options: getMainMenuKeyboard()
 
31
  const handleStartCommand = (ctx: BotContext) => {
32
  const name = ctx.from?.first_name || "عزيزي المستخدم";
33
  const telegramId = ctx.from?.id;
34
+ const botToken = (ctx as any).telegram?.token;
35
 
36
+ if (telegramId && botToken && authService.isUserLoggedIn(telegramId, botToken)) {
37
  return {
38
  message: messageManager.getMessage('start_welcome_back').replace('{name}', name),
39
  options: getLoggedInMenuKeyboard()
 
114
 
115
  const handleHistoryCommand = async (ctx: BotContext) => {
116
  const telegramId = ctx.from?.id;
117
+ const botToken = (ctx as any).telegram?.token;
118
 
119
  if (!telegramId) {
120
  return {
 
123
  };
124
  }
125
 
126
+ if (!botToken || !authService.isUserLoggedIn(telegramId, botToken)) {
127
  return {
128
  message: messageManager.getMessage('history_auth_required'),
129
  options: getMainMenuKeyboard()
src/bots/handlers/mainMenuHandlers.ts CHANGED
@@ -39,13 +39,6 @@ export const handleLoginAction = async (ctx: BotContext) => {
39
  };
40
  }
41
 
42
- if (authService.isUserLoggedIn(telegramId)) {
43
- return {
44
- message: messageManager.getMessage('login_already_logged_in'),
45
- options: getLoggedInMenuKeyboard()
46
- };
47
- }
48
-
49
  const botToken = (ctx as any).telegram?.token;
50
  if (!botToken) {
51
  logger.error('Bot token not found in context');
@@ -55,7 +48,14 @@ export const handleLoginAction = async (ctx: BotContext) => {
55
  };
56
  }
57
 
58
- let user = await authService.loginUser(telegramId);
 
 
 
 
 
 
 
59
 
60
  if (user) {
61
  logger.info(`User ${telegramId} logged in successfully`);
@@ -71,21 +71,10 @@ export const handleLoginAction = async (ctx: BotContext) => {
71
  };
72
  } else {
73
  try {
74
- const { data: bots } = await fetchDataFromTable('bots', 1000, 0, { bot_token: botToken });
75
- const botId = bots && bots.length > 0 ? bots[0].id : null;
76
-
77
- if (!botId) {
78
- logger.error(`Bot not found for token ${botToken}`);
79
- return {
80
- message: messageManager.getMessage('login_error_system'),
81
- options: getBackToMainMenuButton()
82
- };
83
- }
84
-
85
- const { user: newUser, password } = await authService.createUser(telegramId, firstName, botId);
86
- authService.setUserLoggedIn(telegramId, true);
87
 
88
- logger.info(`New user ${telegramId} created successfully with bot ID ${botId}`);
89
  return {
90
  message: messageManager.getMessage('account_created_success')
91
  .replace('{firstName}', firstName)
@@ -133,8 +122,9 @@ export const handleStatsAction = async (ctx: BotContext) => {
133
  export const handleMainMenuAction = async (ctx: BotContext) => {
134
  const name = ctx.from?.first_name || messageManager.getMessage('default_user_name');
135
  const telegramId = ctx.from?.id;
 
136
 
137
- if (telegramId && authService.isUserLoggedIn(telegramId)) {
138
  return {
139
  message: messageManager.getMessage('main_menu_welcome_back').replace('{name}', name),
140
  options: getLoggedInMenuKeyboard()
 
39
  };
40
  }
41
 
 
 
 
 
 
 
 
42
  const botToken = (ctx as any).telegram?.token;
43
  if (!botToken) {
44
  logger.error('Bot token not found in context');
 
48
  };
49
  }
50
 
51
+ if (authService.isUserLoggedIn(telegramId, botToken)) {
52
+ return {
53
+ message: messageManager.getMessage('login_already_logged_in'),
54
+ options: getLoggedInMenuKeyboard()
55
+ };
56
+ }
57
+
58
+ let user = await authService.loginUser(telegramId, botToken);
59
 
60
  if (user) {
61
  logger.info(`User ${telegramId} logged in successfully`);
 
71
  };
72
  } else {
73
  try {
74
+ const { user: newUser, password } = await authService.createUser(telegramId, firstName, botToken);
75
+ authService.setUserLoggedIn(telegramId, botToken, true);
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ logger.info(`New user ${telegramId} created successfully with bot token ${botToken}`);
78
  return {
79
  message: messageManager.getMessage('account_created_success')
80
  .replace('{firstName}', firstName)
 
122
  export const handleMainMenuAction = async (ctx: BotContext) => {
123
  const name = ctx.from?.first_name || messageManager.getMessage('default_user_name');
124
  const telegramId = ctx.from?.id;
125
+ const botToken = (ctx as any).telegram?.token;
126
 
127
+ if (telegramId && botToken && authService.isUserLoggedIn(telegramId, botToken)) {
128
  return {
129
  message: messageManager.getMessage('main_menu_welcome_back').replace('{name}', name),
130
  options: getLoggedInMenuKeyboard()
src/bots/handlers/profileHandlers.ts CHANGED
@@ -4,8 +4,13 @@ import { authService } from "../services/auth";
4
  import { supabase } from "../../db/supabase";
5
  import { createLogger } from "../../utils/logger";
6
  import { messageReplyHandler } from "../utils/handlerUtils";
 
 
 
 
7
 
8
  const logger = createLogger('ProfileHandlers');
 
9
 
10
  // State management for profile actions
11
  const profileStates = new Map<number, {
@@ -15,15 +20,8 @@ const profileStates = new Map<number, {
15
 
16
  export const setupProfileHandlers = (bot: any) => {
17
  // Profile menu handlers
18
- bot.action('profile', async (ctx: BotContext) => {
19
- const result = await handleProfileAction(ctx);
20
- await ctx.editMessageText(result.message, result.options);
21
- });
22
-
23
- bot.action('account_info', async (ctx: BotContext) => {
24
- const result = await handleAccountInfoAction(ctx);
25
- await ctx.editMessageText(result.message, result.options);
26
- });
27
 
28
  bot.action('change_email', async (ctx: BotContext) => {
29
  const result = await handleChangeEmailAction(ctx);
@@ -61,15 +59,16 @@ export const setupProfileHandlers = (bot: any) => {
61
 
62
  const handleProfileAction = async (ctx: BotContext) => {
63
  const telegramId = ctx.from?.id;
 
64
 
65
- if (!telegramId || !authService.isUserLoggedIn(telegramId)) {
66
  return {
67
  message: "⚠️ الرجاء تسجيل الدخول أولاً",
68
  options: getMainMenuKeyboard()
69
  };
70
  }
71
 
72
- const user = await authService.getUserByTelegramId(telegramId);
73
 
74
  if (!user) {
75
  return {
@@ -83,22 +82,23 @@ const handleProfileAction = async (ctx: BotContext) => {
83
  `اختر الإجراء الذي تريد تنفيذه:`,
84
  options: {
85
  ...getProfileKeyboard(),
86
- parse_mode: 'HTML'
87
  }
88
  };
89
  };
90
 
91
  const handleAccountInfoAction = async (ctx: BotContext) => {
92
  const telegramId = ctx.from?.id;
 
93
 
94
- if (!telegramId || !authService.isUserLoggedIn(telegramId)) {
95
  return {
96
  message: "⚠️ الرجاء تسجيل الدخول أولاً",
97
  options: getMainMenuKeyboard()
98
  };
99
  }
100
 
101
- const user = await authService.getUserByTelegramId(telegramId);
102
 
103
  if (!user) {
104
  return {
@@ -115,7 +115,7 @@ const handleAccountInfoAction = async (ctx: BotContext) => {
115
  `تاريخ التسجيل: ${new Date(user.createdAt).toLocaleDateString()}`,
116
  options: {
117
  ...getProfileKeyboard(),
118
- parse_mode: 'HTML'
119
  }
120
  };
121
  };
@@ -140,7 +140,7 @@ const handleChangeEmailAction = async (ctx: BotContext) => {
140
  "يجب أن يكون البريد الإلكتروني صالحاً ويحتوي على @",
141
  options: {
142
  ...getProfileKeyboard(),
143
- parse_mode: 'HTML'
144
  }
145
  };
146
  };
@@ -168,7 +168,7 @@ const handleChangePasswordAction = async (ctx: BotContext) => {
168
  "- رمز خاص",
169
  options: {
170
  ...getProfileKeyboard(),
171
- parse_mode: 'HTML'
172
  }
173
  };
174
  };
@@ -196,7 +196,7 @@ export const handleEmailInput = async (ctx: BotContext) => {
196
  message: "❌ البريد الإلكتروني غير صالح. الرجاء إدخال بريد إلكتروني صحيح.",
197
  options: {
198
  ...getProfileKeyboard(),
199
- parse_mode: 'HTML'
200
  }
201
  };
202
  }
@@ -219,7 +219,7 @@ export const handleEmailInput = async (ctx: BotContext) => {
219
  message: "❌ هذا البريد الإلكتروني مستخدم بالفعل. الرجاء استخدام بريد إلكتروني آخر.",
220
  options: {
221
  ...getProfileKeyboard(),
222
- parse_mode: 'HTML'
223
  }
224
  };
225
  }
@@ -239,7 +239,7 @@ export const handleEmailInput = async (ctx: BotContext) => {
239
  message: "✅ تم تغيير البريد الإلكتروني بنجاح!",
240
  options: {
241
  ...getLoggedInMenuKeyboard(),
242
- parse_mode: 'HTML'
243
  }
244
  };
245
  } catch (error) {
@@ -248,7 +248,7 @@ export const handleEmailInput = async (ctx: BotContext) => {
248
  message: "❌ حدث خطأ أثناء تحديث البريد الإلكتروني. الرجاء المحاولة مرة أخرى.",
249
  options: {
250
  ...getProfileKeyboard(),
251
- parse_mode: 'HTML'
252
  }
253
  };
254
  }
@@ -281,7 +281,7 @@ export const handlePasswordInput = async (ctx: BotContext) => {
281
  "- تحتوي على رمز خاص",
282
  options: {
283
  ...getProfileKeyboard(),
284
- parse_mode: 'HTML'
285
  }
286
  };
287
  }
@@ -302,7 +302,7 @@ export const handlePasswordInput = async (ctx: BotContext) => {
302
  message: "✅ تم تغيير كلمة المرور بنجاح!",
303
  options: {
304
  ...getLoggedInMenuKeyboard(),
305
- parse_mode: 'HTML'
306
  }
307
  };
308
  } catch (error) {
@@ -311,7 +311,7 @@ export const handlePasswordInput = async (ctx: BotContext) => {
311
  message: "❌ حدث خطأ أثناء تحديث كلمة المرور. الرجاء المحاولة مرة أخرى.",
312
  options: {
313
  ...getProfileKeyboard(),
314
- parse_mode: 'HTML'
315
  }
316
  };
317
  }
 
4
  import { supabase } from "../../db/supabase";
5
  import { createLogger } from "../../utils/logger";
6
  import { messageReplyHandler } from "../utils/handlerUtils";
7
+ import { AuthService } from '../services/auth';
8
+ import { callbackReplyHandler } from "../utils/handlerUtils";
9
+ import { messageManager } from "../utils/messageManager";
10
+ import { ParseMode } from "telegraf/types";
11
 
12
  const logger = createLogger('ProfileHandlers');
13
+ const authService = AuthService.getInstance();
14
 
15
  // State management for profile actions
16
  const profileStates = new Map<number, {
 
20
 
21
  export const setupProfileHandlers = (bot: any) => {
22
  // Profile menu handlers
23
+ bot.action('profile', callbackReplyHandler(handleProfileAction));
24
+ bot.action('account_info', callbackReplyHandler(handleAccountInfoAction));
 
 
 
 
 
 
 
25
 
26
  bot.action('change_email', async (ctx: BotContext) => {
27
  const result = await handleChangeEmailAction(ctx);
 
59
 
60
  const handleProfileAction = async (ctx: BotContext) => {
61
  const telegramId = ctx.from?.id;
62
+ const botToken = (ctx as any).telegram?.token;
63
 
64
+ if (!telegramId || !botToken || !authService.isUserLoggedIn(telegramId, botToken)) {
65
  return {
66
  message: "⚠️ الرجاء تسجيل الدخول أولاً",
67
  options: getMainMenuKeyboard()
68
  };
69
  }
70
 
71
+ const user = await authService.getUserByTelegramId(telegramId, botToken);
72
 
73
  if (!user) {
74
  return {
 
82
  `اختر الإجراء الذي تريد تنفيذه:`,
83
  options: {
84
  ...getProfileKeyboard(),
85
+ parse_mode: 'HTML' as ParseMode
86
  }
87
  };
88
  };
89
 
90
  const handleAccountInfoAction = async (ctx: BotContext) => {
91
  const telegramId = ctx.from?.id;
92
+ const botToken = (ctx as any).telegram?.token;
93
 
94
+ if (!telegramId || !botToken || !authService.isUserLoggedIn(telegramId, botToken)) {
95
  return {
96
  message: "⚠️ الرجاء تسجيل الدخول أولاً",
97
  options: getMainMenuKeyboard()
98
  };
99
  }
100
 
101
+ const user = await authService.getUserByTelegramId(telegramId, botToken);
102
 
103
  if (!user) {
104
  return {
 
115
  `تاريخ التسجيل: ${new Date(user.createdAt).toLocaleDateString()}`,
116
  options: {
117
  ...getProfileKeyboard(),
118
+ parse_mode: 'HTML' as ParseMode
119
  }
120
  };
121
  };
 
140
  "يجب أن يكون البريد الإلكتروني صالحاً ويحتوي على @",
141
  options: {
142
  ...getProfileKeyboard(),
143
+ parse_mode: 'HTML' as ParseMode
144
  }
145
  };
146
  };
 
168
  "- رمز خاص",
169
  options: {
170
  ...getProfileKeyboard(),
171
+ parse_mode: 'HTML' as ParseMode
172
  }
173
  };
174
  };
 
196
  message: "❌ البريد الإلكتروني غير صالح. الرجاء إدخال بريد إلكتروني صحيح.",
197
  options: {
198
  ...getProfileKeyboard(),
199
+ parse_mode: 'HTML' as ParseMode
200
  }
201
  };
202
  }
 
219
  message: "❌ هذا البريد الإلكتروني مستخدم بالفعل. الرجاء استخدام بريد إلكتروني آخر.",
220
  options: {
221
  ...getProfileKeyboard(),
222
+ parse_mode: 'HTML' as ParseMode
223
  }
224
  };
225
  }
 
239
  message: "✅ تم تغيير البريد الإلكتروني بنجاح!",
240
  options: {
241
  ...getLoggedInMenuKeyboard(),
242
+ parse_mode: 'HTML' as ParseMode
243
  }
244
  };
245
  } catch (error) {
 
248
  message: "❌ حدث خطأ أثناء تحديث البريد الإلكتروني. الرجاء المحاولة مرة أخرى.",
249
  options: {
250
  ...getProfileKeyboard(),
251
+ parse_mode: 'HTML' as ParseMode
252
  }
253
  };
254
  }
 
281
  "- تحتوي على رمز خاص",
282
  options: {
283
  ...getProfileKeyboard(),
284
+ parse_mode: 'HTML' as ParseMode
285
  }
286
  };
287
  }
 
302
  message: "✅ تم تغيير كلمة المرور بنجاح!",
303
  options: {
304
  ...getLoggedInMenuKeyboard(),
305
+ parse_mode: 'HTML' as ParseMode
306
  }
307
  };
308
  } catch (error) {
 
311
  message: "❌ حدث خطأ أثناء تحديث كلمة المرور. الرجاء المحاولة مرة أخرى.",
312
  options: {
313
  ...getProfileKeyboard(),
314
+ parse_mode: 'HTML' as ParseMode
315
  }
316
  };
317
  }
src/bots/services/auth.ts CHANGED
@@ -22,7 +22,7 @@ import {
22
  balance?: number; // DECIMAL(10, 2) DEFAULT 0
23
  isBanned?: boolean; // BOOLEAN DEFAULT false
24
  lastLogin?: Date | string | null; // TIMESTAMPTZ (can be Date, ISO string, or null)
25
- botId?: string | null; // UUID (string in TypeScript)
26
  createdAt?: Date | string; // TIMESTAMPTZ DEFAULT NOW()
27
  updatedAt?: Date | string; // TIMESTAMPTZ DEFAULT NOW()
28
  }
@@ -57,7 +57,7 @@ import {
57
  return `user_${telegramId}@saerosms.com`;
58
  }
59
 
60
- public async createUser(telegramId: number, name: string, botId:string): Promise<{ user: UserBotTelegraf; password: string }> {
61
  try {
62
  const email = this.generateEmail(telegramId);
63
  const password = this.generatePassword();
@@ -68,7 +68,7 @@ import {
68
  firstName: name,
69
  email,
70
  passwordHash: passwordHash,
71
- botId:botId
72
  };
73
 
74
  const user = await insertDataIntoTable<UserBotTelegraf>('users_bot_telegram', userData);
@@ -82,26 +82,32 @@ import {
82
  }
83
  }
84
 
85
-
86
- private loggedInUsers: Map<number, boolean> = new Map();
87
 
88
- public setUserLoggedIn(telegramId: number, isLoggedIn: boolean = true): void {
89
- this.loggedInUsers.set(telegramId, isLoggedIn);
90
- logger.info(`User ${telegramId} login state set to ${isLoggedIn}`);
91
  }
92
 
93
- public isUserLoggedIn(telegramId: number): boolean {
94
- return this.loggedInUsers.get(telegramId) || false;
 
 
95
  }
96
 
97
- public async loginUser(telegramId: number): Promise<UserBotTelegraf | null> {
 
 
 
 
 
98
  try {
99
  const { data: users } = await fetchDataFromTable<UserBotTelegraf>('users_bot_telegram', 1000, 0, {
100
  telegram_id: telegramId,
 
101
  });
102
 
103
  if (!users || users.length === 0) {
104
- logger.info(`Login attempt for non-existent user ${telegramId}`);
105
  return null;
106
  }
107
 
@@ -114,13 +120,13 @@ import {
114
  });
115
 
116
  // Set user as logged in
117
- this.setUserLoggedIn(telegramId, true);
118
 
119
- logger.info(`User ${telegramId} logged in successfully`);
120
  return user;
121
 
122
  } catch (error: any) {
123
- logger.error(`Error logging in user ${telegramId}: ${error.message}`);
124
  throw new Error(`Failed to login user: ${error.message}`);
125
  }
126
  }
@@ -141,12 +147,13 @@ import {
141
  /**
142
  * Get user by Telegram ID
143
  */
144
- async getUserByTelegramId(telegramId: number): Promise<any> {
145
  try {
146
  const { data: users, error } = await supabase
147
  .from('users_bot_telegram')
148
  .select('*')
149
  .eq('telegram_id', telegramId)
 
150
  .single();
151
 
152
  if (error) throw error;
 
22
  balance?: number; // DECIMAL(10, 2) DEFAULT 0
23
  isBanned?: boolean; // BOOLEAN DEFAULT false
24
  lastLogin?: Date | string | null; // TIMESTAMPTZ (can be Date, ISO string, or null)
25
+ botToken?: string | null; // Bot token instead of botId
26
  createdAt?: Date | string; // TIMESTAMPTZ DEFAULT NOW()
27
  updatedAt?: Date | string; // TIMESTAMPTZ DEFAULT NOW()
28
  }
 
57
  return `user_${telegramId}@saerosms.com`;
58
  }
59
 
60
+ public async createUser(telegramId: number, name: string, botToken: string): Promise<{ user: UserBotTelegraf; password: string }> {
61
  try {
62
  const email = this.generateEmail(telegramId);
63
  const password = this.generatePassword();
 
68
  firstName: name,
69
  email,
70
  passwordHash: passwordHash,
71
+ botToken: botToken
72
  };
73
 
74
  const user = await insertDataIntoTable<UserBotTelegraf>('users_bot_telegram', userData);
 
82
  }
83
  }
84
 
85
+ private loggedInUsers: Map<string, boolean> = new Map();
 
86
 
87
+ private generateUserKey(telegramId: number, botToken: string): string {
88
+ return `${telegramId}_${botToken}`;
 
89
  }
90
 
91
+ public setUserLoggedIn(telegramId: number, botToken: string, isLoggedIn: boolean = true): void {
92
+ const userKey = this.generateUserKey(telegramId, botToken);
93
+ this.loggedInUsers.set(userKey, isLoggedIn);
94
+ logger.info(`User ${telegramId} for bot ${botToken} login state set to ${isLoggedIn}`);
95
  }
96
 
97
+ public isUserLoggedIn(telegramId: number, botToken: string): boolean {
98
+ const userKey = this.generateUserKey(telegramId, botToken);
99
+ return this.loggedInUsers.get(userKey) || false;
100
+ }
101
+
102
+ public async loginUser(telegramId: number, botToken: string): Promise<UserBotTelegraf | null> {
103
  try {
104
  const { data: users } = await fetchDataFromTable<UserBotTelegraf>('users_bot_telegram', 1000, 0, {
105
  telegram_id: telegramId,
106
+ bot_token: botToken
107
  });
108
 
109
  if (!users || users.length === 0) {
110
+ logger.info(`Login attempt for non-existent user ${telegramId} for bot ${botToken}`);
111
  return null;
112
  }
113
 
 
120
  });
121
 
122
  // Set user as logged in
123
+ this.setUserLoggedIn(telegramId, botToken, true);
124
 
125
+ logger.info(`User ${telegramId} for bot ${botToken} logged in successfully`);
126
  return user;
127
 
128
  } catch (error: any) {
129
+ logger.error(`Error logging in user ${telegramId} for bot ${botToken}: ${error.message}`);
130
  throw new Error(`Failed to login user: ${error.message}`);
131
  }
132
  }
 
147
  /**
148
  * Get user by Telegram ID
149
  */
150
+ async getUserByTelegramId(telegramId: number, botToken: string): Promise<any> {
151
  try {
152
  const { data: users, error } = await supabase
153
  .from('users_bot_telegram')
154
  .select('*')
155
  .eq('telegram_id', telegramId)
156
+ .eq('bot_token', botToken)
157
  .single();
158
 
159
  if (error) throw error;