Beispiel #1
0
async def update_user(from_user, update_visit=True):
    if not from_user.is_bot:
        user = await db.users.find_one({'id': from_user.id})

        if not user:
            from_user = from_user.to_python()

            user = from_user
            user.update({'_id': from_user['id']})
            if user.get('first_name'):
                user['first_name'] = quote_html(user['first_name'])
            if user.get('last_name'):
                user['last_name'] = quote_html(user['last_name'])
            if update_visit:
                user.update({'last_visit': datetime.utcnow()})
            await db.users.insert_one(user)
        else:
            from_user = from_user.to_python()
            if 'last_name' not in from_user:
                from_user['last_name'] = None
            if 'username' not in from_user:
                from_user['username'] = None
            if from_user.get('first_name'):
                from_user['first_name'] = quote_html(from_user['first_name'])
            if from_user.get('last_name'):
                from_user['last_name'] = quote_html(from_user['last_name'])
            if update_visit:
                from_user.update({'last_visit': datetime.utcnow()})
            usr = {'$set': from_user}
            user = await db.users.find_one_and_update({'_id': user['id']}, usr, upsert=True,
                                                      return_document=ReturnDocument.AFTER)
    else:
        user = None
    return user
Beispiel #2
0
def detect_message_text_formatting(message: Message) -> Optional[str]:
    """
    Detects message formatting
    (html, markdown or None if message has special entities)
    """

    raw_text: str = message.text

    before_escape_md = raw_text.count('\\')
    before_escape_html = raw_text.count('&')

    escaped_md = escape_md(raw_text).count('\\') - before_escape_md
    escaped_html = quote_html(raw_text).count('&') - before_escape_html

    with dont_change_plain_urls, dont_escape_md:
        with_entities = message.md_text

    escaped_with_entities = escape_md(with_entities).count(
        '\\') - before_escape_md

    if escaped_with_entities > max(escaped_html, escaped_md):
        parse_mode = None
    elif escaped_html > escaped_md:
        parse_mode = 'html'
    else:
        parse_mode = 'markdown'

    return parse_mode
Beispiel #3
0
async def translate_at_transifex(message: types.Message):
    user = await get_user(message.from_user.id)
    language = user.get("language_code") or config.DEFAULT_LANGUAGE
    project = user.get("project") or config.DEFAULT_PROJECT

    resource, string = await random_string(
        language, project, translated=False, max_size=300,
    )
    string_url = transifex_string_url(resource, string["key"], language, project)

    response = await render_template(
        message.from_user.id,
        "translate_at_transifex",
        source=string["source_string"],
        transifex_url=string_url,
        docsurl=docsurl(resource).replace("__", "\_\_"),
    )

    response = quote_html(response)
    try:
        await bot.send_message(
            message.chat.id,
            response,
            disable_web_page_preview=True,
            parse_mode="markdown",
        )
    except BotBlocked:
        logger.exception("i17obot blocked by user. userid=%r", message.chat.id)
Beispiel #4
0
async def karma_change(message: types.Message, karma: dict, user: User, chat: Chat, target: User, config: Config):
    try:
        result_change_karma = await change_karma(
            target_user=target,
            chat=chat,
            user=user,
            how_change=karma['karma_change'],
            comment=karma['comment'],
            bot=message.bot,
        )
    except SubZeroKarma:
        return await message.reply("У Вас слишком мало кармы для этого")
    except DontOffendRestricted:
        return await message.reply("Не обижай его, он и так наказан!")
    except CantChangeKarma as e:
        logger.info("user {user} can't change karma, {e}", user=user.tg_id, e=e)
        return

    if result_change_karma.was_auto_restricted:
        notify_text = config.auto_restriction.render_auto_restriction(
            target, result_change_karma.count_auto_restrict)
    elif result_change_karma.karma_after < 0 and await is_enable_karmic_restriction(chat):
        notify_text = config.auto_restriction.render_negative_karma_notification(
            target, result_change_karma.count_auto_restrict)
    else:
        notify_text = ""

    # How match karma was changed. Sign show changed difference, not difference for cancel
    how_changed_karma = result_change_karma.user_karma.karma \
        - result_change_karma.karma_after \
        + result_change_karma.abs_change

    msg = await message.reply(
        "Вы {how_change} карму <b>{name}</b> до <b>{karma_new:.2f}</b> ({power:+.2f})"
        "\n\n{notify_text}".format(
            how_change=get_how_change_text(karma['karma_change']),
            name=quote_html(target.fullname),
            karma_new=result_change_karma.karma_after,
            power=result_change_karma.abs_change,
            notify_text=notify_text,
        ),
        disable_web_page_preview=True,
        allow_sending_without_reply=True,
        reply_markup=kb.get_kb_karma_cancel(
            user=user,
            karma_event=result_change_karma.karma_event,
            rollback_karma=-how_changed_karma,
            moderator_event=result_change_karma.moderator_event,
        )
    )
    asyncio.create_task(remove_kb(msg, config.time_to_cancel_actions))
Beispiel #5
0
    async def _consume_tg_log(self):
        while True:
            item = await self._queue.get()
            if item is None:
                break

            msg, silent, quote = item

            self._logger.debug('sending message to %s: %s', self._channel_id,
                               item)
            await self._bot.send_message(self._channel_id,
                                         quote_html(msg) if quote else msg,
                                         disable_notification=silent)
            await asyncio.sleep(0.0)
async def update_chat(from_chat):
    chat = await db.chats.find_one({'id': from_chat.id})

    if not chat:
        chat = from_chat.to_python()
        chat['title'] = quote_html(chat['title'])
        c = {'_id': chat['id']}
        chat.update(c)

        await db.chats.insert_one(chat)
    else:
        # I don't care about chat title, really, even username
        pass

    return chat
Beispiel #7
0
async def cmd_report(message: types.Message, config: Config, lang: str):
    """
    Handle /report command in main group

    :param message: Telegram message starting with /report
    :param config: bot config
    :param lang: preferred bot language
    """
    reported = await message.chat.get_member(
        message.reply_to_message.from_user.id)
    if reported.is_chat_admin():
        await message.reply(get_string(lang, "error_report_admin"))
        return

    available_options = {
        get_string(lang, "action_del_msg"): "del",
        get_string(lang, "action_del_and_ban"): "ban"
    }
    parts = message.text.split(maxsplit=1)
    report_msg_template = get_string(lang, "report_message")
    if len(parts) == 2:
        report_msg_template += get_string(
            lang, "report_note").format(note=quote_html(parts[1]))

    msg = await message.reply(get_string(lang, "report_sent"))

    kb = types.InlineKeyboardMarkup()
    for button_text, option in available_options.items():
        kb.add(
            types.InlineKeyboardButton(
                text=button_text,
                callback_data=report_msg_cb.new(
                    option=option,
                    user_id=message.reply_to_message.from_user.id,
                    # Collect all IDs (initial message, report message, report confirmation) to delete afterwards
                    message_ids=
                    f"{message.reply_to_message.message_id},{message.message_id},{msg.message_id}"
                )))
    await message.reply_to_message.forward(config.group.reports)
    await message.bot.send_message(
        config.group.reports,
        report_msg_template.format(
            time=message.reply_to_message.date.strftime(
                get_string(lang, "report_date_format")),
            msg_url=get_message_url(message.chat.id,
                                    message.reply_to_message.message_id),
        ),
        reply_markup=kb)
Beispiel #8
0
async def karma_change(message: types.Message, karma: dict, user: User, chat: Chat, target: User):

    try:
        result_change_karma = await change_karma(
            target_user=target,
            chat=chat,
            user=user,
            how_change=karma['karma_change'],
            comment=karma['comment'],
            bot=message.bot,
        )
    except SubZeroKarma:
        return await message.reply("У Вас слишком мало кармы для этого")
    except DontOffendRestricted:
        return await message.reply("Не обижай его, он и так наказан!")
    except CantChangeKarma as e:
        logger.info("user {user} can't change karma, {e}", user=user.tg_id, e=e)
        return
    if result_change_karma.count_auto_restrict:
        notify_auto_restrict_text = await render_text_auto_restrict(result_change_karma.count_auto_restrict, target)
    else:
        notify_auto_restrict_text = ""

    # How match karma was changed. Sign show changed difference, not difference for cancel
    how_changed_karma = result_change_karma.user_karma.karma \
        - result_change_karma.karma_after \
        + result_change_karma.abs_change

    msg = await message.reply(
        "Вы {how_change} рейтинг <b>{name}</b> до <b>{karma_new}</b> ({power})"
        "\n\n{notify_auto_restrict_text}".format(
            how_change=get_how_change_text(karma['karma_change']),
            name=quote_html(target.fullname),
            karma_new=result_change_karma.karma_after,
            power=result_change_karma.abs_change,
            notify_auto_restrict_text=notify_auto_restrict_text
        ),
        disable_web_page_preview=True,
        reply_markup=kb.get_kb_karma_cancel(
            user=user,
            karma_event=result_change_karma.karma_event,
            rollback_karma=-how_changed_karma,
            moderator_event=result_change_karma.moderator_event,
        )
    )
    asyncio.create_task(remove_kb(msg, config.TIME_TO_CANCEL_ACTIONS))
    asyncio.create_task(delete_message(msg, config.TIME_TO_REMOVE_TEMP_MESSAGES))
Beispiel #9
0
async def text_report_admins(message: types.Message):
    logger.info(
        "User {user} report message {message} in chat {chat} from user {from_user}",
        user=message.from_user.id,
        message=message.message_id,
        chat=message.chat.id,
        from_user=message.reply_to_message.from_user.id,
    )
    if not message.reply_to_message:
        return await message.reply(
            "Используйте эту команду в ответ (реплай) на нужное сообщение пользователя"
        )

    admins: List[types.ChatMember] = await message.chat.get_administrators()
    text = "[РЕПОРТ] Пользователь {user} пожаловался на другого пользователя в чате {chat}.".format(
        user=message.from_user.get_mention(),
        chat=hlink(
            message.chat.title,
            f"https://t.me/{message.chat.username}/{message.reply_to_message.message_id}",
        ) if message.chat.username else quote_html(repr(message.chat.title)),
    )

    admin_ids = [
        admin.user.id for admin in admins
        if admin.is_chat_admin() and not admin.user.is_bot
    ]
    if admin_ids:
        for admin in await User.query.where(User.id.in_(admin_ids)).gino.all():
            with suppress(Unauthorized):
                await bot.send_message(admin.id, text)
                logger.info("Send alert message to admin {admin}",
                            admin=admin.id)
            await asyncio.sleep(0.3)

    reply_msg = await message.reply_to_message.reply(
        "Ваша жалоба была отправлена!")

    await asyncio.sleep(30)

    await reply_msg.delete()
Beispiel #10
0
async def text_report_admins(message: types.Message):
    logger.info(
        "User {user} report message {message} in chat {chat} from user {from_user}",
        user=message.from_user.id,
        message=message.message_id,
        chat=message.chat.id,
        from_user=message.reply_to_message.from_user.id,
    )
    if not message.reply_to_message:
        return await message.reply(
            _(
                "Please use this command is only in reply to message what do you want to report "
                "and this message will be reported to chat administrators."
            )
        )

    admins: List[types.ChatMember] = await message.chat.get_administrators()
    text = _("[ALERT] User {user} is reported message in chat {chat}.").format(
        user=message.from_user.get_mention(),
        chat=hlink(
            message.chat.title,
            f"https://t.me/{message.chat.username}/{message.reply_to_message.message_id}",
        )
        if message.chat.username
        else quote_html(repr(message.chat.title)),
    )

    admin_ids = [
        admin.user.id for admin in admins if admin.is_chat_admin() and not admin.user.is_bot
    ]
    if admin_ids:
        for admin in await User.query.where(
            User.id.in_(admin_ids) & (User.do_not_disturb == False)  # NOQA
        ).gino.all():  # NOQA
            with suppress(Unauthorized):
                await bot.send_message(admin.id, text)
                logger.info("Send alert message to admin {admin}", admin=admin.id)
            await asyncio.sleep(0.3)

    await message.reply_to_message.reply(_("This message is reported to chat administrators."))
Beispiel #11
0
async def ask_for_translation(query: types.CallbackQuery):
    user = await User.get(query.from_user.id)

    if not user.transifex_username:
        response = await render_template(user.id, "missing_username")
        keyboard_markup = make_keyboard(
            ("⚙️ Configurar usuário", "configure-username"),
        )
        await bot.edit_message_text(
            quote_html(response),
            query.message.chat.id,
            query.message.message_id,
            disable_web_page_preview=True,
            reply_markup=keyboard_markup,
            parse_mode="Markdown",
        )
        return

    string = user.translating_string

    user.translate()
    await user.update()

    response = await render_template(
        user.id,
        "init_translation",
        source=string.source,
        transifex_url=string.url,
        docsurl=docsurl(string.resource).replace("__", "\_\_"),
    )

    await bot.edit_message_text(
        response,
        query.message.chat.id,
        query.message.message_id,
        disable_web_page_preview=True,
        parse_mode="Markdown",
    )
Beispiel #12
0
async def admin_commands(m: Message):
    if m.text == '!info':
        count = await db.func.count(User.id).gino.scalar() # pylint: disable=no-member
        time = datetime.now().strftime('|%d.%m.%y - %H:%M|')
        await m.reply(f"<b>Server time:</b> {time}\n<b>User count:</b> {count}")
    elif '!log' in m.text:
        data = ''
        with open('log.log', 'r') as log:
            try:
                for row in deque(log, int(m.text[4:])):
                    data += quote_html(row)
                await m.reply(data)
            except (ValueError) as err:
                await m.reply(f'<b>{err.__class__.__name__}</b> - Введи правильное число строк!')
    elif '!get' in m.text: 
        if len(m.text) > 4:
            lst = m.text.split(' ')
            result = await User.get(int(lst[1]))
            if result:
                m.from_user.first_name = result.id
                await user_profile(m, result, False)
            else:
                await m.reply('❗ Ничего не найдено')
        elif m.text == '!get':
            await AdminStates.getuser.set()
            await m.reply("Перешли любое сообщение от юзера.")
    elif '!deluser' in m.text:
        if m.text == '!deluser':
            await AdminStates.deluser.set()
            await m.reply("Перешли любое сообщение от юзера.")
    elif '!reload' == m.text:
        count, user_count = await broadcaster(text='❗ Бот будет перезагружен через через (1) минуту. <i>Рекомендуется покинуть бой/торговую площадку/лазарет</i>.', disable_notification=False)
        await m.reply(f'❕ Ваше сообщение получили {count}/{user_count} пользователя/ей.')    
    elif m.text[:10] == '!broadcast' or m.text[:11] == '!sbroadcast':
        text = m.text.split(' ', 1)
        count, user_count = await broadcaster(text=text[1], disable_notification=False if text[0] == '!broadcast' else True)
        await m.reply(f'❕ Ваше сообщение получили {count}/{user_count} пользователя/ей.')
Beispiel #13
0
async def guide_cmd(message: types.Message):
    await message.reply(
        quote_html("Here's what I can do:\n\n"
                   "/btns <count:int> <text> - create a new keyboard\n"
                   "/rm - clear the keyboard"))
Beispiel #14
0
 def mention_no_link(self):
     if self.username:
         rez = hlink(self.fullname, f"t.me/{self.username}")
     else:
         rez = quote_html(self.fullname)
     return rez
Beispiel #15
0
async def cmd_version(message: types.Message):
    await message.reply(
        _("My Engine:\n{aiogram}").format(aiogram=quote_html(str(aiogram_core.SysInfo())))
    )
Beispiel #16
0
async def log_info(bot: Bot, log_msg: str):
    logger.info(log_msg)
    await bot.send_message(config.LOG_CHAT_ID,
                           quote_html(log_msg),
                           parse_mode=types.ParseMode.HTML)
Beispiel #17
0
async def update(tg_chatid, ig_profile):
    write(f"\033[2K\rchecking @{ig_profile}…")
    await bot.send_chat_action(tg_chatid, types.ChatActions.TYPING)
    try:
        pl = ProfileLooter(ig_profile)
    except Exception as e:
        write(f"\033[2K\r\033[31munable to get profile @{ig_profile}\033[0m\n")
        print(tb.format_exc())
        return False
    with open(sent_fp, "r") as f:
        sent = json.load(f)
    sent_something = False
    for j, media in enumerate(pl.medias()):
        i = media["id"]
        sc = media["shortcode"]
        write(f"\033[2K\rchecking @{ig_profile} ({j}|{i}|{sc})")
        if i not in sent:
            write(": \033[sgetting post…")
            _pl = PostLooter(sc)
            try:
                info = _pl.get_post_info(sc)
            except Exception as e:  #because the library I use can randomly throw errors while getting stuff…
                write("\033[u\033[0K\033[31munable to get post\033[0m\n")
                print(tb.format_exc())
                continue
            caption = "\n".join(
                edge["node"]["text"]
                for edge in info["edge_media_to_caption"]["edges"])
            with MemoryFS() as fs:
                if media["is_video"]:
                    await bot.send_chat_action(tg_chatid,
                                               types.ChatActions.RECORD_VIDEO)
                    _pl.download_videos(fs, media_count=1)
                    func = bot.send_video
                    fn = fs.listdir("./")[0]
                    await bot.send_chat_action(tg_chatid,
                                               types.ChatActions.UPLOAD_VIDEO)
                elif media["__typename"].lower() == "graphimage":
                    await bot.send_chat_action(tg_chatid,
                                               types.ChatActions.UPLOAD_PHOTO)
                    _pl.download_pictures(fs, media_count=1)
                    func = bot.send_photo
                    fn = fs.listdir("./")[0]
                elif media["__typename"].lower() == "graphsidecar":
                    await bot.send_chat_action(tg_chatid,
                                               types.ChatActions.UPLOAD_PHOTO)
                    _pl.download_pictures(fs)
                    fn = tuple(fs.listdir("./"))
                    if len(fn) == 1:
                        func = bot.send_photo
                        fn = fn[0]
                    else:
                        func = bot.send_media_group
                else:
                    await bot.send_message(
                        tg_chatid,
                        f"Oh-oh. I've encountered a new post type!\nPlease tell my developer, so he can tell me what I should do with a {media}."
                    )
                    print("\n\033[31mUNKNOWN MEDIA TYPE AAAAA\033[0m", media)
                    break
                if isinstance(fn, tuple):
                    write("\033[u\033[0Ksending album…")
                    f = [fs.openbin(_fn) for _fn in fn]
                    _media = types.input_media.MediaGroup()
                    for _f in f:
                        _media.attach_photo(_f)
                else:
                    write("\033[u\033[0Ksending file…")
                    _media = f = fs.openbin(fn)
                if len(
                        caption
                ) > 100:  #telegram media captions have a character limit of 200 chars & I want to have a buffer
                    caption = caption[:100] + "[…]"
                markdown.quote_html(caption)
                text = f"{caption}\n→<a href=\"https://www.instagram.com/p/{sc}\">original post</a>"
                try:
                    if isinstance(fn, tuple):
                        msg_id = (await func(tg_chatid,
                                             _media))[-1]["message_id"]
                        await bot.send_message(tg_chatid,
                                               text,
                                               reply_to_message_id=msg_id,
                                               parse_mode=types.ParseMode.HTML)
                    else:
                        await func(tg_chatid,
                                   _media,
                                   caption=text,
                                   parse_mode=types.ParseMode.HTML)
                except exceptions.BadRequest as e:
                    write(
                        "\033[u\033[0K\033[31mskipped\033[0m\nGot Bad Request while trying to send message.\n"
                    )
                except exceptions.RetryAfter as e:
                    write(
                        "\nMEEP MEEP FLOOD CONTROL - YOU'RE FLOODING TELEGRAM\nstopping sending messages & waiting for next cycle…\n"
                    )
                    break
                else:
                    sent.append(i)
                    write("\033[u\033[0Ksaving sent messages…\033[0m")
                    with open(sent_fp, "w+") as f:
                        json.dump(sent, f)
                    write("\033[u\033[0K\033[32msent\033[0m\n")
                if isinstance(f, list):
                    for _f in f:
                        _f.close()
                else:
                    f.close()
            sent_something = True
        # sometimes the page has to be reloaded, which would prolong the time the checking post…
        # message would be displayed if I didn't do this
        write(f"\033[2K\rchecking @{ig_profile}…")
    return sent_something
Beispiel #18
0
 def mention(self):
     return hlink(self.title,
                  f"t.me/{self.username}") if self.username else quote_html(
                      self.title)
Beispiel #19
0
async def translate(
    message: typing.Union[types.CallbackQuery, types.Message], user: User, string=None
):
    if isinstance(message, types.Message):
        message_id = message.message_id
        chat_id = message.chat.id
    else:
        message_id = message.message.message_id
        chat_id = message.message.chat.id

    await bot.send_chat_action(chat_id, "typing")
    if user.state != "idle":
        user.cancel_translation()
        await user.update()

    if not string:
        string = await random_string(
            user.language_code, user.project, translated=False, max_size=30,
        )

        user.translating_string = string
        await user.update()

    message_1 = f"```\n{string.source}\n```"
    message_2 = await render_template(
        user.id, "translate", docsurl=docsurl(string.resource).replace("__", "\_\_"),
    )
    message_2 = quote_html(message_2)

    if user.is_beta:
        keyboard_markup = make_keyboard(
            ("Traduzir no Telegram", "init-translation"),
            ("Traduzir no Transifex", string.url),
            ("Escolher outro trecho", "translate"),
        )
    else:
        keyboard_markup = make_keyboard(
            ("Traduzir no Transifex", string.url),
            ("Traduzir no Telegram", "init-translation"),
            [("⏭ Próximo", "translate"), ("❌ Cancelar", "cancel-translating"),],
        )

    options = {
        "disable_web_page_preview": True,
        "parse_mode": "markdown",
        "reply_markup": keyboard_markup,
    }
    try:
        if isinstance(message, types.Message):
            await bot.send_message(user.id, message_1, parse_mode="markdown")
            await bot.send_message(user.id, message_2, **options)
        else:
            await bot.edit_message_text(
                message_1, chat_id, message_id - 1, parse_mode="markdown",
            )
            await bot.edit_message_text(
                message_2, chat_id, message_id, **options,
            )

    except BotBlocked:
        logger.exception("i17obot blocked by user. userid=%r", user.id)
    except TelegramAPIError:
        logger.exception(
            "Telegram API Error while sending message. message_1=%r, message_2=%r",
            message_1,
            message_2,
        )