1from datetime import datetime as dt
2from itertools import islice
3from typing import Literal, Dict, List
4
5from telebot import types # noqa
6
7from app.utils.system import readable_size
8
9
10def chunk_dict(data: dict, size: int = 2):
11 it = iter(data)
12 for i in range(0, len(data), size):
13 yield {k: data[k] for k in islice(it, size)}
14
15
16class BotKeyboard:
17
18 @staticmethod
19 def main_menu():
20 keyboard = types.InlineKeyboardMarkup()
21 keyboard.add(
22 types.InlineKeyboardButton(text='🔁 System Info', callback_data='system'),
23 types.InlineKeyboardButton(text='♻️ Restart Xray', callback_data='restart'))
24 keyboard.add(
25 types.InlineKeyboardButton(text='👥 Users', callback_data='users:1'),
26 types.InlineKeyboardButton(text='✏️ Edit All Users', callback_data='edit_all'))
27 #keyboard.add(
28 # types.InlineKeyboardButton(text='➕ Create User From Template', callback_data='template_add_user'))
29 keyboard.add(
30 types.InlineKeyboardButton(text='➕ Create User', callback_data='add_user'))
31 return keyboard
32
33
34 @staticmethod
35 def edit_all_menu():
36 keyboard = types.InlineKeyboardMarkup()
37 keyboard.add(
38 types.InlineKeyboardButton(text='🗑 Delete Expired', callback_data='delete_expired'),
39 types.InlineKeyboardButton(text='🗑 Delete Limited', callback_data='delete_limited'))
40 keyboard.add(
41 types.InlineKeyboardButton(text='🔋 Data (➕|➖)', callback_data='add_data'),
42 types.InlineKeyboardButton(text='📅 Time (➕|➖)', callback_data='add_time'))
43 #keyboard.add(
44 # types.InlineKeyboardButton(text='➕ Add Inbound', callback_data='inbound_add'),
45 # types.InlineKeyboardButton(text='➖ Remove Inbound', callback_data='inbound_remove'))
46 keyboard.add(types.InlineKeyboardButton(text='🔙 Back', callback_data='cancel'))
47 return keyboard
48
49
50 #@staticmethod
51 #def inbounds_menu(action, inbounds):
52 # keyboard = types.InlineKeyboardMarkup()
53 # for inbound in inbounds:
54 # keyboard.add(types.InlineKeyboardButton(text=inbound, callback_data=f'confirm_{action}:{inbound}'))
55 # keyboard.add(types.InlineKeyboardButton(text='🔙 Back', callback_data='cancel'))
56 # return keyboard
57
58
59 @staticmethod
60 def random_username(template_id: str = ''):
61 keyboard = types.InlineKeyboardMarkup()
62
63 keyboard.add(types.InlineKeyboardButton(
64 text='🔡 Random Username',
65 callback_data=f'random:{template_id}'))
66 keyboard.add(types.InlineKeyboardButton(
67 text='🔙 Cancel',
68 callback_data='cancel'))
69 return keyboard
70
71
72 @staticmethod
73 def user_menu(user_info, with_back: bool = True, page: int = 1, note: bool = False):
74 keyboard = types.InlineKeyboardMarkup()
75 keyboard.add(
76 types.InlineKeyboardButton(
77 text='❌ Disable' if user_info['status'] == 'active' else '✅ Activate',
78 callback_data=f"{'suspend' if user_info['status'] == 'active' else 'activate'}:{user_info['username']}"
79 ),
80 types.InlineKeyboardButton(
81 text='🗑 Delete',
82 callback_data=f"delete:{user_info['username']}"
83 ),
84 )
85 if note:
86 keyboard.add(
87 types.InlineKeyboardButton(
88 text='🚫 Revoke Sub',
89 callback_data=f"revoke_sub:{user_info['username']}"),
90 types.InlineKeyboardButton(
91 text='✏️ Edit',
92 callback_data=f"edit:{user_info['username']}"))
93 keyboard.add(
94 types.InlineKeyboardButton(
95 text='📝 Edit Note',
96 callback_data=f"edit_note:{user_info['username']}"),
97 types.InlineKeyboardButton(
98 text='📡 Links',
99 callback_data=f"links:{user_info['username']}"))
100 else:
101 keyboard.add(
102 types.InlineKeyboardButton(
103 text='📡 Links',
104 callback_data=f"links:{user_info['username']}"),
105 types.InlineKeyboardButton(
106 text='✏️ Edit',
107 callback_data=f"edit:{user_info['username']}"))
108 keyboard.add(
109 types.InlineKeyboardButton(
110 text='🔁 Reset usage',
111 callback_data=f"reset_usage:{user_info['username']}"
112 ),
113 types.InlineKeyboardButton(
114 text='🔋 Charge',
115 callback_data=f"charge:{user_info['username']}"
116 )
117 )
118 if with_back:
119 keyboard.add(
120 types.InlineKeyboardButton(
121 text='🔙 Back',
122 callback_data=f'users:{page}'
123 )
124 )
125 return keyboard
126
127 @staticmethod
128 def show_links(username: str):
129 keyboard = types.InlineKeyboardMarkup()
130
131 keyboard.add(
132 types.InlineKeyboardButton(
133 text="🖼 QR code",
134 callback_data=f'genqr:{username}'
135 )
136 )
137 keyboard.add(
138 types.InlineKeyboardButton(
139 text='🔙 Back',
140 callback_data=f'user:{username}'
141 )
142 )
143 return keyboard
144
145
146 @staticmethod
147 def subscription_page(sub_url: str):
148 keyboard = types.InlineKeyboardMarkup()
149 if sub_url[:4] == 'http':
150 keyboard.add(types.InlineKeyboardButton(
151 text='🚀 Subscription Page',
152 url=sub_url))
153 return keyboard
154
155
156 @staticmethod
157 def confirm_action(action: str, username: str = None):
158 keyboard = types.InlineKeyboardMarkup()
159 keyboard.add(
160 types.InlineKeyboardButton(
161 text='Yes',
162 callback_data=f"{action}:{username}"
163 ),
164 types.InlineKeyboardButton(
165 text='No',
166 callback_data=f"cancel"
167 )
168 )
169 return keyboard
170
171 @staticmethod
172 def inline_cancel_action(callback_data: str = "cancel"):
173 keyboard = types.InlineKeyboardMarkup()
174 keyboard.add(
175 types.InlineKeyboardButton(
176 text="🔙 Cancel",
177 callback_data=callback_data
178 )
179 )
180 return keyboard
181
182 @staticmethod
183 def user_list(users: list, page: int, total_pages: int):
184 keyboard = types.InlineKeyboardMarkup()
185 if len(users) >= 2:
186 users = [p for p in users]
187 users = [users[i:i + 2] for i in range(0, len(users), 2)]
188 else:
189 users = [users]
190 for user in users:
191 row = []
192 for p in user:
193 status = {
194 'active': '✅',
195 'expired': '🕰',
196 'limited': '📵',
197 'disabled': '❌'
198 }
199 row.append(types.InlineKeyboardButton(
200 text=f"{p.username} ({status[p.status]})",
201 callback_data=f'user:{p.username}:{page}'
202 ))
203 keyboard.row(*row)
204 # if there is more than one page
205 if total_pages > 1:
206 if page > 1:
207 keyboard.add(
208 types.InlineKeyboardButton(
209 text="⬅️ Previous",
210 callback_data=f'users:{page - 1}'
211 )
212 )
213 if page < total_pages:
214 keyboard.add(
215 types.InlineKeyboardButton(
216 text="➡️ Next",
217 callback_data=f'users:{page + 1}'
218 )
219 )
220 keyboard.add(
221 types.InlineKeyboardButton(
222 text='🔙 Back',
223 callback_data='cancel'
224 )
225 )
226 return keyboard
227
228 @staticmethod
229 def select_services(services,
230 selected_services: List[int],
231 action: Literal["edit", "create"],
232 username: str = None,
233 data_limit: float = None,
234 expire_date: dt = None):
235
236 keyboard = types.InlineKeyboardMarkup()
237
238 if action == "edit":
239 keyboard.add(
240 types.InlineKeyboardButton(
241 text="⚠️ Data Limit:",
242 callback_data=f"help_edit"
243 )
244 )
245 keyboard.add(
246 types.InlineKeyboardButton(
247 text=f"{readable_size(data_limit) if data_limit else 'Unlimited'}",
248 callback_data=f"help_edit"
249 ),
250 types.InlineKeyboardButton(
251 text="✏️ Edit",
252 callback_data=f"edit_user:{username}:data"
253 )
254 )
255 keyboard.add(
256 types.InlineKeyboardButton(
257 text="📅 Expire Date:",
258 callback_data=f"help_edit"
259 )
260 )
261 keyboard.add(
262 types.InlineKeyboardButton(
263 text=f"{expire_date.strftime('%Y-%m-%d') if expire_date else 'Never'}",
264 callback_data=f"help_edit"
265 ),
266 types.InlineKeyboardButton(
267 text="✏️ Edit",
268 callback_data=f"edit_user:{username}:expire"
269 )
270 )
271 for s in services:
272 keyboard.add(
273 types.InlineKeyboardButton(
274 text=f"🌐 {s.name} {'✅' if s.id in selected_services else '❌'}",
275 callback_data=f"switch_service:{s.id}:{action}"
276 )
277 )
278 keyboard.add(
279 types.InlineKeyboardButton(
280 text='Done',
281 callback_data='edit_user_done' if action == "edit" else 'add_user_done'
282 )
283 )
284 keyboard.add(
285 types.InlineKeyboardButton(
286 text='Cancel',
287 callback_data=f'user:{username}' if action == "edit" else 'cancel'
288 )
289 )
290
291 return keyboard