예제 #1
0
async def cmd_readonly(message: types.Message):
    """
    Handler for /ro command in chat.
    Reports which are not replies are ignored.
    Only admins can use this command. A time period may be set after command, f.ex. /ro 2d,
    anything else is treated as commentary with no effect.

    :param message: Telegram message with /ro command and optional time
    """
    # Check if command is sent as reply to some message
    if not message.reply_to_message:
        await message.reply(localization.get_string("error_no_reply"))
        return

    # Admins cannot be restricted
    user = await message.bot.get_chat_member(config.groups.main, message.reply_to_message.from_user.id)
    if user.is_chat_admin():
        await message.reply(localization.get_string("error_restrict_admin"))
        return

    words = message.text.split()
    restriction_time: int = 0
    if len(words) > 1:  # /ro with arg
        restriction_time = utils.get_restriction_time(words[1])
        if not restriction_time:
            await message.reply(localization.get_string("error_wrong_time_format"))
            return

    await message.bot.restrict_chat_member(config.groups.main,
                                           message.reply_to_message.from_user.id,
                                           types.ChatPermissions(),
                                           until_date=int(time()) + restriction_time
                                           )
    await message.reply(localization.get_string("resolved_readonly").format(restriction_time=words[1] if len(words) > 1
    else localization.get_string("restriction_forever")))
예제 #2
0
async def callback_handler(call: types.CallbackQuery):
    """
    Keyboard buttons handler
    :param call: Callback with action put into call.data field
    """
    if call.data.startswith("del_"):
        await bot.delete_message(config.group_main, int(call.data.split("_")[1]))
        await bot.edit_message_text(chat_id=config.group_reports,
                                    message_id=call.message.message_id,
                                    text=call.message.text + lang.get_string("action_deleted"))
        await bot.answer_callback_query(call.id, "Done")
        return
    elif call.data.startswith("delban_"):
        await bot.delete_message(config.group_main, int(call.data.split("_")[1]))
        await bot.kick_chat_member(chat_id=config.group_main, user_id=call.data.split("_")[2])
        await bot.edit_message_text(chat_id=config.group_reports,
                                    message_id=call.message.message_id,
                                    text=call.message.text + lang.get_string("action_deleted_banned"))
        await bot.answer_callback_query(call.id, "Done")
        return
    elif call.data.startswith("mute_"):
        await bot.delete_message(config.group_main, int(call.data.split("_")[1]))
        await bot.restrict_chat_member(chat_id=config.group_main, user_id=call.data.split("_")[2],
                                       permissions=types.ChatPermissions(),
                                       until_date=int(time()) + 7200)  # 2 hours from now
        await bot.edit_message_text(chat_id=config.group_reports,
                                    message_id=call.message.message_id,
                                    text=call.message.text + lang.get_string("action_deleted_readonly"))
        await bot.answer_callback_query(call.id, "Done")
        return
예제 #3
0
async def short_messages(message: types.Message):
    """
    Handler which triggers when there are only 2 or less words in a message.
    If one of the words is considered as "greeting", like "Hello", "Hi" etc, bot kindly
    asks user to express his thoughts without such short useless sentences.
    :param message: Telegram message consisting of 2 or less words
    """
    for word in message.text.lower().split():
        if word.replace(",", "").replace("!", "").replace(".", "") in lang.get_string("greetings_words"):
            await message.reply(lang.get_string("error_message_too_short"))
예제 #4
0
def __get_process_filter_string(pattern):
    if pattern[0] == ARGUMENT_PROCESS_PID:
        return get_string(PROCESS_FILTER_PID_STRING).format(pattern[1])
    elif pattern[0] == ARGUMENT_PROCESS_PATH:
        return get_string(PROCESS_FILTER_PATH_STRING).format(pattern[1])
    elif pattern[0] == ARGUMENT_PROCESS_REGEX:
        return get_string(PROCESS_FILTER_REGEX_STRING).format(
            pattern[1].pattern)
    elif pattern[0] == ARGUMENT_PROCESS_PID_FILE:
        return get_string(PROCESS_FILTER_PID_FILE_STRING).format(pattern[1])
    else:
        return str(pattern)
예제 #5
0
def get_report_comment(message_date: datetime.datetime, message_id: int, report_message: typing.Optional[str]) -> str:
    """
    Generates a report message for admins
    :param message_date: Datetime when reported message was sent
    :param message_id: ID of that message
    :param report_message: An optional note for admins so that they can understand what's wrong
    :return: A report message for admins in report chat
    """
    msg = lang.get_string("report_message").format(
        date=message_date.strftime(lang.get_string("report_date_format")),
        chat_id=get_url_chat_id(config.group_main),
        msg_id=message_id)

    if report_message:
        msg += lang.get_string("report_note").format(note=report_message)
    return msg
예제 #6
0
async def callback_handler(call: types.CallbackQuery):
    """
    Keyboard buttons handler

    :param call: Callback with action put into call.data field
    """
    if call.data.startswith("del_"):
        await call.message.bot.delete_message(Config.GROUP_MAIN,
                                              int(call.data.split("_")[1]))
        await call.message.bot.edit_message_text(
            chat_id=Config.GROUP_REPORTS,
            message_id=call.message.message_id,
            text=call.message.text + localization.get_string("action_deleted"))
        await call.answer(text="Done")

    elif call.data.startswith("delban_"):
        await call.message.bot.delete_message(Config.GROUP_MAIN,
                                              int(call.data.split("_")[1]))
        await call.message.bot.kick_chat_member(
            chat_id=Config.GROUP_MAIN, user_id=call.data.split("_")[2])
        await call.message.bot.edit_message_text(
            chat_id=Config.GROUP_REPORTS,
            message_id=call.message.message_id,
            text=call.message.text +
            localization.get_string("action_deleted_banned"))
        await call.answer(text="Done")

    elif call.data.startswith("mute_"):
        await call.message.bot.delete_message(Config.GROUP_MAIN,
                                              int(call.data.split("_")[1]))
        await call.message.bot.restrict_chat_member(
            chat_id=Config.GROUP_MAIN,
            user_id=call.data.split("_")[2],
            permissions=types.ChatPermissions(),
            until_date=int(time()) + 7200)  # 2 hours from now
        await call.message.bot.edit_message_text(
            chat_id=Config.GROUP_REPORTS,
            message_id=call.message.message_id,
            text=call.message.text +
            localization.get_string("action_deleted_readonly"))
        await call.answer(text="Done")
예제 #7
0
async def calling_all_units(message: types.Message):
    """
    Handler which is triggered when message starts with @admin.
    Honestly any combination will work: @admin, @admins, @adminisshit
    :param message: Telegram message where text starts with @admin
    """
    await bot.send_message(
        config.group_reports,
        lang.get_string("need_admins_attention").format(
            chat_id=utils.get_url_chat_id(config.group_main),
            msg_id=message.reply_to_message.message_id
            if message.reply_to_message else message.message_id))
예제 #8
0
def __draw_graph(tel_type,
                 values,
                 blocks,
                 settings,
                 graph_id_counter,
                 graph_drawers=__GRAPH_DRAWERS):
    if tel_type in __TELEMETRY_FAMILIES:
        family_id = get_string(__TELEMETRY_FAMILIES[tel_type])
        if family_id not in blocks:
            blocks[family_id] = dict()
        blocks = blocks[family_id]

    if tel_type not in graph_drawers:
        blocks[get_string(tel_type)] = \
            '<div class="alert alert-danger" role="alert">{0}</div>'.format(get_string(UNKNOWN_TELEMETRY_TYPE))
        return ''
    else:
        marked_graph_id = graph_id_counter.mark_position()
        java_script = graph_drawers[tel_type](values, settings,
                                              graph_id_counter)

        tel_type_name = get_string(tel_type)
        blocks[tel_type_name] = ''
        for graph_id in graph_id_counter.get_generated_ids(marked_graph_id):
            blocks[tel_type_name] += '<div id="{0}"></div>'.format(graph_id)

        draw_func_name = graph_id + '_draw_func'
        java_script = '''
        function {draw_func_name}(){{
            {draw_code}
        }}

        $("#{graph_id}").parent().parent().on("shown.bs.collapse", function() {{
            {draw_func_name}();
        }});
        '''.format(draw_func_name=draw_func_name,
                   draw_code=java_script,
                   graph_id=graph_id)

        return java_script
예제 #9
0
async def cmd_report(message: types.Message):
    """
    Handler for /report command in chat.
    Reports to admins are ignored. Reports which are not replies are ignored.
    :param message: Telegram message containing /report command
    :return:
    """
    # Check if command is sent as reply to some message
    if not message.reply_to_message:
        await message.reply(lang.get_string("error_no_reply"))
        return

    # We don't want users to report an admin
    user = await bot.get_chat_member(config.group_main,
                                     message.reply_to_message.from_user.id)
    if user.is_chat_admin():
        await message.reply(lang.get_string("error_report_admin"))
        return

    # Check for report message (anything sent after /report command)
    msg_parts = message.text.split()
    report_message = None
    if len(msg_parts) > 1:
        report_message = message.text.replace("/report", "")

    # Generate keyboard with some actions
    action_keyboard = types.InlineKeyboardMarkup()
    # Delete message by its id
    action_keyboard.add(
        types.InlineKeyboardButton(
            text=lang.get_string("action_del_msg"),
            callback_data=f"del_{message.reply_to_message.message_id}"))
    # Delete message by its id and ban user by their id
    action_keyboard.add(
        types.InlineKeyboardButton(
            text=lang.get_string("action_del_and_ban"),
            callback_data=
            f"delban_{message.reply_to_message.message_id}_{message.reply_to_message.from_user.id}"
        ))
    # Delete message by its id and mute user for 2 hours by their id
    action_keyboard.add(
        types.InlineKeyboardButton(
            text=lang.get_string("action_del_and_readonly"),
            callback_data=
            f"mute_{message.reply_to_message.message_id}_{message.reply_to_message.from_user.id}"
        ))

    await message.reply_to_message.forward(config.group_reports)
    await bot.send_message(config.group_reports,
                           utils.get_report_comment(
                               message.reply_to_message.date,
                               message.reply_to_message.message_id,
                               report_message),
                           reply_markup=action_keyboard)
    await message.reply(lang.get_string("report_delivered"))
예제 #10
0
def make_report(settings):
    frames = __read_all_frames(settings[ARGUMENT_COMMAND_PARAMETER])

    templates_path = os.path.join(
        os.path.split(os.path.realpath(__file__))[0], TEMPLATE_DIRECTORY_NAME)
    with open(os.path.join(templates_path, TEMPLATE_HTML_FILE_NAME), 'r') as f:
        template = f.read()

    template = template.replace(TEMPLATE_HEADER_BLOCK,
                                __make_header_block(templates_path))

    telemetries = dict(
    )  # key: TELEMETRY_TYPE, value: list of tuples (datetime, value)
    markers = list()  # list of tuples (datetime, string)
    processes = dict(
    )  # key: process filter, value: dict of key:pid, value:(process_info: dict, telemetries: dict)
    for frame in frames:
        if frame[1] == FRAME_TYPE_TELEMETRY:
            for tel_value in frame[2]:  # tel_value: tuple(type, value)
                if tel_value[0] == TELEMETRY_PROCESSES:
                    for process in tel_value[1]:
                        filter_string = __get_process_filter_string(process[0])
                        if filter_string not in processes:
                            processes[filter_string] = dict()

                        pid = process[1]['pid']
                        if pid not in processes[filter_string]:
                            processes[filter_string][pid] = (process[1],
                                                             dict())
                        else:
                            processes[filter_string][
                                pid] = __merge_process_info(
                                    processes[filter_string][pid], process[1])
                        for p_tel_value in process[2]:
                            if p_tel_value[0] not in processes[filter_string][
                                    pid][1]:
                                processes[filter_string][pid][1][
                                    p_tel_value[0]] = list()
                            processes[filter_string][pid][1][
                                p_tel_value[0]].append(
                                    (frame[0], p_tel_value[1]))
                else:
                    if tel_value[0] not in telemetries:
                        telemetries[tel_value[0]] = list()
                    telemetries[tel_value[0]].append((frame[0], tel_value[1]))
        elif frame[1] == FRAME_TYPE_MARKER:
            markers.append((frame[0], frame[2]))

    js_markers = []
    for marker in markers:
        js_markers.append({
            'value': marker[0].strftime('%H:%M:%S.%f')[:-3],
            'text': marker[1],
            'position': 'start',
        })

    blocks = dict()
    draw_script = '{0} = {1};\n'.format(JS_VAR_MARKERS_LINES,
                                        dump_javascript(js_markers))
    graph_id_counter = GraphIdCounter()
    for tel_type in telemetries:
        draw_script += __draw_graph(tel_type, telemetries[tel_type], blocks,
                                    settings, graph_id_counter)

    content = __get_html_for_block(get_string(SYSTEM_TELEMETRY_STRING), blocks,
                                   graph_id_counter)

    processes_blocks = dict()
    for process_filter in processes:
        processes_blocks[process_filter] = dict()
        pids = processes[process_filter]

        for pid in pids:
            pid_str = str(pid)
            processes_blocks[process_filter][pid_str] = dict()
            processes_blocks[process_filter][pid_str][get_string(PROCESS_INFO_STRING)] = \
                __get_html_for_process_info(pids[pid][0])
            processes_blocks[process_filter][pid_str][get_string(
                TELEMETRY_STRING)] = dict()
            for tel_type in pids[pid][1]:
                draw_script += __draw_graph(
                    tel_type, pids[pid][1][tel_type],
                    processes_blocks[process_filter][pid_str][get_string(
                        TELEMETRY_STRING)], settings, graph_id_counter,
                    __PROCESS_GRAPH_DRAWERS)
    content += __get_html_for_block(get_string(PROCESSES_STRING),
                                    processes_blocks, graph_id_counter)

    template = template.replace(TEMPLATE_CONTENT_BLOCK, content)
    template = template.replace(
        TEMPLATE_END_BLOCK, '''<script type="text/javascript">
                                    $(function(){{
                                        {0}
                                        $('.collapse .in').removeClass('in');
                                    }});
                                    </script>'''.format(draw_script))

    with open(settings[ARGUMENT_OUTPUT], 'w') as f:
        f.write(template)