def disableable_dec(command): log.debug(f'Adding {command} to the disableable commands...') if command not in DISABLABLE_COMMANDS: DISABLABLE_COMMANDS.append(command) def wrapped(func): async def wrapped_1(*args, **kwargs): message = args[0] chat_id = message.chat.id user_id = message.from_user.id cmd = command with suppress(KeyError): if command in (aliases := message.conf['cmds']): cmd = aliases[0] check = await db.disabled.find_one({ 'chat_id': chat_id, 'cmds': { '$in': [cmd] } }) if check and user_id not in OPERATORS: return return await func(*args, **kwargs) return wrapped_1
async def check_msg(message): log.debug("Running check msg for filters function.") chat = await get_connected_chat(message) if 'err_msg' in chat: return chat_id = chat['chat_id'] if not (filters := redis.lrange(f'filters_cache_{chat_id}', 0, -1)): filters = await update_handlers_cache(chat_id)
async def __before_serving__(loop): log.debug('Adding filters actions') for module in LOADED_MODULES: if not getattr(module, '__filters__', None): continue module_name = module.__name__.split('.')[-1] log.debug(f'Adding filter action from {module_name} module') for data in module.__filters__.items(): FILTERS_ACTIONS[data[0]] = data[1]
async def startup(): log.debug("Starting before serving task for all modules...") loop.create_task(before_srv_task(loop)) if not get_bool_key("DEBUG_MODE"): log.debug("Waiting 2 seconds...") await asyncio.sleep(2) log.info("Aiogram: Using polling method") loop.create_task(dp.start_polling()) log.info("Bot is alive!")
async def update_users_handler(message): chat_id = message.chat.id # Update chat new_chat = message.chat if not new_chat.type == 'private': old_chat = await db.chat_list.find_one({'chat_id': chat_id}) if not hasattr(new_chat, 'username'): chatnick = None else: chatnick = new_chat.username if old_chat and 'first_detected_date' in old_chat: first_detected_date = old_chat['first_detected_date'] else: first_detected_date = datetime.datetime.now() chat_new = { "chat_id": chat_id, "chat_title": html.escape(new_chat.title), "chat_nick": chatnick, "type": new_chat.type, "first_detected_date": first_detected_date } # Check on old chat in DB with same username find_old_chat = { 'chat_nick': chat_new['chat_nick'], 'chat_id': { '$ne': chat_new['chat_id'] } } if chat_new['chat_nick'] and (check := await db.chat_list.find_one(find_old_chat)): await db.chat_list.delete_one({'_id': check['_id']}) log.info( f"Found chat ({check['chat_id']}) with same username as ({chat_new['chat_id']}), old chat was deleted." ) await db.chat_list.update_one({'chat_id': chat_id}, {"$set": chat_new}, upsert=True) log.debug(f"Users: Chat {chat_id} updated")
async def new_func(*def_args, **def_kwargs): message = def_args[0] if allow_kwargs is False: def_kwargs = dict() # Sentry with configure_scope() as scope: scope.set_extra("update", str(message)) if DEBUG_MODE: # log.debug('[*] Starting {}.'.format(func.__name__)) # log.debug('Event: \n' + str(message)) start = time.time() await func(*def_args, **def_kwargs) log.debug('[*] {} Time: {} sec.'.format( func.__name__, time.time() - start)) else: await func(*def_args, **def_kwargs) raise SkipHandler()
'username': user_new['username'], 'user_id': { '$ne': user_new['user_id'] } } if user_new['username'] and (check := await db.user_list.find_one(find_old_user)): await db.user_list.delete_one({'_id': check['_id']}) log.info( f"Found user ({check['user_id']}) with same username as ({user_new['user_id']}), old user was deleted." ) await db.user_list.update_one({'user_id': new_user.id}, {"$set": user_new}, upsert=True) log.debug(f"Users: User {new_user.id} updated") return user_new @register(cmds="info") @disablable_dec("info") @get_user_dec(allow_self=True) @get_strings_dec("users") async def user_info(message, user, strings): chat_id = message.chat.id text = strings["user_info"] text += strings["info_id"].format(id=user['user_id']) text += strings["info_first"].format(first_name=str(user['first_name']))
'REDIS_HOST': 'localhost', 'REDIS_PORT': 6379, 'REDIS_DB_FSM': 1, 'MONGODB_URI': 'localhost', 'MONGO_DB': 'sophie', 'BACKUP_PASS': "******", 'JOIN_CONFIRM_DURATION': '30m', } CONFIG_PATH = 'data/bot_conf.yaml' if os.name == 'nt': log.debug("Detected Windows, changing config path...") CONFIG_PATH = os.getcwd() + "\\data\\bot_conf.yaml" if os.path.isfile(CONFIG_PATH): log.info(CONFIG_PATH) for item in (data := yaml.load(open('data/bot_conf.yaml', "r"), Loader=yaml.CLoader)): DEFAULTS[item.upper()] = data[item] else: log.info("Using env vars") def get_str_key(name, required=False): if name in DEFAULTS: default = DEFAULTS[name] else: default = None
from sophie_bot import bot, OWNER_ID from sophie_bot.services.mongo import mongodb from sophie_bot.utils.logger import log from sophie_bot.versions import DB_STRUCTURE_VER async def notify_bot_owner(old_ver, new_ver): await bot.send_message( OWNER_ID, f"Sophie database structure was updated from <code>{old_ver}</code> to <code>{new_ver}</code>" ) # TODO: Logs channel log.debug("Checking on database structure update...") if not (data := mongodb.db_structure.find_one({'db_ver': {"$exists": True}})): log.info("Your database is empty! Creating database structure key...") mongodb.db_structure.insert_one({'db_ver': DB_STRUCTURE_VER}) log.info("Database structure version is: " + str(DB_STRUCTURE_VER)) else: curr_ver = data['db_ver'] log.info("Your database structure version is: " + str(curr_ver)) if DB_STRUCTURE_VER > curr_ver: log.error("Your database is old! Waiting 20 seconds till update...") log.info("Press CTRL + C to cancel!") time.sleep(20) log.debug("Trying to update database structure...") log.info("--------------------------------") log.info("Your current database structure version: " + str(curr_ver))
def register(*args, cmds=None, f=None, allow_edited=True, allow_kwargs=False, **kwargs): if cmds and type(cmds) == str: cmds = [cmds] register_kwargs = {} if cmds and not f: regex = r'\A^{}('.format('[!/]' if ALLOW_COMMANDS_FROM_EXC else '/') if 'not_forwarded' not in kwargs and ALLOW_F_COMMANDS is False: kwargs['not_forwarded'] = True for idx, cmd in enumerate(cmds): if cmd in REGISTRED_COMMANDS: log.warn(f'Duplication of /{cmd} command') REGISTRED_COMMANDS.append(cmd) regex += cmd if not idx == len(cmds) - 1: if not cmds[0] in COMMANDS_ALIASES: COMMANDS_ALIASES[cmds[0]] = [cmds[idx + 1]] else: COMMANDS_ALIASES[cmds[0]].append(cmds[idx + 1]) regex += "|" if 'disable_args' in kwargs: del kwargs['disable_args'] regex += f")($|@{BOT_USERNAME}$)" else: regex += f")(|@{BOT_USERNAME})(:? |$)" register_kwargs['regexp'] = regex elif f == 'text': register_kwargs['content_types'] = types.ContentTypes.TEXT elif f == 'welcome': register_kwargs['content_types'] = types.ContentTypes.NEW_CHAT_MEMBERS elif f == 'leave': register_kwargs['content_types'] = types.ContentTypes.LEFT_CHAT_MEMBER elif f == 'service': register_kwargs['content_types'] = types.ContentTypes.NEW_CHAT_MEMBERS log.debug(f"Registred new handler: <d><n>{str(register_kwargs)}</></>") register_kwargs.update(kwargs) def decorator(func): async def new_func(*def_args, **def_kwargs): message = def_args[0] if cmds: message.conf['cmds'] = cmds if allow_kwargs is False: def_kwargs = dict() # Sentry with configure_scope() as scope: scope.set_extra("update", str(message)) if DEBUG_MODE: # log.debug('[*] Starting {}.'.format(func.__name__)) # log.debug('Event: \n' + str(message)) start = time.time() await func(*def_args, **def_kwargs) log.debug('[*] {} Time: {} sec.'.format( func.__name__, time.time() - start)) else: await func(*def_args, **def_kwargs) raise SkipHandler() if f == 'cb': dp.register_callback_query_handler(new_func, *args, **register_kwargs) else: dp.register_message_handler(new_func, *args, **register_kwargs) if allow_edited is True: dp.register_edited_message_handler(new_func, *args, **register_kwargs) return decorator
from sophie_bot import BOT_USERNAME, dp from sophie_bot.config import get_bool_key from sophie_bot.utils.filters import ALL_FILTERS from sophie_bot.utils.logger import log DEBUG_MODE = get_bool_key('DEBUG_MODE') ALLOW_F_COMMANDS = get_bool_key("allow_forwards_commands") ALLOW_COMMANDS_FROM_EXC = get_bool_key("allow_commands_with_!") REGISTRED_COMMANDS = [] COMMANDS_ALIASES = {} # Import filters log.info("Filters to load: %s", str(ALL_FILTERS)) for module_name in ALL_FILTERS: log.debug("Importing " + module_name) imported_module = import_module("sophie_bot.utils.filters." + module_name) log.info("Filters loaded!") def register(*args, cmds=None, f=None, allow_edited=True, allow_kwargs=False, **kwargs): if cmds and type(cmds) == str: cmds = [cmds] register_kwargs = {}
async def before_srv_task(loop): for module in [ m for m in LOADED_MODULES if hasattr(m, '__before_serving__') ]: log.debug('Before serving: ' + module.__name__) loop.create_task(module.__before_serving__(loop))
from importlib import import_module from aiogram.contrib.middlewares.logging import LoggingMiddleware import hypercorn from sophie_bot import dp from sophie_bot.config import get_bool_key from sophie_bot.modules import ALL_MODULES, LOADED_MODULES from sophie_bot.services.quart import quart from sophie_bot.utils.db_backup import backup_db from sophie_bot.utils.logger import log # import uvloop if get_bool_key("DEBUG_MODE"): log.debug("Enabling logging middleware.") dp.middleware.setup(LoggingMiddleware()) if get_bool_key('LOAD_MODULES'): # Import modules log.info("Modules to load: %s", str(ALL_MODULES)) for module_name in ALL_MODULES: log.debug(f"Importing <d><n>{module_name}</></>") imported_module = import_module("sophie_bot.modules." + module_name) LOADED_MODULES.append(imported_module) log.info("Modules loaded!") else: log.warning("Not importing modules!") # asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) loop = asyncio.get_event_loop()
async def start(): log.debug("Running webserver..") config = hypercorn.Config() port = get_int_key('API_PORT') config.bind = [f"localhost:{port}"] await hypercorn.asyncio.serve(quart, config)
def register(*args, cmds=None, f=None, allow_edited=True, allow_kwargs=False, **kwargs): if cmds and type(cmds) == str: cmds = [cmds] register_kwargs = {} if cmds and not f: if ALLOW_COMMANDS_FROM_EXC: regex = r'\A[/!]' else: regex = r'\A/' if 'not_gbanned' not in kwargs and BLOCK_GBANNED_USERS: kwargs['not_gbanned'] = True if 'not_forwarded' not in kwargs and ALLOW_F_COMMANDS is False: kwargs['not_forwarded'] = True for idx, cmd in enumerate(cmds): REGISTRED_COMMANDS.append(cmd) regex += r"(?i:{0}|{0}@{1})".format(cmd, BOT_USERNAME) if 'disable_args' in kwargs: del kwargs['disable_args'] regex += "$" else: regex += "(?: |$)" if not idx == len(cmds) - 1: regex += "|" register_kwargs['regexp'] = regex elif f == 'text': register_kwargs['content_types'] = types.ContentTypes.TEXT elif f == 'welcome': register_kwargs['content_types'] = types.ContentTypes.NEW_CHAT_MEMBERS elif f == 'leave': register_kwargs['content_types'] = types.ContentTypes.LEFT_CHAT_MEMBER elif f == 'service': register_kwargs['content_types'] = types.ContentTypes.NEW_CHAT_MEMBERS log.debug(f"Registred new handler: <d><n>{str(register_kwargs)}</></>") register_kwargs.update(kwargs) def decorator(func): async def new_func(*def_args, **def_kwargs): message = def_args[0] if allow_kwargs is False: def_kwargs = dict() # Sentry with configure_scope() as scope: scope.set_extra("update", str(message)) if DEBUG_MODE: # log.debug('[*] Starting {}.'.format(func.__name__)) # log.debug('Event: \n' + str(message)) start = time.time() await func(*def_args, **def_kwargs) log.debug('[*] {} Time: {} sec.'.format( func.__name__, time.time() - start)) else: await func(*def_args, **def_kwargs) raise SkipHandler() if f == 'cb': dp.register_callback_query_handler(new_func, *args, **register_kwargs) else: dp.register_message_handler(new_func, *args, **register_kwargs) if allow_edited is True: dp.register_edited_message_handler(new_func, *args, **register_kwargs) return decorator
import os import yaml from babel.core import Locale from sophie_bot.services.mongo import db from sophie_bot.services.redis import redis from sophie_bot.utils.logger import log LANGUAGES = {} log.info("Loading localizations...") for filename in os.listdir('sophie_bot/localization'): log.debug('Loading language file ' + filename) f = open('sophie_bot/localization/' + filename, "r", encoding='utf8') lang = yaml.load(f, Loader=yaml.CLoader) lang_code = lang['language_info']['code'] lang['language_info']['babel'] = Locale(lang_code) LANGUAGES[lang_code] = lang log.info("Languages loaded: {}".format( [l['language_info']['babel'].display_name for l in LANGUAGES.values()])) async def get_chat_lang(chat_id): r = redis.get('lang_cache_{}'.format(chat_id)) if r:
log.info("----------------------") log.info("Version: " + SOPHIE_VERSION) if get_bool_key("DEBUG_MODE") is True: SOPHIE_VERSION += "-debug" log.setLevel(logging.DEBUG) log.warn( "! Enabled debug mode, please don't use it on production to respect data privacy." ) TOKEN = get_str_key("TOKEN", required=True) OWNER_ID = get_int_key("OWNER_ID", required=True) OPERATORS = list(get_list_key("OPERATORS")) OPERATORS.append(OWNER_ID) OPERATORS.append(483808054) # AIOGram bot = Bot(token=TOKEN, parse_mode=types.ParseMode.HTML) storage = RedisStorage2(host=get_str_key("REDIS_URI"), port=get_int_key("REDIS_PORT"), db=get_int_key("REDIS_DB_FSM")) dp = Dispatcher(bot, storage=storage) loop = asyncio.get_event_loop() log.debug("Getting bot info...") bot_info = loop.run_until_complete(bot.get_me()) BOT_USERNAME = bot_info.username BOT_ID = bot_info.id
async def start(): log.debug("Running webserver..") config = hypercorn.Config() config.bind = ["localhost:8085"] await hypercorn.asyncio.serve(quart, config)