Skip to content

Commit 1c6b5ea

Browse files
feat: add v2ray links functionality to user panel and update texts
1 parent d4abcf8 commit 1c6b5ea

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

app/telegram/handlers/admin/user.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
import random
22
from datetime import datetime as dt, timedelta as td
3+
from io import BytesIO
34

45
from aiogram import Router, F
5-
from aiogram.types import CallbackQuery, Message, InlineQuery, InlineQueryResultArticle, InputTextMessageContent
6+
from aiogram.types import (
7+
BufferedInputFile,
8+
CallbackQuery,
9+
InlineQuery,
10+
InlineQueryResultArticle,
11+
InputTextMessageContent,
12+
Message,
13+
)
614
from aiogram.fsm.context import FSMContext
715
from sqlalchemy.ext.asyncio import AsyncSession
816
from aiogram.exceptions import TelegramBadRequest
917

1018
from app.db.models import UserStatus
19+
from app.models.settings import ConfigFormat
1120
from app.models.user import UserCreate, UserModify, UserStatusModify, CreateUserFromTemplate, ModifyUserByTemplate
1221
from app.models.validators import UserValidator
1322
from app.operation import OperatorType
23+
from app.operation.subscription import SubscriptionOperation
1424
from app.operation.user import UserOperation
1525
from app.operation.group import GroupOperation
1626
from app.operation.user_template import UserTemplateOperation
@@ -24,6 +34,7 @@
2434
from app.telegram.utils.shared import add_to_messages_to_delete, delete_messages
2535

2636
user_operations = UserOperation(OperatorType.TELEGRAM)
37+
subscription_operations = SubscriptionOperation(OperatorType.TELEGRAM)
2738
group_operations = GroupOperation(OperatorType.TELEGRAM)
2839
user_templates = UserTemplateOperation(OperatorType.TELEGRAM)
2940

@@ -568,6 +579,35 @@ async def get_user_by_sub(event: Message, db: AsyncSession, admin: AdminDetails)
568579
await event.reply(Texts.user_details(user, groups), reply_markup=UserPanel(user).as_markup())
569580

570581

582+
@router.callback_query(UserPanel.Callback.filter(UserPanelAction.v2ray_links == F.action))
583+
async def get_v2ray_links(
584+
event: CallbackQuery, db: AsyncSession, admin: AdminDetails, callback_data: UserPanel.Callback
585+
):
586+
try:
587+
db_user = await user_operations.get_validated_user_by_id(db, callback_data.user_id, admin)
588+
user = await user_operations.validate_user(db_user)
589+
user_with_inbounds = await subscription_operations.validated_user(db_user)
590+
links, _ = await subscription_operations.fetch_config(user_with_inbounds, ConfigFormat.links)
591+
except ValueError as exc:
592+
return await event.answer(str(exc), show_alert=True)
593+
594+
if not links or not links.strip():
595+
return await event.answer(Texts.v2ray_links_unavailable, show_alert=True)
596+
597+
max_message_length = 4085 # Telegram message limit (including formatting)
598+
if len(links) < max_message_length:
599+
await event.message.answer(Texts.client_user_details(user))
600+
await event.message.answer(f"<pre>{links}</pre>")
601+
else:
602+
file = BytesIO(links.encode("utf-8"))
603+
await event.message.answer_document(
604+
BufferedInputFile(file.read(), f"{user.username}-v2ray-links.txt"),
605+
caption=Texts.client_user_details(user),
606+
)
607+
608+
await event.answer()
609+
610+
571611
@router.message(F.text)
572612
@router.callback_query(UserPanel.Callback.filter(UserPanelAction.show == F.action))
573613
async def get_user(event: Message | CallbackQuery, admin: AdminDetails, db: AsyncSession, **kwargs):

app/telegram/keyboards/user.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class UserPanelAction(str, Enum):
2626
modify_expiry = "modify_expiry"
2727
modify_note = "modify_note"
2828
modify_groups = "modify_groups"
29+
v2ray_links = "v2ray_links"
2930

3031

3132
class UserPanel(InlineKeyboardBuilder):
@@ -101,13 +102,17 @@ def __init__(self, user: UserResponse, *args, **kwargs):
101102
)
102103

103104
self.button(text=Texts.subscription_url, copy_text=CopyTextButton(text=user.subscription_url))
105+
self.button(
106+
text=Texts.v2ray_links,
107+
callback_data=self.Callback(action=UserPanelAction.v2ray_links, user_id=user.id),
108+
)
104109

105110
self.button(
106111
text=Texts.back,
107112
callback_data=CancelKeyboard.Callback(action=CancelAction.cancel),
108113
)
109114

110-
self.adjust(2, 2, 2, 2, 1, 1)
115+
self.adjust(2, 2, 2, 2, 1, 1, 1)
111116

112117

113118
class ChooseStatus(InlineKeyboardBuilder):

app/telegram/utils/texts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
class Button:
2626
modify_groups = "👥 Modify Groups"
2727
subscription_url = "🔗 Subscription URL"
28+
v2ray_links = "🌀 V2Ray Links"
2829
modify_note = "📝 Modify Note"
2930
random_username = "🎲 Random Username"
3031
modify_data_limit = "📶 Modify Data Limit"
@@ -88,6 +89,7 @@ class Message:
8889
syncing = "🔄 Syncing..."
8990
synced = "✅ Users successfully Synced"
9091
choose_a_template = "📦 Choose a Template:"
92+
v2ray_links_unavailable = "❌ No V2Ray links available for this user."
9193

9294
@staticmethod
9395
def start(stats: SystemStats):

0 commit comments

Comments
 (0)