@@ -8,17 +8,16 @@ import { registrationWizard } from "./scenes/registration.ts";
8
8
import { getUserLeetcodeInfo } from "../modules/leetcode.ts" ;
9
9
import { User } from "../types/index.ts" ;
10
10
import { CallbackQuery , Update } from "npm:telegraf/types" ;
11
+ import { skipCommand } from "./commands/skip.ts" ;
12
+ import { ONE_DAY } from "../modules/constants.ts" ;
11
13
12
14
export class LeetCodeBot {
13
15
private bot : Telegraf ;
14
16
private userRepo : UserRepository ;
15
17
16
18
constructor ( ) {
17
19
const token = Deno . env . get ( "TELEGRAM_BOT_TOKEN" ) ;
18
- if ( ! token )
19
- throw Error (
20
- "TELEGRAM_BOT_TOKEN is missing. Try setting in .env as `TELEGRAM_BOT_TOKEN=your_token`"
21
- ) ;
20
+ if ( ! token ) throw Error ( "TELEGRAM_BOT_TOKEN is missing. Try setting in .env as `TELEGRAM_BOT_TOKEN=your_token`" ) ;
22
21
23
22
this . bot = new Telegraf ( token ) ;
24
23
this . userRepo = new UserRepository ( ) ;
@@ -42,41 +41,39 @@ export class LeetCodeBot {
42
41
43
42
// Create and use the stage middleware
44
43
const stage = new Scenes . Stage ( [ registrationWizard ] ) ;
45
- this . bot . use (
46
- stage . middleware ( ) as never as MiddlewareFn < Context < Update > , Update >
47
- ) ;
44
+ this . bot . use ( stage . middleware ( ) as never as MiddlewareFn < Context < Update > , Update > ) ;
48
45
49
46
// Log middleware
50
47
this . bot . use ( async ( ctx , next ) => {
51
- const start = Date . now ( ) ;
52
- await next ( ) ;
53
- const ms = Date . now ( ) - start ;
54
- console . log ( `[${ ctx . updateType } ] Response time: ${ ms } ms` ) ;
48
+ try {
49
+ const start = Date . now ( ) ;
50
+ await next ( ) ;
51
+ const ms = Date . now ( ) - start ;
52
+ console . log ( `[${ ctx . updateType } ] Response time: ${ ms } ms` ) ;
53
+ } catch ( error : unknown ) {
54
+ return ctx . reply ( `Sorry, something went wrong. Please try again later. Error - ${ ( error as Error ) . message } ` ) ;
55
+ }
55
56
} ) ;
56
57
}
57
58
58
59
private registerCommands ( ) {
59
- this . bot . command ( "start" , ( ctx ) =>
60
- ( ctx as unknown as Scenes . SceneContext ) . scene . enter ( "registration-wizard" )
61
- ) ;
60
+ this . bot . command ( "start" , ( ctx ) => ( ctx as unknown as Scenes . SceneContext ) . scene . enter ( "registration-wizard" ) ) ;
62
61
63
62
// TODO add skip command
64
63
// TODO add reschedule logic
65
64
66
65
this . bot . command ( "help" , helpCommand ) ;
67
66
this . bot . command ( "stats" , statsCommand ) ;
67
+ this . bot . command ( "skip" , skipCommand ) ;
68
68
69
69
this . bot . on ( "callback_query" , async ( ctx ) => {
70
- const command = ( ctx . callbackQuery as unknown as CallbackQuery . DataQuery )
71
- . data ;
70
+ const command = ( ctx . callbackQuery as unknown as CallbackQuery . DataQuery ) . data ;
72
71
73
72
await ctx . answerCbQuery ( ) ;
74
73
75
74
switch ( command ) {
76
75
case "/start" :
77
- await ( ctx as never as Scenes . SceneContext ) . scene . enter (
78
- "registration-wizard"
79
- ) ;
76
+ await ( ctx as never as Scenes . SceneContext ) . scene . enter ( "registration-wizard" ) ;
80
77
break ;
81
78
case "/help" :
82
79
await helpCommand ( ctx ) ;
@@ -85,9 +82,7 @@ export class LeetCodeBot {
85
82
await statsCommand ( ctx ) ;
86
83
break ;
87
84
default :
88
- await ctx . reply (
89
- "Unknown command. Please use /help to see available commands."
90
- ) ;
85
+ await ctx . reply ( "Unknown command. Please use /help to see available commands." ) ;
91
86
}
92
87
} ) ;
93
88
}
@@ -115,27 +110,20 @@ export class LeetCodeBot {
115
110
console . log ( `Checking for ${ user . telegramId } ` ) ;
116
111
if ( user . nextDueDate && Date . now ( ) < user . nextDueDate . getTime ( ) ) return ;
117
112
118
- const updatedInfo = await getUserLeetcodeInfo (
119
- user . leetcodeUsername
120
- ) . catch ( ( ) => null ) ;
113
+ const updatedInfo = await getUserLeetcodeInfo ( user . leetcodeUsername ) . catch ( ( ) => null ) ;
121
114
if ( ! updatedInfo ) return ; // Optionally handle later
122
115
123
116
// Get the overall submission stats (for "All" difficulty)
124
- const allSubmissions = updatedInfo . submitStats . acSubmissionNum . find (
125
- ( item : { difficulty : string } ) => item . difficulty === "All"
126
- ) ;
117
+ const allSubmissions = updatedInfo . submitStats . acSubmissionNum . find ( ( item : { difficulty : string } ) => item . difficulty === "All" ) ;
127
118
if ( ! allSubmissions ) {
128
- console . error (
129
- `Could not find submissions for leetcodeUsername: ${ user . leetcodeUsername } `
130
- ) ;
119
+ console . error ( `Could not find submissions for leetcodeUsername: ${ user . leetcodeUsername } ` ) ;
131
120
return ;
132
121
}
133
122
134
123
// Compute "missing" as the difference between expected count and what the user achieved.
135
124
// If your intended logic is that a positive "missing" means the user is behind,
136
125
// you might compute it as:
137
- const missing =
138
- allSubmissions . count - ( user . stats . totalSolved + user . tasksCount ) ;
126
+ const missing = allSubmissions . count - ( user . stats . totalSolved + user . tasksCount ) ;
139
127
140
128
console . log ( `Sending message to ${ user . telegramId } ` ) ;
141
129
@@ -148,17 +136,11 @@ export class LeetCodeBot {
148
136
) ;
149
137
} else if ( missing === 0 ) {
150
138
// User is exactly on track.
151
- await this . bot . telegram . sendMessage (
152
- user . telegramId ,
153
- `Good job ${ user . telegramUsername } , you're right on track today! Keep up the great work! 👍`
154
- ) ;
139
+ await this . bot . telegram . sendMessage ( user . telegramId , `Good job ${ user . telegramUsername } , you're right on track today! Keep up the great work! 👍` ) ;
155
140
} else if ( Math . abs ( Math . round ( missing / user . tasksCount ) ) >= 2 ) {
156
141
// If the user is ahead by a significant margin (using absolute value in case missing is negative),
157
142
// congratulate them.
158
- await this . bot . telegram . sendMessage (
159
- user . telegramId ,
160
- `YOU'RE A BEAST, ${ user . telegramUsername } ! You're crushing it and surpassing your targets! 🚀`
161
- ) ;
143
+ await this . bot . telegram . sendMessage ( user . telegramId , `YOU'RE A BEAST, ${ user . telegramUsername } ! You're crushing it and surpassing your targets! 🚀` ) ;
162
144
}
163
145
164
146
await this . userRepo . update ( user . telegramId , {
@@ -167,7 +149,7 @@ export class LeetCodeBot {
167
149
streakCount : user . stats . streakCount + 1 ,
168
150
} ,
169
151
updatedAt : new Date ( ) ,
170
- nextDueDate : new Date ( Date . now ( ) + user . frequency * 24 * 60 * 60_000 ) ,
152
+ nextDueDate : new Date ( Date . now ( ) + user . frequency * ONE_DAY ) ,
171
153
} ) ;
172
154
} catch ( error ) {
173
155
console . error ( "Error during daily check:" , error ) ;
@@ -180,8 +162,7 @@ export class LeetCodeBot {
180
162
await this . bot . launch ( ( ) => console . log ( "Bot is running..." ) ) ;
181
163
182
164
const signals = [ "SIGTERM" , "SIGINT" ] ;
183
- for ( const signal of signals )
184
- Deno . addSignalListener ( signal as Deno . Signal , ( ) => this . stop ( ) ) ;
165
+ for ( const signal of signals ) Deno . addSignalListener ( signal as Deno . Signal , ( ) => this . stop ( ) ) ;
185
166
} catch ( error ) {
186
167
console . error ( "Failed to start bot:" , error ) ;
187
168
throw error ;
0 commit comments