# meta developer: @codrago_m
# scope: disable_onload_docs
# packurl: https://raw.githubusercontent.com/coddrago/modules/refs/heads/main/translations/chatmodule.yml
import logging
import typing
from datetime import datetime, timedelta, timezone
from telethon.tl import types
from telethon.tl.functions import channels, messages
from .. import loader, utils
logger = logging.getLogger("ChatModule")
@loader.tds
class ChatModuleMod(loader.Module):
strings = {
"name": "ChatModule",
}
async def client_ready(self, client, db):
self._client = client
self._db = db
self.xdlib = await self.import_lib(
"https://raw.githubusercontent.com/coddrago/modules/refs/heads/main/libs/xdlib.py",
suspend_on_error=True,
)
@loader.command(ru_doc="[reply] - Узнать ID")
async def id(self, message):
"""[reply] - Get the ID"""
ids = [self.strings["my_id"].format(id=self.tg_id)]
if message.is_private:
ids.append(self.strings["user_id"].format(id=message.to_id.user_id))
return await utils.answer(message, "\n".join(ids))
ids.append(self.strings["chat_id"].format(id=message.chat_id))
reply = await message.get_reply_message()
if (
reply
and not getattr(reply, "is_private")
and not getattr(reply, "sender_id") == self.tg_id
):
user_id = (await reply.get_sender()).id
ids.append(self.strings["user_id"].format(id=user_id))
return await utils.answer(message, "\n".join(ids))
@loader.command(
ru_doc="[reply/-u username/id] - Посмотреть права администратора пользователя",
)
@loader.tag("no_pm")
async def rights(self, message):
"""[reply/-u username/id] - Check user's admin rights"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reply = await message.get_reply_message()
user = opts.get("u") or opts.get("user") or (reply.sender_id if reply else None)
if not user:
return await utils.answer(message, self.strings["no_user"])
rights = await self.xdlib.chat.get_rights(message.chat, user)
participant = rights.participant
user = await self._client.get_entity(user)
if not hasattr(participant, "admin_rights"):
return await utils.answer(
message, self.strings["not_an_admin"].format(user=user.first_name)
)
if participant.admin_rights:
can_do = []
rights = participant.to_dict().get("admin_rights")
for right, is_permitted in rights.items():
if right == "_":
continue
if is_permitted:
can_do.append(right)
promoter = (
await self._client.get_entity(participant.promoted_by)
if hasattr(participant, "promoted_by")
else None
)
return await utils.answer(
message,
self.strings["admin_rights"].format(
rights="\n".join(
[
f"✅ {self.strings[right]}"
for right in can_do
]
),
promoter_id=promoter.id if promoter else 0,
promoter_name=(
promoter.first_name if promoter else self.strings["no"]
),
name=user.first_name,
),
)
return await utils.answer(
message, self.strings["not_an_admin"].format(user=user.first_name)
)
@loader.command(
ru_doc="Покинуть чат",
)
@loader.tag("no_pm")
async def leave(self, message):
"""Leave chat"""
await message.delete()
await self._client(channels.LeaveChannelRequest((await message.get_chat()).id))
@loader.command(
ru_doc="[a[1-100] b[1-100]] | [reply] Удалить сообщения",
)
async def d(self, message):
"""[a[1-100] b[1-100]] | [reply] - Delete messages"""
await self.xdlib.messages.delete_messages(message)
@loader.command(ru_doc="[reply] - Закрепить сообщение")
@loader.tag("only_reply")
async def pin(self, message):
"""[reply] - Pin a message"""
reply = await message.get_reply_message()
try:
await reply.pin(notify=True, pm_oneside=False)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["pin_failed"])
await utils.answer(message, self.strings["pinned"])
@loader.command(ru_doc="Открепить сообщение")
@loader.tag("only_reply")
async def unpin(self, message):
"""Unpin a message"""
reply = await message.get_reply_message()
try:
await reply.unpin()
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["unpin_failed"])
await utils.answer(message, self.strings["unpinned"])
@loader.command(ru_doc="[-c id] Удаляет группу/канал")
async def dgc(self, message):
"""[-c id] Delete chat/channel"""
args = utils.get_args(message)
opts = self.xdlib.parse.opts(args)
chat_id = opts.get("c") or opts.get("chat")
if chat_id:
chat = await self._client.get_entity(chat_id)
if isinstance(chat, types.Channel):
await self._client(channels.DeleteChannelRequest(chat.id))
elif isinstance(chat, types.Chat):
await self._client(messages.DeleteChatRequest(chat.id))
else:
return await utils.answer(message, self.strings["failed_to_delete"])
return await utils.answer(message, self.strings["successful_delete"])
if isinstance(message.chat, types.Channel):
await self._client(channels.DeleteChannelRequest(message.chat))
elif isinstance(message.chat, types.Chat):
await self._client(messages.DeleteChatRequest(message.chat))
else:
return await utils.answer(message, self.strings["failed_to_delete"])
return
@loader.command(ru_doc="Очищает группу/канал от удаленных аккаунтов")
@loader.tag("no_pm")
async def flush(self, message):
"""Removes deleted accounts from the chat/channel"""
chat = await message.get_chat()
if not getattr(chat, "admin_rights", False) and not getattr(
getattr(chat, "admin_rights", None), "ban_users", False
):
return await utils.answer(message, self.strings["no_rights"])
deleted = await self.xdlib.chat.get_deleted(chat)
if not deleted:
return await utils.answer(message, self.strings["no_deleted_accounts"])
for to_delete in deleted:
try:
await self._client.kick_participant(chat, to_delete)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
return await utils.answer(message, self.strings["kicked_deleted_accounts"])
@loader.command(ru_doc="Показывает админов в группе/канале")
@loader.tag("no_pm")
async def admins(self, message):
"""Shows the admins in the chat/channel"""
admins = await self.xdlib.chat.get_admins(message.chat, True)
creator = await self.xdlib.chat.get_creator(message.chat)
return await utils.answer(
message,
self.strings["admin_list"].format(
id=creator.id if creator else 0,
name=creator.first_name if creator else self.strings["no"],
admins_count=len(admins) or 0,
admins=(
"\n".join(
f"✅ {admin.first_name} [{admin.id}] / {admin.participant.rank}"
for admin in admins
)
if admins
else f"\n{self.strings['no_admins_in_chat']}"
),
),
)
@loader.command(ru_doc="Показывает ботов в группе/канале")
@loader.tag("no_pm")
async def bots(self, message):
"""Shows the bots in the chat/channel"""
bots = await self.xdlib.chat.get_bots(message.chat)
if not bots:
return await utils.answer(message, self.strings["no_bots_in_chat"])
await utils.answer(
message,
self.strings["bot_list"].format(
count=len(bots),
bots="\n".join(
[
f"✅ {bot.first_name} [{bot.id}]"
for bot in bots
]
),
),
)
@loader.command(ru_doc="Показывает простых участников чата/канала")
@loader.tag("no_pm")
async def users(self, message):
"""Shows the users in the chat/channel"""
users = await self.xdlib.chat.get_members(message.chat)
if not users:
return await utils.answer(message, self.strings["no_user_in_chat"])
await utils.answer(
message,
self.strings["user_list"].format(
count=len(users),
users="\n".join(
[
f"✅ {user.first_name} [{user.id}]"
for user in users
]
),
),
)
@loader.command(ru_doc="[-u] [-t] [-r] Забанить участника")
@loader.tag("no_pm")
async def ban(self, message):
"""[-u] [-t] [-r] Ban a participant temporarily or permanently"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reason = opts.get("r")
reply = await message.get_reply_message()
user = opts.get("u") or (reply.sender_id if reply else None)
user = await self._client.get_entity(user) if user else None
strings = []
if not user:
return await utils.answer(message, self.strings["no_user"])
seconds = self.xdlib.parse.time(opts.get("t")) if opts.get("t") else None
until_date = (
(datetime.now(timezone.utc) + timedelta(seconds=seconds))
if seconds
else None
)
time_info = f" {self.xdlib.format.time(seconds)}" if seconds else None
try:
await self._client.edit_permissions(
message.chat,
user,
until_date=until_date,
view_messages=False,
)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
strings.append(
self.strings["user_is_banned"].format(
id=user.id,
name=(
getattr(user, "first_name")
if hasattr(user, "first_name")
else getattr(user, "title")
),
time_info=time_info or self.strings["forever"],
)
)
if reason:
strings.append(self.strings["reason"].format(reason=reason))
return await utils.answer(message, "\n".join(strings))
@loader.command(ru_doc="Разбанить пользователя")
@loader.tag("no_pm")
async def unban(self, message):
"""[-u] Unban a user"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reply = await message.get_reply_message()
user = opts.get("u") or (reply.sender_id if reply else None)
user = await self._client.get_entity(user) if user else None
if not user:
return await utils.answer(message, self.strings["no_user"])
try:
await self._client.edit_permissions(message.chat, user, view_messages=True)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
return await utils.answer(
message,
self.strings["user_is_unbanned"].format(
id=user.id,
name=(
getattr(user, "first_name")
if hasattr(user, "first_name")
else getattr(user, "title")
),
),
)
@loader.command(ru_doc="[-u] [-r] Кикнуть участника")
@loader.tag("no_pm")
async def kick(self, message):
"""[-u] [-r] Kick a participant"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reason = opts.get("r")
reply = await message.get_reply_message()
user = opts.get("u") or (reply.sender_id if reply else None)
user = await self._client.get_entity(user) if user else None
strings = []
if not user:
return await utils.answer(message, self.strings["no_user"])
try:
await self._client.kick_participant(message.chat, user)
except Exception as e:
logging.error(str(e))
return await utils.answer(message, self.strings["error"])
strings.append(
self.strings["user_is_kicked"].format(
id=user.id,
name=(
getattr(user, "first_name")
if hasattr(user, "first_name")
else getattr(user, "title")
),
)
)
if reason:
strings.append(self.strings["reason"].format(reason=reason))
return await utils.answer(message, "\n".join(strings))
@loader.command(ru_doc="[-u] [-t] [-r] Замутить участника")
@loader.tag("no_pm")
async def mute(self, message):
"""[-u] [-t] [-r] Mute a participant temporarily or permanently"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reason = opts.get("r")
reply = await message.get_reply_message()
user = opts.get("u") or (reply.sender_id if reply else None)
user = await self._client.get_entity(user) if user else None
strings = []
if not user:
return await utils.answer(message, self.strings["no_user"])
seconds = self.xdlib.parse.time(opts.get("t")) if opts.get("t") else None
until_date = (
(datetime.now(timezone.utc) + timedelta(seconds=seconds))
if seconds
else None
)
time_info = f" {self.xdlib.format.time(seconds)}" if seconds else None
try:
await self._client.edit_permissions(
message.chat,
user,
until_date=until_date,
send_messages=False,
)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
strings.append(
self.strings["user_is_muted"].format(
id=user.id,
name=(
getattr(user, "first_name")
if hasattr(user, "first_name")
else getattr(user, "title")
),
time_info=time_info or self.strings["forever"],
)
)
if reason:
strings.append(self.strings["reason"].format(reason=reason))
return await utils.answer(message, "\n".join(strings))
@loader.command(ru_doc="Размутить участника")
@loader.tag("no_pm")
async def unmute(self, message):
"""Unmute a participant"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reply = await message.get_reply_message()
user = opts.get("u") or (reply.sender_id if reply else None)
user = await self._client.get_entity(user) if user else None
if not user:
return await utils.answer(message, self.strings["no_user"])
try:
await self._client.edit_permissions(message.chat, user, send_messages=True)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
return await utils.answer(
message,
self.strings["user_is_unmuted"].format(
id=user.id,
name=(
getattr(user, "first_name")
if hasattr(user, "first_name")
else getattr(user, "title")
),
),
)
@loader.command(
ru_doc="[-g|--group name] [-c|--channel name] - Создать группу/канал"
)
async def create(self, message):
"""[-g|--group name] [-c|--channel name] - Create group/channel"""
opts = self.xdlib.parse.opts(utils.get_args(message))
group_name = opts.get("g") or opts.get("group")
channel_name = opts.get("c") or opts.get("channel")
if channel_name:
result = await self._client(
channels.CreateChannelRequest(
title=channel_name, broadcast=True, about=""
)
)
chat = await self.xdlib.chat.get_info(result.chats[0])
return await utils.answer(
message,
self.strings["channel_created"].format(
link=chat.get("link"), title=channel_name
),
)
if group_name:
result = await self._client(
channels.CreateChannelRequest(
title=group_name, megagroup=True, about=""
)
)
chat = await self.xdlib.chat.get_info(result.chats[0])
return await utils.answer(
message,
self.strings["group_created"].format(
link=chat.get("link"), title=group_name
),
)
return await utils.answer(message, self.strings["invalid_args"])
@loader.command(
ru_doc="Отключает звук и архивирует чат",
)
async def dnd(self, message):
"""Mutes and archives the current chat"""
dnd = await utils.dnd(self._client, await message.get_chat())
if dnd:
return await utils.answer(message, self.strings["dnd"])
else:
return await utils.answer(message, self.strings["dnd_failed"])
@loader.command(
ru_doc="-u username/id - Пригласить пользователя в чат (-b пригласить инлайн бота)"
)
async def invite(self, message):
"""-u username/id - Invite a user to the chat (use -b to invite the inline bot)"""
args = utils.get_args(message)
opts = self.xdlib.parse.opts(args)
if opts.get("b") or opts.get("bot"):
invited = await self.xdlib.chat.invite_bot(self._client, message.chat)
entity = await self._client.get_entity(self.inline.bot_id)
if invited:
return await utils.answer(
message,
self.strings["user_invited"].format(
user=entity.first_name, id=entity.id
),
)
return await utils.answer(message, self.strings["user_not_invited"])
reply = await message.get_reply_message()
user = opts.get("u") or opts.get("user") or (reply.sender_id if reply else None)
if not user:
return await utils.answer(message, self.strings["no_user"])
entity = await self._client.get_entity(user)
invited = await self.xdlib.chat.invite_user(message.chat, user)
if invited:
return await utils.answer(
message,
self.strings["user_invited"].format(
user=entity.first_name, id=entity.id
),
)
return await utils.answer(message, self.strings["user_not_invited"])
@loader.command(ru_doc="[-i] Получить информацию о сущности")
async def inspect(self, message):
"""[-i] Get the info about the entity"""
opts = self.xdlib.parse.opts(utils.get_args(message))
reply = await message.get_reply_message()
target = (
opts.get("i")
or (reply.sender if reply else await message.get_chat())
or None
)
if not target:
return await utils.answer(message, self.strings["no_user"])
ent = await self._client.get_entity(target)
if isinstance(ent, types.Channel):
try:
chatinfo = await self.xdlib.chat.get_info(ent)
photo = chatinfo.get("chat_photo")
photo = photo if not isinstance(photo, types.PhotoEmpty) else None
return await utils.answer(
message,
self.strings["chatinfo"].format(
id=chatinfo.get("id"),
title=chatinfo.get("title"),
about=chatinfo.get("about") or self.strings["no"],
admins_count=chatinfo.get("admins_count"),
online_count=chatinfo.get("online_count"),
participants_count=chatinfo.get("participants_count"),
kicked_count=chatinfo.get("kicked_count"),
slowmode_seconds=(
self.xdlib.format.time(chatinfo.get("slowmode_seconds"))
if chatinfo.get("slowmode_seconds")
else self.strings["no"]
),
call=(
self.strings["yes"]
if chatinfo.get("call")
else self.strings["no"]
),
ttl_period=(
self.xdlib.format.time(chatinfo.get("ttl_period"))
if chatinfo.get("ttl_period")
else self.strings["no"]
),
requests_pending=chatinfo.get("requests_pending"),
recent_requesters=", ".join(
[
f"{user}"
for user in chatinfo.get("recent_requesters")
]
)
or self.strings["no"],
linked_chat_id=chatinfo.get("linked_chat_id")
or self.strings["no"],
antispam=(
self.strings["yes"]
if chatinfo.get("antispam")
else self.strings["no"]
),
participants_hidden=(
self.strings["yes"]
if chatinfo.get("participants_hidden")
else self.strings["no"]
),
link=chatinfo.get("link") or self.strings["no"],
is_forum=(
self.strings["yes"]
if chatinfo.get("is_forum")
else self.strings["no"]
),
type_of=(
self.strings["type_group"]
if chatinfo.get("is_group")
else (
self.strings["type_channel"]
if chatinfo.get("is_channel")
else self.strings["type_unknown"]
)
),
),
file=(
types.InputMediaPhoto(
types.InputPhoto(
photo.id, photo.access_hash, photo.file_reference
)
)
if photo
else None
),
)
except Exception as e:
logger.error(str(e))
return await utils.answer(message, self.strings["error"])
if isinstance(ent, types.User):
try:
userinfo = await self.xdlib.user.get_info(ent)
photo = userinfo.get("profile_photo")
working_hours = (
userinfo.get("business_work_hours").weekly_open
if userinfo.get("business_work_hours")
else 0
)
weekdays = [
self.strings["monday"],
self.strings["tuesday"],
self.strings["wednesday"],
self.strings["thursday"],
self.strings["friday"],
self.strings["saturday"],
self.strings["sunday"],
]
personal_channel = userinfo.get("personal_channel")
working_hours_output = []
if working_hours:
for item in working_hours:
day_index = item.start_minute // (24 * 60)
day = weekdays[day_index]
start = self.xdlib.parse.minutes_to_hhmm(item.start_minute)
end = self.xdlib.parse.minutes_to_hhmm(item.end_minute)
working_hours_output.append(f"{day}: {start} - {end}")
return await utils.answer(
message,
self.strings["userinfo"].format(
common_chats_count=userinfo.get("common_chats_count") or 0,
phone=userinfo.get("phone") or self.strings["no"],
common_chats=(
", ".join(
[
f"{channel.title}"
for channel in userinfo.get("common_chats")
]
)
if userinfo.get("common_chats")
else self.strings["no"]
),
user_id=userinfo.get("id", 0),
first_name=userinfo.get("first_name") or self.strings["no"],
last_name=userinfo.get("last_name") or self.strings["no"],
about=userinfo.get("about") or self.strings["no"],
emoji_status=(
f"🌙"
if userinfo.get("emoji_status")
else self.strings["no"]
),
business_work_hours=", ".join(working_hours_output)
or self.strings["no"],
birthday=(
f"{userinfo.get('birthday').day or ''}."
f"{userinfo.get('birthday').month or ''}."
f"{userinfo.get('birthday').year or ''}"
if userinfo.get("birthday")
else self.strings["no"]
),
stargifts_count=userinfo.get("stargifts_count")
or self.strings["no"],
usernames=(
", ".join(
[
f"@{username}"
for username in userinfo.get("usernames")
]
)
if userinfo.get("usernames")
else self.strings["no"]
),
personal_channel=(
f""
f"{personal_channel.title}"
if personal_channel
else self.strings["no"]
),
),
file=(
types.InputMediaPhoto(
types.InputPhoto(
photo.id, photo.access_hash, photo.file_reference
)
)
if photo
else None
),
)
except Exception as e:
logger.error(e)
return await utils.answer(message, self.strings["error"])
@loader.command(ru_doc="[-a] [-d] Управлять заявками на вступление")
@loader.tag("no_pm")
async def requests(self, message):
"""[-a] [-d] Manage join requests"""
opts = self.xdlib.parse.opts(utils.get_args(message))
approve_list = [x for x in str(opts.get("a", "")).split(",") if x]
dismiss_list = [x for x in str(opts.get("d", "")).split(",") if x]
sanitized_approve_list = [int(x) if x.isdigit() else x for x in approve_list]
sanitized_dismiss_list = [int(x) if x.isdigit() else x for x in approve_list]
all_list = sanitized_approve_list + sanitized_dismiss_list
all_targets = [
await self._client.get_entity(
int(ent.strip()) if ent.strip().isdigit() else ent.strip()
)
for ent in all_list
]
for approve in approve_list:
if approve.isdigit():
await self.xdlib.chat.join_request(message.chat, int(approve), True)
else:
await self.xdlib.chat.join_request(message.chat, approve, True)
for dismiss in dismiss_list:
if dismiss.isdigit():
await self.xdlib.chat.join_request(message.chat, int(dismiss), False)
else:
await self.xdlib.chat.join_request(message.chat, dismiss, False)
return await utils.answer(
message,
self.strings["requests_checked"].format(
entities=", ".join(
ent.first_name
or getattr(ent, "username", None)
or str(getattr(ent, "id", "unknown"))
for ent in all_targets
)
),
)
@loader.command(ru_doc="Получить все свои чаты/каналы")
async def owns(self, message):
"""Get all your chats/channels"""
owns = await self.xdlib.dialog.get_owns(self._client)
return await utils.answer(
message,
self.strings["owns"].format(
num=len(owns),
owns="\n".join(
[
f"✅ {own.title} [{str(own.id).replace('-100', '')}]"
for own in owns
]
),
),
)
@loader.command(ru_doc="[-r] [-u] [-f] - Выдать админку участнику")
@loader.tag("no_pm")
async def promote(self, message):
"""[-r] [-u] [-f] - Promote a participant"""
reply = await message.get_reply_message()
opts = self.xdlib.parse.opts(utils.get_args(message))
user = opts.get("u") or getattr(reply, "sender_id") or None
if not user:
return await utils.answer(message, self.strings["no_user"])
user = await self._client.get_entity(user)
rank = (opts.get("r")) or "XD Admin"
chat = await message.get_chat()
rights = await self.xdlib.chat.get_rights(message.chat, user)
if (
not chat.admin_rights
or not getattr(chat.admin_rights, "add_admins")
or (
getattr(rights.participant, "promoted_by", self.tg_id) != self.tg_id
and not getattr(chat, "creator", False)
)
):
return await utils.answer(message, self.strings["no_rights"])
full = opts.get("f")
if full:
my_rights = [
r for r, y in chat.admin_rights.to_dict().items() if y and r != "_"
]
perms = self.xdlib.admin_rights(0)
perms = perms.add(*my_rights)
await self.xdlib.admin.set_rights(chat, user, perms.to_int(), rank)
return await utils.answer(
message,
self.strings["promoted"].format(
id=user.id,
name=user.first_name
if hasattr(user, "first_name")
else user.title
if hasattr(user, "title")
else "None",
rights=self.strings["full_rights"],
),
)
mask = (
self.xdlib.admin_rights.to_mask(rights.participant.admin_rights)
if hasattr(rights.participant, "admin_rights")
else 0
)
await utils.answer(
message,
self.strings["promote"].format(
id=user.id,
name=user.first_name
if hasattr(user, "first_name")
else user.title
if hasattr(user, "title")
else "None",
rank=rank,
),
reply_markup=await self.build_markup(user.id, chat.id, mask, rank),
)
@loader.command(ru_doc="[-t] [-u] - Ограничить участника")
@loader.tag("no_pm")
async def restrict(self, message):
"""[-t] [-u] - Restrict a participant"""
reply = await message.get_reply_message()
opts = self.xdlib.parse.opts(utils.get_args(message))
user = opts.get("u") or getattr(reply, "sender_id") or None
if not user:
return await utils.answer(message, self.strings["no_user"])
user = await self._client.get_entity(user)
chat = await message.get_chat()
if not chat.admin_rights or not getattr(chat.admin_rights, "ban_users"):
return await utils.answer(message, self.strings["no_rights"])
duration = opts.get("t", None)
if duration:
duration = self.xdlib.format.time(self.xdlib.parse.time(duration))
rights = await self.xdlib.chat.get_rights(chat, user)
mask = (
self.xdlib.banned_rights.MAX_MASK
- self.xdlib.banned_rights.to_mask(rights.participant.banned_rights)
if hasattr(rights.participant, "banned_rights")
else 0
)
rank = "-"
await utils.answer(
message,
self.strings["restrict"].format(
id=user.id,
name=user.first_name
if hasattr(user, "first_name")
else user.title
if hasattr(user, "title")
else "None",
time=f" {duration}" if duration else self.strings["forever"],
),
reply_markup=await self.build_markup(
user.id,
chat.id,
mask,
rank,
mode="restrict",
duration=f" {duration}" if duration else None,
),
)
async def build_markup(
self,
user_id: int,
chat_id: int,
mask: int,
rank: str,
duration: typing.Optional[int] = None,
mode="admin",
):
rights_cls = (
self.xdlib.admin_rights if mode == "admin" else self.xdlib.banned_rights
)
rights_names = rights_cls.RIGHTS_LIST
rights = rights_cls(mask)
chat = await self._client.get_entity(chat_id)
markup = utils.chunks(
[
{
"text": f"{'🟢' if rights.has_index(idx) else '🔴'} {self.strings[name]}",
"callback": self._toggle_right,
"args": (user_id, chat_id, mask, idx, rank, mode, duration),
}
for idx, name in enumerate(rights_names)
if (
name != "until_date"
and not (
getattr(chat.default_banned_rights, name, True)
if mode != "admin"
else False
)
)
],
2,
)
markup.append(
[
{
"text": self.strings["apply"],
"callback": self._apply_rights,
"args": (user_id, chat_id, mask, rank, mode, duration),
}
]
)
markup.append([{"text": self.strings["close"], "action": "close"}])
return markup
async def _toggle_right(
self,
call,
user_id: int,
chat_id: int,
mask: int,
idx: int,
rank: str,
mode: str,
duration: str,
):
new_mask = mask ^ (1 << idx)
new_markup = await self.build_markup(
user_id, chat_id, new_mask, rank, mode=mode, duration=duration
)
user = await self._client.get_entity(user_id)
title = self.strings["promote"] if mode == "admin" else self.strings["restrict"]
await utils.answer(
call,
title.format(
id=user_id,
name=user.first_name
if hasattr(user, "first_name")
else user.title
if hasattr(user, "title")
else "None",
rank=rank,
time=f" {duration}" if duration else self.strings["forever"],
),
reply_markup=new_markup,
)
async def _apply_rights(
self,
call,
user_id: int,
chat_id: int,
mask: int,
rank: str,
mode: str,
duration: typing.Optional[str] = None,
):
user = await self._client.get_entity(user_id)
chat = await self._client.get_entity(chat_id)
if mode == "admin":
ok = await self.xdlib.admin.set_rights(chat, user, mask, rank)
rights_items = self.xdlib.admin_rights(mask).to_dict()
else:
ok = await self.xdlib.chat.set_restrictions(
chat, user, mask, duration=duration
)
rights_items = self.xdlib.banned_rights(mask).to_dict()
rights_list = [r for r, v in rights_items.items() if v]
if ok:
text = (
self.strings["promoted"]
if mode == "admin" and mask
else self.strings["demoted"]
if mode == "admin" and not mask
else self.strings["restricted"]
)
await utils.answer(
call,
text.format(
id=user_id,
name=user.first_name
if hasattr(user, "first_name")
else user.title
if hasattr(user, "title")
else "None",
rights=", ".join([self.strings[r] for r in rights_list])
if rights_list
else self.strings["no"],
duration=f" {duration}" if duration else self.strings["forever"],
time=f" {duration}" if duration else self.strings["forever"],
),
reply_markup=[[{"text": self.strings["close"], "action": "close"}]],
)
else:
await utils.answer(
call,
self.strings["error"],
reply_markup=[[{"text": self.strings["close"], "action": "close"}]],
)