Exemplo n.º 1
0
async def all_errors_handler(message, error):
    message = (message.message if message.message is not None else
               message.callback_query.message
               if message.callback_query is not None else message)
    chat_id = message.chat.id
    err_tlt = sys.exc_info()[0].__name__
    err_msg = str(sys.exc_info()[1])

    log.warn('Error caused update is: \n' +
             html.escape(str(parse_update(message))))

    if redis.get(chat_id) == str(error):
        # by err_tlt we assume that it is same error
        return

    if err_tlt == 'BadRequest' and err_msg == 'Have no rights to send a message':
        return True

    if err_tlt in ('FloodWaitError', 'RetryAfter', 'SlowModeWaitError'):
        return True

    text = "<b>Sorry, I encountered a error!</b>\n"
    text += f'<code>{html.escape(err_tlt)}: {html.escape(err_msg)}</code>'
    redis.set(chat_id, str(error), ex=600)
    await bot.send_message(chat_id, text)
Exemplo n.º 2
0
async def export_chat_data(message, chat, strings):
    chat_id = chat['chat_id']
    key = 'export_lock:' + str(chat_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)),
                               strings['language_info']['babel'])
        await message.reply(strings['exports_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    msg = await message.reply(strings['started_exporting'])
    data = {
        'general': {
            'chat_name': chat['chat_title'],
            'chat_id': chat_id,
            'timestamp': datetime.now(),
            'version': VERSION
        }
    }

    for module in [m for m in LOADED_MODULES if hasattr(m, '__export__')]:
        await asyncio.sleep(0.2)
        if k := await module.__export__(chat_id):
            data.update(k)
Exemplo n.º 3
0
async def export_chat_data(message, chat, strings):
    chat_id = chat['chat_id']
    key = 'export_lock:' + str(chat_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)),
                               strings['language_info']['babel'])
        await message.reply(strings['exports_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    msg = await message.reply(strings['started_exporting'])
    data = {
        'general': {
            'chat_name': chat['chat_title'],
            'chat_id': chat_id,
            'timestamp': datetime.now(),
            'version': 1
        }
    }

    for module in [m for m in LOADED_MODULES if hasattr(m, '__export__')]:
        await asyncio.sleep(0.2)
        data.update(await module.__export__(chat_id))

    jfile = InputFile(io.StringIO(ujson.dumps(data, indent=2)),
                      filename=f'{chat_id}_export.json')
    text = strings['export_done'] % chat['chat_title']
    await message.answer_document(jfile, text, reply=message.message_id)
    await msg.delete()
Exemplo n.º 4
0
async def import_fun(message, document, chat, strings):
    chat_id = chat['chat_id']
    key = 'import_lock:' + str(chat_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)),
                               strings['language_info']['babel'])
        await message.reply(strings['imports_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    msg = await message.reply(strings['started_importing'])
    if document['file_size'] > 52428800:
        await message.reply(strings['big_file'])
        return
    data = await bot.download_file_by_id(document.file_id, io.BytesIO())
    data = ujson.load(data)

    if 'general' not in data:
        await message.reply(strings['bad_file'])
        return

    imported = []
    for module in [m for m in LOADED_MODULES if hasattr(m, '__import__')]:
        module_name = module.__name__.replace('sophie_bot.modules.', '')
        print(module_name)
        if module_name in data:
            imported.append(module_name)
            await asyncio.sleep(0.2)
            await module.__import__(chat_id, data[module_name])

    await msg.delete()
    await message.answer(strings['import_done'], reply=message.message_id)
Exemplo n.º 5
0
async def importfbans_cmd(message, fed, strings):
    fed_id = fed['fed_id']
    key = 'importfbans_lock:' + str(fed_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)), strings['language_info']['babel'])
        await message.reply(strings['importfbans_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    if 'document' in message:
        document = message.document
    else:
        if 'reply_to_message' not in message:
            await ImportFbansFileWait.waiting.set()
            await message.reply(strings['send_import_file'])
            return

        elif 'document' not in message.reply_to_message:
            await message.reply(strings['rpl_to_file'])
            return
        document = message.reply_to_message.document

    await importfbans_func(message, fed, document=document)
Exemplo n.º 6
0
async def change_chat_lang(chat_id, lang):
    redis.set('lang_cache_{}'.format(chat_id), lang)
    await db.lang.update_one({'chat_id': chat_id},
                             {"$set": {
                                 'chat_id': chat_id,
                                 'lang': lang
                             }},
                             upsert=True)
Exemplo n.º 7
0
async def welcome_security_handler(message, strings):
    chat_id = message.chat.id

    if not check_admin_rights(chat_id, BOT_ID, ['can_restrict_members']):
        await message.reply(strings['not_admin_ws'])
        return

    user_id = message.from_user.id
    db_item = await db.greetings.find_one({'chat_id': chat_id})

    if not db_item or 'welcome_security' not in db_item:
        return

    user = await message.chat.get_member(user_id)

    # Check if user was muted before
    if 'can_send_messages' in user and user['can_send_messages'] is False:
        return

    # Check on OPs and chat owner
    if await is_user_admin(chat_id, user_id):
        return

    # Mute user
    await mute_user(chat_id, user_id)

    if 'security_note' not in db_item:
        db_item = {'security_note': {}}
        db_item['security_note']['text'] = strings['default_security_note']
        db_item['security_note']['parse_mode'] = 'md'

    text, kwargs = await t_unparse_note_item(message, db_item['security_note'], chat_id)

    kwargs['reply_to'] = message.message_id

    kwargs['buttons'] = None if not kwargs['buttons'] else kwargs['buttons']
    msg = await tbot.send_message(chat_id, text, **kwargs)

    # Edit msg to apply button
    kwargs['buttons'] = [] if not kwargs['buttons'] else kwargs['buttons']
    kwargs['buttons'] += [Button.url(strings['click_here'], f'https://t.me/{BOT_USERNAME}?start=welcome_security_{chat_id}_{user_id}_{msg.id}')]

    del kwargs['reply_to']
    await msg.edit(text, **kwargs)

    redis.set(f'welcomesecurity_users_{user_id}', chat_id)

    scheduler.add_job(
        join_expired,
        "date",
        id=f"wc_expire:{chat_id}:{user_id}",
        run_date=datetime.utcnow() + convert_time(get_str_key('JOIN_CONFIRM_DURATION')),
        kwargs={'chat_id': chat_id, 'user_id': user_id, 'message_id': msg.id, 'wlkm_msg_id': message.message_id},
        replace_existing=True
    )
Exemplo n.º 8
0
async def connect_to_chat_direct(message, strings):
    user_id = message.from_user.id
    chat_id = message.chat.id

    chat_title = (await db.chat_list.find_one({'chat_id': chat_id}))['chat_title']
    text = strings['pm_connected'].format(chat_name=chat_title)

    try:
        await bot.send_message(user_id, text)
        await def_connect_chat(message, user_id, chat_id, chat_title)
    except BotBlocked:
        await message.reply(strings['connected_pm_to_me'].format(chat_name=chat_title))
        redis.set('sophie_connected_start_state:' + str(user_id), 1)
Exemplo n.º 9
0
async def join_expired(chat_id, user_id, message_id, wlkm_msg_id):
    user = await bot.get_chat_member(chat_id, user_id)
    if 'can_send_messages' not in user or user['can_send_messages'] is True:
        return

    bot_user = await bot.get_chat_member(chat_id, BOT_ID)
    if 'can_restrict_members' not in bot_user or bot_user['can_restrict_members'] is False:
        return

    key = 'leave_silent:' + str(chat_id)
    redis.set(key, user_id)

    await unmute_user(chat_id, user_id)
    await kick_user(chat_id, user_id)
    await tbot.delete_messages(chat_id, [message_id, wlkm_msg_id])
Exemplo n.º 10
0
async def connect_to_chat_direct(message, strings):
    user_id = message.from_user.id
    chat_id = message.chat.id

    chat = await db.chat_list.find_one({'chat_id': chat_id})
    chat_title = chat['chat_title'] if chat is not None else message.chat.title
    text = strings['pm_connected'].format(chat_name=chat_title)

    try:
        await bot.send_message(user_id, text)
        await def_connect_chat(message, user_id, chat_id, chat_title)
    except (BotBlocked, CantInitiateConversation):
        await message.reply(
            strings['connected_pm_to_me'].format(chat_name=chat_title))
        redis.set('sophie_connected_start_state:' + str(user_id), 1)
Exemplo n.º 11
0
async def add_handler(message, chat, strings):
    handler = get_args_str(message).lower()
    text = strings['adding_filter'].format(handler=handler, chat_name=chat['chat_title'])

    buttons = InlineKeyboardMarkup(row_width=2)
    for action in FILTERS_ACTIONS.items():
        filter_id = action[0]
        data = action[1]

        buttons.add(InlineKeyboardButton(
            await get_string(chat['chat_id'], data['title']['module'], data['title']['string']),
            callback_data=filter_action_cp.new(filter_id=filter_id)
        ))
    user_id = message.from_user.id
    chat_id = chat['chat_id']
    redis.set(f'add_filter:{user_id}:{chat_id}', handler)
    await message.reply(text, reply_markup=buttons)
Exemplo n.º 12
0
async def get_chat_lang(chat_id):
    r = redis.get('lang_cache_{}'.format(chat_id))
    if r:
        return r
    else:
        db_lang = await db.lang.find_one({'chat_id': chat_id})
        if db_lang:
            # Rebuild lang cache
            redis.set('lang_cache_{}'.format(chat_id), db_lang['lang'])
            return db_lang['lang']
        user_lang = await db.user_list.find_one({'user_id': chat_id})
        if user_lang and user_lang['user_lang'] in LANGUAGES:
            # Add telegram language in lang cache
            redis.set('lang_cache_{}'.format(chat_id), user_lang['user_lang'])
            return user_lang['user_lang']
        else:
            return 'en'
Exemplo n.º 13
0
async def import_fun(message, document, chat, strings):
    chat_id = chat['chat_id']
    key = 'import_lock:' + str(chat_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)),
                               strings['language_info']['babel'])
        await message.reply(strings['imports_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    msg = await message.reply(strings['started_importing'])
    if document['file_size'] > 52428800:
        await message.reply(strings['big_file'])
        return
    data = await bot.download_file_by_id(document.file_id, io.BytesIO())
    data = ujson.load(data)

    if 'general' not in data:
        await message.reply(strings['bad_file'])
        return

    file_version = data['general']['version']

    if file_version > VERSION:
        await message.reply(strings['file_version_so_new'])
        return

    imported = []
    for module in [m for m in LOADED_MODULES if hasattr(m, '__import__')]:
        module_name = module.__name__.replace('sophie_bot.modules.', '')
        if module_name not in data:
            continue
        if not data[module_name]:
            continue

        imported.append(module_name)
        await asyncio.sleep(0)  # Switch to other events before continue
        await module.__import__(chat_id, data[module_name])

    await msg.edit_text(strings['import_done'])
Exemplo n.º 14
0
async def fban_export(message, fed, strings):
    fed_id = fed['fed_id']
    key = 'fbanlist_lock:' + str(fed_id)
    if redis.get(key) and message.from_user.id not in OPERATORS:
        ttl = format_timedelta(timedelta(seconds=redis.ttl(key)), strings['language_info']['babel'])
        await message.reply(strings['fbanlist_locked'] % ttl)
        return

    redis.set(key, 1)
    redis.expire(key, 7200)

    msg = await message.reply(strings['creating_fbanlist'])
    fields = ['user_id', 'reason', 'by', 'time', 'banned_chats']
    with io.StringIO() as f:
        writer = csv.DictWriter(f, fields)
        writer.writeheader()
        async for banned_data in db.fed_bans.find({'fed_id': fed_id}):
            await asyncio.sleep(0)

            data = {'user_id': banned_data['user_id']}

            if 'reason' in banned_data:
                data['reason'] = banned_data['reason']

            if 'time' in banned_data:
                data['time'] = int(time.mktime(banned_data['time'].timetuple()))

            if 'by' in banned_data:
                data['by'] = banned_data['by']

            if 'banned_chats' in banned_data:
                data['banned_chats'] = banned_data['banned_chats']

            writer.writerow(data)

        text = strings['fbanlist_done'] % fed['fed_name']
        f.seek(0)
        await message.answer_document(
            InputFile(f, filename='fban_export.csv'),
            text
        )
    await msg.delete()
Exemplo n.º 15
0
    text = strings['user_kicked'].format(user=await get_user_link(user_id),
                                         admin=await
                                         get_user_link(message.from_user.id),
                                         chat_name=chat['chat_title'])

    # Add reason
    if len(args := message.get_args().split(' ', 1)) > 1:
        text += strings['reason'] % args[1]

    # Check if silent
    silent = False
    if get_cmd(message) == 'skick':
        silent = True
        key = 'leave_silent:' + str(chat_id)
        redis.set(key, user_id)
        redis.expire(key, 30)
        text += strings['purge']

    await kick_user(chat_id, user_id)

    msg = await message.reply(text)

    # Del msgs if silent
    if silent:
        to_del = [msg.message_id, message.message_id]
        if 'reply_to_message' in message and message.reply_to_message.from_user.id == user_id:
            to_del.append(message.reply_to_message.message_id)
        await asyncio.sleep(5)
        await tbot.delete_messages(chat_id, to_del)
Exemplo n.º 16
0
    text, kwargs = await t_unparse_note_item(event.message,
                                             db_item,
                                             chat_id,
                                             event=event)

    if user_id == event.message.chat.id:
        await event.message.delete()

    try:
        await send_note(user_id, text, **kwargs)
        await event.answer(strings['rules_was_pmed'])
    except (UserIsBlockedError, PeerIdInvalidError):
        await event.answer(strings['user_blocked'], show_alert=True)
        key = 'btn_rules_start_state:' + str(user_id)
        redis.set(key, chat_id)
        redis.expire(key, 900)


async def __export__(chat_id):
    rules = await db.rules.find_one({'chat_id': chat_id})
    if rules:
        del rules['_id']
        del rules['chat_id']

        return {'rules': rules}


async def __import__(chat_id, data):
    rules = data
    for column in [i for i in data if i not in ALLOWED_COLUMNS]:
Exemplo n.º 17
0
async def fed_ban_user(message, fed, user, reason, strings):
    user_id = user['user_id']

    # Checks
    if user_id in OPERATORS:
        await message.reply(strings['user_wl'])
        return

    elif user_id == message.from_user.id:
        await message.reply(strings['fban_self'])
        return

    elif user_id == BOT_ID:
        await message.reply(strings['fban_self'])
        return

    elif user_id == fed['creator']:
        await message.reply(strings['fban_creator'])
        return

    elif 'admins' in fed and user_id in fed['admins']:
        await message.reply(strings['fban_fed_admin'])
        return

    elif await db.fed_bans.find_one({'fed_id': fed['fed_id'], 'user_id': user_id}):
        await message.reply(strings['already_fbanned'].format(user=await get_user_link(user_id)))
        return

    text = strings['fbanned_header']
    text += strings['fban_info'].format(
        fed=fed['fed_name'],
        fadmin=await get_user_link(message.from_user.id),
        user=await get_user_link(user_id),
        user_id=user['user_id']
    )
    if reason:
        text += strings['fbanned_reason'].format(reason=reason)

    # fban processing msg
    msg = await message.reply(text + strings['fbanned_process'].format(num=len(fed['chats'])))

    user = await db.user_list.find_one({'user_id': user_id})

    banned_chats = []
    for chat_id in fed['chats']:
        # We not found the user or user wasn't detected
        if not user or 'chats' not in user:
            continue

        if chat_id in user['chats']:
            await asyncio.sleep(0)  # Do not slow down other updates
            if await ban_user(chat_id, user_id):
                banned_chats.append(chat_id)

    new = {
        'fed_id': fed['fed_id'],
        'user_id': user_id,
        'banned_chats': banned_chats,
        'time': datetime.now(),
        'by': message.from_user.id
    }

    if reason:
        new['reason'] = reason

    await db.fed_bans.insert_one(new)

    channel_text = strings['fban_log_fed_log'].format(
        fed_name=fed['fed_name'],
        fed_id=fed['fed_id'],
        user=await get_user_link(user_id),
        user_id=user_id,
        chat_count=len(banned_chats),
        all_chats=len(fed['chats'])
    )

    if reason:
        channel_text += strings['fban_reason_fed_log'].format(reason=reason)

    # Check if silent
    silent = False
    if get_cmd(message) == 'sfban':
        silent = True
        key = 'leave_silent:' + str(message.chat.id)
        redis.set(key, user_id)
        redis.expire(key, 30)
        text += strings['fbanned_silence']

    # SubsFeds process
    if len(sfeds_list := await get_all_subs_feds_r(fed['fed_id'], [])) > 1:
        sfeds_list.remove(fed['fed_id'])
        this_fed_banned_count = len(banned_chats)

        await msg.edit_text(text + strings['fbanned_subs_process'].format(feds=len(sfeds_list)))

        all_banned_chats_count = 0
        for s_fed_id in sfeds_list:
            s_fed = await db.feds.find_one({'fed_id': s_fed_id})
            banned_chats = []
            for chat_id in s_fed['chats']:
                if not user:
                    continue

                elif chat_id == user['user_id']:
                    continue

                elif 'chats' not in user:
                    continue

                elif chat_id not in user['chats']:
                    continue

                # Do not slow down other updates
                await asyncio.sleep(0.2)

                if await ban_user(chat_id, user_id):
                    banned_chats.append(chat_id)
                    all_banned_chats_count += 1

                    new = {
                        'fed_id': s_fed_id,
                        'user_id': user_id,
                        'banned_chats': banned_chats,
                        'time': datetime.now(),
                        'origin_fed': fed['fed_id'],
                        'by': message.from_user.id
                    }

                    if reason:
                        new['reason'] = reason

                    await db.fed_bans.insert_one(new)

        await msg.edit_text(text + strings['fbanned_subs_done'].format(
            chats=this_fed_banned_count,
            subs_chats=all_banned_chats_count,
            feds=len(sfeds_list)
        ))

        channel_text += strings['fban_subs_fed_log'].format(
            subs_chats=all_banned_chats_count,
            feds=len(sfeds_list)
        )