from telethon.tl.functions.messages import ExportChatInviteRequest, EditExportedChatInviteRequest
from telethon.types import Message
from .. import loader, utils
from ..inline.types import InlineCall
import logging
import datetime
"""
███ ███ ██ ██ ██████ ██ ██ ██ ██████ ███████ ███████
████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ████ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ███████ █████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██████ ██ ██ ██████ ███████ ██████ ███████ ███████
Module Name
"""
# scopes:
# 🔒 Licensed under the GNU AGPLv3
# meta banner: https://raw.githubusercontent.com/MuRuLOSE/HikkaModulesRepo/main/assets/modbanners/inumber.png
# meta desc: Manage Telegram invite links
# meta developer: @BruhHikkaModules
logger = logging.getLogger(__name__)
@loader.tds
class InviteManager(loader.Module):
"""Manage Telegram invite links"""
strings = {
"name": "InviteManager",
"no_args": "❌ No arguments provided",
"no_channel": "❌ Please specify a channel or use in a channel",
"created": "✅ Invite link created: {link}",
"select_action": "Select an action for the invite link: {link}",
"revoked": "✅ Invite link revoked",
"select_expiry": "Select expiration period for the invite link: {link}",
"select_limit": "Select usage limit for the invite link: {link}",
"updated_expiry": "✅ Expiry updated to {date}",
"updated_limit": "✅ Usage limit updated to {limit}",
"invalid_date": "❌ Invalid date format. Use YYYY-MM-DD HH:MM",
"invalid_limit": "❌ Invalid number for usage limit",
"invalid_link": "❌ Invalid invite link",
"chat_required": "❌ Please use this command in the target channel or specify the channel",
}
strings_ru = {
"no_args": "❌ Аргументы не указаны",
"no_channel": "❌ Укажите канал или используйте в канале",
"created": "✅ Ссылка-приглашение создана: {link}",
"select_action": "Выберите действие для ссылки: {link}",
"revoked": "✅ Ссылка отозвана",
"select_expiry": "Выберите период действия для ссылки: {link}",
"select_limit": "Выберите лимит использований для ссылки: {link}",
"updated_expiry": "✅ Дата истечения обновлена: {date}",
"updated_limit": "✅ Лимит использований обновлен: {limit}",
"invalid_date": "❌ Неверный формат даты. Используйте ГГГГ-ММ-ДД ЧЧ:ММ",
"invalid_limit": "❌ Неверное число для лимита",
"invalid_link": "❌ Неверная ссылка-приглашение",
"chat_required": "❌ Используйте команду в целевом канале или укажите канал",
}
async def client_ready(self, client, db):
self.client = client
self.db = db
@loader.command(ru_doc="Создать ссылку-приглашение для канала")
async def createinvite(self, message: Message):
"""Create an invite link for a channel"""
args = utils.get_args_raw(message)
chat = None
if args:
try:
chat = await self.client.get_entity(args)
except Exception as e:
logger.error(f"Failed to get entity: {e}")
await utils.answer(message, self.strings["no_channel"])
return
else:
if message.is_channel or message.is_group:
chat = message.peer_id
else:
await utils.answer(message, self.strings["no_channel"])
return
try:
result = await self.client(
ExportChatInviteRequest(
peer=chat,
legacy_revoke_permanent=False,
request_needed=False,
title="Invite Link"
)
)
link = result.link
await utils.answer(message, self.strings["created"].format(link=link))
except Exception as e:
logger.error(f"Error creating invite: {e}")
await utils.answer(message, "❌ Failed to create invite link")
@loader.command(ru_doc="[ссылка] [канал] - Редактировать ссылку-приглашение через инлайн-кнопки")
async def editinvite(self, message: Message):
"""[link] [channel] - Edit an invite link with inline buttons"""
args = utils.get_args_split_by(message, separator=" ")
if len(args) < 2:
if message.is_channel or message.is_group:
chat = message.peer_id
link = args[0] if args else None
else:
await utils.answer(message, self.strings["chat_required"])
return
else:
link, chat_arg = args[0], args[1]
try:
chat = await self.client.get_entity(chat_arg)
except Exception as e:
logger.error(f"Failed to get entity: {e}")
await utils.answer(message, self.strings["no_channel"])
return
if not link:
await utils.answer(message, self.strings["no_args"])
return
try:
if not link.startswith("https://t.me/"):
raise ValueError("Invalid invite link")
await self.inline.form(
message=message,
text=self.strings["select_action"].format(link=link),
reply_markup=[
[
{"text": "Revoke", "callback": self._revoke_link, "args": (link, chat)},
{"text": "Set Expiry", "callback": self._prompt_expiry, "args": (link, chat)},
],
[
{"text": "Set Usage Limit", "callback": self._prompt_limit, "args": (link, chat)},
]
]
)
except Exception as e:
logger.error(f"Error initiating edit: {e}")
await utils.answer(message, self.strings["invalid_link"])
async def _revoke_link(self, call: InlineCall, link: str, chat):
try:
await self.client(
EditExportedChatInviteRequest(
peer=chat,
link=link,
revoked=True
)
)
await call.edit(
text=self.strings["revoked"],
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
except Exception as e:
logger.error(f"Error revoking link: {e}")
await call.edit(
text="❌ Failed to revoke link",
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
async def _prompt_expiry(self, call: InlineCall, link: str, chat):
await call.edit(
text=self.strings["select_expiry"].format(link=link),
reply_markup=[
[
{"text": "1 Hour", "callback": self._set_expiry, "args": (link, chat, 1, "hours")},
{"text": "1 Day", "callback": self._set_expiry, "args": (link, chat, 1, "days")},
],
[
{"text": "1 Week", "callback": self._set_expiry, "args": (link, chat, 1, "weeks")},
{"text": "1 Month", "callback": self._set_expiry, "args": (link, chat, 1, "months")},
],
[
{"text": "No Expiry", "callback": self._set_expiry, "args": (link, chat, None, None)},
{"text": "Cancel", "callback": self._back_to_menu, "args": (link, chat)},
]
]
)
async def _set_expiry(self, call: InlineCall, link: str, chat, value: int, unit: str):
expiry_date = None
if value is not None and unit is not None:
try:
now = datetime.datetime.now()
if unit == "hours":
expiry_date = now + datetime.timedelta(hours=value)
elif unit == "days":
expiry_date = now + datetime.timedelta(days=value)
elif unit == "weeks":
expiry_date = now + datetime.timedelta(weeks=value)
elif unit == "months":
expiry_date = now + datetime.timedelta(days=value * 30) # Approximate month
except Exception as e:
logger.error(f"Error calculating expiry: {e}")
await call.edit(
text=self.strings["invalid_date"],
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
return
try:
await self.client(
EditExportedChatInviteRequest(
peer=chat,
link=link,
expire_date=expiry_date
)
)
expiry_text = expiry_date.strftime("%Y-%m-%d %H:%M") if expiry_date else "no expiry"
await call.edit(
text=self.strings["updated_expiry"].format(date=expiry_text),
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
except Exception as e:
logger.error(f"Error setting expiry: {e}")
await call.edit(
text="❌ Failed to update expiry",
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
async def _prompt_limit(self, call: InlineCall, link: str, chat):
await call.edit(
text=self.strings["select_limit"].format(link=link),
reply_markup=[
[
{"text": "1 Use", "callback": self._set_limit, "args": (link, chat, 1)},
{"text": "10 Uses", "callback": self._set_limit, "args": (link, chat, 10)},
],
[
{"text": "50 Uses", "callback": self._set_limit, "args": (link, chat, 50)},
{"text": "100 Uses", "callback": self._set_limit, "args": (link, chat, 100)},
],
[
{"text": "Unlimited", "callback": self._set_limit, "args": (link, chat, None)},
{"text": "Cancel", "callback": self._back_to_menu, "args": (link, chat)},
]
]
)
async def _set_limit(self, call: InlineCall, link: str, chat, usage_limit: int):
try:
await self.client(
EditExportedChatInviteRequest(
peer=chat,
link=link,
usage_limit=usage_limit
)
)
limit_text = str(usage_limit) if usage_limit is not None else "unlimited"
await call.edit(
text=self.strings["updated_limit"].format(limit=limit_text),
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
except Exception as e:
logger.error(f"Error setting limit: {e}")
await call.edit(
text="❌ Failed to update limit",
reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]]
)
async def _back_to_menu(self, call: InlineCall, link: str, chat):
await call.edit(
text=self.strings["select_action"].format(link=link),
reply_markup=[
[
{"text": "Revoke", "callback": self._revoke_link, "args": (link, chat)},
{"text": "Set Expiry", "callback": self._prompt_expiry, "args": (link, chat)},
],
[
{"text": "Set Usage Limit", "callback": self._prompt_limit, "args": (link, chat)},
]
]
)