Example #1
0
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
Example #2
0
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)
Example #3
0
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]
Example #4
0
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!")
Example #5
0
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")
Example #6
0
        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()
Example #7
0
        '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']))
Example #8
0
    '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
Example #9
0
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))
Example #10
0
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
Example #11
0
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 = {}
Example #12
0
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))
Example #13
0
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()
Example #14
0
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)
Example #15
0
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
Example #16
0
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:
Example #17
0
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
Example #18
0
async def start():
    log.debug("Running webserver..")
    config = hypercorn.Config()
    config.bind = ["localhost:8085"]
    await hypercorn.asyncio.serve(quart, config)