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