Code refactoring

This commit is contained in:
hok7z 2023-01-22 12:27:20 +02:00
parent c7e3ee2ba8
commit 46c11a893a
18 changed files with 299 additions and 207 deletions

23
app.py
View File

@ -1,17 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import logging import logging
from aiogram import executor
from database import db, Member, Restriction
from aiogram import executor
from load import dp, bot, scheduler from load import dp, bot, scheduler
import filters import filters
import config
dp.filters_factory.bind(filters.AvaibleRolesFilter) dp.filters_factory.bind(filters.AvaibleRolesFilter)
dp.filters_factory.bind(filters.ReplayMessageFilter) dp.filters_factory.bind(filters.ReplayMessageFilter)
import handlers import handlers
import config
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
@ -21,15 +22,16 @@ WEBAPP_PORT = 3001
# Don`t touch anything! # Don`t touch anything!
WEBHOOK_HOST = f'http://{WEBAPP_HOST}:{WEBAPP_PORT}' WEBHOOK_HOST = f'http://{WEBAPP_HOST}:{WEBAPP_PORT}'
WEBHOOK_PATH = f'/bot{config.token}/' WEBHOOK_PATH = f'/bot{config.token}/'
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}" WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
async def on_startup(dp): async def on_startup(dp):
from utils.notify_start import notify_started_bot, database_is_empty from utils.notify_start import notify_started_bot, database_is_empty
DATABASE_EMPTY = database_is_empty() DATABASE_EMPTY = database_is_empty()
if DATABASE_EMPTY: if DATABASE_EMPTY:
await bot.send_message(config.second_group_id, await bot.send_message(config.second_group_id,
"Member table is empty, run: `!reload`",parse_mode="Markdown") "Member table is empty, run: `!reload`", parse_mode="Markdown")
await notify_started_bot(bot) await notify_started_bot(bot)
@ -38,7 +40,7 @@ async def on_startup(dp):
# Reloading users data # Reloading users data
from utils import reload_users_data from utils import reload_users_data
scheduler.add_job(reload_users_data,"interval", seconds=config.update_interval) scheduler.add_job(reload_users_data, "interval", seconds=config.update_interval)
scheduler.start() scheduler.start()
from load import tgc from load import tgc
@ -46,6 +48,7 @@ async def on_startup(dp):
await bot.set_webhook(WEBHOOK_URL) await bot.set_webhook(WEBHOOK_URL)
async def on_shutdown(dp): async def on_shutdown(dp):
await bot.delete_webhook() await bot.delete_webhook()
@ -53,6 +56,7 @@ async def on_shutdown(dp):
await dp.storage.close() await dp.storage.close()
await dp.storage.wait_closed() await dp.storage.wait_closed()
def main() -> None: def main() -> None:
if config.USE_WEBHOOK: if config.USE_WEBHOOK:
@ -67,7 +71,8 @@ def main() -> None:
) )
else: else:
executor.start_polling(dp,skip_updates=True) executor.start_polling(dp, skip_updates=True)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -1,6 +1,7 @@
from aiogram import Dispatcher, Bot from aiogram import Dispatcher, Bot
from environs import Env from environs import Env
env = Env() env = Env()
env.read_env() env.read_env()
@ -19,17 +20,17 @@ api_id = env.int("api_id")
api_hash = env.str("api_hash") api_hash = env.str("api_hash")
# Data update interval # Data update interval
update_interval = env.int("update_interval") update_interval = env.int("update_interval")
group_permissions = { group_permissions = {
"can_send_messages":True, "can_send_messages": True,
"can_send_media_messages":False, "can_send_media_messages": False,
"can_send_other_messages":True, "can_send_other_messages": True,
"can_send_polls":False, "can_send_polls": False,
"can_invite_users":False, "can_invite_users": False,
"can_change_info":False, "can_change_info": False,
"can_add_web_page_previews":False, "can_add_web_page_previews": False,
"can_pin_messages":False "can_pin_messages": False
} }
db_url = env.str("db_url") db_url = env.str("db_url")

View File

@ -3,15 +3,16 @@ from aiogram.dispatcher.filters import BoundFilter
from database import Member, MemberRoles from database import Member, MemberRoles
class AvaibleRolesFilter(BoundFilter): class AvaibleRolesFilter(BoundFilter):
"""Filter accessed roles""" """Filter accessed roles"""
key = "available_roles" key = "available_roles"
def __init__(self,available_roles:list[MemberRoles]): def __init__(self, available_roles: list[MemberRoles]):
self.avaible_roles = available_roles self.avaible_roles = available_roles
async def check(self,message:types.Message): async def check(self, message: types.Message):
member = Member.get(Member.user_id == message.from_user.id) member = Member.get(Member.user_id == message.from_user.id)
if (member.role == "owner"): if (member.role == "owner"):

View File

@ -1,6 +1,7 @@
from aiogram import types from aiogram import types
from aiogram.dispatcher.filters import BoundFilter from aiogram.dispatcher.filters import BoundFilter
class ReplayMessageFilter(BoundFilter): class ReplayMessageFilter(BoundFilter):
"""Check if message replied""" """Check if message replied"""
key = 'replied' key = 'replied'

View File

@ -1,7 +1,7 @@
from load import dp,types from load import dp, types
from config import group_id from config import group_id
@dp.channel_post_handler() @dp.channel_post_handler()
async def channel_handler(message:types.Message): async def channel_handler(message: types.Message):
await message.forward(group_id) await message.forward(group_id)

View File

@ -10,20 +10,19 @@ from aiogram.utils.exceptions import Unauthorized
@dp.errors_handler() @dp.errors_handler()
async def errors_handler(update: types.Update, exception): async def errors_handler(update: types.Update, exception):
if (isinstance(exception,Unauthorized)): if (isinstance(exception, Unauthorized)):
logging.info(f"Unathorized:{config.token}") logging.info(f"Unathorized:{config.token}")
return True return True
if (isinstance(exception,DoesNotExist)): if (isinstance(exception, DoesNotExist)):
await update.message.reply("Membser not found, you shoud update database data `!reload`", await update.message.reply("Membser not found, you shoud update database data `!reload`",
parse_mode="Markdown") parse_mode="Markdown")
return True return True
await update.message.answer("Error happaned!\nBot terminated!") await update.message.answer("Error happaned!\nBot terminated!")
await bot.send_message(config.second_group_id, await bot.send_message(config.second_group_id, (
(
"Bot terminated" "Bot terminated"
f"{exception}" f"{exception}"
),parse_mode="Markdown" ), parse_mode="Markdown"
) )

View File

@ -4,8 +4,11 @@ import config
from database import Member from database import Member
@dp.message_handler(commands=["start","help"],chat_type=[types.ChatType.SUPERGROUP]) @dp.message_handler(
async def start_command_group(message:types.Message): commands=["start", "help"],
chat_type=[types.ChatType.SUPERGROUP]
)
async def start_command_group(message: types.Message):
await message.answer(( await message.answer((
f"Hi,**{message.from_user.first_name}**!\n" f"Hi,**{message.from_user.first_name}**!\n"
"My commands:\n" "My commands:\n"
@ -14,26 +17,40 @@ async def start_command_group(message:types.Message):
parse_mode="Markdown" parse_mode="Markdown"
) )
@dp.message_handler(commands=["leave"],chat_type=[types.ChatType.SUPERGROUP])
async def leave_group(message:types.Message): @dp.message_handler(
commands=["leave"],
chat_type=[types.ChatType.SUPERGROUP]
)
async def leave_group(message: types.Message):
user = message.from_user user = message.from_user
if (message.text.split()[0] != "I UNDERSTAND!"): if (message.text.split()[0] != "I UNDERSTAND!"):
await message.answer("use /leave I UNDERSTAND") await message.answer("use /leave I UNDERSTAND")
return return
Member.delete().get(Member.user_id == user.id) Member.delete().get(Member.user_id == user.id)
# Ban user and save (bool) status = await bot.kick_chat_member(
status = await bot.kick_chat_member(chat_id=message.chat.id,user_id=user.id,until_date=None) chat_id=message.chat.id,
user_id=user.id,
until_date=None
)
if status: if status:
await message.answer(f"User [{user.first_name}](tg://user?id={user.id}) has laved chat forever",parse_mode="Markdown") await message.answer((
f"User [{user.first_name}](tg://user?id={user.id})"
"has leaved chat for forever"
), parse_mode="Markdown"
)
Member.delete().where(Member.user_id == user.id).execute() Member.delete().where(Member.user_id == user.id).execute()
@dp.message_handler(commands=["bio","me"],chat_type=[types.ChatType.SUPERGROUP])
@dp.message_handler(
commands=["bio", "me"],
chat_type=[types.ChatType.SUPERGROUP]
)
async def get_information(message: types.Message): async def get_information(message: types.Message):
user = Member.get(Member.user_id == message.from_user.id) user = Member.get(Member.user_id == message.from_user.id)
@ -45,7 +62,7 @@ async def get_information(message: types.Message):
@dp.message_handler( @dp.message_handler(
commands=["report"], commands=["report2"],
replied=True, replied=True,
chat_type=[types.ChatType.SUPERGROUP] chat_type=[types.ChatType.SUPERGROUP]
) )
@ -53,19 +70,19 @@ async def user_report(message: types.Message):
args = message.text.split() args = message.text.split()
if (len(args) != 2): if (len(args) != 2):
await message.answer("!report (reason)") await message.answer("/report (reason)")
return return
reported_user = message.reply_to_message.from_user reported_user = message.reply_to_message.from_user
reporter_user = message.from_user reporter_user = message.from_user
reason = args[1] reason = args[1]
await bot.send_message( await bot.send_message(
config.second_group_id, config.second_group_id,
( (
"Complaint about: [{}](tg://user?id={})\n" "Complaint about: [{}](tg://user?id={})\n"
"Complaint from: [{}](tg://user?id={})\n" "Complaint from: [{}](tg://user?id={})\n\n"
"Reason: {}\n" "Note: {}\n"
"{}" "{}"
).format( ).format(
reported_user.first_name, reported_user.first_name,
@ -73,7 +90,7 @@ async def user_report(message: types.Message):
reporter_user.first_name, reporter_user.first_name,
reporter_user.id, reporter_user.id,
reason, reason,
message.reply_to_message.link("Link message", as_html=False) message.reply_to_message.link("link message", as_html=False)
), ),
parse_mode="Markdown", parse_mode="Markdown",
) )

View File

@ -1,27 +1,26 @@
from load import dp, types from load import dp, types
from database import Member from database import Member
@dp.message_handler(content_types=["new_chat_members"]) @dp.message_handler(content_types=["new_chat_members"])
async def welcome_message(message:types.Message): async def welcome_message(message: types.Message):
user = Member.get_or_none(Member.user_id == message.from_user.id) user = Member.get_or_none(Member.user_id == message.from_user.id)
if (user): if (user):
await message.answer(f"Hi, {user.first_name} again") await message.answer(f"Hi, {user.first_name} again")
if not (user): if not (user):
Member.create( Member.create(
user_id = message.from_user.id, user_id=message.from_user.id,
first_name = message.from_user.first_name, first_name=message.from_user.first_name,
username = message.from_user.username, username=message.from_user.username,
) )
await message.answer(( await message.answer((
f"Hi, **{user.first_name}**!\n" f"Hi, **{user.first_name}**!\n"
"Please, read [chat rules]({})" "Please, read [chat rules]({})"
).format( ).format("https://nometa.xyz"),
"https://nometa.xyz" parse_mode="Markdown"
),parse_mode="Markdown") )
await message.delete() await message.delete()

View File

@ -3,7 +3,7 @@ from aiogram.types.chat_permissions import ChatPermissions
import config import config
from database import Member, Restriction from database import Restriction
from database import MemberRoles from database import MemberRoles
from utils import get_command_args, get_argument, parse_timedelta_from_message from utils import get_command_args, get_argument, parse_timedelta_from_message
@ -20,7 +20,6 @@ async def ban_user(message: types.Message):
to_user = command.to_user to_user = command.to_user
from_user = command.from_user from_user = command.from_user
# If can't descibe user data
if (not to_user) or (not from_user): if (not to_user) or (not from_user):
await message.answer(( await message.answer((
"Usage: !ban (@username|id) reason=None\n" "Usage: !ban (@username|id) reason=None\n"
@ -28,14 +27,18 @@ async def ban_user(message: types.Message):
) )
return return
# Ban user and save (bool) status = await bot.kick_chat_member(
status = await bot.kick_chat_member(chat_id=message.chat.id, user_id=to_user.user_id, until_date=None) chat_id=message.chat.id,
user_id=to_user.user_id,
until_date=None
)
if status and (not command.is_silent): if status and (not command.is_silent):
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has banned [{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has banned "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
# Open restrict
Restriction.create( Restriction.create(
from_user=from_user, from_user=from_user,
to_user=to_user, to_user=to_user,
@ -43,10 +46,11 @@ async def ban_user(message: types.Message):
message_id=message.message_id message_id=message.message_id
) )
@dp.message_handler( @dp.message_handler(
commands=["unban", "sunban"], commands=["unban", "sunban"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.HELPER,MemberRoles.ADMIN] available_roles=[MemberRoles.HELPER, MemberRoles.ADMIN]
) )
async def unban_user(message: types.Message): async def unban_user(message: types.Message):
command = await get_command_args(message) command = await get_command_args(message)
@ -54,7 +58,6 @@ async def unban_user(message: types.Message):
to_user = command.to_user to_user = command.to_user
from_user = command.from_user from_user = command.from_user
# If can't descibe user data
if (not to_user) or (not from_user): if (not to_user) or (not from_user):
await message.answer(( await message.answer((
"Usage: !unban (@username|id) reason=None\n" "Usage: !unban (@username|id) reason=None\n"
@ -62,12 +65,13 @@ async def unban_user(message: types.Message):
) )
return return
# Unban user and set status
status = await bot.unban_chat_member(chat_id=message.chat.id, user_id=to_user.user_id) status = await bot.unban_chat_member(chat_id=message.chat.id, user_id=to_user.user_id)
if status and (not command.is_silent): if status and (not command.is_silent):
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has unbanned [{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has unbanned "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
Restriction.create( Restriction.create(
from_user=from_user, from_user=from_user,
@ -76,6 +80,7 @@ async def unban_user(message: types.Message):
message_id=message.message_id message_id=message.message_id
) )
@dp.message_handler( @dp.message_handler(
commands=["info"], commands=["info"],
commands_prefix="!", commands_prefix="!",
@ -83,8 +88,7 @@ async def unban_user(message: types.Message):
) )
async def info_user(message: types.Message): async def info_user(message: types.Message):
command = await get_command_args(message) command = await get_command_args(message)
to_user = command.to_user
to_user = command.to_user
if (not to_user): if (not to_user):
await message.answer(( await message.answer((
@ -99,6 +103,7 @@ async def info_user(message: types.Message):
parse_mode="Markdown" parse_mode="Markdown"
) )
@dp.message_handler( @dp.message_handler(
commands=["kick", "skick"], commands=["kick", "skick"],
commands_prefix="!", commands_prefix="!",
@ -118,12 +123,23 @@ async def kick_user(message: types.Message):
return return
status1 = await bot.kick_chat_member(chat_id=message.chat.id, user_id=to_user.user_id, until_date=None) status1 = await bot.kick_chat_member(
status2 = await bot.unban_chat_member(chat_id=message.chat.id, user_id=to_user.user_id) chat_id=message.chat.id,
user_id=to_user.user_id,
until_date=None
)
status2 = await bot.unban_chat_member(
chat_id=message.chat.id,
user_id=to_user.user_id
)
if (not status1 and status2) and (not command.is_silent): if (not status1 and status2) and (not command.is_silent):
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has kicked [{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has kicked "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
Restriction.create( Restriction.create(
from_user=from_user, from_user=from_user,
to_user=to_user, to_user=to_user,
@ -132,19 +148,18 @@ async def kick_user(message: types.Message):
) )
@dp.message_handler( @dp.message_handler(
commands=["mute", "smute"], commands=["mute", "smute"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.ADMIN] available_roles=[MemberRoles.ADMIN]
) )
async def mute_user(message:types.Message): async def mute_user(message: types.Message):
command = await get_command_args(message) command = await get_command_args(message)
to_user = command.to_user to_user = command.to_user
from_user = command.from_user from_user = command.from_user
duration = await parse_timedelta_from_message(message) duration = parse_timedelta_from_message(message)
if (not to_user) or (not from_user): if (not to_user) or (not from_user):
await message.answer(( await message.answer((
@ -163,7 +178,10 @@ async def mute_user(message:types.Message):
) )
if status and (not command.is_silent): if status and (not command.is_silent):
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has muted [{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has muted "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
Restriction.create( Restriction.create(
from_user=from_user, from_user=from_user,
@ -174,7 +192,7 @@ async def mute_user(message:types.Message):
@dp.message_handler( @dp.message_handler(
commands=["unmute","sunmute"], commands=["unmute", "sunmute"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.ADMIN] available_roles=[MemberRoles.ADMIN]
) )
@ -185,27 +203,26 @@ async def umute_user(message: types.Message):
to_user = command.to_user to_user = command.to_user
from_user = command.from_user from_user = command.from_user
# If can't
if (not to_user) or (not from_user): if (not to_user) or (not from_user):
await message.answer(( await message.answer((
"Usage:!unmute (@username|id) reason=None.\n" "Usage:!unmute (@username|id) reason=None.\n"
"Reply to a message or use with a username/id.") "Reply to a message or use with a username/id.")
) )
return return
# Get chat permissions # Get chat permissions
group_permissions = config.group_permissions group_permissions = config.group_permissions
# Set permissions # Set permissions
permissions = ChatPermissions( permissions = ChatPermissions(
can_send_messages = group_permissions["can_send_messages"], can_send_messages=group_permissions["can_send_messages"],
can_send_media_messages = group_permissions["can_send_media_messages"], can_send_media_messages=group_permissions["can_send_media_messages"],
can_send_polls = group_permissions["can_send_polls"], can_send_polls=group_permissions["can_send_polls"],
can_send_other_messages = group_permissions["can_send_other_messages"], can_send_other_messages=group_permissions["can_send_other_messages"],
can_add_web_page_previews = group_permissions["can_add_web_page_previews"], can_add_web_page_previews=group_permissions["can_add_web_page_previews"],
can_change_info = group_permissions["can_change_info"], can_change_info=group_permissions["can_change_info"],
can_invite_users = group_permissions["can_invite_users"], can_invite_users=group_permissions["can_invite_users"],
can_pin_messages = group_permissions["can_pin_messages"] can_pin_messages=group_permissions["can_pin_messages"]
) )
# Restrict user and save # Restrict user and save
@ -216,7 +233,10 @@ async def umute_user(message: types.Message):
) )
if status and (not command.is_silent): if status and (not command.is_silent):
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has unmuted [{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has unmuted "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
@dp.message_handler( @dp.message_handler(
@ -229,7 +249,7 @@ async def pin_message(message: types.Message):
@dp.message_handler( @dp.message_handler(
commands=["readonly","ro"], commands=["readonly", "ro"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.ADMIN] available_roles=[MemberRoles.ADMIN]
) )
@ -238,28 +258,32 @@ async def readonly_mode(message: types.Message):
status = config.group_permissions['can_send_messages'] status = config.group_permissions['can_send_messages']
if (status): if (status):
await message.answer("🔕 Readonly mode enabled!") await message.answer("🔕 Readonly mode enabled!")
chat_permissions = ChatPermissions( chat_permissions = ChatPermissions(
can_send_messages = not status can_send_messages=not status
) )
else: else:
await message.answer("🔔 Readonly mode disabled!") await message.answer("🔔 Readonly mode disabled!")
chat_permissions = ChatPermissions( chat_permissions = ChatPermissions(
can_send_messages = group_permissions['can_send_messages'], can_send_messages=group_permissions['can_send_messages'],
can_send_media_messages = group_permissions["can_send_media_messages"], can_send_media_messages=group_permissions["can_send_media_messages"],
can_send_other_messages = group_permissions['can_send_other_messages'], can_send_other_messages=group_permissions['can_send_other_messages'],
can_send_polls = group_permissions['can_send_polls'], can_send_polls=group_permissions['can_send_polls'],
can_invite_users = group_permissions['can_invite_users'], can_invite_users=group_permissions['can_invite_users'],
can_change_info = group_permissions['can_change_info'], can_change_info=group_permissions['can_change_info'],
can_add_web_page_previews = group_permissions['can_add_web_page_previews'], can_add_web_page_previews=group_permissions['can_add_web_page_previews'],
can_pin_messages = group_permissions['can_pin_messages'] can_pin_messages=group_permissions['can_pin_messages']
) )
config.group_permissions["can_send_messages"] = not status config.group_permissions["can_send_messages"] = not status
await bot.set_chat_permissions(chat_id = message.chat.id, permissions = chat_permissions) await bot.set_chat_permissions(
chat_id=message.chat.id,
permissions=chat_permissions
)
@dp.message_handler( @dp.message_handler(
commands=["warn","w"], commands=["warn", "w"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.HELPER, MemberRoles.ADMIN] available_roles=[MemberRoles.HELPER, MemberRoles.ADMIN]
) )
@ -279,14 +303,24 @@ async def warn_user(message: types.Message):
to_user.warns += 1 to_user.warns += 1
to_user.save() to_user.save()
await message.answer(f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has warned [{to_user.first_name}](tg://user?id={to_user.user_id}) ({to_user.warns}/{config.limit_of_warns})",parse_mode="Markdown")
await message.answer((
f"[{from_user.first_name}](tg://user?id={from_user.user_id}) has warned "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")
if (to_user.warns == config.limit_of_warns): if (to_user.warns == config.limit_of_warns):
await message.answer(f"[{to_user.first_name}](tg://user?id={to_user.user_id}) has been banned!",parse_mode="Markdown") await message.answer((
await bot.kick_chat_member(chat_id=message.chat.id, user_id=to_user.user_id, until_date=None) f"[{from_user.first_name}](tg://user?id={from_user.user_id}) "
f"has banned {config.limit_of_warns}/{config.limit_of_warns} ⚠️ "
), parse_mode="Markdown")
await bot.kick_chat_member(
chat_id=message.chat.id,
user_id=to_user.user_id,
until_date=None
)
Restriction.create( Restriction.create(
from_user=from_user, from_user=from_user,
to_user=to_user, to_user=to_user,
@ -305,12 +339,13 @@ async def reload(message: types.Message):
await message.answer("Reloaded!") await message.answer("Reloaded!")
@dp.message_handler( @dp.message_handler(
commands=["setrole"], commands=["setrole"],
commands_prefix="!", commands_prefix="!",
available_roles=[MemberRoles.ADMIN] available_roles=[MemberRoles.ADMIN]
) )
async def set_role(message:types.Message): async def set_role(message: types.Message):
command = await get_command_args(message) command = await get_command_args(message)
new_role = get_argument(command.arguments) new_role = get_argument(command.arguments)
@ -335,5 +370,7 @@ async def set_role(message:types.Message):
to_user.role = new_role to_user.role = new_role
to_user.save() to_user.save()
await message.answer(f"{new_role.capitalize()} role set for \ await message.answer((
[{to_user.first_name}](tg://user?id={to_user.user_id})",parse_mode="Markdown") f"{new_role.capitalize()} role set for "
f"[{to_user.first_name}](tg://user?id={to_user.user_id})"
), parse_mode="Markdown")

View File

@ -1,33 +1,37 @@
from load import dp, types, bot from load import dp, types, bot
from database import Member, Restriction from database import Member, Restriction
from aiogram.types import KeyboardButton,ReplyKeyboardMarkup from aiogram.types import KeyboardButton, ReplyKeyboardMarkup
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.types.reply_keyboard import ReplyKeyboardRemove from aiogram.types.reply_keyboard import ReplyKeyboardRemove
import config import config
from keyboards.default import menu from keyboards.default import menus
from aiogram.types import CallbackQuery from aiogram.types import CallbackQuery
from aiogram.dispatcher.filters import Text from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.storage import FSMContext from aiogram.dispatcher.storage import FSMContext
from states.report_message import States from states.report_message import States
from keyboards.inline.report_button import report_button from keyboards.inline.report import report_callback
from keyboards.inline.callback_data import report_callback
@dp.message_handler(commands=["start","help"],chat_type=[types.ChatType.PRIVATE])
async def start_command_private(message:types.Message): @dp.message_handler(
commands=["start", "help"],
chat_type=[types.ChatType.PRIVATE]
)
async def start_command_private(message: types.Message):
await message.answer(( await message.answer((
f"Hi, **{message.from_user.first_name}**!\n" f"Hi, **{message.from_user.first_name}**!\n"
"My commands:\n" "My commands:\n"
"\t\t/help /start - read this message.") "\t\t/help /start - read this message."
,parse_mode="Markdown",reply_markup=menu ), parse_mode="Markdown", reply_markup=menus.bot_description_menu
) )
# Keyboard
@dp.message_handler(Text(equals=["About Us"])) @dp.message_handler(Text(equals=["About Us"]))
async def about_us(message:types.Message): async def about_us(message: types.Message):
await message.answer(( await message.answer((
"Moderator bot - an open source project for managing a Telegram group.\n\n" "Moderator bot - an open source project for managing a Telegram group.\n\n"
"Possibilities:\n" "Possibilities:\n"
@ -37,13 +41,15 @@ async def about_us(message:types.Message):
"4. Users can report admins.\n" "4. Users can report admins.\n"
"5. Admins can give warnings to users.\n" "5. Admins can give warnings to users.\n"
"\nRelease version:2.5.2\n" "\nRelease version:2.5.2\n"
"[Github](https://github.com/hok7z/moderator-bot)"), "[Github](https://github.com/hok7z/moderator-bot)"),parse_mode="Markdown"
parse_mode="Markdown"
) )
@dp.message_handler(Text(equals=["Check restrictions"]),state=None) @dp.message_handler(
async def check_for_restrict(message:types.Message): Text(equals=["Check restrictions"]),
state=None
)
async def check_for_restrict(message: types.Message):
user = Member.get(Member.user_id == message.from_user.id) user = Member.get(Member.user_id == message.from_user.id)
restrictions = Restriction.select().where(Restriction.to_user == user) restrictions = Restriction.select().where(Restriction.to_user == user)
@ -53,29 +59,48 @@ async def check_for_restrict(message:types.Message):
for restriction in restrictions: for restriction in restrictions:
callback = report_callback.new(restriction_id=restriction.id) callback = report_callback.new(restriction_id=restriction.id)
markup = report_button("✉️ Report restriction",callback)
from_user = restriction.from_user markup = InlineKeyboardMarkup()
to_user = restriction.to_user report_restriction = InlineKeyboardButton(
"✉️ Report restriction",
callback_data=callback
)
markup.insert(report_restriction)
from_user = restriction.from_user
to_user = restriction.to_user
await message.answer( await message.answer((
( "Restriction #{}\n"
f"Restriction #{restriction.id}\n" "from user [{}](tg://user?id={})\n"
f"from user: [{from_user.first_name}](tg://user?id={from_user.user_id})\n" "to user [{}](tg://user?id={})\n"
f"to user: [{from_user.first_name}](tg://user?id={to_user.user_id})\n" "Note: {}\n"
f"{restriction.text}\n" "{}\n"
f"{restriction.timestamp}\n" ).format(
),parse_mode="Markdown", restriction.id,
reply_markup=markup
from_user.first_name,
from_user.user_id,
to_user.first_name,
to_user.user_id,
restriction.text,
restriction.timestamp
), parse_mode="Markdown", reply_markup=markup
) )
await States.state1.set() await States.state1.set()
@dp.callback_query_handler(text_contains="report_restriction",state=States.state1)
async def report_restriction(call:CallbackQuery, state:FSMContext): @dp.callback_query_handler(
text_contains="report_restriction",
state=States.state1
)
async def report_restriction(call: CallbackQuery, state: FSMContext):
await call.answer(cache_time=60) await call.answer(cache_time=60)
callback_data = call.data callback_data = call.data
restriction_id = callback_data.split(":")[1] restriction_id = callback_data.split(":")[1]
markup = ReplyKeyboardMarkup(resize_keyboard=True) markup = ReplyKeyboardMarkup(resize_keyboard=True)
@ -84,30 +109,32 @@ async def report_restriction(call:CallbackQuery, state:FSMContext):
await state.update_data(restriction_id=restriction_id) await state.update_data(restriction_id=restriction_id)
await call.message.answer("Please,enter your report.",reply_markup=markup) await call.message.answer("Please,enter your report.", reply_markup=markup)
await States.next() await States.next()
@dp.message_handler(state=States.state2) @dp.message_handler(state=States.state2)
async def get_message_report(message:types.Message, state:FSMContext): async def get_message_report(message: types.Message, state: FSMContext):
answer = message.text answer = message.text
if not ("Cancel" in answer): if not ("Cancel" in answer):
data = await state.get_data() data = await state.get_data()
restriction_id = data.get("restriction_id") restriction_id = data.get("restriction_id")
restriction = Restriction.get(id=restriction_id) restriction = Restriction.get(id=restriction_id)
from_user = restriction.from_user from_user = restriction.from_user
to_user = restriction.to_user to_user = restriction.to_user
await bot.send_message(config.second_group_id, restriction_timestamp = restriction.timestamp.strftime("%d.%m.%y at %H:%M (server time)")
(
await bot.send_message(config.second_group_id, (
"Report on restriction #{}\n" "Report on restriction #{}\n"
"from user: [{}](tg://user?id={})\n" "Complaint from: [{}](tg://user?id={})\n"
"to user: [{}](tg://user?id={})\n" "Complaint about: [{}](tg://user?id={})\n"
"Sent {}\n"
"{}\n" "{}\n"
"{}\n" "Message: {}"
"Message:{}"
).format( ).format(
restriction_id, restriction_id,
from_user.first_name, from_user.first_name,
@ -115,14 +142,19 @@ async def get_message_report(message:types.Message, state:FSMContext):
to_user.first_name, to_user.first_name,
to_user.user_id, to_user.user_id,
restriction.text, restriction.text,
restriction.timestamp, restriction_timestamp,
answer, answer,
) ), parse_mode="Markdown"
,parse_mode="Markdown"
) )
await message.answer("Report restriction sended",reply_markup=ReplyKeyboardRemove()) await message.answer(
"Report restriction sended",
reply_markup=ReplyKeyboardRemove()
)
else: else:
await message.answer("Operation cancaled",reply_markup=ReplyKeyboardRemove()) await message.answer(
"Operation cancaled",
reply_markup=ReplyKeyboardRemove()
)
await state.finish() await state.finish()

View File

@ -1,2 +1,2 @@
from .menu import menu from .menus import bot_description_menu
from .menu import cancel from .menus import cancel_menu

View File

@ -1,19 +0,0 @@
from aiogram.types import ReplyKeyboardMarkup,KeyboardButton
menu = ReplyKeyboardMarkup(
resize_keyboard=True,
keyboard=[
[
KeyboardButton("Check restrictions"),
KeyboardButton("About Us"),
]
])
cancel = ReplyKeyboardMarkup(
resize_keyboard=True,
keyboard=[
[
KeyboardButton("❌Cancel")
]
]
)

View File

@ -0,0 +1,18 @@
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
bot_description_menu = ReplyKeyboardMarkup(
resize_keyboard=True,
keyboard=[[
KeyboardButton("Check restrictions"),
KeyboardButton("About Us"),
]]
)
cancel_menu = ReplyKeyboardMarkup(
resize_keyboard=True,
keyboard=[[
KeyboardButton("❌Cancel")
]]
)

View File

@ -1 +1 @@
from . import report_button from . import report

View File

@ -1,4 +0,0 @@
from aiogram.utils.callback_data import CallbackData
report_callback = CallbackData("report_restriction","restriction_id")

View File

@ -0,0 +1,12 @@
from aiogram.utils.callback_data import CallbackData
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
report_callback = CallbackData("report_restriction", "restriction_id")
def inline_button(text, callback_data):
markup = InlineKeyboardMarkup()
button = InlineKeyboardButton(text, callback_data=callback_data)
markup.insert(button)
return markup

View File

@ -1,8 +0,0 @@
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
def report_button(text,callback_data):
markup = InlineKeyboardMarkup()
button = InlineKeyboardButton(text,callback_data=callback_data)
markup.insert(button)
return markup

View File

@ -2,30 +2,31 @@ import re
import typing import typing
import datetime import datetime
from load import types from load import types
def parse_timedelta(value: str) -> typing.Optional[datetime.timedelta]: def parse_timedelta(value: str) -> typing.Optional[datetime.timedelta]:
regex = r'(?:(\d+)(?:d|д))?(?:(\d+)(?:h|ч))?(?:(\d+)(?:m|м))?(?:(\d+)(?:s|с))?'
specification = value.strip().replace(' ', '') specification = value.strip().replace(' ', '')
match = re.fullmatch(r'(?:(\d+)(?:d|д))?(?:(\d+)(?:h|ч))?(?:(\d+)(?:m|м))?(?:(\d+)(?:s|с))?', specification) match = re.fullmatch(regex, specification)
if match: if match:
units = [(0 if i is None else int(i)) for i in match.groups()] units = [(0 if i is None else int(i)) for i in match.groups()]
return datetime.timedelta(days=units[0], hours=units[1], minutes=units[2], seconds=units[3]) return datetime.timedelta(
else: days=units[0],
return None hours=units[1],
minutes=units[2],
seconds=units[3]
)
async def parse_timedelta_from_message( def parse_timedelta_from_message(message: types.Message) -> typing.Optional[datetime.timedelta]:
message: types.Message, _, *args = message.text.split()
) -> typing.Optional[datetime.timedelta]:
_, *args = message.text.split()
if args: if args:
duration = re.findall(r"(\d+d|\d+h|\d+m|\d+s)",''.join(message.text)) duration = re.findall(r"(\d+d|\d+h|\d+m|\d+s)", ''.join(message.text))
if duration:
duration = " ".join(duration) duration = " ".join(duration)
duration = parse_timedelta(duration) duration = parse_timedelta(duration)
if not duration:
return duration duration = datetime.timedelta(0, 0, 0)
else: return duration
return datetime.timedelta(0,0,0) # forever