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, 600) 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)
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, 600) 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)
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, "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "version": VERSION, } } for module in [m for m in LOADED_MODULES if hasattr(m, "__export__")]: await asyncio.sleep(0) # Switch to other events before continue if k := await module.__export__(chat_id): data.update(k)
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, 'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 'version': VERSION } } for module in [m for m in LOADED_MODULES if hasattr(m, '__export__')]: await asyncio.sleep(0) # Switch to other events before continue if k := await module.__export__(chat_id): data.update(k)
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)
async def kick_user_cmd(message, chat, user, args, strings): chat_id = chat["chat_id"] user_id = user["user_id"] if user_id == BOT_ID: await message.reply(strings["kick_DaisyX"]) return elif user_id == message.from_user.id: await message.reply(strings["kick_self"]) return elif await is_user_admin(chat_id, user_id): await message.reply(strings["kick_admin"]) return 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 args: text += strings["reason"] % args # 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)
async def join_expired(chat_id, user_id, message_id, wlkm_msg_id): user = await bot.get_chat_member(chat_id, user_id) if user.status != "restricted": 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])
async def get_chat_lang(chat_id): r = redis.get("lang_cache_{}".format(chat_id)) if r: return r 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 not user_lang or user_lang["user_lang"] not in LANGUAGES: return "en" # Add telegram language in lang cache redis.set("lang_cache_{}".format(chat_id), user_lang["user_lang"]) return user_lang["user_lang"]
async def setflood_command(message: Message, chat: dict, strings: dict): try: args = int(get_args(message)[0]) except ValueError: return await message.reply(strings['invalid_args:setflood']) if args > 200: return await message.reply(strings['overflowed_count']) await AntiFloodConfigState.expiration_proc.set() redis.set(f"antiflood_setup:{chat['chat_id']}", args) await message.reply( strings['config_proc_1'], reply_markup=InlineKeyboardMarkup().add( InlineKeyboardButton(text=strings['cancel'], callback_data=cancel_state.new( user_id=message.from_user.id)) ) )
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'
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()) try: data = rapidjson.load(data) except ValueError: return await message.reply(strings["invalid_file"]) 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("DaisyX.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"])
async def kick_user_cmd(message, chat, user, args, strings): chat_id = chat['chat_id'] user_id = user['user_id'] if user_id == BOT_ID: await message.reply(strings['kick_DaisyX']) return elif user_id == message.from_user.id: await message.reply(strings['kick_self']) return elif await is_user_admin(chat_id, user_id): await message.reply(strings['kick_admin']) return 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 args: text += strings['reason'] % args # 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)
async def add_handler(message, chat, strings): # filters doesn't support anon admins if message.from_user.id == 1087968824: return await message.reply(strings["anon_detected"]) # if not await check_admin_rights(message, chat_id, message.from_user.id, ["can_change_info"]): # return await message.reply("You can't change info of this group") handler = get_args_str(message) if handler.startswith("re:"): pattern = handler random_text_str = "".join(random.choice(printable) for i in range(50)) try: regex.match(pattern, random_text_str, timeout=0.2) except TimeoutError: await message.reply(strings["regex_too_slow"]) return else: handler = handler.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.insert( InlineKeyboardButton( await get_string( chat["chat_id"], data["title"]["module"], data["title"]["string"] ), callback_data=filter_action_cp.new(filter_id=filter_id), ) ) buttons.add(InlineKeyboardButton(strings["cancel_btn"], callback_data="cancel")) user_id = message.from_user.id chat_id = chat["chat_id"] redis.set(f"add_filter:{user_id}:{chat_id}", handler) if handler is not None: await message.reply(text, reply_markup=buttons)
async def all_errors_handler(update: Update, error): if update.message is not None: message = update.message elif update.callback_query is not None: message = update.callback_query.message elif update.edited_message is not None: message = update.edited_message else: return True # we don't want other guys in playground 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)), quote=False) ) if redis.get(chat_id) == str(error): # by err_tlt we assume that it is same error return True if err_tlt == "BadRequest" and err_msg == "Have no rights to send a message": return True ignored_errors = ( "FloodWaitError", "RetryAfter", "SlowModeWaitError", "InvalidQueryID", ) if err_tlt in ignored_errors: return True if err_tlt in ("NetworkError", "TelegramAPIError", "RestartingTelegram"): log.error("Conn/API error detected", exc_info=error) return True text = "<b>Sorry, I encountered a error!</b>\n" text += f"<code>{html.escape(err_tlt, quote=False)}: {html.escape(err_msg, quote=False)}</code>" redis.set(chat_id, str(error), ex=600) await bot.send_message(chat_id, text)
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, 600) 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"] % html.escape(fed["fed_name"], False) f.seek(0) await message.answer_document(InputFile(f, filename="fban_export.csv"), text) await msg.delete()
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, 600) 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'] % html.escape(fed['fed_name'], False) f.seek(0) await message.answer_document(InputFile(f, filename='fban_export.csv'), text) await msg.delete()
async def add_handler(message, chat, strings): # filters doesn't support anon admins if message.from_user.id == 1087968824: return await message.reply(strings['anon_detected']) handler = get_args_str(message) if handler.startswith('re:'): pattern = handler random_text_str = ''.join(random.choice(printable) for i in range(50)) try: regex.match(pattern, random_text_str, timeout=0.2) except TimeoutError: await message.reply(strings['regex_too_slow']) return else: handler = handler.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.insert(InlineKeyboardButton( await get_string(chat['chat_id'], data['title']['module'], data['title']['string']), callback_data=filter_action_cp.new(filter_id=filter_id) )) buttons.add(InlineKeyboardButton( strings['cancel_btn'], callback_data='cancel')) user_id = message.from_user.id chat_id = chat['chat_id'] redis.set(f'add_filter:{user_id}:{chat_id}', handler) if handler is not None: await message.reply(text, reply_markup=buttons)
async def connect_to_chat_direct(message, strings): user_id = message.from_user.id chat_id = message.chat.id if user_id == 1087968824: # just warn the user that connections with admin rights doesn't work return await message.reply(strings['anon_admin_conn'], reply_markup=InlineKeyboardMarkup().add( InlineKeyboardButton( strings['click_here'], callback_data="anon_conn_cb"))) 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('DaisyX_connected_start_state:' + str(user_id), 1)
] # FIXME: Better workaround if not (msg := await send_note(chat_id, text, **kwargs)): # Wasn't able to sent message return # Mute user try: await mute_user(chat_id, user_id) except BadRequest as error: # TODO: Delete the "sent" message ^ return await message.reply( f"welcome security failed due to {error.args[0]}") redis.set(f"welcome_security_users:{user_id}:{chat_id}", msg.id) if raw_time := db_item["welcome_security"].get("expire", None): time = convert_time(raw_time) else: time = convert_time(get_str_key("JOIN_CONFIRM_DURATION")) scheduler.add_job( join_expired, "date", id=f"wc_expire:{chat_id}:{user_id}", run_date=datetime.utcnow() + time, kwargs={ "chat_id": chat_id, "user_id": user_id, "message_id": msg.id,
@chat_connection(admin=True) @get_strings_dec("antiflood") async def setfloodaction(message: Message, chat: dict, strings: dict): SUPPORTED_ACTIONS = ["kick", "ban", "mute", "tmute", "tban"] # noqa if (action := message.get_args().lower()) not in SUPPORTED_ACTIONS: return await message.reply( strings["invalid_args"].format( supported_actions=", ".join(SUPPORTED_ACTIONS) ) ) if action.startswith("t"): await message.reply( "Send a time for t action", allow_sending_without_reply=True ) redis.set(f"floodactionstate:{chat['chat_id']}", action) return await AntiFloodActionState.set_time_proc.set() await db.antiflood.update_one( {"chat_id": chat["chat_id"]}, {"$set": {"action": action}}, upsert=True ) await get_data.reset_cache(message.chat.id) return await message.reply(strings["setfloodaction_success"].format(action=action)) @register( state=AntiFloodActionState.set_time_proc, user_can_restrict_members=True, allow_kwargs=True, ) @chat_connection(admin=True)
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)
if len(args) > 1: text += strings["reason"] % " ".join(args[1:]) else: await message.reply(strings["enter_time"]) return else: # Add reason if args is not None and len(args := args.split()) > 0: text += strings["reason"] % " ".join(args[0:]) # Check if silent silent = False if curr_cmd in ("smute", "stmute"): silent = True key = "leave_silent:" + str(chat_id) redis.set(key, user_id) redis.expire(key, 30) text += strings["purge"] await mute_user(chat_id, user_id, until_date=until_date) 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)