diff --git a/.gitignore b/.gitignore index 88e8f67..a0f71a9 100644 --- a/.gitignore +++ b/.gitignore @@ -88,4 +88,6 @@ ENV/ # Rope project settings .ropeproject .idea/ -config.py \ No newline at end of file +config.py + +.vscode diff --git a/README.md b/README.md index 902ca8f..b91f1ba 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,60 @@ # MasterBot CW Master Castle Bot + +# Trello taskboard: +[ТЫЦ](https://trello.com/b/mIKI2omk/%D1%81%D1%83%D0%BC%D1%80%D0%B0%D0%BA%D0%BE%D0%B1%D0%BE%D1%82) + +### installation into venv (recommended): +``` +virtualenv -p python3 .env #make sure you creating python3 venv +source .env/bin/activate +python3 -m pip install -r requirements.txt +``` + +### mysql database setup (only mysql is supported): + +1)Install recent mysql-server distribution +e.g. for GNU/Linux: +``` +sudo apt-get install mysql-server +``` +2)create a root user (if it was not created during installation process) +``` +sudo mysqladmin -u root password 'mynewpassword' +``` +3)login to mysql as root: +``` +sudo mysql -u root -h localhost -p +``` +4)create a new user: +``` +CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypass'; +``` +5)grant privileges to the new user: +``` +GRANT ALL PRIVILEGES ON * . * TO 'myuser'@'localhost'; +exit +``` +6)log in to your new user similarly to step (3). + +7)create a new database +``` +CREATE DATABASE 'test'; +ALTER DATABASE 'test' CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; +``` +8)exit to CLI +``` +exit +``` +9)open the file 'config.py.sample', enter your new database user's credentials, database name and your telegram bot API token + +10)You have to install python3-tk (if not yet installed) to properly run matplotlib requirement. +``` +sudo apt-get install python3-tk +``` + +11)launch the bot: +``` +python3 main.py +``` +the mysql database schema will be created automatically by a built-in script. diff --git a/config.py.sample b/config.py.sample new file mode 100644 index 0000000..4247f9f --- /dev/null +++ b/config.py.sample @@ -0,0 +1,12 @@ +# Содержимое этого файла необходимо скопировать в config.py и изменить под себя + +TOKEN = '' # Токен телеграмбота (получается у @BotFather) +DB = 'mysql+pymysql://:@/?charset=utf8mb4' # Строчка подключения к базе данных (поддерживается только MySql, о формате можно прочитать тут http://docs.sqlalchemy.org/en/latest/dialects/mysql.html) +API_PORT = 88 # Порт, по которому будет доступен внешний апи бота (REST) +GOVERNMENT_CHAT = -1001149271906 # Чат, в который бот будет слать отчёты +SUPER_ADMIN_ID = 0 # id супер админа +# вербовочный функционал: +CASTLE_CHAT_ID = None # id замкового чата (для поиска новых игроков в замке - если None - функционал отключен) +ACADEM_CHAT_ID = None # id чата академии (для уведомления о новых игроках в замке - если None - функционал отключен) +CASTLE = None # Флаг замка, который вы хотите обслуживать (например '🇮🇲'), оставьте None, чтобы не было ограничений +WEB_LINK = 'Please change it. {}' diff --git a/core/__init__.py b/core/__init__.py index 7c68785..40a96af 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1 +1 @@ -# -*- coding: utf-8 -*- \ No newline at end of file +# -*- coding: utf-8 -*- diff --git a/core/chat_commands.py b/core/chat_commands.py new file mode 100644 index 0000000..cfa8f63 --- /dev/null +++ b/core/chat_commands.py @@ -0,0 +1,29 @@ +CC_SET_WELCOME = 'welcome:' +CC_HELP = 'help' +CC_SQUAD = 'squad' +CC_SHOW_WELCOME = 'show welcome message' +CC_TURN_ON_WELCOME = 'turn on welcome message' +CC_TURN_OFF_WELCOME = 'turn off welcome message' +CC_SET_TRIGGER = 'trigger:' +CC_UNSET_TRIGGER = 'untrigger:' +CC_TRIGGER_LIST = 'trigger list' +CC_ADMIN_LIST = 'admin list' +CC_PING = 'ping' +CC_DAY_STATISTICS = 'daily stats' +CC_WEEK_STATISTICS = 'weekly stats' +CC_BATTLE_STATISTICS = 'battle stats' +CC_ALLOW_TRIGGER_ALL = 'allow everyone to trigger' +CC_DISALLOW_TRIGGER_ALL = 'prevent everyone from triggering' +CC_ADMINS = ['admins', 'commander'] +CC_ALLOW_PIN_ALL = 'allow everyone to pin' +CC_DISALLOW_PIN_ALL = 'prevent everyone from pinning' +CC_BOSS_1 = ['бандит', 'краб'] +CC_BOSS_2 = ['жало', 'королева роя'] +CC_BOSS_3 = ['циклоп', 'борода'] +CC_BOSS_4 = ['гидра', 'лич'] +CC_OPEN_HIRING = 'open admissions' +CC_CLOSE_HIRING = 'close admissions' +CC_PIN = 'pin and notify' +CC_SILENT_PIN = 'pin' +CC_DELETE = 'delete' +CC_KICK = 'kick' diff --git a/core/commands.py b/core/commands.py new file mode 100644 index 0000000..6e4446c --- /dev/null +++ b/core/commands.py @@ -0,0 +1,28 @@ +ADMIN_COMMAND_ORDER = '⚔Orders' +ADMIN_COMMAND_STATUS = '🔎Status' +ADMIN_COMMAND_GROUPS = '👥Groups' +ADMIN_COMMAND_RECRUIT = '📬Squad Requests' +ADMIN_COMMAND_FIRE_UP = '⛏Harvest' +ADMIN_COMMAND_SQUAD_LIST = '🗂Squad List' +ADMIN_COMMAND_ADMINPANEL = '🥔Admin Panel🥔' +ADMIN_COMMAND_REPORTS = '📜Reports' + +USER_COMMAND_ME = '🏅Hero' +USER_COMMAND_TOP = '🌟Top' +USER_COMMAND_SQUAD = '⚜Squad' +USER_COMMAND_STATISTICS = '📊Statistics' +USER_COMMAND_BUILD = '🚧Coming Soon' +USER_COMMAND_CONTACTS = '💬Chat' +USER_COMMAND_SQUAD_REQUEST = '⚜Join Squad' +USER_COMMAND_SQUAD_LEAVE = '☄Leave Squad' + +USER_COMMAND_BACK = '🔙Go Back' + +TOP_COMMAND_ATTACK = '⚔' +TOP_COMMAND_DEFENCE = '🛡' +TOP_COMMAND_EXP = '🔥' +TOP_COMMAND_BUILD = '👷🏻' + +TOP_COMMAND_BATTLES = '⛳️' + +STATISTICS_COMMAND_EXP = '🔥XP' diff --git a/core/constants.py b/core/constants.py new file mode 100644 index 0000000..5591fe1 --- /dev/null +++ b/core/constants.py @@ -0,0 +1,3 @@ +MINIMUM_SQUAD_MEMBER_LEVEL = 5 +DAYS_PROFILE_REMIND = 5 +DAYS_OLD_PROFILE_KICK = 14 diff --git a/core/enums.py b/core/enums.py index 634313f..4e3480d 100644 --- a/core/enums.py +++ b/core/enums.py @@ -4,26 +4,26 @@ class Castle(Enum): UNDEFINED = 0 - BLACK = '\U0001f1ec\U0001f1f5' - RED = '\U0001f1ee\U0001f1f2' - BLUE = '\U0001f1ea\U0001f1fa' - YELLOW = '\U0001f1fb\U0001f1e6' - WHITE = '\U0001f1e8\U0001f1fe' - MINT = '\U0001F1F2\U0001F1F4' - DUSK = '\U0001F1F0\U0001F1EE' + BLACK = '🌑' + RED = '🐺' + BLUE = '🥔' + YELLOW = '🦅' + WHITE = '🦌' + MINT = '🐉' + DUSK = '🦈' LES = '\U0001f332Лесной форт' GORY = '\u26f0Горный форт' SEA = '\u2693\uFE0FМорской форт' class Icons(Enum): - BLACK = '\U0001f1ec\U0001f1f5' - RED = '\U0001f1ee\U0001f1f2' - BLUE = '\U0001f1ea\U0001f1fa' - YELLOW = '\U0001f1fb\U0001f1e6' - WHITE = '\U0001f1e8\U0001f1fe' - MINT = '\U0001F1F2\U0001F1F4' - DUSK = '\U0001F1F0\U0001F1EE' + BLACK = '🌑' + RED = '🐺' + BLUE = '🥔' + YELLOW = '🦅' + WHITE = '🦌' + MINT = '🐉' + DUSK = '🦈' LES = '\U0001f332' GORY = '\u26f0' SEA = '\u2693\uFE0F' diff --git a/core/functions/activity.py b/core/functions/activity.py index e8c5806..71835f4 100644 --- a/core/functions/activity.py +++ b/core/functions/activity.py @@ -1,8 +1,10 @@ +from datetime import datetime, timedelta + from telegram import Update, Bot -from core.types import AdminType, admin, Session, Squad + +from core.texts import MSG_ORDER_STATISTIC, MSG_ORDER_STATISTIC_OUT_FORMAT +from core.types import AdminType, admin_allowed, Squad from core.utils import send_async -from datetime import datetime, timedelta -from core.texts import * def activity(squad, days=0, hours=0): @@ -25,37 +27,25 @@ def activity(squad, days=0, hours=0): return msg -@admin(adm_type=AdminType.GROUP) -def day_activity(bot: Bot, update: Update): - session = Session() - try: - squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() - if squad is not None: - msg = activity(squad, days=1) - send_async(bot, chat_id=update.message.chat.id, text=msg) - except: - session.rollback() - - -@admin(adm_type=AdminType.GROUP) -def week_activity(bot: Bot, update: Update): - session = Session() - try: - squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() - if squad is not None: - msg = activity(squad, days=7) - send_async(bot, chat_id=update.message.chat.id, text=msg) - except: - session.rollback() - - -@admin(adm_type=AdminType.GROUP) -def battle_activity(bot: Bot, update: Update): - session = Session() - try: - squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() - if squad is not None: - msg = activity(squad, hours=4) - send_async(bot, chat_id=update.message.chat.id, text=msg) - except: - session.rollback() +@admin_allowed(adm_type=AdminType.GROUP) +def day_activity(bot: Bot, update: Update, session): + squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() + if squad is not None: + msg = activity(squad, days=1) + send_async(bot, chat_id=update.message.chat.id, text=msg) + + +@admin_allowed(adm_type=AdminType.GROUP) +def week_activity(bot: Bot, update: Update, session): + squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() + if squad is not None: + msg = activity(squad, days=7) + send_async(bot, chat_id=update.message.chat.id, text=msg) + + +@admin_allowed(adm_type=AdminType.GROUP) +def battle_activity(bot: Bot, update: Update, session): + squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() + if squad is not None: + msg = activity(squad, hours=4) + send_async(bot, chat_id=update.message.chat.id, text=msg) diff --git a/core/functions/admins.py b/core/functions/admins.py index 94ee713..094087d 100644 --- a/core/functions/admins.py +++ b/core/functions/admins.py @@ -1,204 +1,243 @@ from telegram import Update, Bot -from core.types import User, AdminType, Admin, admin, Session + +# from core.texts import * +from core.texts import ( + MSG_USER_UNKNOWN, MSG_NEW_GROUP_ADMIN, MSG_DEL_GROUP_ADMIN, + MSG_NEW_GROUP_ADMIN_EXISTS, MSG_DEL_GROUP_ADMIN_NOT_EXIST, + MSG_LIST_ADMINS_HEADER, MSG_LIST_ADMINS_FORMAT, + MSG_EMPTY, MSG_LIST_ADMINS_USER_FORMAT, + MSG_NEW_GLOBAL_ADMIN, MSG_NEW_GLOBAL_ADMIN_EXISTS, + MSG_NEW_SUPER_ADMIN, MSG_NEW_SUPER_ADMIN_EXISTS, + MSG_DEL_GLOBAL_ADMIN, MSG_DEL_GLOBAL_ADMIN_NOT_EXIST +) +from core.types import User, AdminType, Admin, admin_allowed, user_allowed from core.utils import send_async -from core.texts import * +from config import SUPER_ADMIN_ID + + +@admin_allowed() +def set_admin(bot: Bot, update: Update, session): + msg = update.message.text.split(' ', 1)[1] + msg = msg.replace('@', '') + if msg != '': + user = session.query(User).filter_by(username=msg).first() + if user is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + + else: + adm = session.query(Admin).filter_by(user_id=user.id, + admin_group=update.message.chat.id).first() + + if adm is None: + new_group_admin = Admin(user_id=user.id, + admin_type=AdminType.GROUP.value, + admin_group=update.message.chat.id) + session.add(new_group_admin) + session.commit() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_GROUP_ADMIN.format(user.username)) + + else: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_GROUP_ADMIN_EXISTS.format(user.username)) -@admin() -def set_admin(bot: Bot, update: Update): - try: - msg = update.message.text.split(' ', 1)[1] + +def del_adm(bot, chat_id, user, session): + adm = session.query(Admin).filter_by(user_id=user.id, + admin_group=chat_id).first() + + if adm is None: + send_async(bot, + chat_id=chat_id, + text=MSG_DEL_GROUP_ADMIN_NOT_EXIST.format(user.username)) + + else: + session.delete(adm) + session.commit() + send_async(bot, + chat_id=chat_id, + text=MSG_DEL_GROUP_ADMIN.format(user.username)) + + +@admin_allowed() +def del_admin(bot: Bot, update: Update, session): + msg = update.message.text.split(' ', 1)[1] + if msg.find('@') != -1: msg = msg.replace('@', '') if msg != '': - session = Session() user = session.query(User).filter_by(username=msg).first() if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + else: - adm = session.query(Admin).filter_by(user_id=user.id, admin_group=update.message.chat.id).first() - if adm is None: - new_group_admin = Admin(user_id=user.id, - admin_type=AdminType.GROUP.value, - admin_group=update.message.chat.id) - session.add(new_group_admin) - session.commit() - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_GROUP_ADMIN.format(user.username)) - else: - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_GROUP_ADMIN_EXISTS.format(user.username)) - except Exception as e: - Session.rollback() - - -def del_adm(bot, chat_id, user): - session = Session() - try: - adm = session.query(Admin).filter_by(user_id=user.id, admin_group=chat_id).first() - if adm is None: - send_async(bot, chat_id=chat_id, - text=MSG_DEL_GROUP_ADMIN_NOT_EXIST.format(user.username)) - else: - session.delete(adm) - session.commit() - send_async(bot, chat_id=chat_id, - text=MSG_DEL_GROUP_ADMIN.format(user.username)) - except: - session.rollback() - - -@admin() -def del_admin(bot: Bot, update: Update): - session = Session() - try: - msg = update.message.text.split(' ', 1)[1] - if msg.find('@') != -1: - msg = msg.replace('@', '') - if msg != '': - user = session.query(User).filter_by(username=msg).first() - if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) - else: - del_adm(bot, update.message.chat.id, user) + del_adm(bot, update.message.chat.id, user, session) + else: + user = session.query(User).filter_by(id=msg).first() + if user is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + else: - user = session.query(User).filter_by(id=msg).first() - if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) - else: - del_adm(bot, update.message.chat.id, user) - except: - session.rollback() - - -@admin() -def list_admins(bot: Bot, update: Update): - session = Session() - try: - admins = session.query(Admin).filter(Admin.admin_group == update.message.chat.id).all() - users = [] - for admin_user in admins: - users.append(session.query(User).filter_by(id=admin_user.user_id).first()) - msg = MSG_LIST_ADMINS_HEADER + del_adm(bot, update.message.chat.id, user, session) + + +@admin_allowed() +def list_admins(bot: Bot, update: Update, session): + admins = session.query(Admin).filter(Admin.admin_group == update.message.chat.id).all() + users = [] + for admin_user in admins: + users.append(session.query(User).filter_by(id=admin_user.user_id).first()) + msg = MSG_LIST_ADMINS_HEADER + for user in users: + msg += MSG_LIST_ADMINS_FORMAT.format(user.id, + user.username, + user.first_name, + user.last_name) + + send_async(bot, chat_id=update.message.chat.id, text=msg) + + +@user_allowed +def admins_for_users(bot: Bot, update: Update, session): + admins = session.query(Admin).filter(Admin.admin_group == update.message.chat.id).all() + users = [] + for admin_user in admins: + users.append(session.query(User).filter_by(id=admin_user.user_id).first()) + msg = MSG_LIST_ADMINS_HEADER + if users is None: + msg += MSG_EMPTY + else: for user in users: - msg += MSG_LIST_ADMINS_FORMAT.format(user.id, user.username, user.first_name, user.last_name) - send_async(bot, chat_id=update.message.chat.id, text=msg) - except: - session.rollback() - - -def admins_for_users(bot: Bot, update: Update): - session = Session() - try: - admins = session.query(Admin).filter(Admin.admin_group == update.message.chat.id).all() - users = [] - for admin_user in admins: - users.append(session.query(User).filter_by(id=admin_user.user_id).first()) - msg = MSG_LIST_ADMINS_HEADER - if users is None: - msg += MSG_EMPTY + msg += MSG_LIST_ADMINS_USER_FORMAT.format(user.username or '', + user.first_name or '', + user.last_name or '') + + send_async(bot, chat_id=update.message.chat.id, text=msg) + + +@admin_allowed(adm_type=AdminType.SUPER) +def set_global_admin(bot: Bot, update: Update, session): + msg = update.message.text.split(' ', 1)[1] + msg = msg.replace('@', '') + if msg != '': + user = session.query(User).filter_by(username=msg).first() + if user is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + else: - for user in users: - msg += MSG_LIST_ADMINS_USER_FORMAT.format(user.username or '', user.first_name or '', user.last_name or '') - send_async(bot, chat_id=update.message.chat.id, text=msg) - except: - session.rollback() - - -@admin(adm_type=AdminType.SUPER) -def set_global_admin(bot: Bot, update: Update): - session = Session() - try: - msg = update.message.text.split(' ', 1)[1] - msg = msg.replace('@', '') - if msg != '': - user = session.query(User).filter_by(username=msg).first() - if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) + adm = session.query(Admin).filter_by(user_id=user.id, + admin_type=AdminType.FULL.value).first() + + if adm is None: + new_group_admin = Admin(user_id=user.id, + admin_type=AdminType.FULL.value, + admin_group=0) + session.add(new_group_admin) + session.commit() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_GLOBAL_ADMIN.format(user.username)) + else: - adm = session.query(Admin).filter_by(user_id=user.id, admin_type=AdminType.FULL.value).first() - if adm is None: - new_group_admin = Admin(user_id=user.id, - admin_type=AdminType.FULL.value, + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_GLOBAL_ADMIN_EXISTS.format(user.username)) + + +@user_allowed(False) +def set_super_admin(bot: Bot, update: Update, session): + msg = update.message.text.split(' ', 1)[1] + msg = msg.replace('@', '') + if msg != '': + user = session.query(User).filter_by(username=msg).first() + if user is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + + else: + if user.id == SUPER_ADMIN_ID and update.message.from_user.id == SUPER_ADMIN_ID: + adm = session.query(Admin).filter_by(user_id=user.id, admin_group=0).first() + if adm is not None: + if adm.admin_type == AdminType.SUPER.value: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_SUPER_ADMIN_EXISTS.format(user.username)) + + else: + adm.admin_type = AdminType.SUPER.value + session.add(adm) + session.commit() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_SUPER_ADMIN.format(user.username)) + + else: + new_super_admin = Admin(user_id=user.id, + admin_type=AdminType.SUPER.value, admin_group=0) - session.add(new_group_admin) + + session.add(new_super_admin) session.commit() - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_GLOBAL_ADMIN.format(user.username)) - else: - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_GLOBAL_ADMIN_EXISTS.format(user.username)) - except: - session.rollback() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_NEW_SUPER_ADMIN.format(user.username)) -def set_super_admin(bot: Bot, update: Update): - session = Session() - try: - msg = update.message.text.split(' ', 1)[1] +@admin_allowed(adm_type=AdminType.SUPER) +def del_global_admin(bot: Bot, update: Update, session): + msg = update.message.text.split(' ', 1)[1] + if msg.find('@') != -1: msg = msg.replace('@', '') if msg != '': user = session.query(User).filter_by(username=msg).first() if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) - else: - if user.id == 79612802 and update.message.from_user.id == 79612802: - adm = session.query(Admin).filter_by(user_id=user.id, admin_group=0).first() - if adm is not None: - if adm.admin_type == AdminType.SUPER.value: - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_SUPER_ADMIN_EXISTS.format(user.username)) - else: - adm.admin_type = AdminType.SUPER.value - session.add(adm) - session.commit() - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_SUPER_ADMIN.format(user.username)) - else: - new_super_admin = Admin(user_id=user.id, - admin_type=AdminType.SUPER.value, - admin_group=0) - session.add(new_super_admin) - session.commit() - send_async(bot, chat_id=update.message.chat.id, - text=MSG_NEW_SUPER_ADMIN.format(user.username)) - except: - session.rollback() - - -@admin(adm_type=AdminType.SUPER) -def del_global_admin(bot: Bot, update: Update): - session = Session() - try: - msg = update.message.text.split(' ', 1)[1] - if msg.find('@') != -1: - msg = msg.replace('@', '') - if msg != '': - user = session.query(User).filter_by(username=msg).first() - if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) - else: - adm = session.query(Admin).filter_by(user_id=user.id, admin_type=AdminType.FULL.value).first() - if adm is None: - send_async(bot, chat_id=update.message.chat.id, - text=MSG_DEL_GLOBAL_ADMIN_NOT_EXIST.format(user.username)) - else: - session.delete(adm) - session.commit() - send_async(bot, chat_id=update.message.chat.id, - text=MSG_DEL_GLOBAL_ADMIN.format(user.username)) - else: - user = session.query(User).filter_by(id=msg).first() - if user is None: - send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + else: - adm = session.query(Admin).filter_by(user_id=user.id, admin_type=AdminType.FULL.value).first() + adm = session.query(Admin).filter_by(user_id=user.id, + admin_type=AdminType.FULL.value).first() + if adm is None: - send_async(bot, chat_id=update.message.chat.id, + send_async(bot, + chat_id=update.message.chat.id, text=MSG_DEL_GLOBAL_ADMIN_NOT_EXIST.format(user.username)) + else: session.delete(adm) session.commit() - send_async(bot, chat_id=update.message.chat.id, + send_async(bot, + chat_id=update.message.chat.id, text=MSG_DEL_GLOBAL_ADMIN.format(user.username)) - except: - session.rollback() + else: + user = session.query(User).filter_by(id=msg).first() + if user is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_USER_UNKNOWN) + + else: + adm = session.query(Admin).filter_by(user_id=user.id, + admin_type=AdminType.FULL.value).first() + if adm is None: + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_DEL_GLOBAL_ADMIN_NOT_EXIST.format(user.username)) + else: + session.delete(adm) + session.commit() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_DEL_GLOBAL_ADMIN.format(user.username)) diff --git a/core/functions/api.py b/core/functions/api.py index 4688740..bd4d137 100644 --- a/core/functions/api.py +++ b/core/functions/api.py @@ -1,8 +1,13 @@ -import json from datetime import datetime, timedelta +import json + import flask -from core.types import Order, Session, Squad, SquadMember, OrderCleared from werkzeug.routing import IntegerConverter as BaseIntegerConverter +from core.texts import MSG_MAIN_READY_TO_BATTLE +from core.types import Order, Session, Squad, SquadMember, OrderCleared + +from sqlalchemy.exc import SQLAlchemyError + app = flask.Flask(__name__) @@ -21,13 +26,18 @@ def new_ready_to_battle(chat_id): order = Order() order.chat_id = chat_id order.confirmed_msg = 0 - order.text = 'К битве готовсь!' + order.text = MSG_MAIN_READY_TO_BATTLE order.date = datetime.now() session.add(order) session.commit() - order = session.query(Order).filter_by(chat_id=chat_id, date=order.date, text='К битве готовсь!').first() - return flask.Response(status=200, mimetype="application/json", response=json.dumps({'order_id': order.id})) - except: + order = session.query(Order).filter_by(chat_id=chat_id, + date=order.date, + text=MSG_MAIN_READY_TO_BATTLE).first() + + return flask.Response(status=200, + mimetype="application/json", + response=json.dumps({'order_id': order.id})) + except SQLAlchemyError: Session.rollback() return flask.Response(status=400) @@ -41,27 +51,34 @@ def new_order_click(order_id, user_id): squad = session.query(Squad).filter_by(chat_id=order.chat_id).first() if squad is not None: squad_member = session.query(SquadMember).filter_by(squad_id=squad.chat_id, - user_id=user_id) + user_id=user_id, + approved=True) + if squad_member is not None: order_ok = session.query(OrderCleared).filter_by(order_id=order_id, user_id=user_id).first() + if order_ok is None and datetime.now() - order.date < timedelta(minutes=10): order_ok = OrderCleared() order_ok.order_id = order_id order_ok.user_id = user_id session.add(order_ok) session.commit() + else: order_ok = session.query(OrderCleared).filter_by(order_id=order_id, user_id=user_id).first() + if order_ok is None and datetime.now() - order.date < timedelta(minutes=10): order_ok = OrderCleared() order_ok.order_id = order_id order_ok.user_id = user_id session.add(order_ok) session.commit() + return flask.Response(status=200) - except: + + except SQLAlchemyError: Session.rollback() return flask.Response(status=400) @@ -74,10 +91,15 @@ def order_status(order_id): if order is not None: users = [] for order_ok in order.cleared: - users.append({'username': order_ok.user.username, 'id': order_ok.user.id, + users.append({'username': order_ok.user.username, + 'id': order_ok.user.id, 'attack': order_ok.user.character.attack if order_ok.user.character else 0, 'defence': order_ok.user.character.defence if order_ok.user.character else 0}) - return flask.Response(status=200, mimetype="application/json", response=json.dumps({'users': users})) - except: + + return flask.Response(status=200, + mimetype="application/json", + response=json.dumps({'users': users})) + + except SQLAlchemyError: Session.rollback() return flask.Response(status=400) diff --git a/core/functions/ban.py b/core/functions/ban.py new file mode 100644 index 0000000..f1eebbe --- /dev/null +++ b/core/functions/ban.py @@ -0,0 +1,59 @@ +from datetime import datetime + +from telegram import Bot, Update + +from core.texts import MSG_USER_UNKNOWN, MSG_USER_BANNED, MSG_YOU_BANNED, MSG_BAN_COMPLETE, MSG_ALREADY_BANNED, \ + MSG_USER_NOT_BANNED, MSG_USER_UNBANNED, MSG_YOU_UNBANNED, MSG_NO_REASON +from core.types import admin_allowed, Ban, User, Squad, SquadMember, Admin +from core.utils import send_async + + +@admin_allowed() +def ban(bot: Bot, update: Update, session): + username, reason = update.message.text.split(' ', 2)[1:] + username = username.replace('@', '') + user = session.query(User).filter_by(username=username).first() + if user: + banned = session.query(Ban).filter_by(user_id=user.id).first() + if banned: + send_async(bot, chat_id=update.message.chat.id, + text=MSG_ALREADY_BANNED.format(banned.to_date, banned.reason)) + else: + banned = Ban() + banned.user_id = user.id + banned.from_date = datetime.now() + banned.to_date = datetime.max + banned.reason = reason or MSG_NO_REASON + member = session.query(SquadMember).filter_by(user_id=user.id).first() + if member: + session.delete(member) + admins = session.query(Admin).filter_by(user_id=user.id).all() + for admin in admins: + session.delete(admin) + session.add(banned) + session.commit() + squads = session.query(Squad).all() + for squad in squads: + send_async(bot, chat_id=squad.chat_id, text=MSG_USER_BANNED.format('@' + username)) + send_async(bot, chat_id=user.id, text=MSG_YOU_BANNED.format(banned.reason)) + send_async(bot, chat_id=update.message.chat.id, text=MSG_BAN_COMPLETE) + else: + send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) + + +@admin_allowed() +def unban(bot: Bot, update: Update, session): + username = update.message.text.split(' ', 1)[1] + username = username.replace('@', '') + user = session.query(User).filter_by(username=username).first() + if user: + banned = session.query(Ban).filter_by(user_id=user.id).first() + if banned: + session.delete(banned) + session.commit() + send_async(bot, chat_id=user.id, text=MSG_YOU_UNBANNED) + send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNBANNED.format('@' + user.username)) + else: + send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_NOT_BANNED) + else: + send_async(bot, chat_id=update.message.chat.id, text=MSG_USER_UNKNOWN) diff --git a/core/functions/bosses.py b/core/functions/bosses.py index 098f7dc..acec968 100644 --- a/core/functions/bosses.py +++ b/core/functions/bosses.py @@ -1,11 +1,12 @@ from telegram import Update, Bot + from core.functions.triggers import trigger_decorator from core.utils import send_async, update_group @trigger_decorator -def boss_leader(bot: Bot, update: Update): - group = update_group(update.message.chat) +def boss_leader(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if len(group.squad) == 1: members = [] for member in group.squad[0].members: @@ -17,8 +18,8 @@ def boss_leader(bot: Bot, update: Update): @trigger_decorator -def boss_zhalo(bot: Bot, update: Update): - group = update_group(update.message.chat) +def boss_zhalo(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if len(group.squad) == 1: members = [] for member in group.squad[0].members: @@ -30,8 +31,8 @@ def boss_zhalo(bot: Bot, update: Update): @trigger_decorator -def boss_monoeye(bot: Bot, update: Update): - group = update_group(update.message.chat) +def boss_monoeye(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if len(group.squad) == 1: members = [] for member in group.squad[0].members: @@ -43,8 +44,8 @@ def boss_monoeye(bot: Bot, update: Update): @trigger_decorator -def boss_hydra(bot: Bot, update: Update): - group = update_group(update.message.chat) +def boss_hydra(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if len(group.squad) == 1: members = [] for member in group.squad[0].members: diff --git a/core/functions/common.py b/core/functions/common.py index 5161342..40a61b4 100644 --- a/core/functions/common.py +++ b/core/functions/common.py @@ -1,14 +1,20 @@ -from telegram import Update, Bot, ParseMode, TelegramError +import uuid +from datetime import datetime +from enum import Enum import logging + +from telegram import Update, Bot, ParseMode + from core.functions.triggers import trigger_decorator -from core.types import AdminType, Admin, Stock, admin, Session, Group -from core.utils import send_async, add_user -from core.functions.reply_markup import generate_admin_markup -from enum import Enum -from datetime import datetime +from core.functions.reply_markup import generate_admin_markup, generate_user_markup from core.texts import * +from core.types import AdminType, Admin, Stock, admin_allowed, user_allowed, SquadMember, Auth +from core.utils import send_async, add_user -logger = logging.getLogger(__name__) +from config import WEB_LINK + + +LOGGER = logging.getLogger(__name__) class StockType(Enum): @@ -18,52 +24,48 @@ class StockType(Enum): def error(bot: Bot, update, error, **kwargs): """ Error handling """ - logger.error("An error (%s) occurred: %s" + LOGGER.error("An error (%s) occurred: %s" % (type(error), error.message)) -def start(bot: Bot, update: Update): - add_user(update.message.from_user) +@user_allowed +def start(bot: Bot, update: Update, session): + add_user(update.message.from_user, session) if update.message.chat.type == 'private': - send_async(bot, chat_id=update.message.chat.id, text=MSG_START_WELCOME) + send_async(bot, chat_id=update.message.chat.id, text=MSG_START_WELCOME, parse_mode=ParseMode.HTML) -@admin(adm_type=AdminType.GROUP) -def admin_panel(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def admin_panel(bot: Bot, update: Update, session): if update.message.chat.type == 'private': - session = Session() admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() full_adm = False - grp_adm = False for adm in admin: if adm.admin_type <= AdminType.FULL.value: full_adm = True - else: - grp_adm = True send_async(bot, chat_id=update.message.chat.id, text=MSG_ADMIN_WELCOME, - reply_markup=generate_admin_markup(full_adm, grp_adm)) - - -def check_bot_in_chats(bot: Bot, update: Update): - session = Session() - groups = session.query(Group).filter_by(bot_in_group=True).all() - for group in groups: - try: - bot.getChatMember(group.id, bot.id) - except TelegramError as e: - group.bot_in_group = False - session.add(group) - session.commit() + reply_markup=generate_admin_markup(full_adm)) + + +@user_allowed +def user_panel(bot: Bot, update: Update, session): + if update.message.chat.type == 'private': + admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() + is_admin = False + for _ in admin: + is_admin = True + break + send_async(bot, chat_id=update.message.chat.id, text=MSG_START_WELCOME, parse_mode=ParseMode.HTML, + reply_markup=generate_user_markup(is_admin)) -@admin() -def kick(bot: Bot, update: Update): +@admin_allowed() +def kick(bot: Bot, update: Update, session): bot.leave_chat(update.message.chat.id) @trigger_decorator -def help_msg(bot: Bot, update): - session = Session() +def help_msg(bot: Bot, update, session): admin_user = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() global_adm = False for adm in admin_user: @@ -78,8 +80,8 @@ def help_msg(bot: Bot, update): send_async(bot, chat_id=update.message.chat.id, text=MSG_HELP_USER) -@admin(adm_type=AdminType.GROUP) -def ping(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def ping(bot: Bot, update: Update, session): send_async(bot, chat_id=update.message.chat.id, text=MSG_PING.format(update.message.from_user.username)) @@ -103,8 +105,8 @@ def get_diff(dict_one, dict_two): return resource_diff_add, resource_diff_del -def stock_compare(bot: Bot, update: Update, chat_data: dict): - session = Session() +@user_allowed(False) +def stock_compare(bot: Bot, update: Update, session, chat_data: dict): old_stock = session.query(Stock).filter_by(user_id=update.message.from_user.id, stock_type=StockType.Stock.value).order_by(Stock.date.desc()).first() new_stock = Stock() @@ -142,23 +144,23 @@ def stock_compare(bot: Bot, update: Update, chat_data: dict): msg += MSG_EMPTY send_async(bot, chat_id=update.message.chat.id, text=msg, parse_mode=ParseMode.HTML) else: - send_async(bot, chat_id=update.message.chat.id, text=MSG_STOCK_COMPARE_WAIT) + send_async(bot, chat_id=update.message.chat.id, text=MSG_STOCK_COMPARE_WAIT, parse_mode=ParseMode.HTML) -@admin(adm_type=AdminType.GROUP) -def delete_msg(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def delete_msg(bot: Bot, update: Update, session): bot.delete_message(update.message.reply_to_message.chat_id, update.message.reply_to_message.message_id) bot.delete_message(update.message.reply_to_message.chat_id, update.message.message_id) -@admin() -def delete_user(bot: Bot, update: Update): +@admin_allowed() +def delete_user(bot: Bot, update: Update, session): bot.kickChatMember(update.message.reply_to_message.chat_id, update.message.reply_to_message.from_user.id) bot.unbanChatMember(update.message.reply_to_message.chat_id, update.message.reply_to_message.from_user.id) -def trade_compare(bot: Bot, update: Update, chat_data: dict): - session = Session() +@user_allowed(False) +def trade_compare(bot: Bot, update: Update, session, chat_data: dict): old_stock = session.query(Stock).filter_by(user_id=update.message.from_user.id, stock_type=StockType.TradeBot.value).order_by(Stock.date.desc()).first() new_stock = Stock() @@ -198,4 +200,19 @@ def trade_compare(bot: Bot, update: Update, chat_data: dict): msg += MSG_EMPTY send_async(bot, chat_id=update.message.chat.id, text=msg, parse_mode=ParseMode.HTML) else: - send_async(bot, chat_id=update.message.chat.id, text=MSG_STOCK_COMPARE_WAIT) + send_async(bot, chat_id=update.message.chat.id, text=MSG_STOCK_COMPARE_WAIT, parse_mode=ParseMode.HTML) + + +@user_allowed +def web_auth(bot: Bot, update: Update, session): + user = add_user(update.message.from_user, session) + auth = session.query(Auth).filter_by(user_id=user.id).first() + if auth is None: + auth = Auth() + auth.id = uuid.uuid4().hex + auth.user_id = user.id + session.add(auth) + session.commit() + link = WEB_LINK.format(auth.id) + send_async(bot, chat_id=update.message.chat.id, text=MSG_PERSONAL_SITE_LINK.format(link), + parse_mode=ParseMode.HTML, disable_web_page_preview=True) diff --git a/core/functions/inline_keyboard_handling.py b/core/functions/inline_keyboard_handling.py index 6f6921c..bb3f0f7 100644 --- a/core/functions/inline_keyboard_handling.py +++ b/core/functions/inline_keyboard_handling.py @@ -1,54 +1,39 @@ +from datetime import datetime, timedelta import json +from json import loads +import logging -from telegram import Bot, Update, InlineKeyboardButton, InlineKeyboardMarkup, TelegramError +from telegram import Bot, Update, InlineKeyboardButton, InlineKeyboardMarkup, TelegramError, ParseMode +from telegram.ext import JobQueue, Job from telegram.ext.dispatcher import run_async -from core.template import fill_char_template -from core.types import User, Group, Admin, Session, admin, Order, OrderGroup, OrderGroupItem, OrderCleared, Squad, \ - Character, Session, SquadMember, MessageType -from core.utils import send_async, update_group, add_user -from core.functions.admins import del_adm -from enum import Enum from core.enums import Castle, Icons -import logging -from core.types import AdminType -from datetime import datetime, timedelta +from core.functions.admins import del_adm +from core.functions.inline_markup import generate_group_info, generate_order_chats_markup, generate_order_groups_markup, \ + generate_ok_markup, generate_groups_manage, generate_group_manage, generate_profile_buttons, generate_squad_list, \ + generate_leave_squad, generate_other_reports, generate_squad_members, QueryType +from core.functions.reply_markup import generate_user_markup +from core.functions.squad import leave_squad +from core.functions.top import global_build_top, week_build_top, week_battle_top, global_battle_top, \ + week_squad_build_top, global_squad_build_top +from core.template import fill_char_template +from core.types import ( + User, Admin, admin_allowed, Order, OrderGroup, + OrderGroupItem, OrderCleared, Squad, user_allowed, + SquadMember, MessageType, AdminType, Report) from core.texts import * -from multiprocessing.pool import ThreadPool -from json import loads +from core.utils import send_async, update_group, add_user -logger = logging.getLogger('MyApp') +from sqlalchemy import and_ +LOGGER = logging.getLogger('MyApp') -class QueryType(Enum): - GroupList = 0 - GroupInfo = 1 - DelAdm = 2 - Order = 3 - OrderOk = 4 - Orders = 5 - OrderGroup = 6 - OrderGroupManage = 7 - OrderGroupTriggerChat = 8 - OrderGroupAdd = 9 - OrderGroupDelete = 10 - OrderGroupList = 11 - ShowStock = 12 - ShowEquip = 13 - ShowHero = 14 - MemberList = 15 - LeaveSquad = 16 - RequestSquad = 17 - RequestSquadAccept = 18 - RequestSquadDecline = 19 - InviteSquadAccept = 20 - InviteSquadDecline = 21 - TriggerOrderPin = 22 +order_updated = {} -@admin() -def send_status(bot: Bot, update: Update): - session = Session() + +@admin_allowed() +def send_status(bot: Bot, update: Update, session): msg = MSG_GROUP_STATUS_CHOOSE_CHAT squads = session.query(Squad).all() inline_keys = [] @@ -60,290 +45,65 @@ def send_status(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=msg, reply_markup=inline_markup) -def generate_group_info(group_id): - session = Session() - group = session.query(Group).filter(Group.id == group_id).first() - admins = session.query(Admin).filter(Admin.admin_group == group_id).all() - adm_msg = '' - adm_del_keys = [] - for adm in admins: - user = session.query(User).filter_by(id=adm.user_id).first() - adm_msg += MSG_GROUP_STATUS_ADMIN_FORMAT.format(user.id, user.username or '', user.first_name or '', user.last_name or '') - adm_del_keys.append([InlineKeyboardButton(MSG_GROUP_STATUS_DEL_ADMIN.format(user.first_name or '', user.last_name or ''), - callback_data=json.dumps( - {'t': QueryType.DelAdm.value, 'uid': user.id, - 'gid': group_id}))]) - msg = MSG_GROUP_STATUS.format(group.title, - adm_msg, - MSG_ON if group.welcome_enabled else MSG_OFF, - MSG_ON if group.allow_trigger_all else MSG_OFF, - MSG_ON if len(group.squad) and group.squad[0].thorns_enabled else MSG_OFF) - adm_del_keys.append([InlineKeyboardButton(MSG_BACK, callback_data=json.dumps( - {'t': QueryType.GroupList.value}))]) - inline_markup = InlineKeyboardMarkup(adm_del_keys) - return msg, inline_markup - - -def generate_flag_orders(): - flag_btns = [[InlineKeyboardButton(Castle.BLACK.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.BLACK.value})), - InlineKeyboardButton(Castle.WHITE.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.WHITE.value})), - InlineKeyboardButton(Castle.BLUE.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.BLUE.value}))], - [InlineKeyboardButton(Castle.YELLOW.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.YELLOW.value})), - InlineKeyboardButton(Castle.RED.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.RED.value})), - InlineKeyboardButton(Castle.DUSK.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.DUSK.value}))], - [InlineKeyboardButton(Castle.MINT.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Castle.MINT.value})), - InlineKeyboardButton(Castle.GORY.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Icons.GORY.value})), - InlineKeyboardButton(Castle.LES.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Icons.LES.value}))], - [InlineKeyboardButton(Castle.SEA.value, callback_data=json.dumps( - {'t': QueryType.OrderGroup.value, 'txt': Icons.SEA.value}))]] - inline_markup = InlineKeyboardMarkup(flag_btns) - return inline_markup - - -def generate_order_chats_markup(bot: Bot, pin=True): - session = Session() - squads = session.query(Squad).all() - inline_keys = [] - for squad in squads: - inline_keys.append([InlineKeyboardButton(squad.squad_name, callback_data=json.dumps( - {'t': QueryType.Order.value, 'g': False, 'id': squad.chat_id}))]) - inline_keys.append([InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, callback_data=json.dumps( - {'t': QueryType.TriggerOrderPin.value, 'g': False}))]) - inline_markup = InlineKeyboardMarkup(inline_keys) - return inline_markup - - -def generate_order_groups_markup(bot: Bot, admin_user: list=None, pin: bool=True): - session = Session() - if admin_user: - group_adm = True - for adm in admin_user: - if adm.admin_type < AdminType.GROUP.value: - group_adm = False - break - if group_adm: - inline_keys = [] - for adm in admin_user: - group = session.query(Group).filter_by(id=adm.admin_group, bot_in_group=True).first() - if group: - inline_keys.append([InlineKeyboardButton(group.title, callback_data=json.dumps( - {'t': QueryType.Order.value, 'g': False, 'id': group.id}))]) - inline_keys.append( - [InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, callback_data=json.dumps( - {'t': QueryType.TriggerOrderPin.value, 'g': True}))]) - inline_markup = InlineKeyboardMarkup(inline_keys) - return inline_markup - groups = session.query(OrderGroup).all() - inline_keys = [] - for group in groups: - inline_keys.append([InlineKeyboardButton(group.name, callback_data=json.dumps( - {'t': QueryType.Order.value, 'g': True, 'id': group.id}))]) - inline_keys.append([InlineKeyboardButton(MSG_ORDER_TO_SQUADS, callback_data=json.dumps( - {'t': QueryType.Orders.value}))]) - inline_keys.append([InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, callback_data=json.dumps( - {'t': QueryType.TriggerOrderPin.value, 'g': True}))]) - inline_markup = InlineKeyboardMarkup(inline_keys) - return inline_markup - - -def generate_ok_markup(order_id, count): - inline_markup = InlineKeyboardMarkup([[InlineKeyboardButton(MSG_ORDER_ACCEPT.format(count), - callback_data=json.dumps( - {'t': QueryType.OrderOk.value, 'id': order_id}))]]) - return inline_markup - - -def generate_groups_manage(): - session = Session() - groups = session.query(OrderGroup).all() - inline_keys = [] - for group in groups: - inline_keys.append([InlineKeyboardButton(group.name, callback_data=json.dumps( - {'t': QueryType.OrderGroupManage.value, 'id': group.id}))]) - inline_keys.append([InlineKeyboardButton(MSG_ORDER_GROUP_ADD, callback_data=json.dumps( - {'t': QueryType.OrderGroupAdd.value}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_group_manage(group_id): - session = Session() - squads = session.query(Squad).all() - inline_keys = [] - for squad in squads: - in_group = False - for item in squad.chat.group_items: - if item.group_id == group_id: - in_group = True - break - inline_keys.append([InlineKeyboardButton((MSG_SYMBOL_ON if in_group else MSG_SYMBOL_OFF) + - squad.squad_name, callback_data=json.dumps( - {'t': QueryType.OrderGroupTriggerChat.value, 'id': group_id, 'c': squad.chat_id}))]) - inline_keys.append([InlineKeyboardButton(MSG_ORDER_GROUP_DEL, callback_data=json.dumps( - {'t': QueryType.OrderGroupDelete.value, 'id': group_id}))]) - inline_keys.append([InlineKeyboardButton(MSG_BACK, callback_data=json.dumps( - {'t': QueryType.OrderGroupList.value}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_profile_buttons(user): - inline_keys = [] - inline_keys.append([InlineKeyboardButton('🏅Герой', callback_data=json.dumps( - {'t': QueryType.ShowHero.value, 'id': user.id}))]) - if user.stock: - inline_keys.append([InlineKeyboardButton('📦Склад', callback_data=json.dumps( - {'t': QueryType.ShowStock.value, 'id': user.id}))]) - if user.equip: - inline_keys.append([InlineKeyboardButton('🎽Экипировка', callback_data=json.dumps( - {'t': QueryType.ShowEquip.value, 'id': user.id}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_squad_list_key(squad): - session = Session() - attack = 0 - defence = 0 - members = session.query(SquadMember).filter_by(squad_id=squad.chat_id).all() - for member in members: - character = session.query(Character).filter_by(user_id=member.user_id).order_by(Character.date.desc()).limit(1).first() - attack += character.attack - defence += character.defence - return [InlineKeyboardButton( - '{} : {}⚔ {}🛡 {}👥'.format( - squad.squad_name, - attack, - defence, - len(members) - ), - callback_data=json.dumps({'t': QueryType.MemberList.value, 'id': squad.chat_id}))] - - -def generate_squad_list(squads): - inline_keys = [] - pool = ThreadPool(processes=10) - threads = [] - for squad in squads: - threads.append(pool.apply_async(generate_squad_list_key, (squad,))) - for thread in threads: - inline_keys.append(thread.get()) - return InlineKeyboardMarkup(inline_keys) - - -def generate_leave_squad(user_id): - inline_keys = [] - inline_keys.append([InlineKeyboardButton('Выйти', - callback_data=json.dumps({'t': QueryType.LeaveSquad.value, 'id': user_id}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_squad_request(): - session = Session() - inline_keys = [] - squads = session.query(Squad).filter_by(hiring=True).all() - for squad in squads: - inline_keys.append([InlineKeyboardButton(squad.squad_name, - callback_data=json.dumps( - {'t': QueryType.RequestSquad.value, 'id': squad.chat_id}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_squad_members(members): - inline_keys = [] - for member in members: - user = member.user - character = user.character - inline_keys.append([InlineKeyboardButton('{}: {}⚔ {}🛡'.format(user, character.attack, character.defence), callback_data=json.dumps( - {'t': QueryType.ShowHero.value, 'id': member.user_id}))]) - return InlineKeyboardMarkup(inline_keys) - - -def generate_squad_request_answer(user_id): - inline_keys = [] - inline_keys.append(InlineKeyboardButton('✅Принять', - callback_data=json.dumps( - {'t': QueryType.RequestSquadAccept.value, 'id': user_id}))) - inline_keys.append(InlineKeyboardButton('❌Отклонить', - callback_data=json.dumps( - {'t': QueryType.RequestSquadDecline.value, 'id': user_id}))) - return InlineKeyboardMarkup([inline_keys]) - - -def generate_squad_invite_answer(user_id): - inline_keys = [] - inline_keys.append(InlineKeyboardButton('✅Зелёное Да', - callback_data=json.dumps( - {'t': QueryType.InviteSquadAccept.value, 'id': user_id}))) - inline_keys.append(InlineKeyboardButton('❌Красное Да', - callback_data=json.dumps( - {'t': QueryType.InviteSquadDecline.value, 'id': user_id}))) - return InlineKeyboardMarkup([inline_keys]) - - -def generate_fire_up(members): - inline_keys = [] - for member in members: - inline_keys.append([InlineKeyboardButton('🔥{}: {}⚔ {}🛡'.format(member.user, member.user.character.attack, - member.user.character.defence), - callback_data=json.dumps( - {'t': QueryType.LeaveSquad.value, 'id': member.user_id}))]) - return InlineKeyboardMarkup(inline_keys) - - @run_async def send_order(bot, order, order_type, chat_id, markup): - msg_sent = None - if order_type == MessageType.AUDIO.value: - msg_sent = bot.send_audio(chat_id, order, reply_markup=markup) - elif order_type == MessageType.DOCUMENT.value: - msg_sent = bot.send_document(chat_id, order, reply_markup=markup) - elif order_type == MessageType.VOICE.value: - msg_sent = bot.send_voice(chat_id, order, reply_markup=markup) - elif order_type == MessageType.STICKER.value: - msg_sent = bot.send_sticker(chat_id, order, reply_markup=markup) - elif order_type == MessageType.CONTACT.value: - msg = order.replace('\'', '"') - contact = loads(msg) - if 'phone_number' not in contact.keys(): - contact['phone_number'] = None - if 'first_name' not in contact.keys(): - contact['first_name'] = None - if 'last_name' not in contact.keys(): - contact['last_name'] = None - msg_sent = bot.send_contact(chat_id, - contact['phone_number'], - contact['first_name'], - contact['last_name'], - reply_markup=markup) - elif order_type == MessageType.VIDEO.value: - msg_sent = bot.send_video(chat_id, order, reply_markup=markup) - elif order_type == MessageType.VIDEO_NOTE.value: - msg_sent = bot.send_video_note(chat_id, order, reply_markup=markup) - elif order_type == MessageType.LOCATION.value: - msg = order.replace('\'', '"') - location = loads(msg) - msg_sent = bot.send_location(chat_id, location['latitude'], location['longitude'], reply_markup=markup) - elif order_type == MessageType.PHOTO.value: - msg_sent = bot.send_photo(chat_id, order, reply_markup=markup) - else: - msg_sent = send_async(bot, chat_id=chat_id, text=order, disable_web_page_preview=True, reply_markup=markup) - return msg_sent + try: + msg_sent = None + if order_type == MessageType.AUDIO.value: + msg_sent = bot.send_audio(chat_id, order, reply_markup=markup) + elif order_type == MessageType.DOCUMENT.value: + msg_sent = bot.send_document(chat_id, order, reply_markup=markup) + elif order_type == MessageType.VOICE.value: + msg_sent = bot.send_voice(chat_id, order, reply_markup=markup) + elif order_type == MessageType.STICKER.value: + msg_sent = bot.send_sticker(chat_id, order, reply_markup=markup) + elif order_type == MessageType.CONTACT.value: + msg = order.replace('\'', '"') + contact = loads(msg) + if 'phone_number' not in contact.keys(): + contact['phone_number'] = None + if 'first_name' not in contact.keys(): + contact['first_name'] = None + if 'last_name' not in contact.keys(): + contact['last_name'] = None + msg_sent = bot.send_contact(chat_id, + contact['phone_number'], + contact['first_name'], + contact['last_name'], + reply_markup=markup) + elif order_type == MessageType.VIDEO.value: + msg_sent = bot.send_video(chat_id, order, reply_markup=markup) + elif order_type == MessageType.VIDEO_NOTE.value: + msg_sent = bot.send_video_note(chat_id, order, reply_markup=markup) + elif order_type == MessageType.LOCATION.value: + msg = order.replace('\'', '"') + location = loads(msg) + msg_sent = bot.send_location(chat_id, location['latitude'], location['longitude'], reply_markup=markup) + elif order_type == MessageType.PHOTO.value: + msg_sent = bot.send_photo(chat_id, order, reply_markup=markup) + else: + msg_sent = send_async(bot, chat_id=chat_id, text=order, disable_web_page_preview=True, reply_markup=markup) + return msg_sent + except TelegramError as err: + bot.logger.error(err.message) + return None + + +def update_confirmed(bot: Bot, job: Job): + order = job.context + confirmed = order.cleared + msg = MSG_ORDER_CLEARED_BY_HEADER + for confirm in confirmed: + msg += str(confirm.user) + '\n' + bot.editMessageText(msg, order.chat_id, order.confirmed_msg) @run_async -def callback_query(bot: Bot, update: Update, chat_data: dict): - session = Session() - update_group(update.callback_query.message.chat) - user = add_user(update.callback_query.from_user) +@user_allowed +def callback_query(bot: Bot, update: Update, session, chat_data: dict, job_queue: JobQueue): + update_group(update.callback_query.message.chat, session) + user = add_user(update.effective_user, session) data = json.loads(update.callback_query.data) - logger.warning(data) if data['t'] == QueryType.GroupList.value: msg = MSG_GROUP_STATUS_CHOOSE_CHAT squads = session.query(Squad).all() @@ -356,51 +116,71 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): bot.editMessageText(msg, update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=inline_markup) elif data['t'] == QueryType.GroupInfo.value: - msg, inline_markup = generate_group_info(data['id']) + msg, inline_markup = generate_group_info(data['id'], session) bot.editMessageText(msg, update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=inline_markup) elif data['t'] == QueryType.DelAdm.value: - del_adm(bot, data['gid'], user) - msg, inline_markup = generate_group_info(data['gid']) + admin_user = session.query(User).filter_by(id=data['uid']).first() + if admin_user: + del_adm(bot, data['gid'], admin_user, session) + msg, inline_markup = generate_group_info(data['gid'], session) bot.editMessageText(msg, update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=inline_markup) elif data['t'] == QueryType.Order.value: + order_text = chat_data['order'] + order_type = chat_data['order_type'] + order_pin = chat_data['pin'] if 'pin' in chat_data else True + order_btn = chat_data['btn'] if 'btn' in chat_data else True if not data['g']: - order = Order() - order.text = chat_data['order'] - order.chat_id = data['id'] - order.date = datetime.now() - order.confirmed_msg = send_async(bot, chat_id=order.chat_id, text=MSG_ORDER_CLEARED_BY_HEADER + MSG_EMPTY).result().message_id - session.add(order) - session.commit() - markup = generate_ok_markup(order.id, 0) - msg = send_order(bot, order.text, chat_data['order_type'], order.chat_id, markup).result().result() - if 'pin' in chat_data and chat_data['pin'] or 'pin' not in chat_data: + if order_btn: + order = Order() + order.text = order_text + order.chat_id = data['id'] + order.date = datetime.now() + msg = send_async(bot, chat_id=order.chat_id, text=MSG_ORDER_CLEARED_BY_HEADER + MSG_EMPTY).result() + if msg: + order.confirmed_msg = msg.message_id + else: + order.confirmed_msg = 0 + session.add(order) + session.commit() + markup = generate_ok_markup(order.id, 0) + msg = send_order(bot, order.text, order_type, order.chat_id, markup).result().result() + else: + msg = send_order(bot, order_text, order_type, data['id'], None).result().result() + if order_pin and msg: try: - bot.request.post(bot.base_url + '/pinChatMessage', {'chat_id': order.chat_id, + bot.request.post(bot.base_url + '/pinChatMessage', {'chat_id': data['id'], 'message_id': msg.message_id, 'disable_notification': False}) - except: - pass + except TelegramError as err: + bot.logger.error(err.message) else: group = session.query(OrderGroup).filter_by(id=data['id']).first() for item in group.items: - order = Order() - order.text = chat_data['order'] - order.chat_id = item.chat_id - order.date = datetime.now() - order.confirmed_msg = send_async(bot, chat_id=order.chat_id, text=MSG_ORDER_CLEARED_BY_HEADER + MSG_EMPTY).result().message_id - session.add(order) - session.commit() - markup = generate_ok_markup(order.id, 0) - msg = send_order(bot, order.text, chat_data['order_type'], order.chat_id, markup).result().result() - if 'pin' in chat_data and chat_data['pin'] or 'pin' not in chat_data: + if order_btn: + order = Order() + order.text = order_text + order.chat_id = item.chat_id + order.date = datetime.now() + msg = send_async(bot, chat_id=order.chat_id, text=MSG_ORDER_CLEARED_BY_HEADER + MSG_EMPTY).result() + if msg: + order.confirmed_msg = msg.message_id + else: + order.confirmed_msg = 0 + session.add(order) + session.commit() + markup = generate_ok_markup(order.id, 0) + msg = send_order(bot, order.text, order_type, order.chat_id, markup).result().result() + else: + msg = send_order(bot, order_text, order_type, item.chat_id, None).result().result() + if order_pin and msg: try: bot.request.post(bot.base_url + '/pinChatMessage', - {'chat_id': order.chat_id, 'message_id': msg.message_id, + {'chat_id': item.chat_id, 'message_id': msg.message_id, 'disable_notification': False}) - except: - pass + except TelegramError as err: + bot.logger.error(err.message) update.callback_query.answer(text=MSG_ORDER_SENT) elif data['t'] == QueryType.OrderOk.value: order = session.query(Order).filter_by(id=data['id']).first() @@ -408,7 +188,8 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): squad = session.query(Squad).filter_by(chat_id=order.chat_id).first() if squad is not None: squad_member = session.query(SquadMember).filter_by(squad_id=squad.chat_id, - user_id=update.callback_query.from_user.id).first() + user_id=update.callback_query.from_user.id, + approved=True).first() if squad_member is not None: order_ok = session.query(OrderCleared).filter_by(order_id=data['id'], user_id=squad_member.user_id).first() @@ -419,11 +200,10 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): session.add(order_ok) session.commit() if order.confirmed_msg != 0: - confirmed = order.cleared - msg = MSG_ORDER_CLEARED_BY_HEADER - for confirm in confirmed: - msg += str(confirm.user) + '\n' - bot.editMessageText(msg, order.chat_id, order.confirmed_msg) + if order.id not in order_updated or \ + datetime.now() - order_updated[order.id] > timedelta(seconds=4): + order_updated[order.id] = datetime.now() + job_queue.run_once(update_confirmed, 5, order) update.callback_query.answer(text=MSG_ORDER_CLEARED) else: update.callback_query.answer(text=MSG_ORDER_CLEARED_ERROR) @@ -438,10 +218,16 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): order_ok.user_id = update.callback_query.from_user.id session.add(order_ok) session.commit() + if order.confirmed_msg != 0: + if order.id not in order_updated or \ + datetime.now() - order_updated[order.id] > timedelta(seconds=4): + order_updated[order.id] = datetime.now() + job_queue.run_once(update_confirmed, 5, order) update.callback_query.answer(text=MSG_ORDER_CLEARED) else: update.callback_query.answer(text=MSG_ORDER_CLEARED_ERROR) elif data['t'] == QueryType.Orders.value: + chat_data['order_wait'] = False if 'txt' in data and len(data['txt']): if data['txt'] == Icons.LES.value: chat_data['order'] = Castle.LES.value @@ -451,12 +237,14 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): chat_data['order'] = Castle.SEA.value else: chat_data['order'] = data['txt'] - markup = generate_order_chats_markup(bot, chat_data['pin'] if 'pin' in chat_data else True) + markup = generate_order_chats_markup(session, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=markup) elif data['t'] == QueryType.OrderGroup.value: + chat_data['order_wait'] = False if 'txt' in data and len(data['txt']): chat_data['order_type'] = MessageType.TEXT if data['txt'] == Icons.LES.value: @@ -468,14 +256,15 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): else: chat_data['order'] = data['txt'] admin_user = session.query(Admin).filter(Admin.user_id == update.callback_query.from_user.id).all() - markup = generate_order_groups_markup(bot, admin_user, chat_data['pin'] if 'pin' in chat_data else True) + markup = generate_order_groups_markup(session, admin_user, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=markup) elif data['t'] == QueryType.OrderGroupManage.value: group = session.query(OrderGroup).filter_by(id=data['id']).first() - markup = generate_group_manage(data['id']) + markup = generate_group_manage(data['id'], session) bot.editMessageText(MSG_ORDER_GROUP_CONFIG_HEADER.format(group.name), update.callback_query.message.chat.id, update.callback_query.message.message_id, @@ -494,7 +283,7 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): item.chat_id = data['c'] session.add(item) session.commit() - markup = generate_group_manage(data['id']) + markup = generate_group_manage(data['id'], session) bot.editMessageText(MSG_ORDER_GROUP_CONFIG_HEADER.format(group.name), update.callback_query.message.chat.id, update.callback_query.message.message_id, @@ -510,69 +299,51 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): bot.editMessageText(MSG_ORDER_GROUP_LIST, update.callback_query.message.chat.id, update.callback_query.message.message_id, - reply_markup=generate_groups_manage()) + reply_markup=generate_groups_manage(session)) elif data['t'] == QueryType.OrderGroupList.value: bot.editMessageText(MSG_ORDER_GROUP_LIST, update.callback_query.message.chat.id, update.callback_query.message.message_id, - reply_markup=generate_groups_manage()) + reply_markup=generate_groups_manage(session)) elif data['t'] == QueryType.ShowEquip.value: user = session.query(User).filter_by(id=data['id']).first() update.callback_query.answer(text=MSG_CLEARED) - bot.editMessageText('{}\n🕑 Последнее обновление {}'.format(user.equip.equip, user.equip.date), + back = data['b'] if 'b' in data else False + bot.editMessageText('{}\n{} {}'.format(user.equip.equip, MSG_LAST_UPDATE, user.equip.date), update.callback_query.message.chat.id, update.callback_query.message.message_id, - reply_markup=generate_profile_buttons(user)) + reply_markup=generate_profile_buttons(user, back) + ) elif data['t'] == QueryType.ShowStock.value: user = session.query(User).filter_by(id=data['id']).first() update.callback_query.answer(text=MSG_CLEARED) - bot.editMessageText('{}\n🕑 Последнее обновление {}'.format(user.stock.stock, user.stock.date.strftime("%Y-%m-%d %H:%M:%S")), + back = data['b'] if 'b' in data else False + bot.editMessageText('{}\n{} {}'. + format(user.stock.stock, MSG_LAST_UPDATE, user.stock.date.strftime("%Y-%m-%d %H:%M:%S")), update.callback_query.message.chat.id, update.callback_query.message.message_id, - reply_markup=generate_profile_buttons(user)) + reply_markup=generate_profile_buttons(user, back) + ) elif data['t'] == QueryType.ShowHero.value: user = session.query(User).filter_by(id=data['id']).first() update.callback_query.answer(text=MSG_CLEARED) + back = data['b'] if 'b' in data else False bot.editMessageText(fill_char_template(MSG_PROFILE_SHOW_FORMAT, user, user.character), update.callback_query.message.chat.id, update.callback_query.message.message_id, - reply_markup=generate_profile_buttons(user)) + reply_markup=generate_profile_buttons(user, back) + ) elif data['t'] == QueryType.MemberList.value: squad = session.query(Squad).filter_by(chat_id=data['id']).first() - markup = generate_squad_members(squad.members) + markup = generate_squad_members(squad.members, session) bot.editMessageText(squad.squad_name, update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=markup) elif data['t'] == QueryType.LeaveSquad.value: member = session.query(SquadMember).filter_by(user_id=data['id']).first() - if member: - squad = member.squad - user = member.user - session.delete(member) - session.commit() - admins = session.query(Admin).filter_by(admin_group=squad.chat_id).all() - for adm in admins: - if adm.user_id != update.callback_query.from_user.id: - send_async(bot, chat_id=adm.user_id, - text=MSG_SQUAD_LEAVED.format(user.character.name, squad.squad_name)) - send_async(bot, chat_id=member.squad_id, - text=MSG_SQUAD_LEAVED.format(user.character.name, squad.squad_name)) - send_async(bot, chat_id=member.user_id, - text=MSG_SQUAD_LEAVED.format(user.character.name, squad.squad_name)) - if data['id'] == update.callback_query.from_user.id: - bot.editMessageText(MSG_SQUAD_LEAVED.format(user.character.name, squad.squad_name), - update.callback_query.message.chat.id, - update.callback_query.message.message_id) - else: - members = session.query(SquadMember).filter_by(squad_id=member.squad_id).all() - bot.editMessageText(update.callback_query.message.text, - update.callback_query.message.chat.id, - update.callback_query.message.message_id, - reply_markup=generate_fire_up(members)) - else: - update.callback_query.answer(text='Этот пользователь уже выпилен из отряда, кнопка больше не работает =(') + leave_squad(bot, user, member, update.effective_message, session) elif data['t'] == QueryType.RequestSquad.value: member = session.query(SquadMember).filter_by(user_id=update.callback_query.from_user.id).first() if member is None: @@ -585,7 +356,7 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): usernames = ['@' + session.query(User).filter_by(id=admin.user_id).first().username for admin in admins] bot.editMessageText(MSG_SQUAD_REQUESTED.format(member.squad.squad_name, ', '.join(usernames)), update.callback_query.message.chat.id, - update.callback_query.message.message_id) + update.callback_query.message.message_id, parse_mode=ParseMode.HTML) admins = session.query(Admin).filter_by(admin_group=member.squad.chat_id).all() for adm in admins: send_async(bot, chat_id=adm.user_id, text=MSG_SQUAD_REQUEST_NEW) @@ -596,7 +367,7 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): update.callback_query.message.message_id, reply_markup=markup) elif data['t'] == QueryType.RequestSquadAccept.value: - member = session.query(SquadMember).filter_by(user_id=data['id']).first() + member = session.query(SquadMember).filter_by(user_id=data['id'], approved=False).first() if member: member.approved = True session.add(member) @@ -604,10 +375,16 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): bot.editMessageText(MSG_SQUAD_REQUEST_ACCEPTED.format('@'+member.user.username), update.callback_query.message.chat.id, update.callback_query.message.message_id) - send_async(bot, chat_id=member.user_id, text=MSG_SQUAD_REQUEST_ACCEPTED_ANSWER) + admin = session.query(Admin).filter_by(user_id=member.user_id).all() + is_admin = False + for _ in admin: + is_admin = True + break + send_async(bot, chat_id=member.user_id, text=MSG_SQUAD_REQUEST_ACCEPTED_ANSWER, + reply_markup=generate_user_markup(is_admin)) send_async(bot, chat_id=member.squad_id, text=MSG_SQUAD_REQUEST_ACCEPTED.format('@'+member.user.username)) elif data['t'] == QueryType.RequestSquadDecline.value: - member = session.query(SquadMember).filter_by(user_id=data['id']).first() + member = session.query(SquadMember).filter_by(user_id=data['id'], approved=False).first() if member: bot.editMessageText(MSG_SQUAD_REQUEST_DECLINED.format('@' + member.user.username), update.callback_query.message.chat.id, @@ -617,15 +394,13 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): send_async(bot, chat_id=member.user_id, text=MSG_SQUAD_REQUEST_DECLINED_ANSWER) elif data['t'] == QueryType.InviteSquadAccept.value: if update.callback_query.from_user.id != data['id']: - update.callback_query.answer(text='Пшёл вон!') + update.callback_query.answer(text=MSG_GO_AWAY) return member = session.query(SquadMember).filter_by(user_id=data['id']).first() if member is None: member = SquadMember() member.user_id = user.id member.squad_id = update.callback_query.message.chat.id - session.add(member) - session.commit() member.approved = True session.add(member) session.commit() @@ -634,7 +409,7 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): update.callback_query.message.message_id) elif data['t'] == QueryType.InviteSquadDecline.value: if update.callback_query.from_user.id != data['id']: - update.callback_query.answer(text='Пшёл вон!') + update.callback_query.answer(text=MSG_GO_AWAY) return user = session.query(User).filter_by(id=data['id']).first() bot.editMessageText(MSG_SQUAD_REQUEST_DECLINED.format('@' + user.username), @@ -647,14 +422,128 @@ def callback_query(bot: Bot, update: Update, chat_data: dict): chat_data['pin'] = False if data['g']: admin_user = session.query(Admin).filter(Admin.user_id == update.callback_query.from_user.id).all() - markup = generate_order_groups_markup(bot, admin_user, chat_data['pin'] if 'pin' in chat_data else True) + markup = generate_order_groups_markup(session, admin_user, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=markup) else: - markup = generate_order_chats_markup(bot, chat_data['pin'] if 'pin' in chat_data else True) + markup = generate_order_chats_markup(session, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), update.callback_query.message.chat.id, update.callback_query.message.message_id, reply_markup=markup) + elif data['t'] == QueryType.TriggerOrderButton.value: + if 'btn' in chat_data: + chat_data['btn'] = not chat_data['btn'] + else: + chat_data['btn'] = False + if data['g']: + admin_user = session.query(Admin).filter(Admin.user_id == update.callback_query.from_user.id).all() + markup = generate_order_groups_markup(session, admin_user, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) + bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), + update.callback_query.message.chat.id, + update.callback_query.message.message_id, + reply_markup=markup) + else: + markup = generate_order_chats_markup(session, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) + bot.editMessageText(MSG_ORDER_SEND_HEADER.format(chat_data['order']), + update.callback_query.message.chat.id, + update.callback_query.message.message_id, + reply_markup=markup) + elif data['t'] == QueryType.SquadList.value: + admin = session.query(Admin).filter_by(user_id=update.callback_query.from_user.id).all() + global_adm = False + for adm in admin: + if adm.admin_type <= AdminType.FULL.value: + global_adm = True + break + if global_adm: + squads = session.query(Squad).all() + else: + group_ids = [] + for adm in admin: + group_ids.append(adm.admin_group) + squads = session.query(Squad).filter(Squad.chat_id in group_ids).all() + markup = generate_squad_list(squads, session) + bot.editMessageText(MSG_SQUAD_LIST, + update.callback_query.message.chat.id, + update.callback_query.message.message_id, + reply_markup=markup) + elif data['t'] == QueryType.GroupDelete.value: + squad = session.query(Squad).filter_by(chat_id=data['gid']).first() + if squad is not None: + for member in squad.members: + session.delete(member) + session.delete(squad) + session.commit() + send_async(bot, chat_id=data['gid'], text=MSG_SQUAD_DELETE) + msg = MSG_GROUP_STATUS_CHOOSE_CHAT + squads = session.query(Squad).all() + inline_keys = [] + for squad in squads: + inline_keys.append(InlineKeyboardButton(squad.squad_name, + callback_data=json.dumps({'t': QueryType.GroupInfo.value, + 'id': squad.chat_id}))) + inline_markup = InlineKeyboardMarkup([[key] for key in inline_keys]) + bot.editMessageText(msg, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=inline_markup) + elif data['t'] == QueryType.OtherReport.value: + squad = session.query(Squad).filter(Squad.chat_id == data['c']).first() + time_from = datetime.fromtimestamp(data['ts']) + time_to = time_from + timedelta(hours=4) + reports = session.query(User, Report) \ + .join(SquadMember) \ + .outerjoin(Report, and_(User.id == Report.user_id, Report.date > time_from, Report.date < time_to)) \ + .filter(SquadMember.squad_id == data['c']).order_by(Report.date.desc()).all() + text = '' + full_def = 0 + full_atk = 0 + full_exp = 0 + full_gold = 0 + full_stock = 0 + for user, report in reports: + if report: + text += MSG_REPORT_SUMMARY_ROW.format( + report.name, user.username, report.attack, report.defence, + report.earned_exp, report.earned_gold, report.earned_stock) + full_atk += report.attack + full_def += report.defence + full_exp += report.earned_exp + full_gold += report.earned_gold + full_stock += report.earned_stock + else: + text += MSG_REPORT_SUMMARY_ROW_EMPTY.format(user.character.name, user.username) + text = MSG_REPORT_SUMMARY_HEADER.format(squad.squad_name, time_from.strftime('%d-%m-%Y %H:%M'), full_atk, full_def, + full_exp, full_gold, full_stock) + text + markup = generate_other_reports(time_from, squad.chat_id) + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + parse_mode=ParseMode.HTML, reply_markup=markup) + elif data['t'] == QueryType.GlobalBuildTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + global_build_top(bot, update) + elif data['t'] == QueryType.WeekBuildTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + week_build_top(bot, update) + elif data['t'] == QueryType.SquadGlobalBuildTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + global_squad_build_top(bot, update) + elif data['t'] == QueryType.SquadWeekBuildTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + week_squad_build_top(bot, update) + elif data['t'] == QueryType.BattleGlobalTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + global_battle_top(bot, update) + elif data['t'] == QueryType.BattleWeekTop.value: + update.callback_query.answer(text=MSG_TOP_GENERATING) + week_battle_top(bot, update) + elif data['t'] == QueryType.Yes.value: + leave_squad(bot, user, user.member, update.effective_message, session) + elif data['t'] == QueryType.No.value: + bot.editMessageText(MSG_SQUAD_LEAVE_DECLINE, + update.callback_query.message.chat.id, + update.callback_query.message.message_id) diff --git a/core/functions/inline_markup.py b/core/functions/inline_markup.py new file mode 100644 index 0000000..6a4237e --- /dev/null +++ b/core/functions/inline_markup.py @@ -0,0 +1,407 @@ +import json +from datetime import datetime, timedelta +from enum import Enum + +from sqlalchemy import func, tuple_ +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + +from config import CASTLE +from core.enums import Castle, Icons +from core.texts import MSG_GROUP_STATUS_ADMIN_FORMAT, MSG_GROUP_STATUS_DEL_ADMIN, MSG_GROUP_STATUS, MSG_ON, MSG_OFF, \ + MSG_ORDER_GROUP_DEL, MSG_BACK, MSG_ORDER_PIN, MSG_ORDER_NO_PIN, MSG_ORDER_BUTTON, MSG_ORDER_NO_BUTTON, \ + MSG_ORDER_TO_SQUADS, MSG_ORDER_ACCEPT, MSG_ORDER_GROUP_ADD, MSG_SYMBOL_ON, MSG_SYMBOL_OFF, \ + MSG_SQUAD_GREEN_INLINE_BUTTON, MSG_SQUAD_RED_INLINE_BUTTON, BTN_HERO, BTN_STOCK, BTN_EQUIPMENT, BTN_YES, BTN_NO, \ + BTN_LEAVE, BTN_ACCEPT, BTN_DECLINE, BTN_WEEK, BTN_ALL_TIME, BTN_SQUAD_WEEK, BTN_SQUAD_ALL_TIME +from core.types import Group, Admin, User, Squad, AdminType, OrderGroup, Character + + +class QueryType(Enum): + GroupList = 0 + GroupInfo = 1 + DelAdm = 2 + Order = 3 + OrderOk = 4 + Orders = 5 + OrderGroup = 6 + OrderGroupManage = 7 + OrderGroupTriggerChat = 8 + OrderGroupAdd = 9 + OrderGroupDelete = 10 + OrderGroupList = 11 + ShowStock = 12 + ShowEquip = 13 + ShowHero = 14 + MemberList = 15 + LeaveSquad = 16 + RequestSquad = 17 + RequestSquadAccept = 18 + RequestSquadDecline = 19 + InviteSquadAccept = 20 + InviteSquadDecline = 21 + TriggerOrderPin = 22 + SquadList = 23 + GroupDelete = 24 + TriggerOrderButton = 25 + OtherReport = 26 + GlobalBuildTop = 27 + WeekBuildTop = 28 + SquadGlobalBuildTop = 29 + SquadWeekBuildTop = 30 + BattleGlobalTop = 31 + BattleWeekTop = 32 + Yes = 100 + No = 200 + + +def generate_group_info(group_id, session): + group = session.query(Group).filter(Group.id == group_id).first() + admins = session.query(Admin).filter(Admin.admin_group == group_id).all() + adm_msg = '' + adm_del_keys = [] + for adm in admins: + user = session.query(User).filter_by(id=adm.user_id).first() + adm_msg += MSG_GROUP_STATUS_ADMIN_FORMAT.\ + format(user.id, user.username or '', user.first_name or '', user.last_name or '') + adm_del_keys.append([InlineKeyboardButton(MSG_GROUP_STATUS_DEL_ADMIN. + format(user.first_name or '', user.last_name or ''), + callback_data=json.dumps( + {'t': QueryType.DelAdm.value, 'uid': user.id, + 'gid': group_id}))]) + msg = MSG_GROUP_STATUS.format(group.title, + adm_msg, + MSG_ON if group.welcome_enabled else MSG_OFF, + MSG_ON if group.allow_trigger_all else MSG_OFF, + MSG_ON if len(group.squad) and group.squad[0].thorns_enabled else MSG_OFF) + adm_del_keys.append([InlineKeyboardButton(MSG_ORDER_GROUP_DEL, callback_data=json.dumps( + {'t': QueryType.GroupDelete.value, 'gid': group_id}))]) + adm_del_keys.append([InlineKeyboardButton(MSG_BACK, callback_data=json.dumps( + {'t': QueryType.GroupList.value}))]) + inline_markup = InlineKeyboardMarkup(adm_del_keys) + return msg, inline_markup + + +def generate_flag_orders(): + flag_btns = [InlineKeyboardButton(Castle.BLACK.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.BLACK.value})), + InlineKeyboardButton(Castle.WHITE.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.WHITE.value})), + InlineKeyboardButton(Castle.BLUE.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.BLUE.value})), + InlineKeyboardButton(Castle.YELLOW.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.YELLOW.value})), + InlineKeyboardButton(Castle.RED.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.RED.value})), + InlineKeyboardButton(Castle.DUSK.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.DUSK.value})), + InlineKeyboardButton(Castle.MINT.value, callback_data=json.dumps( + {'t': QueryType.OrderGroup.value, 'txt': Castle.MINT.value})), + # InlineKeyboardButton(Castle.GORY.value, callback_data=json.dumps( + # {'t': QueryType.OrderGroup.value, 'txt': Icons.GORY.value})), + # InlineKeyboardButton(Castle.LES.value, callback_data=json.dumps( + # {'t': QueryType.OrderGroup.value, 'txt': Icons.LES.value})), + # InlineKeyboardButton(Castle.SEA.value, callback_data=json.dumps( + # {'t': QueryType.OrderGroup.value, 'txt': Icons.SEA.value})) + ] + btns = [] + i = 0 + for btn in flag_btns: + if CASTLE: + if btn.text == CASTLE: + continue + if i % 3 == 0: + btns.append([]) + btns[-1].append(btn) + i += 1 + + if CASTLE: + btns.append([]) + for btn in flag_btns: + if btn.text == CASTLE: + btns[-1].append(btn) + + inline_markup = InlineKeyboardMarkup(btns) + return inline_markup + + +def generate_order_chats_markup(session, pin=True, btn=True): + squads = session.query(Squad).all() + inline_keys = [] + for squad in squads: + inline_keys.append([InlineKeyboardButton(squad.squad_name, callback_data=json.dumps( + {'t': QueryType.Order.value, 'g': False, 'id': squad.chat_id}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, callback_data=json.dumps( + {'t': QueryType.TriggerOrderPin.value, 'g': False}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_BUTTON if btn else MSG_ORDER_NO_BUTTON, callback_data=json.dumps( + {'t': QueryType.TriggerOrderButton.value, 'g': False}))]) + inline_markup = InlineKeyboardMarkup(inline_keys) + return inline_markup + + +def generate_order_groups_markup(session, admin_user: list=None, pin: bool=True, btn=True): + if admin_user: + group_adm = True + for adm in admin_user: + if adm.admin_type < AdminType.GROUP.value: + group_adm = False + break + if group_adm: + inline_keys = [] + for adm in admin_user: + group = session.query(Group).filter_by(id=adm.admin_group, bot_in_group=True).first() + if group: + inline_keys.append([InlineKeyboardButton(group.title, callback_data=json.dumps( + {'t': QueryType.Order.value, 'g': False, 'id': group.id}))]) + inline_keys.append( + [InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, callback_data=json.dumps( + {'t': QueryType.TriggerOrderPin.value, 'g': True}))]) + inline_keys.append( + [InlineKeyboardButton(MSG_ORDER_BUTTON if btn else MSG_ORDER_NO_BUTTON, callback_data=json.dumps( + {'t': QueryType.TriggerOrderButton.value, 'g': True}))]) + inline_markup = InlineKeyboardMarkup(inline_keys) + return inline_markup + else: + groups = session.query(OrderGroup).all() + inline_keys = [] + for group in groups: + inline_keys.append([InlineKeyboardButton(group.name, callback_data=json.dumps( + {'t': QueryType.Order.value, 'g': True, 'id': group.id}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_TO_SQUADS, callback_data=json.dumps( + {'t': QueryType.Orders.value}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_PIN if pin else MSG_ORDER_NO_PIN, + callback_data=json.dumps( + {'t': QueryType.TriggerOrderPin.value, 'g': True}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_BUTTON if btn else MSG_ORDER_NO_BUTTON, + callback_data=json.dumps( + {'t': QueryType.TriggerOrderButton.value, 'g': True}))]) + inline_markup = InlineKeyboardMarkup(inline_keys) + return inline_markup + + +def generate_ok_markup(order_id, count): + inline_markup = InlineKeyboardMarkup([[InlineKeyboardButton(MSG_ORDER_ACCEPT.format(count), + callback_data=json.dumps( + {'t': QueryType.OrderOk.value, 'id': order_id}))]]) + return inline_markup + + +def generate_groups_manage(session): + groups = session.query(OrderGroup).all() + inline_keys = [] + for group in groups: + inline_keys.append([InlineKeyboardButton(group.name, callback_data=json.dumps( + {'t': QueryType.OrderGroupManage.value, 'id': group.id}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_GROUP_ADD, callback_data=json.dumps( + {'t': QueryType.OrderGroupAdd.value}))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_group_manage(group_id, session): + squads = session.query(Squad).all() + inline_keys = [] + for squad in squads: + in_group = False + for item in squad.chat.group_items: + if item.group_id == group_id: + in_group = True + break + inline_keys.append([InlineKeyboardButton((MSG_SYMBOL_ON if in_group else MSG_SYMBOL_OFF) + + squad.squad_name, callback_data=json.dumps( + {'t': QueryType.OrderGroupTriggerChat.value, 'id': group_id, 'c': squad.chat_id}))]) + inline_keys.append([InlineKeyboardButton(MSG_ORDER_GROUP_DEL, callback_data=json.dumps( + {'t': QueryType.OrderGroupDelete.value, 'id': group_id}))]) + inline_keys.append([InlineKeyboardButton(MSG_BACK, callback_data=json.dumps( + {'t': QueryType.OrderGroupList.value}))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_profile_buttons(user, back_key=False): + inline_keys = [[InlineKeyboardButton(BTN_HERO, callback_data=json.dumps( + {'t': QueryType.ShowHero.value, 'id': user.id, 'b': back_key}))]] + if user.stock: + inline_keys.append([InlineKeyboardButton(BTN_STOCK, callback_data=json.dumps( + {'t': QueryType.ShowStock.value, 'id': user.id, 'b': back_key}))]) + if user.equip: + inline_keys.append([InlineKeyboardButton(BTN_EQUIPMENT, callback_data=json.dumps( + {'t': QueryType.ShowEquip.value, 'id': user.id, 'b': back_key}))]) + if back_key: + inline_keys.append( + [InlineKeyboardButton(MSG_BACK, + callback_data=json.dumps( + {'t': QueryType.MemberList.value, 'id': user.member.squad_id} + ))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_squad_list_key(squad, session): + attack = 0 + defence = 0 + level = 0 + members = squad.members + user_ids = [] + for member in members: + user_ids.append(member.user_id) + actual_profiles = session.query(Character.user_id, func.max(Character.date)).\ + filter(Character.user_id.in_(user_ids)).\ + group_by(Character.user_id).all() + characters = session.query(Character).filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles])).all() + for character in characters: + attack += character.attack + defence += character.defence + level += character.level + return [InlineKeyboardButton( + '{} : {}⚔ {}🛡 {}👥 {}🏅'.format( + squad.squad_name, + attack, + defence, + len(members), + int(level/(len(members) or 1)) + ), + callback_data=json.dumps({'t': QueryType.MemberList.value, 'id': squad.chat_id}))] + + +def generate_yes_no(user_id): + inline_keys = [InlineKeyboardButton(BTN_YES, + callback_data=json.dumps( + {'t': QueryType.Yes.value, 'id': user_id})), + InlineKeyboardButton(BTN_NO, + callback_data=json.dumps( + {'t': QueryType.No.value, 'id': user_id}))] + return InlineKeyboardMarkup([inline_keys]) + + +def generate_squad_list(squads, session): + inline_keys = [] + for squad in squads: + inline_keys.append(generate_squad_list_key(squad, session)) + return InlineKeyboardMarkup(inline_keys) + + +def generate_leave_squad(user_id): + inline_keys = [[InlineKeyboardButton(BTN_LEAVE, + callback_data=json.dumps({'t': QueryType.LeaveSquad.value, + 'id': user_id}))]] + return InlineKeyboardMarkup(inline_keys) + + +def generate_squad_request(session): + inline_keys = [] + squads = session.query(Squad).filter_by(hiring=True).all() + for squad in squads: + inline_keys.append([InlineKeyboardButton(squad.squad_name, + callback_data=json.dumps( + {'t': QueryType.RequestSquad.value, 'id': squad.chat_id}))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_other_reports(time: datetime, squad_id): + inline_keys = [[InlineKeyboardButton('<< ' + (time - timedelta(hours=4)).strftime('%d-%m-%Y %H:%M'), + callback_data=json.dumps( + {'t': QueryType.OtherReport.value, + 'ts': (time - timedelta(hours=4)).timestamp(), + 'c': squad_id}))]] + if time + timedelta(hours=4) < datetime.now(): + inline_keys[0].append(InlineKeyboardButton((time + timedelta(hours=4)).strftime('%d-%m-%Y %H:%M') + ' >>', + callback_data=json.dumps( + {'t': QueryType.OtherReport.value, + 'ts': (time + timedelta(hours=4)).timestamp(), + 'c': squad_id}))) + return InlineKeyboardMarkup(inline_keys) + + +def generate_squad_members(members, session): + inline_keys = [] + user_ids = [] + for member in members: + user_ids.append(member.user_id) + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + filter(Character.user_id.in_(user_ids)). \ + group_by(Character.user_id).all() + characters = session.query(Character).filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]))\ + .order_by(Character.level.desc()).all() + for character in characters: + time_passed = datetime.now() - character.date + status_emoji = '❇' + if time_passed > timedelta(days=7): + status_emoji = '⁉' + elif time_passed > timedelta(days=4): + status_emoji = '‼' + elif time_passed > timedelta(days=3): + status_emoji = '❗' + elif time_passed < timedelta(days=1): + status_emoji = '🕐' + inline_keys.append( + [InlineKeyboardButton('{}{}: {}⚔ {}🛡 {}🏅'. + format(status_emoji, + character.name, + character.attack, + character.defence, + character.level), + callback_data=json.dumps( + {'t': QueryType.ShowHero.value, + 'id': character.user_id, + 'b': True} + ))]) + inline_keys.append( + [InlineKeyboardButton(MSG_BACK, + callback_data=json.dumps( + {'t': QueryType.SquadList.value} + ))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_squad_request_answer(user_id): + inline_keys = [InlineKeyboardButton(BTN_ACCEPT, + callback_data=json.dumps( + {'t': QueryType.RequestSquadAccept.value, 'id': user_id})), + InlineKeyboardButton(BTN_DECLINE, + callback_data=json.dumps( + {'t': QueryType.RequestSquadDecline.value, 'id': user_id}))] + return InlineKeyboardMarkup([inline_keys]) + + +def generate_squad_invite_answer(user_id): + inline_keys = [InlineKeyboardButton(MSG_SQUAD_GREEN_INLINE_BUTTON, + callback_data=json.dumps( + {'t': QueryType.InviteSquadAccept.value, 'id': user_id})), + InlineKeyboardButton(MSG_SQUAD_RED_INLINE_BUTTON, + callback_data=json.dumps( + {'t': QueryType.InviteSquadDecline.value, 'id': user_id}))] + return InlineKeyboardMarkup([inline_keys]) + + +def generate_fire_up(members): + inline_keys = [] + for member in members: + inline_keys.append([InlineKeyboardButton('🔥{}: {}⚔ {}🛡'.format(member.user, member.user.character.attack, + member.user.character.defence), + callback_data=json.dumps( + {'t': QueryType.LeaveSquad.value, 'id': member.user_id}))]) + return InlineKeyboardMarkup(inline_keys) + + +def generate_build_top(): + inline_keys = [[InlineKeyboardButton(BTN_WEEK, + callback_data=json.dumps( + {'t': QueryType.WeekBuildTop.value})), + InlineKeyboardButton(BTN_ALL_TIME, + callback_data=json.dumps( + {'t': QueryType.GlobalBuildTop.value}))], + [InlineKeyboardButton(BTN_SQUAD_WEEK, + callback_data=json.dumps( + {'t': QueryType.SquadWeekBuildTop.value})), + InlineKeyboardButton(BTN_SQUAD_ALL_TIME, + callback_data=json.dumps( + {'t': QueryType.SquadGlobalBuildTop.value}))]] + return InlineKeyboardMarkup(inline_keys) + + +def generate_battle_top(): + inline_keys = [[InlineKeyboardButton(BTN_WEEK, + callback_data=json.dumps( + {'t': QueryType.BattleWeekTop.value})), + InlineKeyboardButton(BTN_ALL_TIME, + callback_data=json.dumps( + {'t': QueryType.BattleGlobalTop.value}))]] + return InlineKeyboardMarkup(inline_keys) diff --git a/core/functions/newbies.py b/core/functions/newbies.py index 1715739..173e8e6 100644 --- a/core/functions/newbies.py +++ b/core/functions/newbies.py @@ -1,17 +1,18 @@ from telegram import Update, Bot -from core.types import User, Group, Session +from core.types import User, Group, user_allowed from core.template import fill_template from core.utils import send_async from core.texts import * +from config import ACADEM_CHAT_ID, CASTLE_CHAT_ID - -def newbie(bot: Bot, update: Update): - if update.message.chat.id in [-1001045426965]: - if update.message.new_chat_member is not None: - session = Session() - user = session.query(User).filter(User.id == update.message.new_chat_member.id).first() - if user is None: - group = session.query(Group).filter(Group.id == -1001146975451).first() - if group is not None: - send_async(bot, chat_id=group.id, - text=fill_template(MSG_NEWBIE, update.message.new_chat_member)) +@user_allowed +def newbie(bot: Bot, update: Update, session): + if ACADEM_CHAT_ID and CASTLE_CHAT_ID: + if update.message.chat.id in [CASTLE_CHAT_ID]: + for new_chat_member in update.message.new_chat_members: + user = session.query(User).filter(User.id == new_chat_member.id).first() + if user is None: + group = session.query(Group).filter(Group.id == ACADEM_CHAT_ID).first() + if group is not None: + send_async(bot, chat_id=group.id, + text=fill_template(MSG_NEWBIE, new_chat_member)) diff --git a/core/functions/order_groups.py b/core/functions/order_groups.py index 35ff068..3ef5638 100644 --- a/core/functions/order_groups.py +++ b/core/functions/order_groups.py @@ -1,22 +1,23 @@ from telegram import Update, Bot -from core.types import Session, OrderGroup +from core.types import OrderGroup, admin_allowed, AdminType from core.utils import send_async from core.functions.inline_keyboard_handling import generate_groups_manage, generate_group_manage from core.texts import * -def group_list(bot: Bot, update: Update): - markup = generate_groups_manage() +@admin_allowed(AdminType.FULL) +def group_list(bot: Bot, update: Update, session): + markup = generate_groups_manage(session) send_async(bot, chat_id=update.message.chat.id, text=MSG_ORDER_GROUP_LIST, reply_markup=markup) -def add_group(bot: Bot, update: Update, chat_data): - session = Session() +@admin_allowed(AdminType.FULL) +def add_group(bot: Bot, update: Update, session, chat_data): chat_data['wait_group_name'] = False group = OrderGroup() group.name = update.message.text session.add(group) session.commit() - markup = generate_group_manage(group.id) + markup = generate_group_manage(group.id, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_ORDER_GROUP_CONFIG_HEADER.format(group.name), reply_markup=markup) diff --git a/core/functions/orders.py b/core/functions/orders.py index 4ebcab1..a4a8559 100644 --- a/core/functions/orders.py +++ b/core/functions/orders.py @@ -1,15 +1,16 @@ from telegram import Update, Bot -from core.types import AdminType, Admin, admin, Session, MessageType +from core.types import AdminType, Admin, admin_allowed, MessageType from core.utils import send_async -from core.functions.inline_keyboard_handling import generate_order_groups_markup, generate_flag_orders +from core.functions.inline_markup import generate_order_groups_markup, generate_flag_orders from core.texts import * -@admin(adm_type=AdminType.GROUP) -def order(bot: Bot, update: Update, chat_data): - session = Session() +@admin_allowed(adm_type=AdminType.GROUP) +def order(bot: Bot, update: Update, session, chat_data): + chat_data['order_wait'] = False admin_user = session.query(Admin).filter(Admin.user_id == update.message.from_user.id).all() - markup = generate_order_groups_markup(bot, admin_user, chat_data['pin'] if 'pin' in chat_data else True) + markup = generate_order_groups_markup(session, admin_user, chat_data['pin'] if 'pin' in chat_data else True, + chat_data['btn'] if 'btn' in chat_data else True) msg = update.message if msg.audio: chat_data['order'] = msg.audio.file_id @@ -45,7 +46,8 @@ def order(bot: Bot, update: Update, chat_data): reply_markup=markup) -@admin(adm_type=AdminType.GROUP) -def orders(bot: Bot, update: Update, chat_data): +@admin_allowed(adm_type=AdminType.GROUP) +def orders(bot: Bot, update: Update, session, chat_data): markup = generate_flag_orders() + chat_data['order_wait'] = True send_async(bot, chat_id=update.message.chat.id, text=MSG_FLAG_CHOOSE_HEADER, reply_markup=markup) diff --git a/core/functions/pin.py b/core/functions/pin.py index 82d7575..ade330c 100644 --- a/core/functions/pin.py +++ b/core/functions/pin.py @@ -1,24 +1,26 @@ -from telegram import Bot, Update, Message +from telegram import Bot, Update from core.texts import MSG_PIN_ALL_ENABLED, MSG_PIN_ALL_DISABLED -from core.types import AdminType, admin, Session +from core.types import AdminType, admin_allowed, user_allowed, check_admin from core.utils import update_group, send_async def pin_decorator(func): - def wrapper(bot, update, *args, **kwargs): - group = update_group(update.message.chat) - if group is None: - ((admin(adm_type=AdminType.FULL))(func))(bot, update, *args, **kwargs) - elif group.allow_pin_all: - func(bot, update, *args, **kwargs) - else: - ((admin(adm_type=AdminType.GROUP))(func))(bot, update, *args, **kwargs) + @user_allowed + def wrapper(bot, update, session, *args, **kwargs): + group = update_group(update.message.chat, session) + if group is None and \ + check_admin(update, session, AdminType.FULL) or \ + group is not None and \ + (group.allow_pin_all or + check_admin(update, session, AdminType.GROUP)): + func(bot, update, session, *args, **kwargs) + return wrapper @pin_decorator -def pin(bot: Bot, update: Update): +def pin(bot: Bot, update: Update, session): bot.request.post(bot.base_url + '/pinChatMessage', {'chat_id': update.message.reply_to_message.chat.id, 'message_id': update.message.reply_to_message.message_id, @@ -26,17 +28,16 @@ def pin(bot: Bot, update: Update): @pin_decorator -def silent_pin(bot: Bot, update: Update): +def silent_pin(bot: Bot, update: Update, session): bot.request.post(bot.base_url + '/pinChatMessage', {'chat_id': update.message.reply_to_message.chat.id, 'message_id': update.message.reply_to_message.message_id, 'disable_notification': True}) -@admin(AdminType.GROUP) -def pin_all(bot: Bot, update: Update): - group = update_group(update.message.chat) - session = Session() +@admin_allowed(AdminType.GROUP) +def pin_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if not group.allow_pin_all: group.allow_pin_all = True session.add(group) @@ -44,10 +45,9 @@ def pin_all(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_PIN_ALL_ENABLED) -@admin(AdminType.GROUP) -def not_pin_all(bot: Bot, update: Update): - group = update_group(update.message.chat) - session = Session() +@admin_allowed(AdminType.GROUP) +def not_pin_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) if group.allow_pin_all: group.allow_pin_all = False session.add(group) diff --git a/core/functions/profile.py b/core/functions/profile.py index e38d78e..7f359eb 100644 --- a/core/functions/profile.py +++ b/core/functions/profile.py @@ -1,19 +1,25 @@ -from telegram import Update, Bot +from telegram import Update, Bot, ParseMode from core.functions.inline_keyboard_handling import generate_profile_buttons -from core.regexp import hero, profile -from core.types import Character, User, admin, Session, Equip +from core.regexp import HERO, PROFILE, REPORT, BUILD_REPORT, REPAIR_REPORT +from core.types import Character, Report, User, admin_allowed, Equip, user_allowed, BuildReport from core.utils import send_async -from datetime import timedelta +from datetime import timedelta, datetime import re -from core import regexp from core.template import fill_char_template from core.texts import * +from enum import Enum +from config import CASTLE -def parse_profile(profile, user_id, date): - session = Session() - parsed_data = re.search(regexp.profile, profile) + +class BuildType(Enum): + Build = 1 + Repair = 0 + + +def parse_profile(profile, user_id, date, session): + parsed_data = re.search(PROFILE, profile) char = session.query(Character).filter_by(user_id=user_id, date=date).first() if char is None: char = Character() @@ -38,9 +44,8 @@ def parse_profile(profile, user_id, date): return char -def parse_hero(profile, user_id, date): - session = Session() - parsed_data = re.search(regexp.hero, profile) +def parse_hero(profile, user_id, date, session): + parsed_data = re.search(HERO, profile) char = session.query(Character).filter_by(user_id=user_id, date=date).first() if char is None: char = Character() @@ -55,8 +60,8 @@ def parse_hero(profile, user_id, date): char.exp = int(parsed_data.group(7)) char.needExp = int(parsed_data.group(8)) char.maxStamina = int(parsed_data.group(10)) - char.gold = int(parsed_data.group(11)) - char.donateGold = int(parsed_data.group(12)) + char.gold = int(parsed_data.group(11)) + int(parsed_data.group(12)) if parsed_data.group(12) else 0 + char.donateGold = 0 # int(parsed_data.group(12)) if parsed_data.group(18): char.pet = str(parsed_data.group(18)) char.petLevel = int(parsed_data.group(20)) @@ -71,37 +76,178 @@ def parse_hero(profile, user_id, date): return char -def char_update(bot: Bot, update: Update): +def parse_reports(report, user_id, date, session): + parsed_data = re.search(REPORT, report) + report = session.query(Report).filter_by(user_id=user_id, date=date).first() + if report is None: + report = Report() + report.user_id = user_id + report.date = date + report.castle = str(parsed_data.group(1)) + report.name = str(parsed_data.group(2)) + report.attack = str(parsed_data.group(3)) + report.defence = str(parsed_data.group(4)) + report.level = int(parsed_data.group(5)) + if parsed_data.group(6): + report.earned_exp = int(parsed_data.group(6)) + else: + report.earned_exp = 0 + if parsed_data.group(7): + report.earned_gold = int(parsed_data.group(7)) + else: + report.earned_gold = 0 + if parsed_data.group(8): + report.earned_stock = int(parsed_data.group(8)) + else: + report.earned_stock = 0 + session.add(report) + session.commit() + return report + + +def parse_build_reports(report, user_id, date, session): + parsed_data = re.search(BUILD_REPORT, report) + report = session.query(BuildReport).filter_by(user_id=user_id, date=date).first() + if report is None: + report = BuildReport() + report.user_id = user_id + report.date = date + report.building = str(parsed_data.group(1)) + report.progress_percent = str(parsed_data.group(2)) + report.report_type = BuildType.Build.value + session.add(report) + session.commit() + return report + + +def parse_repair_reports(report, user_id, date, session): + parsed_data = re.search(REPAIR_REPORT, report) + report = session.query(BuildReport).filter_by(user_id=user_id, date=date).first() + if report is None: + report = BuildReport() + report.user_id = user_id + report.date = date + report.building = str(parsed_data.group(1)) + report.report_type = BuildType.Repair.value + session.add(report) + session.commit() + return report + + +@user_allowed(False) +def build_report_received(bot: Bot, update: Update, session): + if datetime.now() - update.message.forward_date > timedelta(minutes=10): + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_TOO_OLD) + return + report = re.search(BUILD_REPORT, update.message.text) + user = session.query(User).filter_by(id=update.message.from_user.id).first() + if report and user.character: + old_report = session.query(BuildReport) \ + .filter(BuildReport.user_id == user.id, + BuildReport.date > update.message.forward_date - timedelta(minutes=5), + BuildReport.date < update.message.forward_date + timedelta(minutes=5)).first() + if old_report is None: + parse_build_reports(update.message.text, update.message.from_user.id, update.message.forward_date, session) + user_builds = session.query(BuildReport).filter_by(user_id=user.id).count() + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_OK.format(user_builds)) + else: + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_EXISTS) + + +@user_allowed(False) +def repair_report_received(bot: Bot, update: Update, session): + if datetime.now() - update.message.forward_date > timedelta(minutes=10): + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_TOO_OLD) + return + report = re.search(REPAIR_REPORT, update.message.text) + user = session.query(User).filter_by(id=update.message.from_user.id).first() + if report and user.character: + old_report = session.query(BuildReport) \ + .filter(BuildReport.user_id == user.id, + BuildReport.date > update.message.forward_date - timedelta(minutes=5), + BuildReport.date < update.message.forward_date + timedelta(minutes=5)).first() + if old_report is None: + parse_repair_reports(update.message.text, update.message.from_user.id, update.message.forward_date, session) + user_builds = session.query(BuildReport).filter_by(user_id=user.id).count() + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_OK.format(user_builds)) + else: + send_async(bot, chat_id=update.message.from_user.id, text=MSG_BUILD_REPORT_EXISTS) + + +@user_allowed(False) +def report_received(bot: Bot, update: Update, session): + # if datetime.now() - update.message.forward_date > timedelta(minutes=1): + # send_async(bot, chat_id=update.message.chat.id, text=MSG_REPORT_OLD) + # else: + report = re.search(REPORT, update.message.text) + user = session.query(User).filter_by(id=update.message.from_user.id).first() + if report and user.character and str(report.group(2)) == user.character.name: + time_from = datetime(update.message.forward_date.year, update.message.forward_date.month, + update.message.forward_date.day + (-1 if update.message.forward_date.hour < 3 else 0), + (int((update.message.forward_date.hour+1) / 4) * 4 - 1 + 24) % 24, 0, 0) + time_to = datetime(update.message.forward_date.year, update.message.forward_date.month, + update.message.forward_date.day + (1 if update.message.forward_date.hour >= 20 else 0), + (int((update.message.forward_date.hour+1) / 4 + 1) * 4 - 1) % 24, 0, 0) + report = session.query(Report).filter(Report.date > time_from, Report.date < time_to, + Report.user_id == update.message.from_user.id).all() + if len(report) == 0: + parse_reports(update.message.text, update.message.from_user.id, update.message.forward_date, session) + send_async(bot, chat_id=update.message.from_user.id, text=MSG_REPORT_OK) + else: + send_async(bot, chat_id=update.message.from_user.id, text=MSG_REPORT_EXISTS) + + +@user_allowed(False) +def char_update(bot: Bot, update: Update, session): if update.message.date - update.message.forward_date > timedelta(minutes=1): send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_OLD) else: char = None - if re.search(hero, update.message.text): - char = parse_hero(update.message.text, update.message.from_user.id, update.message.forward_date) - elif re.search(profile, update.message.text): - char = parse_profile(update.message.text, update.message.from_user.id, update.message.forward_date) - send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_SAVED.format(char.name)) + if re.search(HERO, update.message.text): + char = parse_hero(update.message.text, + update.message.from_user.id, + update.message.forward_date, + session) + elif re.search(PROFILE, update.message.text): + char = parse_profile(update.message.text, + update.message.from_user.id, + update.message.forward_date, + session) + if CASTLE: + if char and char.castle == CASTLE: + send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_SAVED.format(char.name), + parse_mode=ParseMode.HTML) + else: + send_async(bot, chat_id=update.message.chat.id, + text=MSG_PROFILE_CASTLE_MISTAKE, parse_mode=ParseMode.HTML) + else: + send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_SAVED.format(char.name), + parse_mode=ParseMode.HTML) -def char_show(bot: Bot, update: Update): +@user_allowed +def char_show(bot: Bot, update: Update, session): if update.message.chat.type == 'private': - session = Session() user = session.query(User).filter_by(id=update.message.from_user.id).first() if user is not None and user.character is not None: - char =user.character - text = fill_char_template(MSG_PROFILE_SHOW_FORMAT, user, char) - btns = generate_profile_buttons(user) - send_async(bot, chat_id=update.message.chat.id, text=text, reply_markup=btns) + char = user.character + if CASTLE: + if char.castle == CASTLE: + text = fill_char_template(MSG_PROFILE_SHOW_FORMAT, user, char) + btns = generate_profile_buttons(user) + send_async(bot, chat_id=update.message.chat.id, text=text, reply_markup=btns) + else: + text = fill_char_template(MSG_PROFILE_SHOW_FORMAT, user, char) + btns = generate_profile_buttons(user) + send_async(bot, chat_id=update.message.chat.id, text=text, reply_markup=btns) -#@data_update -@admin() -def find_by_username(bot: Bot, update: Update): +@admin_allowed() +def find_by_username(bot: Bot, update: Update, session): if update.message.chat.type == 'private': msg = update.message.text.split(' ', 1)[1] msg = msg.replace('@', '') if msg != '': - session = Session() user = session.query(User).filter_by(username=msg).first() if user is not None and user.character: char = user.character @@ -109,4 +255,4 @@ def find_by_username(bot: Bot, update: Update): btns = generate_profile_buttons(user) send_async(bot, chat_id=update.message.chat.id, text=text, reply_markup=btns) else: - send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_NOT_FOUND) + send_async(bot, chat_id=update.message.chat.id, text=MSG_PROFILE_NOT_FOUND, parse_mode=ParseMode.HTML) diff --git a/core/functions/reply_markup.py b/core/functions/reply_markup.py index 9f35991..3ddb46f 100644 --- a/core/functions/reply_markup.py +++ b/core/functions/reply_markup.py @@ -1,12 +1,52 @@ from telegram import ReplyKeyboardMarkup, KeyboardButton +from core.commands import ADMIN_COMMAND_ORDER, ADMIN_COMMAND_STATUS, ADMIN_COMMAND_GROUPS, ADMIN_COMMAND_RECRUIT, \ + ADMIN_COMMAND_FIRE_UP, ADMIN_COMMAND_SQUAD_LIST, USER_COMMAND_ME, USER_COMMAND_TOP, USER_COMMAND_SQUAD, \ + USER_COMMAND_STATISTICS, USER_COMMAND_BUILD, USER_COMMAND_CONTACTS, ADMIN_COMMAND_ADMINPANEL, \ + USER_COMMAND_SQUAD_REQUEST, USER_COMMAND_BACK, TOP_COMMAND_ATTACK, TOP_COMMAND_DEFENCE, TOP_COMMAND_EXP, \ + STATISTICS_COMMAND_EXP, USER_COMMAND_SQUAD_LEAVE, ADMIN_COMMAND_REPORTS, TOP_COMMAND_BUILD, \ + TOP_COMMAND_BATTLES -def generate_admin_markup(full=False, grp=False): - buttons = [] - buttons.append([KeyboardButton('Приказы')]) + +def generate_admin_markup(full=False): + buttons = [[KeyboardButton(ADMIN_COMMAND_ORDER)]] if full: - buttons.append([KeyboardButton('Статус'), KeyboardButton('Группы')]) - if grp: - buttons.append([KeyboardButton('Заявки в отряд'), KeyboardButton('Чистка отряда')]) - buttons.append([KeyboardButton('Список отряда')]) + buttons.append([KeyboardButton(ADMIN_COMMAND_STATUS), KeyboardButton(ADMIN_COMMAND_GROUPS)]) + buttons.append([KeyboardButton(ADMIN_COMMAND_SQUAD_LIST)]) + buttons.append([KeyboardButton(USER_COMMAND_BACK)]) + return ReplyKeyboardMarkup(buttons, True) + + +def generate_user_markup(is_admin=False): + buttons = [[KeyboardButton(USER_COMMAND_ME), KeyboardButton(USER_COMMAND_TOP)], + [KeyboardButton(USER_COMMAND_SQUAD), KeyboardButton(USER_COMMAND_STATISTICS)], + [KeyboardButton(USER_COMMAND_BUILD), KeyboardButton(USER_COMMAND_CONTACTS)]] + if is_admin: + buttons.append([KeyboardButton(ADMIN_COMMAND_ADMINPANEL)]) + return ReplyKeyboardMarkup(buttons, True) + + +def generate_top_markup(): + buttons = [[KeyboardButton(TOP_COMMAND_ATTACK), KeyboardButton(TOP_COMMAND_DEFENCE), + KeyboardButton(TOP_COMMAND_EXP), KeyboardButton(TOP_COMMAND_BUILD), + KeyboardButton(TOP_COMMAND_BATTLES)], + [KeyboardButton(USER_COMMAND_BACK)]] + return ReplyKeyboardMarkup(buttons, True) + + +def generate_statistics_markup(): + buttons = [[KeyboardButton(STATISTICS_COMMAND_EXP)], + [KeyboardButton(USER_COMMAND_BACK)]] + return ReplyKeyboardMarkup(buttons, True) + + +def generate_squad_markup(is_group_admin=False, in_squad=False): + if in_squad: + buttons = [[KeyboardButton(USER_COMMAND_SQUAD_LEAVE)]] + else: + buttons = [[KeyboardButton(USER_COMMAND_SQUAD_REQUEST)]] + if is_group_admin: + buttons.append([KeyboardButton(ADMIN_COMMAND_REPORTS), KeyboardButton(ADMIN_COMMAND_RECRUIT)]) + buttons.append([KeyboardButton(ADMIN_COMMAND_SQUAD_LIST), KeyboardButton(ADMIN_COMMAND_FIRE_UP)]) + buttons.append([KeyboardButton(USER_COMMAND_BACK)]) return ReplyKeyboardMarkup(buttons, True) diff --git a/core/functions/squad.py b/core/functions/squad.py index 48cdde2..df7bb3f 100644 --- a/core/functions/squad.py +++ b/core/functions/squad.py @@ -1,19 +1,34 @@ -from sqlalchemy.orm import scoped_session -from telegram import Update, Bot +from datetime import datetime +from sqlalchemy import or_, and_ +from telegram import Update, Bot, ParseMode, TelegramError + +from core.functions.reply_markup import generate_squad_markup from core.template import fill_char_template -from core.types import User, AdminType, Admin, admin, Group, Squad, Session, SquadMember +from core.types import User, AdminType, Admin, admin_allowed, Group, Squad, SquadMember, user_allowed, Report, Character from core.utils import send_async -from core.functions.inline_keyboard_handling import generate_squad_list, \ - generate_leave_squad, generate_squad_request, generate_squad_request_answer, generate_fire_up, \ - generate_squad_invite_answer +from core.functions.inline_markup import generate_squad_list, generate_leave_squad, generate_squad_request, \ + generate_other_reports, generate_squad_request_answer, generate_squad_invite_answer, generate_fire_up, \ + generate_yes_no from core.texts import * +from core.constants import * + +@user_allowed +def squad_about(bot: Bot, update: Update, session): + admin = session.query(Admin).filter(Admin.user_id == update.message.from_user.id, + Admin.admin_group != 0).first() + squad_member = session.query(SquadMember).filter_by(user_id=update.message.from_user.id, approved=True).first() + markup = generate_squad_markup(is_group_admin=admin is not None, in_squad=True if squad_member else False) + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_SQUAD_ABOUT, + reply_markup=markup) -@admin() -def add_squad(bot: Bot, update: Update): + +@admin_allowed() +def add_squad(bot: Bot, update: Update, session): if update.message.chat.type == 'supergroup': - session = Session() squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if squad is None: squad = Squad() @@ -27,12 +42,12 @@ def add_squad(bot: Bot, update: Update): squad.squad_name = group.title session.add(squad) session.commit() - send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_NEW.format(squad.squad_name)) + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_NEW.format(squad.squad_name), + parse_mode=ParseMode.HTML) -@admin() -def set_invite_link(bot: Bot, update: Update): - session = Session() +@admin_allowed() +def set_invite_link(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if update.message.chat.type == 'supergroup' and squad is not None: msg = update.message.text.split(' ', 1) @@ -43,9 +58,8 @@ def set_invite_link(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_LINK_SAVED) -@admin() -def set_squad_name(bot: Bot, update: Update): - session = Session() +@admin_allowed() +def set_squad_name(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if update.message.chat.type == 'supergroup' and squad is not None: msg = update.message.text.split(' ', 1) @@ -53,24 +67,25 @@ def set_squad_name(bot: Bot, update: Update): squad.squad_name = msg[1] session.add(squad) session.commit() - send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_RENAMED.format(squad.squad_name)) + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_RENAMED.format(squad.squad_name), + parse_mode=ParseMode.HTML) -@admin() -def del_squad(bot: Bot, update: Update): - session = Session() +@admin_allowed() +def del_squad(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if update.message.chat.type == 'supergroup' and squad is not None: for member in squad.members: session.delete(member) + for order_group_item in squad.chat.group_items: + session.delete(order_group_item) session.delete(squad) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_DELETE) -@admin(AdminType.GROUP) -def enable_thorns(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def enable_thorns(bot: Bot, update: Update, session): group = session.query(Group).filter_by(id=update.message.chat.id).first() if update.message.chat.type == 'supergroup' and group is not None and len(group.squad) == 1: group.squad[0].thorns_enabled = True @@ -79,9 +94,8 @@ def enable_thorns(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_THORNS_ENABLED) -@admin(AdminType.GROUP) -def disable_thorns(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def disable_thorns(bot: Bot, update: Update, session): group = session.query(Group).filter_by(id=update.message.chat.id).first() if update.message.chat.type == 'supergroup' and group is not None and len(group.squad) == 1: group.squad[0].thorns_enabled = False @@ -90,45 +104,49 @@ def disable_thorns(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_THORNS_DISABLED) -@admin(AdminType.GROUP) -def squad_list(bot: Bot, update: Update): - session = scoped_session(Session)() +@admin_allowed(AdminType.GROUP) +def squad_list(bot: Bot, update: Update, session): admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() global_adm = False for adm in admin: if adm.admin_type <= AdminType.FULL.value: global_adm = True break - squads = [] if global_adm: squads = session.query(Squad).all() else: + group_ids = [] for adm in admin: - group = session.query(Group).filter_by(id=adm.admin_group).first() - if len(group.squad) and group.squad[0]: - squads.append(group.squad[0]) - markup = generate_squad_list(squads) + group_ids.append(adm.admin_group) + squads = session.query(Squad).filter(Squad.chat_id.in_(group_ids)).all() + markup = generate_squad_list(squads, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_LIST, reply_markup=markup) -def squad_request(bot: Bot, update: Update): - session = Session() +@user_allowed +def squad_request(bot: Bot, update: Update, session): user = session.query(User).filter_by(id=update.message.from_user.id).first() if user is not None: - if user.character: + if user.username is None: + send_async(bot, chat_id=update.message.chat.id, text=MSG_NO_USERNAME) + elif user.character: if user.member: markup = generate_leave_squad(user.id) - send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_REQUEST_EXISTS, reply_markup=markup) + send_async(bot, chat_id=update.message.chat.id, + text=MSG_SQUAD_REQUEST_EXISTS, reply_markup=markup) else: - markup = generate_squad_request() - send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_REQUEST, reply_markup=markup) + if user.character.level < MINIMUM_SQUAD_MEMBER_LEVEL: + send_async(bot, chat_id=update.message.chat.id, + text=MSG_SQUAD_LEVEL_TOO_LOW.format(MINIMUM_SQUAD_MEMBER_LEVEL)) + else: + markup = generate_squad_request(session) + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_REQUEST, reply_markup=markup) else: - send_async(bot, chat_id=update.message.chat.id, text='Сначала дай мне профиль!') + send_async(bot, chat_id=update.message.chat.id, text=MSG_NO_PROFILE_IN_BOT) -@admin(AdminType.GROUP) -def list_squad_requests(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def list_squad_requests(bot: Bot, update: Update, session): admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() group_admin = [] for adm in admin: @@ -148,31 +166,28 @@ def list_squad_requests(bot: Bot, update: Update): text=MSG_SQUAD_REQUEST_EMPTY) -@admin(AdminType.GROUP) -def open_hiring(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def open_hiring(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if squad is not None: squad.hiring = True session.add(squad) session.commit() - send_async(bot, chat_id=update.message.chat.id, text='Набор открыт') + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_RECRUITING_ENABLED) -@admin(AdminType.GROUP) -def close_hiring(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def close_hiring(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if squad is not None: squad.hiring = False session.add(squad) session.commit() - send_async(bot, chat_id=update.message.chat.id, text='Набор закрыт') + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_RECRUITING_DISABLED) -@admin(AdminType.GROUP) -def remove_from_squad(bot: Bot, update: Update): - session = Session() +@admin_allowed(AdminType.GROUP) +def remove_from_squad(bot: Bot, update: Update, session): admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() group_admin = [] for adm in admin: @@ -180,30 +195,141 @@ def remove_from_squad(bot: Bot, update: Update): if squad is not None: group_admin.append(adm) for adm in group_admin: - members = session.query(SquadMember).filter_by(squad_id=adm.admin_group) + members = session.query(SquadMember).filter_by(squad_id=adm.admin_group, approved=True).all() markup = generate_fire_up(members) squad = session.query(Squad).filter_by(chat_id=adm.admin_group).first() send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_CLEAN.format(squad.squad_name), + reply_markup=markup, parse_mode=ParseMode.HTML) + + +@user_allowed +def leave_squad_request(bot: Bot, update: Update, session): + member = session.query(SquadMember).filter_by(user_id=update.message.from_user.id).first() + user = session.query(User).filter_by(id=update.message.from_user.id).first() + if member: + squad = member.squad + markup = generate_yes_no(user_id=user.id) + send_async(bot, chat_id=member.user_id, + text=MSG_SQUAD_LEAVE_ASK.format(user.character.name, squad.squad_name), parse_mode=ParseMode.HTML, reply_markup=markup) + else: + send_async(bot, chat_id=user.id, + text=MSG_SQUAD_NONE, parse_mode=ParseMode.HTML) + + +def leave_squad(bot: Bot, user: User, member: SquadMember, message, session): + if member: + squad = session.query(Squad).filter(Squad.chat_id == member.squad_id).first() + member_user = session.query(User).filter(User.id == member.user_id).first() + session.delete(member) + session.commit() + if member.approved: + admins = session.query(Admin).filter_by(admin_group=squad.chat_id).all() + for adm in admins: + if adm.user_id != user.id: + send_async(bot, chat_id=adm.user_id, + text=MSG_SQUAD_LEAVED.format(member_user.character.name, squad.squad_name), + parse_mode=ParseMode.HTML) + send_async(bot, chat_id=member.squad_id, + text=MSG_SQUAD_LEAVED.format(member_user.character.name, squad.squad_name), + parse_mode=ParseMode.HTML) + try: + bot.kick_chat_member(squad.chat_id, member.user_id) + except TelegramError as err: + bot.logger.error(err.message) + if member.user_id == user.id: + bot.editMessageText(MSG_SQUAD_LEAVED.format(member_user.character.name, squad.squad_name), + message.chat.id, + message.message_id, parse_mode=ParseMode.HTML) + else: + send_async(bot, chat_id=member.user_id, + text=MSG_SQUAD_LEAVED.format(member_user.character.name, squad.squad_name), + parse_mode=ParseMode.HTML) + members = session.query(SquadMember).filter_by(squad_id=member.squad_id, approved=True).all() + bot.editMessageText(message.text, + message.chat.id, + message.message_id, + reply_markup=generate_fire_up(members)) + else: + send_async(bot, chat_id=user.id, text=MSG_SQUAD_ALREADY_DELETED) -@admin(AdminType.GROUP) -def add_to_squad(bot: Bot, update: Update): - session = Session() + +@admin_allowed(AdminType.GROUP) +def add_to_squad(bot: Bot, update: Update, session): squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() if squad is not None: username = update.message.text.split(' ', 1) if len(username) == 2: username = username[1].replace('@', '') user = session.query(User).filter_by(username=username).first() - if user is not None and user.character is not None and user.member is None: - markup = generate_squad_invite_answer(user.id) - send_async(bot, chat_id=update.message.chat.id, - text=MSG_SQUAD_ADD.format('@' + username), - reply_markup=markup) - elif user.member is not None: - send_async(bot, chat_id=update.message.chat.id, - text=MSG_SQUAD_ADD_IN_SQUAD.format('@' + username)) - elif user.character is None: - send_async(bot, chat_id=update.message.chat.id, text='Сначала пусть даст профиль!') + if user is not None: + if user.character is None: + send_async(bot, chat_id=update.message.chat.id, text=MSG_SQUAD_NO_PROFILE) + elif user.member is not None: + send_async(bot, chat_id=update.message.chat.id, + text=MSG_SQUAD_ADD_IN_SQUAD.format('@' + username)) + else: + markup = generate_squad_invite_answer(user.id) + send_async(bot, chat_id=update.message.chat.id, + text=MSG_SQUAD_ADD.format('@' + username), + reply_markup=markup) + + +@admin_allowed(AdminType.GROUP) +def call_squad(bot: Bot, update: Update, session): + squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() + if squad is not None: + users = session.query(User).join(SquadMember).filter(User.id == SquadMember.user_id)\ + .filter(SquadMember.squad_id == squad.chat_id).all() + msg = MSG_SQUAD_CALL_HEADER + for user in users: + msg += '@' + user.username + ' ' + send_async(bot, chat_id=update.message.chat.id, text=msg) + + +@admin_allowed(AdminType.GROUP) +def battle_reports_show(bot: Bot, update: Update, session): + admin = session.query(Admin, Squad).filter(Admin.user_id == update.message.from_user.id, + Squad.chat_id == Admin.admin_group).all() + group_admin = [] + for adm, squad in admin: + if squad is not None: + group_admin.append([adm, squad]) + for adm, squad in group_admin: + now = datetime.now() + time_from = datetime(now.year, now.month, + now.day + (-1 if now.hour < 3 else 0), + (int((now.hour+1) / 4) * 4 - 1 + 24) % 24, 0, 0) + reports = session.query(User, Report) \ + .join(SquadMember) \ + .outerjoin(Report, and_(User.id == Report.user_id, Report.date > time_from)) \ + .filter(SquadMember.squad_id == adm.admin_group).order_by(Report.date.desc()).all() + text = '' + full_def = 0 + full_atk = 0 + full_exp = 0 + full_gold = 0 + full_stock = 0 + total_reports = 0 + total_members = 0 + for user, report in reports: + total_members += 1 + if report: + text += MSG_REPORT_SUMMARY_ROW.format( + report.name, user.username, report.attack, report.defence, + report.earned_exp, report.earned_gold, report.earned_stock) + full_atk += report.attack + full_def += report.defence + full_exp += report.earned_exp + full_gold += report.earned_gold + full_stock += report.earned_stock + total_reports += 1 + else: + text += MSG_REPORT_SUMMARY_ROW_EMPTY.format(user.character.name, user.username) + text = MSG_REPORT_SUMMARY_HEADER.format(squad.squad_name, time_from.strftime('%d-%m-%Y %H:%M'), total_reports, + total_members, full_atk, full_def, full_exp, full_gold, + full_stock) + text + markup = generate_other_reports(time_from, squad.chat_id) + send_async(bot, chat_id=update.message.chat.id, text=text, parse_mode=ParseMode.HTML, reply_markup=markup) diff --git a/core/functions/statistics.py b/core/functions/statistics.py new file mode 100644 index 0000000..af2a226 --- /dev/null +++ b/core/functions/statistics.py @@ -0,0 +1,73 @@ +from telegram import Update, Bot + +from core.functions.reply_markup import generate_statistics_markup +from core.texts import MSG_STATISTICS_ABOUT, PLOT_X_LABEL, PLOT_Y_LABEL, MSG_DAY_SINGLE, MSG_DAY_PLURAL1, \ + MSG_DAY_PLURAL2, MSG_DATE_FORMAT, MSG_PLOT_DESCRIPTION +from core.types import user_allowed, Character +from core.utils import send_async + +import matplotlib.pyplot as plot + +from datetime import datetime, time, timedelta + +import os + + +@user_allowed +def statistic_about(bot: Bot, update: Update, session): + markup = generate_statistics_markup() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_STATISTICS_ABOUT, + reply_markup=markup) + + +@user_allowed +def exp_statistic(bot: Bot, update: Update, session): + profiles = session.query(Character).filter_by(user_id=update.message.from_user.id)\ + .order_by(Character.date).all() + plot.switch_backend('ps') + plot.xlabel(PLOT_X_LABEL) + plot.ylabel(PLOT_Y_LABEL) + x = [profile.date for profile in profiles] + y = [profile.exp for profile in profiles] + need_exp = profiles[-1].needExp + x.append(datetime.now()) + y.append(y[-1]) + plot.plot(x, y) + plot.gcf().autofmt_xdate() + filename = str(datetime.now()).replace(':', '').replace(' ', '').replace('-', '') + '.png' + with open(filename, 'wb') as file: + plot.savefig(file, format='png') + + now_date = x[-2] + prev_date = x[0] + now_exp = y[-2] + prev_exp = y[0] + for date, exp in zip(x[-3::-1], y[-3::-1]): + if date <= now_date - timedelta(days=3): + prev_date = date + prev_exp = exp + break + + delta = now_date - prev_date + interval = (delta.days * 86400 + delta.seconds) or 1 + day_exp = (now_exp - prev_exp) * 86400 / interval + delta_exp = need_exp - now_exp + + text = '' + if day_exp: + delta_days = round(delta_exp / day_exp) or 1 + if (delta_days % 10 == 0) or (delta_days % 10 >= 5) or ((delta_days % 100) in (11, 12, 13, 14)): + days_text = MSG_DAY_PLURAL2 + elif (delta_days % 10) in (2, 3, 4): + days_text = MSG_DAY_PLURAL1 + else: + days_text = MSG_DAY_SINGLE + text = (MSG_DATE_FORMAT.format(delta_days, days_text)) + + with open(filename, 'rb') as file: + bot.sendPhoto(update.message.chat.id, file, MSG_PLOT_DESCRIPTION + .format(int(day_exp), delta_exp, text)) + plot.clf() + os.remove(filename) diff --git a/core/functions/top.py b/core/functions/top.py new file mode 100644 index 0000000..bb1b1da --- /dev/null +++ b/core/functions/top.py @@ -0,0 +1,302 @@ +from sqlalchemy import func, text as text_, tuple_ +from telegram import Update, Bot + +from core.functions.inline_markup import generate_build_top, generate_battle_top +from core.functions.reply_markup import generate_top_markup +from core.texts import MSG_TOP_ABOUT, MSG_TOP_FORMAT, MSG_TOP_ATTACK, MSG_TOP_DEFENCE, MSG_TOP_EXPERIENCE, \ + MSG_TOP_GLOBAL_BUILDERS, MSG_TOP_WEEK_BUILDERS, MSG_TOP_WEEK_WARRIORS, MSG_SQUAD_TOP_FORMAT +from core.types import user_allowed, Character, BuildReport, Report, Squad, SquadMember +from core.utils import send_async + +from config import CASTLE + +from datetime import datetime, timedelta + +TOP_START_DATE = datetime(2017, 12, 11) + + +@user_allowed +def top_about(bot: Bot, update: Update, session): + markup = generate_top_markup() + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_TOP_ABOUT, + reply_markup=markup) + + +def get_top(condition, session, header, field_name, icon, user_id, additional_filter=text_('')): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + characters = session.query(Character).filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7), + additional_filter)\ + .order_by(condition) + if CASTLE: + characters = characters.filter_by(castle=CASTLE) + characters = characters.all() + text = header + str_format = MSG_TOP_FORMAT + for i in range(min(10, len(characters))): + text += str_format.format(i + 1, characters[i].name, characters[i].level, + getattr(characters[i], field_name), icon) + if user_id in [character.user_id for character in characters]: + if user_id not in [character.user_id for character in characters[:10]]: + for i in range(10, len(characters)): + if characters[i].user_id == user_id: + text += '...\n' + text += str_format.format(i, characters[i - 1].name, characters[i-1].level, + getattr(characters[i-1], field_name), icon) + text += str_format.format(i + 1, characters[i].name, characters[i].level, + getattr(characters[i], field_name), icon) + if i != len(characters) - 1: + text += str_format.format(i + 2, characters[i + 1].name, characters[i+1].level, + getattr(characters[i+1], field_name), icon) + break + return text + + +@user_allowed +def attack_top(bot: Bot, update: Update, session): + text = get_top(Character.attack.desc(), session, MSG_TOP_ATTACK, 'attack', '⚔', update.message.from_user.id) + send_async(bot, + chat_id=update.message.chat.id, + text=text) + + +@user_allowed +def def_top(bot: Bot, update: Update, session): + text = get_top(Character.defence.desc(), session, MSG_TOP_DEFENCE, 'defence', '🛡', update.message.from_user.id) + send_async(bot, + chat_id=update.message.chat.id, + text=text) + + +@user_allowed +def exp_top(bot: Bot, update: Update, session): + text = get_top(Character.exp.desc(), session, MSG_TOP_EXPERIENCE, 'exp', '🔥', update.message.from_user.id) + send_async(bot, + chat_id=update.message.chat.id, + text=text) + + +def gen_top_msg(data, user_id, header, icon): + text = header + str_format = MSG_TOP_FORMAT + for i in range(min(10, len(data))): + text += str_format.format(i + 1, data[i][0].name, data[i][0].level, + data[i][1], icon) + if len(data) and hasattr(data[0][0], 'user_id') and user_id in [build[0].user_id for build in data]: + if user_id not in [build[0].user_id for build in data[:10]]: + for i in range(10, len(data)): + if data[i][0].user_id == user_id: + text += '...\n' + text += str_format.format(i, data[i - 1][0].name, data[i - 1][0].level, + data[i - 1][1], icon) + text += str_format.format(i + 1, data[i][0].name, data[i][0].level, + data[i][1], icon) + if i != len(data) - 1: + text += str_format.format(i + 2, data[i + 1][0].name, data[i + 1][0].level, + data[i + 1][1], icon) + break + return text + + +def gen_squad_top_msg(data, counts, header, icon): + text = header + str_format = MSG_SQUAD_TOP_FORMAT + for i in range(min(10, len(data))): + squad_count = 1 + for squad, count in counts: + if squad.chat_id == data[i][0].chat_id: + squad_count = count + break + text += str_format.format(i + 1, data[i][0].squad_name, squad_count, + data[i][1], icon, round(data[i][1]/squad_count, 2), icon) + return text + + +@user_allowed +def global_build_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + builds = session.query(Character, func.count(BuildReport.user_id))\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(BuildReport, BuildReport.user_id == Character.user_id) \ + .filter(BuildReport.date > TOP_START_DATE).group_by(Character)\ + .order_by(func.count(BuildReport.user_id).desc()) + if CASTLE: + builds = builds.filter(Character.castle == CASTLE) + builds = builds.all() + user_id = 0 + if update.message: + user_id = update.message.from_user.id + elif update.callback_query: + user_id = update.callback_query.from_user.id + text = gen_top_msg(builds, user_id, MSG_TOP_GLOBAL_BUILDERS, '⚒') + markup = generate_build_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) + + +@user_allowed +def week_build_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + today = datetime.today().date() + builds = session.query(Character, func.count(BuildReport.user_id))\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(BuildReport, BuildReport.user_id == Character.user_id) \ + .filter(BuildReport.date > today - timedelta(days=today.weekday())).group_by(Character)\ + .order_by(func.count(BuildReport.user_id).desc()) + if CASTLE: + builds = builds.filter(Character.castle == CASTLE) + builds = builds.all() + user_id = 0 + if update.message: + user_id = update.message.from_user.id + elif update.callback_query: + user_id = update.callback_query.from_user.id + text = gen_top_msg(builds, user_id, MSG_TOP_WEEK_BUILDERS, '⚒') + markup = generate_build_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) + + +@user_allowed +def week_squad_build_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + today = datetime.today().date() + builds = session.query(Squad, func.count(BuildReport.user_id))\ + .join(SquadMember).join(Character, SquadMember.user_id == Character.user_id)\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(BuildReport, BuildReport.user_id == Character.user_id) \ + .filter(BuildReport.date > today - timedelta(days=today.weekday()))\ + .order_by(func.count(BuildReport.user_id).desc()) + if CASTLE: + builds = builds.filter(Character.castle == CASTLE) + builds = builds.group_by(Squad).all() + counts = session.query(Squad, func.count(SquadMember.user_id)).join(SquadMember).group_by(Squad) + text = gen_squad_top_msg(builds, counts, MSG_TOP_WEEK_BUILDERS, '⚒') + markup = generate_build_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) + + +@user_allowed +def global_squad_build_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + builds = session.query(Squad, func.count(BuildReport.user_id))\ + .join(SquadMember).join(Character, SquadMember.user_id == Character.user_id)\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(BuildReport, BuildReport.user_id == Character.user_id) \ + .filter(BuildReport.date > TOP_START_DATE) \ + .order_by(func.count(BuildReport.user_id).desc()) + if CASTLE: + builds = builds.filter(Character.castle == CASTLE) + builds = builds.group_by(Squad).all() + counts = session.query(Squad, func.count(SquadMember.user_id)).join(SquadMember).group_by(Squad) + text = gen_squad_top_msg(builds, counts, MSG_TOP_GLOBAL_BUILDERS, '⚒') + markup = generate_build_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) + + +@user_allowed +def week_battle_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + today = datetime.today().date() + battles = session.query(Character, func.count(Report.user_id))\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(Report, Report.user_id == Character.user_id) \ + .filter(Report.date > today - timedelta(days=today.weekday())) \ + .filter(Report.earned_exp > 1).group_by(Character) \ + .order_by(func.count(Report.user_id).desc()) + if CASTLE: + battles = battles.filter(Character.castle == CASTLE) + battles = battles.all() + user_id = 0 + if update.message: + user_id = update.message.from_user.id + elif update.callback_query: + user_id = update.callback_query.from_user.id + text = gen_top_msg(battles, user_id, MSG_TOP_WEEK_WARRIORS, '⛳️') + markup = generate_battle_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) + + +@user_allowed +def global_battle_top(bot: Bot, update: Update, session): + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + battles = session.query(Character, func.count(Report.user_id))\ + .filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date > datetime.now() - timedelta(days=7))\ + .outerjoin(Report, Report.user_id == Character.user_id) \ + .filter(Report.earned_exp > 1) \ + .filter(Report.date > TOP_START_DATE).group_by(Character) \ + .order_by(func.count(Report.user_id).desc()) + if CASTLE: + battles = battles.filter(Character.castle == CASTLE) + battles = battles.all() + user_id = 0 + if update.message: + user_id = update.message.from_user.id + elif update.callback_query: + user_id = update.callback_query.from_user.id + text = gen_top_msg(battles, user_id, MSG_TOP_WEEK_WARRIORS, '⛳️') + markup = generate_battle_top() + if update.message: + send_async(bot, + chat_id=update.message.chat.id, + text=text, reply_markup=markup) + elif update.callback_query: + bot.editMessageText(text, update.callback_query.message.chat.id, update.callback_query.message.message_id, + reply_markup=markup) diff --git a/core/functions/triggers.py b/core/functions/triggers.py index b622ba1..2c8ddf5 100644 --- a/core/functions/triggers.py +++ b/core/functions/triggers.py @@ -1,24 +1,24 @@ from telegram import Update, Bot, Message, ParseMode -from core.types import Trigger, AdminType, admin, Session, MessageType, LocalTrigger +from core.types import Trigger, AdminType, admin_allowed, MessageType, LocalTrigger, user_allowed, check_admin from core.utils import send_async, update_group from core.texts import * from json import loads def trigger_decorator(func): - def wrapper(bot, update, *args, **kwargs): - group = update_group(update.message.chat) - if group is None: - ((admin(adm_type=AdminType.FULL))(func))(bot, update, *args, **kwargs) - elif group.allow_trigger_all: - func(bot, update, *args, **kwargs) - else: - ((admin(adm_type=AdminType.GROUP))(func))(bot, update, *args, **kwargs) + @user_allowed + def wrapper(bot, update, session, *args, **kwargs): + group = update_group(update.message.chat, session) + if group is None and \ + check_admin(update, session, AdminType.FULL) or \ + group is not None and \ + (group.allow_trigger_all or + check_admin(update, session, AdminType.GROUP)): + func(bot, update, session, *args, **kwargs) return wrapper -def add_global_trigger_db(msg: Message, trigger_text: str): - session = Session() +def add_global_trigger_db(msg: Message, trigger_text: str, session): trigger = session.query(Trigger).filter_by(trigger=trigger_text).first() if trigger is None: trigger = Trigger() @@ -57,28 +57,27 @@ def add_global_trigger_db(msg: Message, trigger_text: str): session.commit() -@admin() -def set_global_trigger(bot: Bot, update: Update): +@admin_allowed() +def set_global_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1) if len(msg) == 2 and len(msg[1]) > 0 and update.message.reply_to_message: trigger = msg[1].strip() data = update.message.reply_to_message - add_global_trigger_db(data, trigger) + add_global_trigger_db(data, trigger, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW.format(trigger)) else: send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW_ERROR) -@admin() -def add_global_trigger(bot: Bot, update: Update): +@admin_allowed() +def add_global_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1) if len(msg) == 2 and len(msg[1]) > 0 and update.message.reply_to_message: trigger_text = msg[1].strip() - session = Session() trigger = session.query(Trigger).filter_by(trigger=trigger_text).first() if trigger is None: data = update.message.reply_to_message - add_global_trigger_db(data, trigger_text) + add_global_trigger_db(data, trigger_text, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW.format(trigger_text)) else: send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_EXISTS.format(trigger_text)) @@ -87,8 +86,7 @@ def add_global_trigger(bot: Bot, update: Update): @trigger_decorator -def trigger_show(bot: Bot, update: Update): - session = Session() +def trigger_show(bot: Bot, update: Update, session): trigger = session.query(LocalTrigger).filter_by(chat_id=update.message.chat.id, trigger=update.message.text).first() if trigger is None: trigger = session.query(Trigger).filter_by(trigger=update.message.text).first() @@ -110,7 +108,10 @@ def trigger_show(bot: Bot, update: Update): contact['first_name'] = None if 'last_name' not in contact.keys(): contact['last_name'] = None - bot.send_contact(update.message.chat.id, contact['phone_number'], contact['first_name'], contact['last_name']) + bot.send_contact(update.message.chat.id, + contact['phone_number'], + contact['first_name'], + contact['last_name']) elif trigger.message_type == MessageType.VIDEO.value: bot.send_video(update.message.chat.id, trigger.message) elif trigger.message_type == MessageType.VIDEO_NOTE.value: @@ -125,30 +126,27 @@ def trigger_show(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=trigger.message, disable_web_page_preview=True) -@admin(adm_type=AdminType.GROUP) -def enable_global_trigger_all(bot: Bot, update: Update): - session = Session() - group = update_group(update.message.chat) +@admin_allowed(adm_type=AdminType.GROUP) +def enable_global_trigger_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) group.allow_trigger_all = True session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_ALL_ENABLED) -@admin(adm_type=AdminType.GROUP) -def disable_global_trigger_all(bot: Bot, update: Update): - session = Session() - group = update_group(update.message.chat) +@admin_allowed(adm_type=AdminType.GROUP) +def disable_global_trigger_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) group.allow_trigger_all = False session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_ALL_DISABLED) -@admin() -def del_global_trigger(bot: Bot, update: Update): +@admin_allowed() +def del_global_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1)[1] - session = Session() trigger = session.query(Trigger).filter_by(trigger=msg).first() if trigger is not None: session.delete(trigger) @@ -159,18 +157,16 @@ def del_global_trigger(bot: Bot, update: Update): @trigger_decorator -def list_triggers(bot: Bot, update: Update): - session = Session() +def list_triggers(bot: Bot, update: Update, session): triggers = session.query(Trigger).all() local_triggers = session.query(LocalTrigger).filter_by(chat_id=update.message.chat.id).all() msg = MSG_TRIGGER_LIST_HEADER + \ - 'Глобальные:\n' + ('\n'.join([trigger.trigger for trigger in triggers]) or MSG_EMPTY) + \ - '\nЛокальные:\n' + ('\n'.join([trigger.trigger for trigger in local_triggers]) or MSG_EMPTY) + MSG_TRIGGER_GLOBAL + ('\n'.join([trigger.trigger for trigger in triggers]) or MSG_EMPTY) + \ + MSG_TRIGGER_LOCAL + ('\n'.join([trigger.trigger for trigger in local_triggers]) or MSG_EMPTY) send_async(bot, chat_id=update.message.chat.id, text=msg, parse_mode=ParseMode.HTML) -def add_trigger_db(msg: Message, chat, trigger_text: str): - session = Session() +def add_trigger_db(msg: Message, chat, trigger_text: str, session): trigger = session.query(LocalTrigger).filter_by(chat_id=chat.id, trigger=trigger_text).first() if trigger is None: trigger = LocalTrigger() @@ -210,28 +206,27 @@ def add_trigger_db(msg: Message, chat, trigger_text: str): session.commit() -@admin(adm_type=AdminType.GROUP) -def set_trigger(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def set_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1) if len(msg) == 2 and len(msg[1]) > 0 and update.message.reply_to_message: trigger = msg[1].strip() data = update.message.reply_to_message - add_trigger_db(data, update.message.chat, trigger) + add_trigger_db(data, update.message.chat, trigger, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW.format(trigger)) else: send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW_ERROR) -@admin(adm_type=AdminType.GROUP) -def add_trigger(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def add_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1) if len(msg) == 2 and len(msg[1]) > 0 and update.message.reply_to_message: trigger_text = msg[1].strip() - session = Session() trigger = session.query(LocalTrigger).filter_by(chat_id=update.message.chat.id, trigger=trigger_text).first() if trigger is None: data = update.message.reply_to_message - add_trigger_db(data, update.message.chat, trigger_text) + add_trigger_db(data, update.message.chat, trigger_text, session) send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW.format(trigger_text)) else: send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_EXISTS.format(trigger_text)) @@ -239,30 +234,27 @@ def add_trigger(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_NEW_ERROR) -@admin(adm_type=AdminType.GROUP) -def enable_trigger_all(bot: Bot, update: Update): - session = Session() - group = update_group(update.message.chat) +@admin_allowed(adm_type=AdminType.GROUP) +def enable_trigger_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) group.allow_trigger_all = True session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_ALL_ENABLED) -@admin(adm_type=AdminType.GROUP) -def disable_trigger_all(bot: Bot, update: Update): - session = Session() - group = update_group(update.message.chat) +@admin_allowed(adm_type=AdminType.GROUP) +def disable_trigger_all(bot: Bot, update: Update, session): + group = update_group(update.message.chat, session) group.allow_trigger_all = False session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_TRIGGER_ALL_DISABLED) -@admin(adm_type=AdminType.GROUP) -def del_trigger(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def del_trigger(bot: Bot, update: Update, session): msg = update.message.text.split(' ', 1)[1] - session = Session() trigger = session.query(LocalTrigger).filter_by(trigger=msg).first() if trigger is not None: session.delete(trigger) diff --git a/core/functions/welcome.py b/core/functions/welcome.py index 5c60ff1..1c8579f 100644 --- a/core/functions/welcome.py +++ b/core/functions/welcome.py @@ -1,5 +1,5 @@ from telegram import Update, Bot -from core.types import Wellcomed, WelcomeMsg, AdminType, admin, Session, Admin +from core.types import Wellcomed, WelcomeMsg, AdminType, admin_allowed, Admin, user_allowed from core.template import fill_template from time import time from core.utils import send_async, add_user, update_group @@ -9,22 +9,22 @@ last_welcome = 0 -def welcome(bot: Bot, update: Update): +@user_allowed(False) +def welcome(bot: Bot, update: Update, session): newbie(bot, update) global last_welcome if update.message.chat.type in ['group', 'supergroup']: - group = update_group(update.message.chat) + group = update_group(update.message.chat, session) for new_chat_member in update.message.new_chat_members: - session = Session() - user = add_user(new_chat_member) + user = add_user(new_chat_member, session) administrator = session.query(Admin).filter_by(user_id=user.id).all() allow_anywhere = False for adm in administrator: if adm.admin_type == AdminType.FULL.value: allow_anywhere = True break - if len(group.squad) == 1 and group.squad[0].thorns_enabled and user.id != 386494081 and \ - (user.member or user.member not in group.squad[0].members) and not allow_anywhere: + if len(group.squad) == 1 and group.squad[0].thorns_enabled and user.id != bot.id and \ + (user.member and user.member not in group.squad[0].members) and not allow_anywhere: send_async(bot, chat_id=update.message.chat.id, text=MSG_THORNS.format(str(user))) bot.kickChatMember(update.message.chat.id, new_chat_member.id) @@ -48,11 +48,10 @@ def welcome(bot: Bot, update: Update): session.commit() -@admin(adm_type=AdminType.GROUP) -def set_welcome(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def set_welcome(bot: Bot, update: Update, session): if update.message.chat.type in ['group', 'supergroup']: - group = update_group(update.message.chat) - session = Session() + group = update_group(update.message.chat, session) welcome_msg = session.query(WelcomeMsg).filter_by(chat_id=group.id).first() if welcome_msg is None: welcome_msg = WelcomeMsg(chat_id=group.id, message=update.message.text.split(' ', 1)[1]) @@ -63,33 +62,30 @@ def set_welcome(bot: Bot, update: Update): send_async(bot, chat_id=update.message.chat.id, text=MSG_WELCOME_SET) -@admin(adm_type=AdminType.GROUP) -def enable_welcome(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def enable_welcome(bot: Bot, update: Update, session): if update.message.chat.type in ['group', 'supergroup']: - session = Session() - group = update_group(update.message.chat) + group = update_group(update.message.chat, session) group.welcome_enabled = True session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_WELCOME_ENABLED) -@admin(adm_type=AdminType.GROUP) -def disable_welcome(bot: Bot, update: Update): +@admin_allowed(adm_type=AdminType.GROUP) +def disable_welcome(bot: Bot, update: Update, session): if update.message.chat.type in ['group', 'supergroup']: - session = Session() - group = update_group(update.message.chat) + group = update_group(update.message.chat, session) group.welcome_enabled = False session.add(group) session.commit() send_async(bot, chat_id=update.message.chat.id, text=MSG_WELCOME_DISABLED) -@admin(adm_type=AdminType.GROUP) -def show_welcome(bot: Bot, update): +@admin_allowed(adm_type=AdminType.GROUP) +def show_welcome(bot: Bot, update, session): if update.message.chat.type in ['group', 'supergroup']: - session = Session() - group = update_group(update.message.chat) + group = update_group(update.message.chat, session) welcome_msg = session.query(WelcomeMsg).filter_by(chat_id=group.id).first() if welcome_msg is None: welcome_msg = WelcomeMsg(chat_id=group.id, message=MSG_WELCOME_DEFAULT) diff --git a/core/regexp.py b/core/regexp.py index b548269..e3afe2f 100644 --- a/core/regexp.py +++ b/core/regexp.py @@ -1,25 +1,41 @@ # -*- coding: utf-8 -*- -profile = '(🇬🇵|🇮🇲|🇨🇾|🇻🇦|🇪🇺|🇲🇴|🇰🇮)(.+), (.+) .+ замка\n' \ +# FIX: переделать строки в """ +PROFILE = '(🌑|🐺|🥔|🦅|🦌|🐉|🦈)(.+), (.+) .+ замка\n' \ '🏅Уровень: ([0-9]+)\n' \ '(?:.*)Атака: ([0-9]+) 🛡Защита: ([0-9]+)\n' \ '🔥Опыт: ([0-9]+)/([0-9]+)\n' \ '🔋Выносливость: ([0-9]+)/([0-9]+)\n' \ '(?:💧Мана: [0-9]+/[0-9]+\n)?' \ - '💰([0-9]+) 💠([0-9]+)\n\n' \ + '💰(-?[0-9]+) 💠([0-9]+)\n\n' \ '🎽Экипировка (.+)\n' \ '🎒Рюкзак: ([0-9]+)/([0-9]+) /inv' \ '(?:\n\nПомощник:\n(.+?) (?:.+?) (.+)? \(([0-9]+) ур\.\) (.+) /pet)?' -hero = '(🇬🇵|🇮🇲|🇨🇾|🇻🇦|🇪🇺|🇲🇴|🇰🇮)(.+), (.+) .+ замка\n' \ - '🏅Уровень: ([0-9]+)\n' \ - '(?:.*)Атака: ([0-9]+) 🛡Защита: ([0-9]+)\n' \ - '🔥Опыт: ([0-9]+)/([0-9]+)\n' \ - '🔋Выносливость: ([0-9]+)/([0-9]+)\n' \ +HERO = '(🌑|🐺|🥔|🦅|🦌|🐉|🦈)(.+) of (.+) .+\n' \ + '🏅Level: ([0-9]+)\n' \ + '.+Atk: ([0-9]+) 🛡Def: ([0-9]+)\n' \ + '🔥Exp: ([0-9]+)/([0-9]+)\n' \ + '🔋Stamina: ([0-9]+)/([0-9]+)\n' \ '(?:💧Мана: [0-9]+/[0-9]+\n)?' \ - '💰([0-9]+) 💠([0-9]+)\n' \ - '🤺Побед: ([0-9]+)\n\n' \ - '🎽Экипировка(?:(.+)(?:\n)?((?:.|\n)+)?)\n\n' \ - '🎒Рюкзак: ([0-9]+)/([0-9]+) /inv\n' \ - '📦Склад: (?:[0-9]+) /stock(?:\n\n' \ + '💰Gold: (-?[0-9]+)(?: \(\+([0-9]+)\))?\n' \ + '🤺PVP: ([0-9]+)\n' \ + '.+\n\n' \ + '🎽Equipment(?:(.+)(?:\n)?((?:.|\n)+)?)\n\n' \ + '🎒Bag: ([0-9]+)/([0-9]+) /inv\n' \ + '📦Warehouse: (?:[0-9]+) /stock(?:\n\n' \ 'Помощник:\n' \ '(.+?) (?:.+?) (.+)? \(([0-9]+) ур\.\) (.+) /pet)?' + +REPORT = '(🌑|🐺|🥔|🦅|🦌|🐉|🦈)(.+) ⚔:([0-9]+) 🛡:([0-9]+) \(Lvl: ([0-9]+)\)\n' \ + 'Your result on the battlefield:(?:\n' \ + '🔥Exp: ([0-9]+))?(?:\n' \ + '💰Gold: (-?[0-9]+))?(?:\n' \ + '📦Stock: (-?[0-9]+))?' + +BUILD_REPORT = 'Ты вернулся со стройки: (.+), прогресс работ: ([0-9]+)%' + +REPAIR_REPORT = 'Здание отремонтировано: (.+)' + +STOCK = '📦storage' + +TRADE_BOT = '📦твой склад с материалами:' diff --git a/core/template.py b/core/template.py index 1a62f37..fc1e9f8 100644 --- a/core/template.py +++ b/core/template.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from core.texts import MSG_NO_SQUAD -from core.types import * +from core.texts import MSG_NO_SQUAD, MSG_WANTS_TO_JOIN, MSG_NO_PET +from core.types import User, Character def fill_template(msg: str, user: User): @@ -33,9 +33,10 @@ def fill_char_template(msg: str, user: User, char: Character, squad_request=Fals else: msg = msg.replace('%squad%', MSG_NO_SQUAD) if char.pet is not None: - msg = msg.replace('%pet%', '{} {} lvl'.format(str(char.pet), str(char.petLevel))) + msg = msg.replace('%pet%', '{} {} lvl'.format(str(char.pet), + str(char.petLevel))) else: - msg = msg.replace('%pet%', 'Животины нет') + msg = msg.replace('%pet%', MSG_NO_PET) if squad_request: - msg += '\n\nХочет вступить в отряд {}'.format(user.member.squad.squad_name) + msg += MSG_WANTS_TO_JOIN.format(user.member.squad.squad_name) return msg diff --git a/core/texts.py b/core/texts.py index 29212e5..348711a 100644 --- a/core/texts.py +++ b/core/texts.py @@ -1,188 +1,353 @@ -MSG_ORDER_STATISTIC = 'Статистика выполнения приказов за {} дней:\n' +""" Строки """ + +MSG_ORDER_STATISTIC = 'Statistics of who followed the orders for {} days:\n' MSG_ORDER_STATISTIC_OUT_FORMAT = '{}: {}/{}\n' -MSG_USER_UNKNOWN = 'Не знаю таких' +MSG_USER_UNKNOWN = 'No such user' -MSG_NEW_GROUP_ADMIN = 'Приветствуйте нового админа: @{}!\nДля списка команд бота используй /help' -MSG_NEW_GROUP_ADMIN_EXISTS = '@{} и без тебя тут правит!' +MSG_NEW_GROUP_ADMIN = """Welcome our new administrator: @{}! +Check the commands list with /help command""" +MSG_NEW_GROUP_ADMIN_EXISTS = '@{} already has administrator rights' -MSG_DEL_GROUP_ADMIN_NOT_EXIST = 'У @{} здесь нет власти!' -MSG_DEL_GROUP_ADMIN = '@{}, тебя разжаловали.' +MSG_DEL_GROUP_ADMIN_NOT_EXIST = '@{} never had any power here!' +MSG_DEL_GROUP_ADMIN = '@{}, now you have no power here!' -MSG_NEW_GLOBAL_ADMIN = 'Новый глобальный админ: @{}!' -MSG_NEW_GLOBAL_ADMIN_EXISTS = '@{} и без тебя админ!' +MSG_NEW_GLOBAL_ADMIN = 'New global administrator: @{}!' +MSG_NEW_GLOBAL_ADMIN_EXISTS = '@{} already has global administrator rights' -MSG_DEL_GLOBAL_ADMIN_NOT_EXIST = 'У @{} нет власти!' -MSG_DEL_GLOBAL_ADMIN = '@{} разжалован.' +MSG_DEL_GLOBAL_ADMIN_NOT_EXIST = '{} never had any global rights!' +MSG_DEL_GLOBAL_ADMIN = '@{} now you have no global rights' -MSG_NEW_SUPER_ADMIN = 'Новый бог: @{}!' -MSG_NEW_SUPER_ADMIN_EXISTS = '@{} уже бог!' +MSG_NEW_SUPER_ADMIN = 'New super administrator: @{}!' +MSG_NEW_SUPER_ADMIN_EXISTS = '@{} is already a super administrator!' -MSG_LIST_ADMINS_HEADER = 'Список здешних админов:\n' +MSG_LIST_ADMINS_HEADER = 'Administrators list:\n' MSG_LIST_ADMINS_FORMAT = '{} @{} {} {}\n' MSG_LIST_ADMINS_USER_FORMAT = '@{} {} {}\n' -MSG_EMPTY = '[Пусто]\n' - -MSG_START_WELCOME = 'Привет' -MSG_ADMIN_WELCOME = 'Да здравствует админ!' - -MSG_HELP_GLOBAL_ADMIN = 'Команды приветствия:\n'\ - '/enable_welcome - Включить приветствие\n'\ - '/disable_welcome - Выключить приветствие\n'\ - '/set_welcome <текст> - Установить текст приветствия. '\ - 'Может содержать %username% - будет заменено на @username, '\ - 'если не установлено на Имя Фамилия, %first_name% - на имя, '\ - '%last_name% - на фамилию, %id% - на id\n'\ - '/show_welcome - Показать текущий текст приветствия для '\ - 'данного чата'\ - '\n\n'\ - 'Команды триггеров:\n'\ - '/set_trigger <триггер>::<сообщение> - Установить сообщение, '\ - 'которое бот будет кидать по триггеру.\n'\ - '/add_trigger <триггер>::<сообщение> - Добавляет сообщение, '\ - 'которое бот будет кидать по триггеру, но не заменяет старый.\n'\ - '/del_trigger <триггер> - Удалить соответствующий триггер\n'\ - '/list_triggers - Показать все существующие триггеры'\ - '\n\n'\ - 'Команды глобаладмина:\n'\ - '/add_admin <юзернэйм> - Добавить админа для текущего чата\n'\ - '/del_admin <юзернэйм> - Забрать привелегии у админа текущего '\ - 'чата\n'\ - '/list_admins - Показать список местных админов\n'\ - '/enable_trigger - Разрешить триггерить всем в группе\n'\ - '/disable_trigger - Запретить триггерить всем в группе' - -MSG_HELP_GROUP_ADMIN = 'Команды приветствия:\n'\ - '/enable_welcome - Включить приветствие\n'\ - '/disable_welcome - Выключить приветствие\n'\ - '/set_welcome <текст> - Установить текст приветствия. '\ - 'Может содержать %username% - будет заменено на @username, '\ - 'если не установлено на Имя Фамилия, %first_name% - на имя, '\ - '%last_name% - на фамилию, %id% - на id\n'\ - '/show_welcome - Показать текущий текст приветствия для '\ - 'данного чата'\ - '\n\n'\ - 'Команды триггеров:\n'\ - '/add_trigger <триггер>::<сообщение> - Добавляет сообщение, '\ - 'которое бот будет кидать по триггеру, но не заменяет старый.\n'\ - '/list_triggers - Показать все существующие триггеры\n'\ - '/enable_trigger - Разрешить триггерить всем в группе\n'\ - '/disable_trigger - Запретить триггерить всем в группе' - -MSG_HELP_USER = 'Команды триггеров:\n'\ - '/list_triggers - Показать все существующие триггеры' - -MSG_PING = 'Иди освежись, @{}!' - -MSG_STOCK_COMPARE_HARVESTED = '📦Награблено:\n' -MSG_STOCK_COMPARE_LOST = '\n📦Потеряно:\n' +MSG_EMPTY = '[Empty]\n' + +MSG_START_WELCOME = 'Greetings, warrior! I am the Castle Bot of 🥔Potato Castle! ' \ + 'Please send me your game profile from @chtwrsbot ("/hero" command).' +MSG_ADMIN_WELCOME = 'Welcome, master!' + +MSG_HELP_GLOBAL_ADMIN = """Welcome commands: +/enable_welcome — enable welcome message. +/disable_welcome — disable welcome message. +/set_welcome  — set welcome message. \ +Can contain %username% — will be shown as @username, \ +if not set to First and Last name, or ID, +using %last_name%, %first_name%, %id%. +/show_welcome — show welcome message. + +Trigger commands: +Reply to a message or file with /set_trigger  — \ +set message to reply with on a trigger (only current chat) +/del_trigger  — delete trigger. +/list_triggers — show all triggers. +Reply to a message or file with /set_global_trigger  — \ +set message to reply with on a trigger (all chats) +/del_global_trigger  — delete trigger. + +Super administrator commands: +/add_admin  — add administrator to current chat. +/del_admin  — delete administrator from current chat. +/list_admins — show list of current chat administrators. +/enable_trigger — allow everyone to call trigger. +/disable_trigger — forbid everyone to call trigger. +/find - Show user status + + + +Squad commands: +/add_squad - Create a new squad and associates it to the current group +/del_squad - Delete the squad associated with teh group +/enable_thorns - Prevent non members of the squad be in the group +/disable_thorns - Allow non members of the group to be in the squad +/set_squad_name - Change the name of the squad + +/add - Ask an user to join the squad +/ban - Ban an user form the squad +/unban - Unban an user from the squad + + +Free text commands: +daily stats - Show squad daily stats +weekly stats - Show squad weekly stats +battle stats - Show last batle stats for batle +allow everyone to trigger - Allow every member to set triggers +prevent everyone from triggering - Allow only admins to set triggers +allow everyone to pin - Allow all members to pin messages +prevent everyone from pinning - Allow only admins to pin messages + +Reply any message with Pin to Pin it (admins always can do that, other members if its enabled) +Reply any message with Delete to delete it + +""" + +MSG_HELP_GROUP_ADMIN = """Welcome commands: +/enable_welcome — enable welcome message. +/disable_welcome — disable welcome message. +/set_welcome  — set welcome message. \ +Can contain %username% — will be shown as @username, \ +if not set to First and Last name, or ID, +using %last_name%, %first_name%, %id%. +/show_welcome — show welcome message. + + +Trigger commands: +Reply to a message or file with /set_trigger  — \ +set message to reply with on a trigger +/del_trigger  — delete trigger. +/list_triggers — show all triggers. +/enable_trigger — allow everyone to call trigger. +/disable_trigger — forbid everyone to call trigger. + +Free text commands: +daily stats - Show squad daily stats +weekly stats - Show squad weekly stats +battle stats - Show last batle stats for batle +allow everyone to trigger - Allow every member to set triggers +prevent everyone from triggering - Allow only admins to set triggers +allow everyone to pin - Allow all members to pin messages +prevent everyone from pinning - Allow only admins to pin messages + + +Reply any message with Pin to Pin it (admins always can do that, other members if its enabled) +Reply any message with Delete to delete it + +""" + +MSG_HELP_USER = "/list_triggers — show all triggers." + +MSG_PING = 'Go and dig some potatoes, @{}!' + +MSG_STOCK_COMPARE_HARVESTED = '📦You got:\n' +MSG_STOCK_COMPARE_LOST = '\n📦You lost:\n' MSG_STOCK_COMPARE_FORMAT = '{} ({})\n' -MSG_STOCK_COMPARE_WAIT = 'Жду с чем сравнивать...' - -MSG_GROUP_STATUS_CHOOSE_CHAT = 'Выбери чат' -MSG_GROUP_STATUS = 'Группа: {}\n\n' \ - 'Админы:\n' \ - '{}\n' \ - 'Приветствие: {}\n' \ - 'Триггерят все: {}\n' \ - 'Тернии: {}' +MSG_STOCK_COMPARE_WAIT = 'Waiting for data to compare...' + +MSG_PERSONAL_SITE_LINK = 'Your personal link: {}' + +MSG_GROUP_STATUS_CHOOSE_CHAT = 'Choose chat' +MSG_GROUP_STATUS = """Group: {} + +Admins: +{} +Welcome: {} +Trigger allowed: {} +Thorns: {}""" + MSG_GROUP_STATUS_ADMIN_FORMAT = '{} @{} {} {}\n' -MSG_GROUP_STATUS_DEL_ADMIN = 'Разжаловать {} {}' +MSG_GROUP_STATUS_DEL_ADMIN = 'Bust {} {}' -MSG_ON = 'Включено' -MSG_OFF = 'Выключено' +MSG_ON = 'Enabled' +MSG_OFF = 'Disabled' MSG_SYMBOL_ON = '✅' MSG_SYMBOL_OFF = '❌' -MSG_BACK = '🔙Назад' - -MSG_ORDER_TO_SQUADS = 'По отрядам' -MSG_ORDER_ACCEPT = 'Принято!' -MSG_ORDER_PIN = '✅Пинить' -MSG_ORDER_NO_PIN = '❌Не Пинить' - -MSG_ORDER_CLEARED_BY_HEADER = 'Приказ выполнили:\n' - -MSG_ORDER_SENT = 'Ваше сообщение отправлено' - -MSG_ORDER_CLEARED = 'Я тебя записал' -MSG_ORDER_CLEARED_ERROR = 'Хорош тыкать, уже всё' - -MSG_ORDER_SEND_HEADER = 'Куда слать?' - -MSG_ORDER_GROUP_CONFIG_HEADER = 'Настройки группы {}' -MSG_ORDER_GROUP_NEW = 'Напиши мне название новой группы отрядов' -MSG_ORDER_GROUP_LIST = 'Список групп' -MSG_ORDER_GROUP_ADD = '➕Добавить группу' -MSG_ORDER_GROUP_DEL = '🔥🚨Удалить группу🚨🔥' - -MSG_NEWBIE = 'Новый игрок в замке!\n' \ - 'Все на вербовку %username%!' - -MSG_FLAG_CHOOSE_HEADER = 'Выбирай' - -MSG_PROFILE_OLD = 'Твой профиль завял, нужно что-то посвежей...' -MSG_PROFILE_SAVED = 'Располагайся в зарослях мяты, {}!\nНе забывай поливать свой профиль хотя бы раз в день. 🌱' -MSG_PROFILE_CASTLE_MISTAKE = 'Перед тобой во всей красе предстали обширные заросли мяты. '\ - 'Ты бесстрашно зашёл в них, в надежде добраться до таинственных новых земель. '\ - 'Однако долгие часы скитаний не привели тебя ни к чему. '\ - 'Повезло хоть, что выбраться смог! Без проводника здесь делать нечего...' -MSG_PROFILE_SHOW_FORMAT = '👤 %first_name% %last_name% (%username%)\n' \ - '%castle% %name%\n' \ - '🏅 %prof% %level% уровня\n' \ - '⚜️ Отряд %squad%\n' \ - '⚔️ %attack% | 🛡 %defence% | 🔥 %exp%/%needExp%\n' \ - '💰 %gold% | 🔋 %maxStamina%\n' \ - '%pet%\n' \ - '🕑 Последнее обновление %date%' -MSG_PROFILE_NOT_FOUND = 'В мятных записях ещё нет данных об этом герое' -MSG_SQUAD_REQUEST_EMPTY = 'На данный момент к вам никто не хочет.' - -MSG_SQUAD_NEW = 'Теперь здесь будет обитать отряд {}!\n'\ - 'Не забудьте задать ссылку для приглашения новых участников.' -MSG_SQUAD_LINK_SAVED = 'Ссылка приглашений сохранена!\nНовые участники теперь не пройдут мимо!' -MSG_SQUAD_RENAMED = 'Теперь этот отряд будет называться {}!' -MSG_SQUAD_DELETE = 'Отряд распущен' -MSG_SQUAD_THORNS_ENABLED = 'Непроходимые тернии выросли вокруг' -MSG_SQUAD_THORNS_DISABLED = 'Тернии завяли, теперь каждый может видеть происходящее' - -MSG_TRIGGER_NEW = 'Триггер на фразу "{}" установлен.' -MSG_TRIGGER_NEW_ERROR = 'Какие-то у тебя несвежие мысли, попробуй ещё раз.' -MSG_TRIGGER_EXISTS = 'Триггер "{}" уже существует, выбери другой.' -MSG_TRIGGER_ALL_ENABLED = 'Теперь триггерить могут все.' -MSG_TRIGGER_ALL_DISABLED = 'Теперь триггерить могут только админы.' -MSG_TRIGGER_DEL = 'Триггер на фразу "{}" удалён.' -MSG_TRIGGER_DEL_ERROR = 'Где ты такой триггер видел? 0_о' -MSG_TRIGGER_LIST_HEADER = 'Список текущих триггеров:\n' - -MSG_THORNS = '{} не смог пробраться через МЯТНЫЕ, МАТЬ ЕГО, тернии и ему пришлось уйти' - -MSG_WELCOME_DEFAULT = 'Привет, %username%!' -MSG_WELCOME_SET = 'Текст приветствия установлен.' -MSG_WELCOME_ENABLED = 'Приветствие включено.' -MSG_WELCOME_DISABLED = 'Приветствие выключено.' - -MSG_PIN_ALL_ENABLED = 'Пусть пинят...' -MSG_PIN_ALL_DISABLED = 'Совсем уже распустились, вот мучайтесь теперь 😡' - -MSG_ORDER_CLEARED_BY_DUMMY = 'эта функция перерабатывается в связи с высокой нагрузкой от постоянного обновления' - -MSG_NO_SQUAD = 'Безотрядный тунеядец' - -MSG_CLEARED = 'Выполнено' - -MSG_SQUAD_LIST = 'Список ваших отрядов:' -MSG_SQUAD_REQUEST_EXISTS = 'Вы уже состоите в отряде или подали запрос. Выйдите из текущего отряда или отмените запрос, чтобы создать новый.' -MSG_SQUAD_REQUEST = 'Вот отряды, в которые тебя могут принять:' -MSG_SQUAD_LEAVED = '{} покинул отряд {}, теперь он бесполезен и никто ему больше не поможет.' -MSG_SQUAD_REQUESTED = 'Ты попросился в отряд {}. Чтобы ускорить процесс принятия решения ты можешь пофлудить главам отряда: {}.' -MSG_SQUAD_REQUEST_ACCEPTED = 'Заявка от {} принята.' -MSG_SQUAD_REQUEST_DECLINED = '{} бесполезен и никто ему не поможет.' -MSG_SQUAD_REQUEST_NEW = 'К вам в отряд есть новые заявки.' -MSG_SQUAD_REQUEST_ACCEPTED_ANSWER = 'Вас приняли в отряд.' -MSG_SQUAD_REQUEST_DECLINED_ANSWER = 'Ваша заявка в отряд отклонена.' -MSG_SQUAD_CLEAN = 'Чистка отряда {}.\n' \ - 'Кого сегодня отправим на покой?' -MSG_SQUAD_ADD = '{}, вас хотят в отряд. А вы хотите?' -MSG_SQUAD_ADD_IN_SQUAD = '{} уже в отряде (возможно не в вашем, мне честно лень проверять).' -MSG_SQUAD_ADD_ACCEPTED = '{} принял предложение.' -MSG_SQUAD_ADD_DECLINED = '{} бесполезен и никто ему не поможет.' +MSG_BACK = '🔙Back' + +MSG_ORDER_TO_SQUADS = 'Choose Squad' +MSG_ORDER_ACCEPT = 'Accept!' +MSG_ORDER_PIN = '✅Pin' +MSG_ORDER_NO_PIN = '❌No pin' +MSG_ORDER_BUTTON = '✅Button' +MSG_ORDER_NO_BUTTON = '❌No button' + +MSG_ORDER_CLEARED_BY_HEADER = 'Order accepted by:\n' + +MSG_ORDER_SENT = 'Message is sent' + +MSG_ORDER_CLEARED = 'Recorded, soldier!' + + +MSG_ORDER_CLEARED_ERROR = 'STOP! You do not bellong here!!!!' +MSG_ORDER_SEND_HEADER = 'Where to send?' + +MSG_ORDER_GROUP_CONFIG_HEADER = 'Group settings: {}' +MSG_ORDER_GROUP_NEW = 'Send me the name of a new group of squads' +MSG_ORDER_GROUP_LIST = 'List groups' +MSG_ORDER_GROUP_ADD = '➕Add group' +MSG_ORDER_GROUP_DEL = '🔥🚨Delete group🚨🔥' + +MSG_NEWBIE = """There is a new player in castle!\n +Hurry up to recruit %username%!""" + +MSG_FLAG_CHOOSE_HEADER = 'Choose a flag or send me the order' + +MSG_PROFILE_OLD = 'Your profile smells rotten, forward a new one...' +MSG_PROFILE_SAVED = """Your profile now smells like a really good potato, {}! +Don't forget to water it regularly 🥔 """ +MSG_PROFILE_CASTLE_MISTAKE = """\ +You saw a beautiful potato field not far away from you. +There was just a fence between you. +You decided to walk around and find a way in. +Two hours later you returned to the same place you started at...""" +MSG_PROFILE_SHOW_FORMAT = """\ +👤 %first_name% %last_name% (%username%) of +%castle% %name% +🏅 %prof% %level% level +⚜️ Squad %squad% +⚔️ %attack% | 🛡 %defence% | 🔥 %exp%/%needExp% +💰 %gold% | 🔋 %maxStamina% +%pet% +🕑 Last update %date%""" + +# main.py texts +MSG_MAIN_INLINE_BATTLE = 'ROGER THAT!' +MSG_MAIN_READY_TO_BATTLE = 'The battle is in 10 minutes, 🛡🥔 HOLD DEFENSE HIDE GOLD AND WAIT FOR COMMANDS' +# ----------------------- +MSG_BUILD_REPORT_EXISTS = 'This report already exists!' +MSG_BUILD_REPORT_OK = 'Thanks for the help! This is your {} report.' +MSG_BUILD_REPORT_FORWARDED = 'Do not send me any more reports from alternative accounts !!! ' +MSG_BUILD_REPORT_TOO_OLD = 'This report is very old, I can not accept it.' + +MSG_REPORT_OLD = 'Your report stinks like rotten potato, next time try to send it within a minute after receiving."' +MSG_REPORT_EXISTS = 'The report for this battle has already been submitted.' +MSG_REPORT_OK = 'Thank you. Do not forget to forward reports on every battle.' + +MSG_PROFILE_NOT_FOUND = 'In the potato plantation records, there is still no data about this hero' +MSG_SQUAD_REQUEST_EMPTY = 'At the moment no one wants to join you.' + +MSG_NO_PROFILE_IN_BOT = 'First give me a recent profile!' +MSG_SQUAD_RECRUITING_ENABLED = 'Squad recruiting is enabled!' +MSG_SQUAD_RECRUITING_DISABLED = 'Squad recruiting is disabled!' +MSG_SQUAD_NO_PROFILE = 'First let him give me a recent profile!' +MSG_SQUAD_GREEN_INLINE_BUTTON = '✅Yes' +MSG_SQUAD_RED_INLINE_BUTTON = '❌No' +MSG_SQUAD_NEW = """Now this is the squad {}! +Do not forget to set a link to invite new members.""" +MSG_SQUAD_LINK_SAVED = """Invitation link saved! +New members will not pass by now!""" +MSG_SQUAD_RENAMED = 'Now this squad will be called {}!' +MSG_SQUAD_DELETE = 'The squad is dissolved' +MSG_SQUAD_THORNS_ENABLED = 'The straw man in around, only members can be here' +MSG_SQUAD_THORNS_DISABLED = 'The straw man disappeared, \ +now everyone can see what is happening' +MSG_SQUAD_ALREADY_DELETED = 'This user is already expelled from the squad, this button no longer works=(' +MSG_SQUAD_LEVEL_TOO_LOW = 'This squad takes soldiers at level {} and above. Come back when you get pumped!' + +MSG_TRIGGER_NEW = 'The trigger for the phrase "{}" is set.' +MSG_TRIGGER_GLOBAL = 'Global:\n' +MSG_TRIGGER_LOCAL = '\nLocal:\n' +MSG_TRIGGER_NEW_ERROR = 'You thoughts are not clear, try one more time' +MSG_TRIGGER_EXISTS = 'Trigger "{}" already exists, select another one.' +MSG_TRIGGER_ALL_ENABLED = 'now everything can be triggered.' +MSG_TRIGGER_ALL_DISABLED = 'Now only admins can trigger.' +MSG_TRIGGER_DEL = 'The trigger for "{}" has been deleted.' +MSG_TRIGGER_DEL_ERROR = 'Where did you see such a trigger? 0_o' +MSG_TRIGGER_LIST_HEADER = 'List of current triggers: \n' + +MSG_THORNS = 'This fool {} does not look like a potato, let the straw man kick his ass' + +MSG_WELCOME_DEFAULT = 'Hi, %username%!' +MSG_WELCOME_SET = 'The welcome text is set.' +MSG_WELCOME_ENABLED = 'Welcome enabled' +MSG_WELCOME_DISABLED = 'Welcome disabled' + +MSG_PIN_ALL_ENABLED = 'Anyone can pin' +MSG_PIN_ALL_DISABLED = 'Now only admins can pin😡' + +MSG_ORDER_CLEARED_BY_DUMMY = 'The requested is being is being processed \ +because of high server load due to continuous updates' + +MSG_NO_SQUAD = 'squadless parasite' +MSG_NO_PET = 'No pets' +MSG_WANTS_TO_JOIN = '\n\nWants to join {}' + +MSG_CLEARED = 'Done' + +MSG_SQUAD_LIST = 'List of your squads:' +MSG_SQUAD_REQUEST_EXISTS = 'You are already have requested to enter this squad. \ +Exit the current squad or cancel the request to create a new one. ' +MSG_SQUAD_REQUEST = 'Here are the requests you have receive:' +MSG_SQUAD_LEAVED = '{} left the squad {}, Who cares ?' +MSG_SQUAD_LEAVE_ASK = 'Are you sure you want to leave the squad?' +MSG_SQUAD_LEAVE_DECLINE = 'Have you changed your mind? Well, it is nice, let it remain a secret!' +MSG_SQUAD_REQUESTED = 'You requested to join for the squad {}. \ +To speed up the decision-making process, you can write to the heads of the squad: {}.' +MSG_SQUAD_REQUEST_ACCEPTED = 'The request from {} is accepted.' +MSG_SQUAD_REQUEST_DECLINED = '{} is useless, no one cares.' +MSG_SQUAD_REQUEST_NEW = 'There are new applications for your squad' +MSG_SQUAD_REQUEST_ACCEPTED_ANSWER = 'You were accepted into the squad' +MSG_SQUAD_REQUEST_DECLINED_ANSWER = 'You application was rejected' +MSG_SQUAD_CLEAN = """Harvesting in the squad {}. +Guess who is going to have a rest later today? """ +MSG_SQUAD_ADD = '{}, Do you want to join the squad?' +MSG_SQUAD_ADD_IN_SQUAD = '{} is already in a squad (perhaps not yours)' +MSG_SQUAD_ADD_ACCEPTED = '{} Accepted the offer' +MSG_SQUAD_ADD_DECLINED = '{} declined, who cares?' +MSG_SQUAD_NONE = 'It looks like you are not in a squad' + +MSG_SQUAD_READY = '{} warriors of {} are ready to battle!\n{}⚔ {}🛡' +MSG_FULL_TEXT_LINE = '{}: {}👥 {}⚔ {}🛡\n' +MSG_FULL_TEXT_TOTAL = '\nTotal: {}👥 {}⚔ {}🛡' + +MSG_IN_DEV = 'Under construction=(' + +MSG_TOP_ABOUT = '🏆 Tops 🏆' +MSG_STATISTICS_ABOUT = '📈Statistics📈' +MSG_SQUAD_ABOUT = '⚜Squad⚜' + +MSG_TOP_FORMAT = '{}. {} ({}🌟) - {}{}\n' +MSG_SQUAD_TOP_FORMAT = '{}. {} ({}👥) - {}{} ({}{}/👤)\n' +MSG_TOP_DEFENCE = '🛡Top Defenders:\n' +MSG_TOP_ATTACK = '⚔Тop attackers:\n' +MSG_TOP_EXPERIENCE = '🔥Top XP:\n' +MSG_TOP_GLOBAL_BUILDERS = '⚒Top Builders:\n' +MSG_TOP_WEEK_BUILDERS = '👷Top builders of the week:\n' +MSG_TOP_WEEK_WARRIORS = '⛳️Top in the battle:\n' + +MSG_UPDATE_PROFILE = 'Send me a new profile (🏅 command "/hero"), or you might be kicked of .' +MSG_SQUAD_DELETE_OUTDATED = 'You were kicked from the squad for not updating your profile for a long time.' +MSG_SQUAD_DELETE_OUTDATED_EXT = '{} (@{}) was kicked from {} for not updating profile for a long time.' + +MSG_ALREADY_BANNED = 'This user is already banned. The reason is: {2}.' +MSG_USER_BANNED = 'A member of {} violated the rules and was kicked!' +MSG_YOU_BANNED = 'You were banned because: {}' +MSG_BAN_COMPLETE = 'Warrior successfully banned' +MSG_USER_NOT_BANNED = 'This warrior is not banned' +MSG_USER_UNBANNED = '{} is no longer banned.' +MSG_YOU_UNBANNED = 'We can talk again 🌚' + +PLOT_X_LABEL = 'Date' +PLOT_Y_LABEL = 'XP' + +MSG_DAY_SINGLE = 'Day' +MSG_DAY_PLURAL1 = 'Day' +MSG_DAY_PLURAL2 = 'Days' +MSG_DATE_FORMAT = '{} {}' +MSG_PLOT_DESCRIPTION = 'On average {} of experience per day. For next level, you need {} experience and {}' + +MSG_SQUAD_CALL_HEADER = 'Everybody come here!\n' +MSG_REPORT_SUMMARY_HEADER = 'Reports of the squad {} for the batle {}\n' \ + 'Reports: {} from {}\n' \ + 'General\n' \ + 'Attack: ⚔{}\n' \ + 'Defense: 🛡{}\n' \ + 'Profit: 🔥{} 💰{} 📦{}\n\n' \ + 'Personal\n' +MSG_REPORT_SUMMARY_ROW = '{} (@{})\n⚔{} 🛡{} 🔥{} 💰{} 📦{}\n' +MSG_REPORT_SUMMARY_ROW_EMPTY = '{} (@{}) ❗\n' + +BTN_HERO = '🏅Hero' +BTN_STOCK = '📦Stock' +BTN_EQUIPMENT = '🎽Equipment' + +BTN_YES = '✅YES' +BTN_NO = '❌NO' + +BTN_LEAVE = 'Leave' + +BTN_ACCEPT = '✅Accept' +BTN_DECLINE = '❌Decline' + +BTN_WEEK = "Week" +BTN_ALL_TIME = "All Time" +BTN_SQUAD_WEEK = "Squads per Week" +BTN_SQUAD_ALL_TIME = "Squads of all time" + +MSG_LAST_UPDATE = '🕑 Last Update' +MSG_GO_AWAY = 'Go Away!' +MSG_TOP_GENERATING = 'Generating Top' + +MSG_NO_REASON = 'Reason not specified' diff --git a/core/types.py b/core/types.py index 71be4f1..15acfbb 100644 --- a/core/types.py +++ b/core/types.py @@ -1,19 +1,20 @@ # -*- coding: utf-8 -*- -from sqlalchemy import create_engine -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import Column, Integer, DateTime, Boolean, ForeignKey, UnicodeText, BigInteger +from datetime import datetime +from enum import Enum +import logging + +from sqlalchemy import ( + create_engine, + Column, Integer, DateTime, Boolean, ForeignKey, UnicodeText, BigInteger, Text +) from sqlalchemy.dialects.mysql import DATETIME -from datetime import datetime, timedelta +from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship, scoped_session -from sqlalchemy import event -from sqlalchemy.pool import Pool -import logging -from enum import Enum +from sqlalchemy.exc import SQLAlchemyError + +from telegram import Bot + from config import DB -import requests -from json import loads -from core.enums import Castle -import threading class AdminType(Enum): @@ -21,6 +22,12 @@ class AdminType(Enum): FULL = 1 GROUP = 2 + '''Дополнительные группы. Не используйте их в параметре adm_type!!!''' + WARLORD = 10 + SQUAD_CONTROLLER = 11 + + NOT_ADMIN = 100 + class MessageType(Enum): TEXT = 0 @@ -35,26 +42,22 @@ class MessageType(Enum): PHOTO = 9 -engine = create_engine(DB, echo=False, pool_size=200, max_overflow=50, isolation_level="READ UNCOMMITTED") -logger = logging.getLogger('sqlalchemy.engine') -Base = declarative_base() -Session = scoped_session(sessionmaker(bind=engine)) -last_update = datetime.now() - timedelta(minutes=10) - +ENGINE = create_engine(DB, + echo=False, + pool_size=200, + max_overflow=50, + isolation_level="READ UNCOMMITTED") -@event.listens_for(Pool, "connect") -def set_unicode(dbapi_conn, conn_record): - cursor = dbapi_conn.cursor() - try: - cursor.execute("SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'") - except Exception as e: - logger.error(e) +# FIX: имена констант? +LOGGER = logging.getLogger('sqlalchemy.engine') +Base = declarative_base() +Session = scoped_session(sessionmaker(bind=ENGINE)) class Group(Base): __tablename__ = 'groups' - id = Column(BigInteger, primary_key=True) + id = Column(BigInteger, primary_key=True) # FIX: invalid name username = Column(UnicodeText(250)) title = Column(UnicodeText(250)) welcome_enabled = Column(Boolean, default=False) @@ -76,11 +79,30 @@ class User(Base): last_name = Column(UnicodeText(250)) date_added = Column(DateTime, default=datetime.now()) - character = relationship('Character', back_populates='user', order_by='Character.date.desc()', uselist=False) + character = relationship('Character', + back_populates='user', + order_by='Character.date.desc()', + uselist=False) + orders_confirmed = relationship('OrderCleared', back_populates='user') member = relationship('SquadMember', back_populates='user', uselist=False) - equip = relationship('Equip', back_populates='user', order_by='Equip.date.desc()', uselist=False) - stock = relationship('Stock', back_populates='user', order_by='Stock.date.desc()', uselist=False) + equip = relationship('Equip', + back_populates='user', + order_by='Equip.date.desc()', + uselist=False) + + stock = relationship('Stock', + back_populates='user', + order_by='Stock.date.desc()', + uselist=False) + + report = relationship('Report', + back_populates='user', + order_by='Report.date.desc()') + + build_report = relationship('BuildReport', + back_populates='user', + order_by='BuildReport.date.desc()') def __repr__(self): user = '' @@ -209,6 +231,35 @@ class Character(Base): user = relationship('User', back_populates='character') +class BuildReport(Base): + __tablename__ = 'build_reports' + + user_id = Column(BigInteger, ForeignKey(User.id), primary_key=True) + date = Column(DATETIME(fsp=6), primary_key=True) + building = Column(UnicodeText(250)) + progress_percent = Column(Integer) + report_type = Column(Integer) + + user = relationship('User', back_populates='build_report') + + +class Report(Base): + __tablename__ = 'reports' + + user_id = Column(BigInteger, ForeignKey(User.id), primary_key=True) + date = Column(DATETIME(fsp=6), primary_key=True) + name = Column(UnicodeText(250)) + level = Column(Integer) + attack = Column(Integer) + defence = Column(Integer) + castle = Column(UnicodeText(100)) + earned_exp = Column(Integer) + earned_gold = Column(Integer) + earned_stock = Column(Integer) + + user = relationship('User', back_populates='report') + + class Squad(Base): __tablename__ = 'squads' @@ -254,31 +305,102 @@ class LocalTrigger(Base): message_type = Column(Integer, default=0) -def admin(adm_type=AdminType.FULL): +class Ban(Base): + __tablename__ = 'banned_users' + + user_id = Column(BigInteger, ForeignKey(User.id), primary_key=True) + reason = Column(UnicodeText(2500)) + from_date = Column(DATETIME(fsp=6)) + to_date = Column(DATETIME(fsp=6)) + + +class Log(Base): + __tablename__ = 'log' + + id = Column(BigInteger, autoincrement=True, primary_key=True) + user_id = Column(BigInteger, ForeignKey(User.id)) + chat_id = Column(BigInteger) + date = Column(DATETIME(fsp=6)) + func_name = Column(UnicodeText(2500)) + args = Column(UnicodeText(2500)) + + +class Auth(Base): + __tablename__ = 'auth' + + id = Column(Text(length=32)) + user_id = Column(BigInteger, ForeignKey(User.id), primary_key=True) + + +def check_admin(update, session, adm_type, allowed_types=()): + allowed = False + if adm_type == AdminType.NOT_ADMIN: + allowed = True + else: + admins = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() + for adm in admins: + if (AdminType(adm.admin_type) in allowed_types or adm.admin_type <= adm_type.value) and \ + (adm.admin_group in [0, update.message.chat.id] or + update.message.chat.id == update.message.from_user.id): + if adm.admin_group != 0: + group = session.query(Group).filter_by(id=adm.admin_group).first() + if group and group.bot_in_group: + allowed = True + break + else: + allowed = True + break + return allowed + + +def check_ban(update, session): + ban = session.query(Ban).filter_by(user_id=update.message.from_user.id + if update.message else update.callback_query.from_user.id).first() + if ban is None or ban.to_date < datetime.now(): + return True + else: + return False + + +def log(session, user_id, chat_id, func_name, args): + log_item = Log() + log_item.date = datetime.now() + log_item.user_id = user_id + log_item.chat_id = chat_id + log_item.func_name = func_name + log_item.args = args + session.add(log_item) + session.commit() + + +def admin_allowed(adm_type=AdminType.FULL, ban_enable=True, allowed_types=()): def decorate(func): - def wrapper(bot, update, *args, **kwargs): + def wrapper(bot: Bot, update, *args, **kwargs): session = Session() try: - adms = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() - allowed = False - for adm in adms: - if adm is not None and adm.admin_type <= adm_type.value and \ - (adm.admin_group in [0, update.message.chat.id] or - update.message.chat.id == update.message.from_user.id): - if adm.admin_group != 0: - group = session.query(Group).filter_by(id=adm.admin_group).first() - if group and group.bot_in_group: - allowed = True - break - else: - allowed = True - break + allowed = check_admin(update, session, adm_type, allowed_types) + if ban_enable: + allowed &= check_ban(update, session) if allowed: - func(bot, update, *args, **kwargs) - except Exception as e: + if func.__name__ not in ['manage_all', 'trigger_show', 'user_panel', 'wrapper']: + log(session, update.effective_user.id, update.effective_chat.id, func.__name__, + update.message.text if update.message else None or + update.callback_query.data if update.callback_query else None) + func(bot, update, session, *args, **kwargs) + except SQLAlchemyError as err: + bot.logger.error(str(err)) session.rollback() return wrapper return decorate -Base.metadata.create_all(engine) +def user_allowed(ban_enable=True): + if callable(ban_enable): + return admin_allowed(AdminType.NOT_ADMIN)(ban_enable) + else: + def wrap(func): + return admin_allowed(AdminType.NOT_ADMIN, ban_enable)(func) + return wrap + + +Base.metadata.create_all(ENGINE) diff --git a/core/utils.py b/core/utils.py index c9a8cdd..a4ba5b6 100644 --- a/core/utils.py +++ b/core/utils.py @@ -1,89 +1,74 @@ +import http.client + from telegram import Bot +from telegram.error import TelegramError from telegram.ext.dispatcher import run_async + from core.types import Session, User, Group -from telegram.error import ChatMigrated @run_async def send_async(bot: Bot, *args, **kwargs): try: return bot.sendMessage(*args, **kwargs) - except ChatMigrated as e: + + except TelegramError as err: + bot.logger.error(err.message) session = Session() group = session.query(Group).filter_by(id=kwargs['chat_id']).first() if group is not None: group.bot_in_group = False session.add(group) session.commit() - kwargs['chat_id'] = e.new_chat_id - return bot.sendMessage(*args, **kwargs) - except Exception as e: - print(e) + return None -def send_pin_async(bot: Bot, *args, **kwargs): - try: - msg = bot.sendMessage(*args, **kwargs) - except ChatMigrated as e: - kwargs['chat_id'] = e.new_chat_id - msg = bot.sendMessage(*args, **kwargs) - import http.client - conn = http.client.HTTPConnection("127.0.0.1") - conn.request("GET", "/{}/{}/".format(msg.message_id, msg.chat.id)) +def add_user(tg_user, session): + user = session.query(User).filter_by(id=tg_user.id).first() + if user is None: + user = User(id=tg_user.id, username=tg_user.username or '', + first_name=tg_user.first_name or '', + last_name=tg_user.last_name or '') + session.add(user) + else: + updated = False + if user.username != tg_user.username: + user.username = tg_user.username + updated = True + if user.first_name != tg_user.first_name: + user.first_name = tg_user.first_name + updated = True + if user.last_name != tg_user.last_name: + user.last_name = tg_user.last_name + updated = True + if updated: + session.add(user) + session.commit() + return user -def add_user(tg_user): - session = Session() - try: - user = session.query(User).filter_by(id=tg_user.id).first() - if user is None: - user = User(id=tg_user.id, username=tg_user.username or '', - first_name=tg_user.first_name or '', - last_name=tg_user.last_name or '') - session.add(user) +def update_group(grp, session): + if grp.type in ['group', 'supergroup', 'channel']: + group = session.query(Group).filter_by(id=grp.id).first() + if group is None: + group = Group(id=grp.id, title=grp.title, + username=grp.username) + session.add(group) + else: updated = False - if user.username != tg_user.username: - user.username = tg_user.username + if group.username != grp.username: + group.username = grp.username updated = True - if user.first_name != tg_user.first_name: - user.first_name = tg_user.first_name + if group.title != grp.title: + group.title = grp.title updated = True - if user.last_name != tg_user.last_name: - user.last_name = tg_user.last_name + if not group.bot_in_group: + group.bot_in_group = True updated = True if updated: - session.add(user) - session.commit() - return user - except Exception as e: - session.rollback() - - -def update_group(grp): - session = Session() - try: - if grp.type in ['group', 'supergroup', 'channel']: - group = session.query(Group).filter_by(id=grp.id).first() - if group is None: - group = Group(id=grp.id, title=grp.title, - username=grp.username) session.add(group) - else: - updated = False - if group.username != grp.username: - group.username = grp.username - updated = True - if group.title != grp.title: - group.title = grp.title - updated = True - if not group.bot_in_group: - group.bot_in_group = True - updated = True - if updated: - session.add(group) - session.commit() - return group - return None - except Exception as e: - session.rollback() + + session.commit() + return group + return None diff --git a/main.py b/main.py index 9c234a5..e733865 100644 --- a/main.py +++ b/main.py @@ -1,195 +1,331 @@ # -*- coding: utf-8 -*- + +from datetime import datetime, time, timedelta import json import logging -from threading import Thread +import re -from telegram import Bot, Update, InlineKeyboardButton, InlineKeyboardMarkup, ParseMode -from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackQueryHandler, JobQueue +from sqlalchemy import func, tuple_ +from telegram import ( + Bot, Update, InlineKeyboardButton, InlineKeyboardMarkup, ParseMode +) +from telegram.ext import ( + Updater, CommandHandler, MessageHandler, + Filters, CallbackQueryHandler +) from telegram.ext.dispatcher import run_async +from telegram.error import TelegramError -from core.functions.bosses import boss_leader, boss_zhalo, boss_monoeye, boss_hydra -from core.functions.orders import order, orders, MSG_ORDER_ACCEPT -from core.functions.admins import list_admins, admins_for_users, set_admin, del_admin, set_global_admin, \ - set_super_admin, del_global_admin -from core.functions.common import help_msg, ping, start, error, kick, admin_panel, stock_compare, trade_compare, \ - check_bot_in_chats, delete_msg, delete_user -from core.functions.inline_keyboard_handling import callback_query, send_status, generate_ok_markup, send_order, \ - QueryType -from core.functions.pin import pin, not_pin_all, pin_all, silent_pin -from core.functions.triggers import set_trigger, add_trigger, del_trigger, list_triggers, enable_trigger_all, \ - disable_trigger_all, trigger_show, set_global_trigger, add_global_trigger, del_global_trigger -from core.functions.welcome import welcome, set_welcome, show_welcome, enable_welcome, disable_welcome +from config import TOKEN, GOVERNMENT_CHAT, CASTLE +from core.chat_commands import CC_SET_WELCOME, CC_HELP, CC_SQUAD, CC_SHOW_WELCOME, CC_TURN_ON_WELCOME, \ + CC_TURN_OFF_WELCOME, CC_SET_TRIGGER, CC_UNSET_TRIGGER, CC_TRIGGER_LIST, CC_ADMIN_LIST, CC_PING, CC_DAY_STATISTICS, \ + CC_WEEK_STATISTICS, CC_BATTLE_STATISTICS, CC_ALLOW_TRIGGER_ALL, CC_DISALLOW_TRIGGER_ALL, CC_ADMINS, \ + CC_ALLOW_PIN_ALL, CC_DISALLOW_PIN_ALL, CC_BOSS_1, CC_BOSS_2, CC_BOSS_3, CC_BOSS_4, CC_OPEN_HIRING, CC_CLOSE_HIRING, \ + CC_PIN, CC_SILENT_PIN, CC_DELETE, CC_KICK +from core.commands import ADMIN_COMMAND_STATUS, ADMIN_COMMAND_RECRUIT, ADMIN_COMMAND_ORDER, ADMIN_COMMAND_SQUAD_LIST, \ + ADMIN_COMMAND_GROUPS, ADMIN_COMMAND_FIRE_UP, USER_COMMAND_ME, USER_COMMAND_BUILD, USER_COMMAND_CONTACTS, \ + USER_COMMAND_SQUAD, USER_COMMAND_STATISTICS, USER_COMMAND_TOP, USER_COMMAND_SQUAD_REQUEST, USER_COMMAND_BACK, \ + TOP_COMMAND_ATTACK, TOP_COMMAND_DEFENCE, TOP_COMMAND_EXP, STATISTICS_COMMAND_EXP, USER_COMMAND_SQUAD_LEAVE, \ + ADMIN_COMMAND_REPORTS, ADMIN_COMMAND_ADMINPANEL, TOP_COMMAND_BUILD, \ + TOP_COMMAND_BATTLES +from core.constants import DAYS_PROFILE_REMIND, DAYS_OLD_PROFILE_KICK +from core.functions.activity import ( + day_activity, week_activity, battle_activity +) +from core.functions.admins import ( + list_admins, admins_for_users, set_admin, del_admin, + set_global_admin, set_super_admin, del_global_admin +) +from core.functions.ban import unban, ban +from core.functions.bosses import ( + boss_leader, boss_zhalo, boss_monoeye, boss_hydra) +from core.functions.orders import order, orders + +from core.functions.common import ( + help_msg, ping, start, error, kick, + admin_panel, stock_compare, trade_compare, + delete_msg, delete_user, + user_panel, web_auth) +from core.functions.inline_keyboard_handling import ( + callback_query, send_status, send_order +) +from core.functions.inline_markup import QueryType from core.functions.order_groups import group_list, add_group -from core.types import Session, Group, Order, Squad, Admin +from core.functions.pin import pin, not_pin_all, pin_all, silent_pin +from core.functions.profile import char_update, char_show, find_by_username, report_received, build_report_received, \ + repair_report_received +from core.functions.squad import ( + add_squad, del_squad, set_invite_link, set_squad_name, + enable_thorns, disable_thorns, + squad_list, squad_request, list_squad_requests, + open_hiring, close_hiring, remove_from_squad, add_to_squad, + leave_squad_request, squad_about, call_squad, battle_reports_show) +from core.functions.statistics import statistic_about, exp_statistic +from core.functions.top import top_about, attack_top, exp_top, def_top, global_build_top, week_build_top, \ + week_battle_top +from core.functions.triggers import ( + set_trigger, add_trigger, del_trigger, list_triggers, enable_trigger_all, + disable_trigger_all, trigger_show, + set_global_trigger, add_global_trigger, del_global_trigger +) +from core.functions.welcome import ( + welcome, set_welcome, show_welcome, enable_welcome, disable_welcome +) +from core.regexp import PROFILE, HERO, REPORT, BUILD_REPORT, REPAIR_REPORT, STOCK, TRADE_BOT +from core.texts import ( + MSG_SQUAD_READY, MSG_FULL_TEXT_LINE, MSG_FULL_TEXT_TOTAL, + MSG_MAIN_INLINE_BATTLE, MSG_MAIN_READY_TO_BATTLE, MSG_IN_DEV, MSG_UPDATE_PROFILE, MSG_SQUAD_DELETE_OUTDATED, + MSG_SQUAD_DELETE_OUTDATED_EXT) +from core.types import Session, Order, Squad, Admin, user_allowed, Character, SquadMember, User from core.utils import add_user, send_async -from config import TOKEN, API_PORT, GOVERNMENT_CHAT -from core.regexp import profile, hero -import re -from core.functions.profile import char_update, char_show, find_by_username -from core.functions.squad import add_squad, del_squad, set_invite_link, set_squad_name, enable_thorns, disable_thorns, \ - squad_list, squad_request, list_squad_requests, open_hiring, close_hiring, remove_from_squad, add_to_squad -from core.functions.activity import day_activity, week_activity, battle_activity -from datetime import datetime, time -from core.functions.api import app -last_welcome = 0 -logging.basicConfig(level=logging.WARNING, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +from sqlalchemy.exc import SQLAlchemyError + +# -----constants---- +CWBOT_ID = 408101137 +TRADEBOT_ID = 278525885 +# ------------------- + +logging.basicConfig( + level=logging.WARNING, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) def battle_time(): + """ Определяет, наступило ли время битвы """ now = datetime.now().time() - _BATTLE_TIME = [[time(7, 57), time(8, 0)], - [time(11, 57), time(12, 0)], - [time(15, 57), time(16, 0)], - [time(19, 57), time(20, 0)], - [time(23, 57), time(0, 0)]] - for time_start, time_end in _BATTLE_TIME: - if time_start <= time_end and time_start <= now <= time_end or \ - not time_start <= time_end and (time_start <= now or now <= time_end): - return True + if (now.hour + 1) % 4 == 3 and now.minute >= 57: + return True return False def del_msg(bot, job): - bot.delete_message(job.context[0], job.context[1]) + try: + bot.delete_message(job.context[0], job.context[1]) + except TelegramError: + pass @run_async -def manage_all(bot: Bot, update: Update, chat_data, job_queue): - try: - add_user(update.message.from_user) - if update.message.chat.type in ['group', 'supergroup', 'channel']: - session = Session() - squad = session.query(Squad).filter_by(chat_id=update.message.chat.id).first() - admin = session.query(Admin).filter(Admin.user_id == update.message.from_user.id and - Admin.admin_group in [update.message.chat.id, 0]).first() - if squad is not None and admin is None and battle_time(): - bot.delete_message(update.message.chat.id, update.message.message_id) - if update.message.text and update.message.text.upper().startswith('Приветствие:'.upper()): - set_welcome(bot, update) - elif update.message.text and 'Твои результаты в бою:' in update.message.text and \ - update.message.forward_from and update.message.forward_from.id == 265204902: - job_queue.run_once(del_msg, 2, (update.message.chat.id, update.message.message_id)) - elif update.message.text and update.message.text.upper() == 'Помощь'.upper(): - help_msg(bot, update) - elif update.message.text and update.message.text.upper() == 'Покажи приветствие'.upper(): - show_welcome(bot, update) - elif update.message.text and update.message.text.upper() == 'Включи приветствие'.upper(): - enable_welcome(bot, update) - elif update.message.text and update.message.text.upper() == 'Выключи приветствие'.upper(): - disable_welcome(bot, update) - elif update.message.text and update.message.text.upper().startswith('Затриггерь:'.upper()): - set_trigger(bot, update) - elif update.message.text and update.message.text.upper().startswith('Разтриггерь:'.upper()): - del_trigger(bot, update) - elif update.message.text and update.message.text.upper() == 'Список триггеров'.upper(): - list_triggers(bot, update) - elif update.message.text and update.message.text.upper() == 'Список админов'.upper(): - list_admins(bot, update) - elif update.message.text and update.message.text.upper() == 'Пинг'.upper(): - ping(bot, update) - elif update.message.text and update.message.text.upper() == 'Статистика за день'.upper(): - day_activity(bot, update) - elif update.message.text and update.message.text.upper() == 'Статистика за неделю'.upper(): - week_activity(bot, update) - elif update.message.text and update.message.text.upper() == 'Статистика за бой'.upper(): - battle_activity(bot, update) - elif update.message.text and update.message.text.upper() == 'Разрешить триггерить всем'.upper(): - enable_trigger_all(bot, update) - elif update.message.text and update.message.text.upper() == 'Запретить триггерить всем'.upper(): - disable_trigger_all(bot, update) - elif update.message.text and update.message.text.upper() in ['Админы'.upper(), 'офицер'.upper()]: - admins_for_users(bot, update) - elif update.message.text and update.message.text.upper() == 'Пинят все'.upper(): - pin_all(bot, update) - elif update.message.text and update.message.text.upper() == 'Хорош пинить'.upper(): - not_pin_all(bot, update) - elif update.message.text and update.message.text.upper() == 'Пин'.upper() and update.message.reply_to_message is not None: +@user_allowed +def manage_all(bot: Bot, update: Update, session, chat_data, job_queue): + add_user(update.message.from_user, session) + if update.message.chat.type in ['group', 'supergroup', 'channel']: + squad = session.query(Squad).filter_by( + chat_id=update.message.chat.id).first() + admin = session.query(Admin).filter( + Admin.user_id == update.message.from_user.id and + Admin.admin_group in [update.message.chat.id, 0]).first() + + if squad is not None and admin is None and battle_time(): + bot.delete_message(update.message.chat.id, + update.message.message_id) + + if not update.message.text: + return + + text = update.message.text.lower() + + if text.startswith(CC_SET_WELCOME): + set_welcome(bot, update) + elif text == CC_HELP: + help_msg(bot, update) + elif text == CC_SQUAD: + call_squad(bot, update) + elif text == CC_SHOW_WELCOME: + show_welcome(bot, update) + elif text == CC_TURN_ON_WELCOME: + enable_welcome(bot, update) + elif text == CC_TURN_OFF_WELCOME: + disable_welcome(bot, update) + elif text.startswith(CC_SET_TRIGGER): + set_trigger(bot, update) + elif text.startswith(CC_UNSET_TRIGGER): + del_trigger(bot, update) + elif text == CC_TRIGGER_LIST: + list_triggers(bot, update) + elif text == CC_ADMIN_LIST: + list_admins(bot, update) + elif text == CC_PING: + ping(bot, update) + elif text == CC_DAY_STATISTICS: + day_activity(bot, update) + elif text == CC_WEEK_STATISTICS: + week_activity(bot, update) + elif text == CC_BATTLE_STATISTICS: + battle_activity(bot, update) + elif text == CC_ALLOW_TRIGGER_ALL: + enable_trigger_all(bot, update) + elif text == CC_DISALLOW_TRIGGER_ALL: + disable_trigger_all(bot, update) + elif text in CC_ADMINS: + admins_for_users(bot, update) + elif text == CC_ALLOW_PIN_ALL: + pin_all(bot, update) + elif text == CC_DISALLOW_PIN_ALL: + not_pin_all(bot, update) + elif text in CC_BOSS_1: + boss_leader(bot, update) + elif text in CC_BOSS_2: + boss_zhalo(bot, update) + elif text in CC_BOSS_3: + boss_monoeye(bot, update) + elif text in CC_BOSS_4: + boss_hydra(bot, update) + elif text == CC_OPEN_HIRING: + open_hiring(bot, update) + elif text == CC_CLOSE_HIRING: + close_hiring(bot, update) + elif update.message.reply_to_message is not None: + if text == CC_PIN: pin(bot, update) - elif update.message.text and update.message.text.upper() == 'сайлентпин'.upper() and update.message.reply_to_message is not None: + elif text == CC_SILENT_PIN: silent_pin(bot, update) - elif update.message.text and update.message.text.upper() in ['бандит'.upper(), 'краб'.upper()]: - boss_leader(bot, update) - elif update.message.text and update.message.text.upper() in ['жало'.upper(), 'королева роя'.upper()]: - boss_zhalo(bot, update) - elif update.message.text and update.message.text.upper() in ['циклоп'.upper(), 'борода'.upper()]: - boss_monoeye(bot, update) - elif update.message.text and update.message.text.upper() in ['гидра'.upper(), 'лич'.upper()]: - boss_hydra(bot, update) - elif update.message.text and update.message.text.upper() == 'открыть набор'.upper(): - open_hiring(bot, update) - elif update.message.text and update.message.text.upper() == 'закрыть набор'.upper(): - close_hiring(bot, update) - elif update.message.text and update.message.text.upper() == 'удоли'.upper() and update.message.reply_to_message is not None: + elif text == CC_DELETE: delete_msg(bot, update) - elif update.message.text and update.message.text.upper() == 'свали'.upper() and update.message.reply_to_message is not None: + elif text == CC_KICK: delete_user(bot, update) - elif update.message.text: + else: trigger_show(bot, update) - elif update.message.chat.type == 'private': - if update.message.text and update.message.text.upper() == 'Статус'.upper(): + elif re.search(REPORT, update.message.text): + if update.message.forward_from.id == CWBOT_ID: + report_received(bot, update) + else: + trigger_show(bot, update) + + elif update.message.chat.type == 'private': + admin = session.query(Admin).filter_by(user_id=update.message.from_user.id).all() + is_admin = False + for _ in admin: + is_admin = True + break + + if 'order_wait' in chat_data and chat_data['order_wait']: + order(bot, update, chat_data) + + elif update.message.text: + text = update.message.text.lower() + + if text == ADMIN_COMMAND_STATUS.lower(): send_status(bot, update) - elif update.message.text and update.message.text.upper() == 'хочу в отряд'.upper(): + elif text == USER_COMMAND_BACK.lower(): + user_panel(bot, update) + elif text == USER_COMMAND_SQUAD_REQUEST.lower(): squad_request(bot, update) - elif update.message.text and update.message.text.upper() == 'заявки в отряд'.upper(): + elif text == ADMIN_COMMAND_RECRUIT.lower(): list_squad_requests(bot, update) - elif update.message.text and update.message.text.upper() in ['Приказы'.upper(), 'пин'.upper()]: + elif text == ADMIN_COMMAND_ORDER.lower(): orders(bot, update, chat_data) - elif update.message.text and update.message.text.upper() in ['список отряда'.upper(), 'список'.upper()]: - Thread(target=squad_list, args=(bot, update)).start() - elif update.message.text and update.message.text.upper() == 'Группы'.upper(): + elif text == ADMIN_COMMAND_SQUAD_LIST.lower(): + squad_list(bot, update) + elif text == ADMIN_COMMAND_GROUPS.lower(): group_list(bot, update) - elif update.message.text and update.message.text.upper() == 'чистка отряда'.upper(): + elif text == ADMIN_COMMAND_REPORTS.lower(): + battle_reports_show(bot, update) + elif text == ADMIN_COMMAND_FIRE_UP.lower(): remove_from_squad(bot, update) - elif update.message.forward_from and update.message.forward_from.id == 265204902 and \ - update.message.text.startswith('📦Содержимое склада'): - stock_compare(bot, update, chat_data) - elif update.message.forward_from and update.message.forward_from.id == 278525885 and \ - '📦Твой склад с материалами:' in update.message.text: - trade_compare(bot, update, chat_data) + elif text == USER_COMMAND_ME.lower(): + char_show(bot, update) + elif text == USER_COMMAND_TOP.lower(): + top_about(bot, update) + elif text == TOP_COMMAND_ATTACK.lower(): + attack_top(bot, update) + elif text == TOP_COMMAND_DEFENCE.lower(): + def_top(bot, update) + elif text == TOP_COMMAND_EXP.lower(): + exp_top(bot, update) + elif text == TOP_COMMAND_BUILD.lower(): + week_build_top(bot, update) + elif text == TOP_COMMAND_BATTLES.lower(): + week_battle_top(bot, update) + elif text == USER_COMMAND_BUILD.lower(): + send_async(bot, + chat_id=update.message.chat.id, + text=MSG_IN_DEV, + parse_mode=ParseMode.HTML) + elif text == USER_COMMAND_STATISTICS.lower(): + statistic_about(bot, update) + elif text == STATISTICS_COMMAND_EXP.lower(): + exp_statistic(bot, update) + elif text == USER_COMMAND_SQUAD.lower(): + squad_about(bot, update) + elif text == USER_COMMAND_SQUAD_LEAVE.lower(): + leave_squad_request(bot, update) + elif text == USER_COMMAND_CONTACTS.lower(): + web_auth(bot, update) + elif text == ADMIN_COMMAND_ADMINPANEL.lower(): + admin_panel(bot, update) elif 'wait_group_name' in chat_data and chat_data['wait_group_name']: add_group(bot, update, chat_data) - elif update.message.text and update.message.forward_from and update.message.forward_from.id == 265204902 and \ - (re.search(profile, update.message.text) or re.search(hero, update.message.text)): - char_update(bot, update) + + elif update.message.forward_from: + from_id = update.message.forward_from.id + + if from_id == CWBOT_ID: + if text.startswith(STOCK): + stock_compare(bot, update, chat_data) + elif re.search(PROFILE, update.message.text) or re.search(HERO, update.message.text): + char_update(bot, update) + elif re.search(REPORT, update.message.text): + report_received(bot, update) + elif re.search(BUILD_REPORT, update.message.text): + build_report_received(bot, update) + elif re.search(REPAIR_REPORT, update.message.text): + repair_report_received(bot, update) + elif from_id == TRADEBOT_ID: + if TRADE_BOT in text: + trade_compare(bot, update, chat_data) + elif not is_admin: + user_panel(bot, update) else: order(bot, update, chat_data) - except Exception as e: - Session.rollback() + elif not is_admin: + user_panel(bot, update) + else: + order(bot, update, chat_data) @run_async -def ready_to_battle(bot, job_queue): +def ready_to_battle(bot: Bot, job_queue): session = Session() try: group = session.query(Squad).all() for item in group: - if item.chat_id == -1001062678288: - continue - order = Order() - order.text = 'К битве готовсь!' - order.chat_id = item.chat_id - order.date = datetime.now() - order.confirmed_msg = 0 - session.add(order) + new_order = Order() + new_order.text = MSG_MAIN_READY_TO_BATTLE + new_order.chat_id = item.chat_id + new_order.date = datetime.now() + new_order.confirmed_msg = 0 + session.add(new_order) session.commit() - markup = InlineKeyboardMarkup([[InlineKeyboardButton('ГРАБЬНАСИЛУЙУБИВАЙ!', - callback_data=json.dumps({'t': QueryType.OrderOk.value, 'id': order.id}))]]) - msg = send_order(bot, order.text, 0, order.chat_id, markup) + + callback_data = json.dumps( + {'t': QueryType.OrderOk.value, 'id': new_order.id}) + markup = InlineKeyboardMarkup([ + [InlineKeyboardButton(MSG_MAIN_INLINE_BATTLE, + callback_data=callback_data)]]) + + msg = send_order(bot, new_order.text, 0, new_order.chat_id, markup) + try: msg = msg.result().result() - bot.request.post(bot.base_url + '/pinChatMessage', - {'chat_id': order.chat_id, 'message_id': msg.message_id, - 'disable_notification': False}) - except Exception as e: - print(e) - except Exception as e: + if msg is not None: + bot.request.post(bot.base_url + '/pinChatMessage', + {'chat_id': new_order.chat_id, + 'message_id': msg.message_id, + 'disable_notification': False}) + + except TelegramError as err: + bot.logger.error(err.message) + + except SQLAlchemyError as err: + bot.logger.error(str(err)) Session.rollback() @run_async -def ready_to_battle_result(bot, job_queue): +def ready_to_battle_result(bot: Bot, job_queue): session = Session() try: group = session.query(Squad).all() @@ -197,93 +333,184 @@ def ready_to_battle_result(bot, job_queue): full_defence = 0 full_text = '' full_count = 0 + for item in group: - order = session.query(Order).filter_by(chat_id=item.chat_id, text='К битве готовсь!').order_by(Order.date.desc()).first() - if order is not None: + ready_order = session.query(Order).filter_by( + chat_id=item.chat_id, + text=MSG_MAIN_READY_TO_BATTLE).order_by(Order.date.desc()).first() + + if ready_order is not None: attack = 0 defence = 0 - for clear in order.cleared: + for clear in ready_order.cleared: if clear.user.character: attack += clear.user.character.attack defence += clear.user.character.defence - text = '{} бойцов отряда {} к битве готовы!\n{}⚔ {}🛡'\ - .format(len(order.cleared), item.squad_name, attack, defence) - send_async(bot, chat_id=item.chat_id, text=text, parse_mode=ParseMode.HTML) - full_text += '{}: {}👥 {}⚔ {}🛡\n'.format(item.squad_name, len(order.cleared), attack, defence) + + text = MSG_SQUAD_READY.format(len(ready_order.cleared), + item.squad_name, + attack, + defence) + + send_async(bot, + chat_id=item.chat_id, + text=text, + parse_mode=ParseMode.HTML) + full_attack += attack full_defence += defence - full_count += len(order.cleared) - send_async(bot, chat_id=GOVERNMENT_CHAT, text=full_text + '\nВсего: {}👥 {}⚔ {}🛡' - .format(full_count, full_attack, full_defence), parse_mode=ParseMode.HTML) - except Exception as e: + full_count += len(ready_order.cleared) + full_text += MSG_FULL_TEXT_LINE.format(item.squad_name, + len(ready_order.cleared), + attack, + defence) + + full_text += MSG_FULL_TEXT_TOTAL.format(full_count, + full_attack, + full_defence) + + send_async(bot, + chat_id=GOVERNMENT_CHAT, + text=full_text, + parse_mode=ParseMode.HTML) + + except SQLAlchemyError as err: + bot.logger.error(str(err)) Session.rollback() +@run_async +def fresh_profiles(bot: Bot, job_queue): + session = Session() + try: + actual_profiles = session.query(Character.user_id, func.max(Character.date)). \ + group_by(Character.user_id) + actual_profiles = actual_profiles.all() + characters = session.query(Character).filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + datetime.now() - timedelta( + days=DAYS_PROFILE_REMIND) > Character.date, + Character.date > datetime.now() - timedelta( + days=DAYS_OLD_PROFILE_KICK)) + if CASTLE: + characters = characters.filter_by(castle=CASTLE) + characters = characters.all() + for character in characters: + send_async(bot, + chat_id=character.user_id, + text=MSG_UPDATE_PROFILE, + parse_mode=ParseMode.HTML) + characters = session.query(Character).filter(tuple_(Character.user_id, Character.date) + .in_([(a[0], a[1]) for a in actual_profiles]), + Character.date < datetime.now() - timedelta( + days=DAYS_OLD_PROFILE_KICK)).all() + members = session.query(SquadMember, User).filter(SquadMember.user_id + .in_([character.user_id for character in characters])) \ + .join(User, User.id == SquadMember.user_id).all() + for member, user in members: + session.delete(member) + admins = session.query(Admin).filter_by(admin_group=member.squad_id).all() + for adm in admins: + send_async(bot, chat_id=adm.user_id, + text=MSG_SQUAD_DELETE_OUTDATED_EXT + .format(member.user.character.name, member.user.username, member.squad.squad_name), + parse_mode=ParseMode.HTML) + send_async(bot, chat_id=member.squad_id, + text=MSG_SQUAD_DELETE_OUTDATED_EXT.format(member.user.character.name, member.user.username, + member.squad.squad_name), + parse_mode=ParseMode.HTML) + send_async(bot, + chat_id=member.user_id, + text=MSG_SQUAD_DELETE_OUTDATED, + parse_mode=ParseMode.HTML) + session.commit() + except SQLAlchemyError as err: + bot.logger.error(str(err)) + Session.rollback() + def main(): # Create the EventHandler and pass it your bot's token. updater = Updater(TOKEN) # Get the dispatcher to register handlers - dp = updater.dispatcher + disp = updater.dispatcher # on different commands - answer in Telegram - dp.add_handler(CommandHandler("start", start)) - dp.add_handler(CommandHandler("admin", admin_panel)) - dp.add_handler(CommandHandler("help", help_msg)) - dp.add_handler(CommandHandler("ping", ping)) - dp.add_handler(CommandHandler("set_global_trigger", set_global_trigger)) - dp.add_handler(CommandHandler("add_global_trigger", add_global_trigger)) - dp.add_handler(CommandHandler("del_global_trigger", del_global_trigger)) - dp.add_handler(CommandHandler("set_trigger", set_trigger)) - dp.add_handler(CommandHandler("add_trigger", add_trigger)) - dp.add_handler(CommandHandler("del_trigger", del_trigger)) - dp.add_handler(CommandHandler("list_triggers", list_triggers)) - dp.add_handler(CommandHandler("set_welcome", set_welcome)) - dp.add_handler(CommandHandler("enable_welcome", enable_welcome)) - dp.add_handler(CommandHandler("disable_welcome", disable_welcome)) - dp.add_handler(CommandHandler("show_welcome", show_welcome)) - dp.add_handler(CommandHandler("add_admin", set_admin)) - dp.add_handler(CommandHandler("add_global_admin", set_global_admin)) - dp.add_handler(CommandHandler("del_global_admin", del_global_admin)) - dp.add_handler(CommandHandler("add_super_admin", set_super_admin)) - dp.add_handler(CommandHandler("del_admin", del_admin)) - dp.add_handler(CommandHandler("list_admins", list_admins)) - dp.add_handler(CommandHandler("kick", kick)) - dp.add_handler(CommandHandler("enable_trigger", enable_trigger_all)) - dp.add_handler(CommandHandler("disable_trigger", disable_trigger_all)) - dp.add_handler(CommandHandler("me", char_show)) - dp.add_handler(CommandHandler("check_bot_in_chats", check_bot_in_chats)) - - dp.add_handler(CommandHandler("add_squad", add_squad)) - dp.add_handler(CommandHandler("del_squad", del_squad)) - dp.add_handler(CommandHandler("enable_thorns", enable_thorns)) - dp.add_handler(CommandHandler("disable_thorns", disable_thorns)) - dp.add_handler(CommandHandler("set_squad_name", set_squad_name)) - dp.add_handler(CommandHandler("set_invite_link", set_invite_link)) - dp.add_handler(CommandHandler("find", find_by_username)) - dp.add_handler(CommandHandler("add", add_to_squad)) - - dp.add_handler(CallbackQueryHandler(callback_query, pass_chat_data=True)) + disp.add_handler(CommandHandler("start", user_panel)) + disp.add_handler(CommandHandler("admin", admin_panel)) + disp.add_handler(CommandHandler("help", help_msg)) + disp.add_handler(CommandHandler("ping", ping)) + disp.add_handler(CommandHandler("set_global_trigger", set_global_trigger)) + disp.add_handler(CommandHandler("add_global_trigger", add_global_trigger)) + disp.add_handler(CommandHandler("del_global_trigger", del_global_trigger)) + disp.add_handler(CommandHandler("set_trigger", set_trigger)) + disp.add_handler(CommandHandler("add_trigger", add_trigger)) + disp.add_handler(CommandHandler("del_trigger", del_trigger)) + disp.add_handler(CommandHandler("list_triggers", list_triggers)) + disp.add_handler(CommandHandler("set_welcome", set_welcome)) + disp.add_handler(CommandHandler("enable_welcome", enable_welcome)) + disp.add_handler(CommandHandler("disable_welcome", disable_welcome)) + disp.add_handler(CommandHandler("show_welcome", show_welcome)) + disp.add_handler(CommandHandler("add_admin", set_admin)) + disp.add_handler(CommandHandler("add_global_admin", set_global_admin)) + disp.add_handler(CommandHandler("del_global_admin", del_global_admin)) + disp.add_handler(CommandHandler("add_super_admin", set_super_admin)) + disp.add_handler(CommandHandler("del_admin", del_admin)) + disp.add_handler(CommandHandler("list_admins", list_admins)) + disp.add_handler(CommandHandler("kick", kick)) + disp.add_handler(CommandHandler("enable_trigger", enable_trigger_all)) + disp.add_handler(CommandHandler("disable_trigger", disable_trigger_all)) + disp.add_handler(CommandHandler("me", char_show)) + + disp.add_handler(CommandHandler("add_squad", add_squad)) + disp.add_handler(CommandHandler("del_squad", del_squad)) + disp.add_handler(CommandHandler("enable_thorns", enable_thorns)) + disp.add_handler(CommandHandler("disable_thorns", disable_thorns)) + disp.add_handler(CommandHandler("set_squad_name", set_squad_name)) + disp.add_handler(CommandHandler("set_invite_link", set_invite_link)) + disp.add_handler(CommandHandler("find", find_by_username)) + disp.add_handler(CommandHandler("add", add_to_squad)) + disp.add_handler(CommandHandler("ban", ban)) + disp.add_handler(CommandHandler("unban", unban)) + + disp.add_handler(CallbackQueryHandler(callback_query, pass_chat_data=True, pass_job_queue=True)) # on noncommand i.e message - echo the message on Telegram - dp.add_handler(MessageHandler(Filters.status_update, welcome)) - # dp.add_handler(MessageHandler(Filters.text, manage_text, pass_chat_data=True)) - dp.add_handler(MessageHandler(Filters.all, manage_all, pass_chat_data=True, pass_job_queue=True)) + disp.add_handler(MessageHandler(Filters.status_update, welcome)) + # disp.add_handler(MessageHandler( + # Filters.text, manage_text, pass_chat_data=True)) + disp.add_handler(MessageHandler( + Filters.all, manage_all, pass_chat_data=True, pass_job_queue=True)) # log all errors - dp.add_error_handler(error) - - updater.job_queue.run_daily(ready_to_battle, time(hour=7, minute=50)) - updater.job_queue.run_daily(ready_to_battle_result, time(hour=7, minute=55)) - updater.job_queue.run_daily(ready_to_battle, time(hour=11, minute=50)) - updater.job_queue.run_daily(ready_to_battle_result, time(hour=11, minute=55)) - updater.job_queue.run_daily(ready_to_battle, time(hour=15, minute=50)) - updater.job_queue.run_daily(ready_to_battle_result, time(hour=15, minute=55)) - updater.job_queue.run_daily(ready_to_battle, time(hour=19, minute=50)) - updater.job_queue.run_daily(ready_to_battle_result, time(hour=19, minute=55)) - updater.job_queue.run_daily(ready_to_battle, time(hour=23, minute=50)) - updater.job_queue.run_daily(ready_to_battle_result, time(hour=23, minute=55)) + disp.add_error_handler(error) + # + # updater.job_queue.run_daily(ready_to_battle, time(hour=6, minute=50)) + # updater.job_queue.run_daily(ready_to_battle_result, + # time(hour=6, minute=55)) + # updater.job_queue.run_daily(ready_to_battle, time(hour=10, minute=50)) + # updater.job_queue.run_daily(ready_to_battle_result, + # time(hour=10, minute=55)) + # updater.job_queue.run_daily(ready_to_battle, time(hour=14, minute=50)) + # updater.job_queue.run_daily(ready_to_battle_result, + # time(hour=14, minute=55)) + # updater.job_queue.run_daily(ready_to_battle, time(hour=18, minute=50)) + # updater.job_queue.run_daily(ready_to_battle_result, + # time(hour=18, minute=55)) + # updater.job_queue.run_daily(ready_to_battle, time(hour=22, minute=50)) + # updater.job_queue.run_daily(ready_to_battle_result, + # time(hour=22, minute=55)) + updater.job_queue.run_daily(fresh_profiles, + time(hour=6, minute=40)) + updater.job_queue.run_daily(fresh_profiles, + time(hour=10, minute=40)) + updater.job_queue.run_daily(fresh_profiles, + time(hour=14, minute=40)) + updater.job_queue.run_daily(fresh_profiles, + time(hour=18, minute=40)) + updater.job_queue.run_daily(fresh_profiles, + time(hour=22, minute=40)) # Start the Bot updater.start_polling() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..42b0915 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +matplotlib +Flask +PyMySQL +python-telegram-bot +requests +SQLAlchemy