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")))
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
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"))
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)
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
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")
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))
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
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"))
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)