diff --git a/.renovaterc b/.renovaterc index 39a2b6e..abb2f10 100644 --- a/.renovaterc +++ b/.renovaterc @@ -1,6 +1,6 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ] -} + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} \ No newline at end of file diff --git a/bwtbot.py b/bwtbot.py index 36c13e7..4900664 100644 --- a/bwtbot.py +++ b/bwtbot.py @@ -1,214 +1,37 @@ -# -*- coding: utf-8 -*- +import logging +from os import getpid -from os import getpid, system -from subprocess import call -from pyrogram import filters -from pyrogram.client import Client -from pyrogram.sync import idle -from pyrogram.types import ( - ForceReply, - BotCommand, - BotCommandScopeChat, - Message, - ReplyKeyboardRemove, -) -from pyrogram.enums.chat_action import ChatAction -from convopyro import Conversation, listen_message -from functions import * -from modules.colors import * -from modules.bwt import * +from convopyro import Conversation -config = jsonLoad("config.json") +from modules.app import PyroClient -owner_id = config["owner_id"] - -app = Client( - config["bot_name"], - api_id=config["api_id"], - api_hash=config["api_hash"], - bot_token=config["bot_token"], +logging.basicConfig( + level=logging.INFO, + format="%(name)s.%(funcName)s | %(levelname)s | %(message)s", + datefmt="[%X]", ) -Conversation(app) +logger = logging.getLogger(__name__) + +try: + import uvloop + + uvloop.install() +except ImportError: + pass -@app.on_message( - ~filters.scheduled - & filters.command(["setcard", "задать карту"], prefixes=["/", ""]) -) -async def setcard(_: Client, msg: Message): - await msg.reply_text( - string("send_number"), - reply_markup=ForceReply(placeholder=string("enter_number")), - ) - answer = await listen_message(_, msg.chat.id, timeout=None) - if answer is None: - return - elif answer.text.strip() in ["/cancel", "cancel", "/відміна", "відміна"]: - await msg.reply_text(string("cancel"), reply_markup=ReplyKeyboardRemove()) - return - userSet(answer.from_user.id, "card", answer.text) - appendLog(f"User {str(msg.from_user.id)} set card id to {answer.text}") - await msg.reply_text( - string("card_linked").format(answer.text), reply_markup=ReplyKeyboardRemove() - ) +def main(): + client = PyroClient() + Conversation(client) - -@app.on_message( - ~filters.scheduled - & filters.command(["resetcard", "забути картку"], prefixes=["/", ""]) -) -async def resetcard(_: Client, msg: Message): - if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]: - userReset(msg.from_user.id, "card") - await msg.reply_text(string("card_unlinked")) - appendLog(f"User {str(msg.from_user.id)} reseted his card") - else: - await msg.reply_text(string("card_not_linked").format(string("get_number"))) - appendLog(f"User {str(msg.from_user.id)} tried to reset non-existent card") - - -@app.on_message( - ~filters.scheduled & filters.command(["balance", "баланс"], prefixes=["/", ""]) -) -async def balance(_: Client, msg: Message): try: - if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]: - await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING) - water_left = await getWaterLeft( - userGet(msg.from_user.id, "card"), msg.from_user.id, app - ) - if water_left == "": - await msg.reply_text( - string("error_new").format( - f'https://bwtaqua.com.ua/card-topup/?id={userGet(msg.from_user.id, "card")}' - ) - ) - # raise EmptyCardException("Card information is empty") - elif water_left == "Failure": - await msg.reply_text( - string("error_occured").format(string("get_number")) - ) - appendLog( - f"User {str(msg.from_user.id)} could not get left water amount" - ) - else: - await msg.reply_text(string("card_balance").format(water_left)) - appendLog( - f"User {str(msg.from_user.id)} has {water_left} liters remaining" - ) - else: - await msg.reply_text(string("card_not_linked").format(string("get_number"))) - appendLog( - f"User {str(msg.from_user.id)} tried to get balance without card set" - ) - except Exception as exp: - if msg.from_user.id != config["owner_id"]: - await msg.reply_text(string("error_occured").format(string("get_number"))) - await app.send_message( - owner_id, - f"Error occured by {str(msg.from_user.id)}:\nException: `{exp}`\nTraceback: `{format_exc()}`", - ) - appendLog(f"User {str(msg.from_user.id)} could not get left water amount") + client.run() + except KeyboardInterrupt: + logger.warning(f"Forcefully shutting down with PID {getpid()}...") + finally: + exit() -@app.on_message( - ~filters.scheduled - & filters.command(["topup", "refill", "поповнити"], prefixes=["/", ""]) -) -async def topup_cmd(_: Client, msg: Message): - try: - if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]: - await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING) - await msg.reply_text( - string("top_up").format(str(userGet(msg.from_user.id, "card"))) - ) - appendLog(f"User {str(msg.from_user.id)} requested top up") - else: - await msg.reply_text(string("card_not_linked").format(string("get_number"))) - appendLog( - f"User {str(msg.from_user.id)} tried to request top up without card set" - ) - except Exception as exp: - await msg.reply_text(str(exp)) - - -@app.on_message( - ~filters.scheduled - & filters.command(["start", "help", "допомога"], prefixes=["/", ""]) -) -async def help(_: Client, msg: Message): - await msg.reply_text(string("welcome").format(string("get_number"))) - if msg.from_user.language_code in jsonLoad("strings.json"): - userSet(msg.from_user.id, "locale", msg.from_user.language_code) - else: - userSet(msg.from_user.id, "locale", "en") - - -pid = getpid() - - -@app.on_message( - ~filters.scheduled & filters.command(["kill", "die", "shutdown"], prefixes="/") -) -async def kill(_: Client, msg: Message): - if msg.from_user.id == owner_id: - await msg.reply_text(f"Shutting down bot with pid **{pid}**") - system(f"kill -9 {pid}") - - -print(f"{nowtime()} {WHITE}Starting with PID {YELLOW}{pid}{RESET}") - -app.start() # type: ignore -app.send_message(owner_id, f"Starting bot with pid **{pid}**") # type: ignore - -app.set_bot_commands( - [ - BotCommand("help", "Меню допомоги"), - BotCommand("balance", "Баланс картки"), - BotCommand("topup", "Поповнити картку"), - BotCommand("setcard", "Прив'язати картку"), - BotCommand("resetcard", "Відв'язати картку"), - ], - language_code="uk", -) # type: ignore - -app.set_bot_commands( - [ - BotCommand("help", "Меню допомоги"), - BotCommand("balance", "Баланс картки"), - BotCommand("topup", "Поповнити картку"), - BotCommand("setcard", "Прив'язати картку"), - BotCommand("resetcard", "Відв'язати картку"), - ], - language_code="ru", -) # type: ignore - -app.set_bot_commands( - [ - BotCommand("help", "Help menu"), - BotCommand("balance", "Card's balance"), - BotCommand("topup", "Refill card"), - BotCommand("setcard", "Link card"), - BotCommand("resetcard", "Unlink card"), - ] -) # type: ignore - -app.set_bot_commands( - [ - BotCommand("help", "Help menu"), - BotCommand("balance", "Card's balance"), - BotCommand("topup", "Refill card"), - BotCommand("setcard", "Link card"), - BotCommand("resetcard", "Unlink card"), - BotCommand("shutdown", "Turn off the bot"), - ], - scope=BotCommandScopeChat(chat_id=owner_id), -) # type: ignore - -idle() - -app.send_message(owner_id, f"Shutting down bot with pid **{pid}**") # type: ignore -print(f"\n{nowtime()} {WHITE}Shutting down with PID {YELLOW}{pid}{RESET}") - -call(f"kill -9 {pid}", shell=True) +if __name__ == "__main__": + main() diff --git a/config.json b/config.json index a4835a1..688ea35 100644 --- a/config.json +++ b/config.json @@ -1,9 +1,10 @@ { "owner_id": 0, - "log_size": 1024, - "api_id": 0, - "api_hash": "", - "bot_token": "", - "bot_name": "", + "bot": { + "api_id": 0, + "api_hash": "", + "bot_token": "", + "workers": 1 + }, "use_compiled_page_saver": false } \ No newline at end of file diff --git a/functions.py b/functions.py deleted file mode 100644 index 91c2de5..0000000 --- a/functions.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- - -from os import makedirs, stat -from gzip import open as gzipopen -from shutil import copyfileobj -from time import sleep -from ujson import loads, dumps -from modules.colors import * -from datetime import datetime - -users_path = "users/" -logs_folder = "logs/" - - -def jsonSave(filename, value): - with open(filename, "w", encoding="utf-8") as f: - f.write(dumps(value, indent=4, ensure_ascii=False)) - - -def jsonLoad(filename): - with open(filename, "r", encoding="utf-8") as f: - value = loads(f.read()) - return value - - -config = jsonLoad(f"config.json") - -log_size = config["log_size"] -owner_id = config["owner_id"] - - -def nowtime(): - return f'{BBLACK}[{CYAN}{datetime.now().strftime("%H:%M:%S")}{BBLACK}]{RESET}' - - -def checkSize(): - global logs_folder, log_size - - i = 0 - - while i < 2: - try: - log = stat(logs_folder + "latest.log") - - if (log.st_size / 1024) > log_size: - with open(logs_folder + "latest.log", "rb") as f_in: - with gzipopen( - f'{logs_folder}{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.zip', - "wb", - ) as f_out: - copyfileobj(f_in, f_out) - - open(logs_folder + "latest.log", "w").close() - - i = 2 - - except FileNotFoundError: - try: - log = open(logs_folder + "latest.log", "a") - open(logs_folder + "latest.log", "a").close() - except: - try: - makedirs(logs_folder, exist_ok=True) - log = open(logs_folder + "latest.log", "a") - open(logs_folder + "latest.log", "a").close() - except: - pass - - i += 1 - - -def appendLog(message): - global logs_folder - - checkSize() - - try: - log = open(logs_folder + "latest.log", "a") - open(logs_folder + "latest.log", "a").close() - except: - try: - makedirs(logs_folder, exist_ok=True) - log = open(logs_folder + "latest.log", "a") - open(logs_folder + "latest.log", "a").close() - except: - sleep(2) - print("Log file could not be created") - return - - print(message, flush=True) - log.write(f'[{datetime.now().strftime("%H:%M:%S | %d.%m.%Y")}] {message}\n') - - log.close() - - -def string(key: str, *args: str, userlocale="uk"): - locales = jsonLoad("strings.json") - strings = locales[userlocale] - string = strings - for dict_key in args: - string = string[dict_key] - return string[key] - - -def userSet(userid, key: str, value): - database = jsonLoad("data/database.json") - if str(userid) not in database: - database[str(userid)] = {} - database[str(userid)][key] = value - jsonSave("data/database.json", database) - - -def userReset(userid, key: str): - database = jsonLoad("data/database.json") - del database[str(userid)][key] - jsonSave("data/database.json", database) - - -def userGet(userid, key: str): - try: - return jsonLoad("data/database.json")[str(userid)][key] - except KeyError: - return None - except FileNotFoundError: - return None diff --git a/modules/app.py b/modules/app.py new file mode 100644 index 0000000..757e61b --- /dev/null +++ b/modules/app.py @@ -0,0 +1,59 @@ +import logging +from os import getpid +from time import time + +import pyrogram +from libbot import config_get +from pyrogram.client import Client +from pyrogram.errors import BadRequest +from pyrogram.raw.all import layer +from ujson import loads + +logger = logging.getLogger(__name__) + + +class PyroClient(Client): + def __init__(self): + with open("config.json", "r", encoding="utf-8") as f: + config = loads(f.read()) + super().__init__( + name="bwtbot", + api_id=config["bot"]["api_id"], + api_hash=config["bot"]["api_hash"], + bot_token=config["bot"]["bot_token"], + workers=config["bot"]["workers"], + plugins=dict(root="plugins", exclude=config["disabled_plugins"]), + sleep_threshold=120, + ) + + async def start(self): + await super().start() + + self.start_time = time() + + logger.info( + "Bot is running with Pyrogram v%s (Layer %s) and has started as @%s on PID %s.", + pyrogram.__version__, + layer, + self.me.username, + getpid(), + ) + + try: + await self.send_message( + chat_id=await config_get("chat_id", "reports"), + text=f"Bot started PID `{getpid()}`", + ) + except BadRequest: + logger.warning("Unable to send message to report chat.") + + async def stop(self): + try: + await self.send_message( + chat_id=await config_get("chat_id", "reports"), + text=f"Bot stopped with PID `{getpid()}`", + ) + except BadRequest: + logger.warning("Unable to send message to report chat.") + await super().stop() + logger.warning(f"Bot stopped with PID {getpid()}.") diff --git a/modules/bwt.py b/modules/bwt.py index 96c8fee..364a0db 100644 --- a/modules/bwt.py +++ b/modules/bwt.py @@ -1,13 +1,17 @@ # -*- coding: utf-8 -*- +import logging from os import makedirs, path from subprocess import check_output from traceback import format_exc from uuid import uuid4 -from functions import * -from bs4 import BeautifulSoup -config = jsonLoad("config.json") +from bs4 import BeautifulSoup +from libbot import config_get + +from modules.utils import * + +logger = logging.getLogger(__name__) class EmptyCardException(Exception): @@ -21,9 +25,9 @@ async def getWaterLeft(cardid, filename, app=None): # if path.exists(f"data/pages/{str(filename)}.html") is False: # run(["touch", f"data/pages/{str(filename)}.html"]) - appendLog(f"Trying to get liters for url '{url}'") + logger.info(f"Trying to get liters for url '{url}'") - if config["use_compiled_page_saver"] is True: + if await config_get("use_compiled_page_saver") is True: proc = check_output( [ "PageSaver/pageSaver", @@ -58,12 +62,14 @@ async def getWaterLeft(cardid, filename, app=None): .replace(" л", "") ) - appendLog( + logger.info( f"Parsed {output} liters of water remaining (user: {str(filename)}, cardid: {cardid})" ) except Exception as exp: - appendLog(f"Exception occured: {exp} (user: {str(filename)}, cardid: {cardid})") + logger.exception( + f"Exception occured: {exp} (user: {str(filename)}, cardid: {cardid})", exp + ) try: tmp_name = str(uuid4()) @@ -72,16 +78,16 @@ async def getWaterLeft(cardid, filename, app=None): f.write(html_file) except NameError: tmp_name = "N/A" - appendLog(f"'html_file' is not defined so I won't gather any tmp data") + logger.warning(f"'html_file' is not defined so I won't gather any tmp data") if app != None: await app.send_message( - config["owner_id"], + await config_get("owner_id"), f"**Exception occured:**\n • User: `{str(filename)}`\n • Card: [{cardid}]({url})\n • Exception: `{exp}`\n • TMP UUID: `{tmp_name}`\n • Traceback: `{format_exc()}`", disable_web_page_preview=True, ) else: - appendLog(f"Exception occured and could not send to user: {exp}") + logger.warning(f"Exception occurred and could not send to user: {exp}") output = "Failure" diff --git a/modules/colors.py b/modules/colors.py deleted file mode 100644 index 04642d9..0000000 --- a/modules/colors.py +++ /dev/null @@ -1,22 +0,0 @@ -RESET = "\u001b[0m" - -BLACK = "\u001b[30m" -RED = "\u001b[31m" -GREEN = "\u001b[32m" -YELLOW = "\u001b[33m" -BLUE = "\u001b[34m" -MAGENTA = "\u001b[35m" -CYAN = "\u001b[36m" -WHITE = "\u001b[37m" - -BBLACK = "\u001b[30;1m" -BRED = "\u001b[31;1m" -BGREEN = "\u001b[32;1m" -BYELLOW = "\u001b[33;1m" -BBLUE = "\u001b[34;1m" -BMAGENTA = "\u001b[35;1m" -BCYAN = "\u001b[36;1m" -BWHITE = "\u001b[37;1m" - -ULINE = "\u001b[4m" -REVERSE = "\u001b[7m" diff --git a/modules/utils.py b/modules/utils.py new file mode 100644 index 0000000..34b3823 --- /dev/null +++ b/modules/utils.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +from libbot import json_read, sync + + +async def string(key: str, *args: str, userlocale="uk"): + locales = await json_read("strings.json") + strings = locales[userlocale] + string = strings + for dict_key in args: + string = string[dict_key] + return string[key] + + +def userSet(userid, key: str, value): + database = sync.json_read("data/database.json") + if str(userid) not in database: + database[str(userid)] = {} + database[str(userid)][key] = value + sync.json_write(database, "data/database.json") + + +def userReset(userid, key: str): + database = sync.json_read("data/database.json") + del database[str(userid)][key] + sync.json_write(database, "data/database.json") + + +def userGet(userid, key: str): + try: + return sync.json_read("data/database.json")[str(userid)][key] + except KeyError: + return None + except FileNotFoundError: + return None diff --git a/plugins/balance.py b/plugins/balance.py new file mode 100644 index 0000000..b7fd4a6 --- /dev/null +++ b/plugins/balance.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +import logging +from traceback import format_exc + +from libbot import config_get, json_read +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.enums.chat_action import ChatAction +from pyrogram.types import Message + +from modules.utils import string, userGet +from modules.bwt import getWaterLeft + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled & filters.command(["balance", "баланс"], prefixes=["/", ""]) # type: ignore +) +async def command_balance(app: Client, msg: Message): + try: + if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]: + await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING) + water_left = await getWaterLeft( + userGet(msg.from_user.id, "card"), msg.from_user.id, app + ) + if water_left == "": + await msg.reply_text( + (await string("error_new")).format( + f'https://bwtaqua.com.ua/card-topup/?id={userGet(msg.from_user.id, "card")}' + ) + ) + # raise EmptyCardException("Card information is empty") + elif water_left == "Failure": + await msg.reply_text( + (await string("error_occured")).format(await string("get_number")) + ) + logger.warning( + f"User {str(msg.from_user.id)} could not get left water amount" + ) + else: + await msg.reply_text((await string("card_balance")).format(water_left)) + logger.info( + f"User {str(msg.from_user.id)} has {water_left} liters remaining" + ) + else: + await msg.reply_text( + (await string("card_not_linked")).format(await string("get_number")) + ) + logger.info( + f"User {str(msg.from_user.id)} tried to get balance without card set" + ) + except Exception as exp: + if msg.from_user.id != await config_get("owner_id"): + await msg.reply_text( + (await string("error_occured")).format(await string("get_number")) + ) + await app.send_message( + await config_get("owner_id"), + f"Error occured by {str(msg.from_user.id)}:\nException: `{exp}`\nTraceback: `{format_exc()}`", + ) + logger.warning(f"User {str(msg.from_user.id)} could not get left water amount") diff --git a/plugins/help.py b/plugins/help.py new file mode 100644 index 0000000..83a555d --- /dev/null +++ b/plugins/help.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +import logging + +from libbot import json_read +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.types import Message + +from modules.utils import string, userSet + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled + & filters.command(["start", "help", "допомога"], prefixes=["/", ""]) # type: ignore +) +async def command_help(app: Client, msg: Message): + await msg.reply_text((await string("welcome")).format(await string("get_number"))) + if msg.from_user.language_code in await json_read("strings.json"): + userSet(msg.from_user.id, "locale", msg.from_user.language_code) + else: + userSet(msg.from_user.id, "locale", "en") diff --git a/plugins/register_commands.py b/plugins/register_commands.py new file mode 100644 index 0000000..05a384f --- /dev/null +++ b/plugins/register_commands.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +import logging + +from libbot import config_get +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.types import BotCommand, BotCommandScopeChat, Message + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled & filters.command(["register_commands"], prefixes="/") # type: ignore +) +async def command_register_commands(app: Client, msg: Message): + if msg.from_user.id == await config_get("owner_id"): + app.set_bot_commands( + [ + BotCommand("help", "Меню допомоги"), + BotCommand("balance", "Баланс картки"), + BotCommand("topup", "Поповнити картку"), + BotCommand("setcard", "Прив'язати картку"), + BotCommand("resetcard", "Відв'язати картку"), + ], + language_code="uk", + ) # type: ignore + + app.set_bot_commands( + [ + BotCommand("help", "Меню допомоги"), + BotCommand("balance", "Баланс картки"), + BotCommand("topup", "Поповнити картку"), + BotCommand("setcard", "Прив'язати картку"), + BotCommand("resetcard", "Відв'язати картку"), + ], + language_code="ru", + ) # type: ignore + + app.set_bot_commands( + [ + BotCommand("help", "Help menu"), + BotCommand("balance", "Card's balance"), + BotCommand("topup", "Refill card"), + BotCommand("setcard", "Link card"), + BotCommand("resetcard", "Unlink card"), + ] + ) # type: ignore + + app.set_bot_commands( + [ + BotCommand("help", "Help menu"), + BotCommand("balance", "Card's balance"), + BotCommand("topup", "Refill card"), + BotCommand("setcard", "Link card"), + BotCommand("resetcard", "Unlink card"), + BotCommand("shutdown", "Turn off the bot"), + ], + scope=BotCommandScopeChat(chat_id=await config_get("owner_id")), + ) # type: ignore diff --git a/plugins/resetcard.py b/plugins/resetcard.py new file mode 100644 index 0000000..537d406 --- /dev/null +++ b/plugins/resetcard.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +import logging + +from libbot import json_read +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.types import Message + +from modules.utils import string, userReset + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled + & filters.command(["resetcard", "забути картку"], prefixes=["/", ""]) # type: ignore +) +async def command_resetcard(app: Client, msg: Message): + if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]: + userReset(msg.from_user.id, "card") + await msg.reply_text(await string("card_unlinked")) + logger.info(f"User {str(msg.from_user.id)} reseted his card") + else: + await msg.reply_text( + (await string("card_not_linked")).format(await string("get_number")) + ) + logger.info(f"User {str(msg.from_user.id)} tried to reset non-existent card") diff --git a/plugins/setcard.py b/plugins/setcard.py new file mode 100644 index 0000000..999b404 --- /dev/null +++ b/plugins/setcard.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +import logging + +from convopyro import listen_message +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove + +from modules.utils import string, userSet + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled + & filters.command(["setcard", "задать карту"], prefixes=["/", ""]) # type: ignore +) +async def command_setcard(app: Client, msg: Message): + await msg.reply_text( + await string("send_number"), + reply_markup=ForceReply(placeholder=await string("enter_number")), + ) + answer = await listen_message(app, msg.chat.id, timeout=None) + if answer is None: + return + elif answer.text.strip() in ["/cancel", "cancel", "/відміна", "відміна"]: + await msg.reply_text(await string("cancel"), reply_markup=ReplyKeyboardRemove()) + return + userSet(answer.from_user.id, "card", answer.text) + logger.info(f"User {str(msg.from_user.id)} set card id to {answer.text}") + await msg.reply_text( + (await string("card_linked")).format(answer.text), + reply_markup=ReplyKeyboardRemove(), + ) diff --git a/plugins/shutdown.py b/plugins/shutdown.py new file mode 100644 index 0000000..a80e5a1 --- /dev/null +++ b/plugins/shutdown.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import logging +from os import getpid + +from libbot import config_get +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.types import Message + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled & filters.command(["kill", "die", "shutdown"], prefixes="/") # type: ignore +) +async def kill(app: Client, msg: Message): + if msg.from_user.id == await config_get("owner_id"): + await msg.reply_text(f"Shutting down bot with pid **{getpid()}**") + logger.info(f"Shutting down as requested by {msg.from_user.id}") + exit() diff --git a/plugins/topup.py b/plugins/topup.py new file mode 100644 index 0000000..8e649b6 --- /dev/null +++ b/plugins/topup.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +import logging + +from libbot import json_read +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.enums.chat_action import ChatAction +from pyrogram.types import Message + +from modules.utils import string, userGet + +logger = logging.getLogger(__name__) + + +@Client.on_message( + ~filters.scheduled + & filters.command(["topup", "refill", "поповнити"], prefixes=["/", ""]) # type: ignore +) +async def command_topup(app: Client, msg: Message): + try: + if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]: + await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING) + await msg.reply_text( + (await string("top_up")).format(str(userGet(msg.from_user.id, "card"))) + ) + logger.info(f"User {str(msg.from_user.id)} requested top up") + else: + await msg.reply_text( + (await string("card_not_linked")).format(await string("get_number")) + ) + logger.info( + f"User {str(msg.from_user.id)} tried to request top up without card set" + ) + except Exception as exp: + await msg.reply_text(str(exp)) diff --git a/requirements.txt b/requirements.txt index 106f4ac..2f70bb5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,7 @@ convopyro==0.5 pathlib~=1.0.1 pyrogram==2.0.106 tgcrypto==1.2.5 -ujson==5.7.0 \ No newline at end of file +ujson==5.7.0 +uvloop==0.17.0 +--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple +libbot[speed,pyrogram]==0.4 \ No newline at end of file