diff --git a/tg_bot/modules/sql/welcome_sql.py b/tg_bot/modules/sql/welcome_sql.py index ca24f591..452a9f46 100644 --- a/tg_bot/modules/sql/welcome_sql.py +++ b/tg_bot/modules/sql/welcome_sql.py @@ -62,14 +62,80 @@ def __init__(self, chat_id, name, url, same_line=False): self.url = url self.same_line = same_line +class WelcomeMute(BASE): + __tablename__ = "welcome_mutes" + chat_id = Column(String(14), primary_key=True) + welcomemutes = Column(UnicodeText, default=False) + + def __init__(self, chat_id, welcomemutes): + self.chat_id = str(chat_id) # ensure string + self.welcomemutes = welcomemutes + +class WelcomeMuteUsers(BASE): + __tablename__ = "human_checks" + user_id = Column(Integer, primary_key=True) + chat_id = Column(String(14), primary_key=True) + human_check = Column(Boolean) + def __init__(self, user_id, chat_id, human_check): + + self.user_id = (user_id) # ensure string + self.chat_id = str(chat_id) + self.human_check = human_check + Welcome.__table__.create(checkfirst=True) WelcomeButtons.__table__.create(checkfirst=True) GoodbyeButtons.__table__.create(checkfirst=True) +WelcomeMute.__table__.create(checkfirst=True) +WelcomeMuteUsers.__table__.create(checkfirst=True) INSERTION_LOCK = threading.RLock() WELC_BTN_LOCK = threading.RLock() LEAVE_BTN_LOCK = threading.RLock() +WM_LOCK = threading.RLock() + +def welcome_mutes(chat_id): + try: + welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id)) + if welcomemutes: + return welcomemutes.welcomemutes + return False + finally: + SESSION.close() + + +def set_welcome_mutes(chat_id, welcomemutes): + with WM_LOCK: + prev = SESSION.query(WelcomeMute).get((str(chat_id))) + if prev: + SESSION.delete(prev) + welcome_m = WelcomeMute(str(chat_id), welcomemutes) + SESSION.add(welcome_m) + SESSION.commit() + +def set_human_checks(user_id, chat_id): + with INSERTION_LOCK: + human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id))) + if not human_check: + human_check = WelcomeMuteUsers(user_id, str(chat_id), True) + + else: + human_check.human_check = True + + SESSION.add(human_check) + SESSION.commit() + + return human_check + +def get_human_checks(user_id, chat_id): + try: + human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id))) + if not human_check: + return None + human_check = human_check.human_check + return human_check + finally: + SESSION.close() def get_welc_pref(chat_id): @@ -112,6 +178,15 @@ def get_clean_pref(chat_id): return welc.clean_welcome return False + +def get_welc_mutes_pref(chat_id): + welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id)) + SESSION.close() + + if welcomemutes: + return welcomemutes.welcomemutes + + return False def set_del_joined(chat_id, del_joined): @@ -125,7 +200,6 @@ def set_del_joined(chat_id, del_joined): SESSION.add(curr) SESSION.commit() - def get_del_pref(chat_id): welc = SESSION.query(Welcome).get(str(chat_id)) SESSION.close() diff --git a/tg_bot/modules/welcome.py b/tg_bot/modules/welcome.py index 3df11420..7ba5ba00 100644 --- a/tg_bot/modules/welcome.py +++ b/tg_bot/modules/welcome.py @@ -1,14 +1,16 @@ import html, time +import re from typing import Optional, List -from telegram import Message, Chat, Update, Bot, User -from telegram import ParseMode, InlineKeyboardMarkup +from telegram import Message, Chat, Update, Bot, User, CallbackQuery +from telegram import ParseMode, InlineKeyboardMarkup, InlineKeyboardButton from telegram.error import BadRequest -from telegram.ext import MessageHandler, Filters, CommandHandler, run_async +from telegram.ext import MessageHandler, Filters, CommandHandler, run_async, CallbackQueryHandler from telegram.utils.helpers import mention_markdown, mention_html, escape_markdown import tg_bot.modules.sql.welcome_sql as sql from tg_bot.modules.sql.safemode_sql import is_safemoded +from tg_bot.modules.sql.global_bans_sql import get_gbanned_user from tg_bot import dispatcher, OWNER_ID, LOGGER from tg_bot.modules.helper_funcs.chat_status import user_admin, can_delete, is_user_ban_protected from tg_bot.modules.helper_funcs.misc import build_keyboard, revert_buttons @@ -94,6 +96,10 @@ def new_member(bot: Bot, update: Update): LOGGER.exception("ERROR muting user %s in chat %s (%s) due to %s", mems.id, chat.title, chat.id, excp.message) should_welc, cust_welcome, welc_type = sql.get_welc_pref(chat.id) + welc_mutes = sql.welcome_mutes(chat.id) + user_id = user.id + human_checks = sql.get_human_checks(user_id, chat.id) + gban_checks = get_gbanned_user(user_id) if should_welc: sent = None new_members = update.effective_message.new_chat_members @@ -142,6 +148,23 @@ def new_member(bot: Bot, update: Update): sent = send(update, res, keyboard, sql.DEFAULT_WELCOME.format(first=first_name)) # type: Optional[Message] + + + #User exception from mutes: + if is_user_ban_protected(chat, new_mem.id, chat.get_member(new_mem.id)) or human_checks or gban_checks: + continue + + #Join welcome: + if welc_mutes == "on": + new_join_mem = "[{}](tg://user?id={})".format(new_mem.first_name, user.id) + msg.reply_text("{},\nClick the button below to prove you're human".format(new_join_mem), + reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text="Yes, I'm a human", + callback_data="user_join_({})".format(new_mem.id))]]), parse_mode=ParseMode.MARKDOWN) + bot.restrict_chat_member(chat.id, new_mem.id, + can_send_messages=False, + can_send_media_messages=False, + can_send_other_messages=False, + can_add_web_page_previews=False) delete_join(bot, update) @@ -374,6 +397,41 @@ def reset_goodbye(bot: Bot, update: Update) -> str: "\nReset the goodbye message.".format(html.escape(chat.title), mention_html(user.id, user.first_name)) +@run_async +@user_admin +@loggable +def welcomemute(bot: Bot, update: Update, args: List[str]) -> str: + chat = update.effective_chat # type: Optional[Chat] + user = update.effective_user # type: Optional[User] + msg = update.effective_message # type: Optional[Message] + + if len(args) >= 1: + if args[0].lower() in ("off", "no"): + sql.set_welcome_mutes(chat.id, False) + msg.reply_text("I will no longer mute people on joining!") + return "{}:" \ + "\n#WELCOME_MUTE" \ + "\nAdmin: {}" \ + "\nHas toggled welcome mute to OFF.".format(html.escape(chat.title), + mention_html(user.id, user.first_name)) + + elif args[0].lower() in ("on", "yes"): + sql.set_welcome_mutes(chat.id, "on") + msg.reply_text("I will now mute people when they join and" + " click on the button to be unmuted.") + return "{}:" \ + "\n#WELCOME_MUTE" \ + "\nAdmin: {}" \ + "\nHas toggled welcome mute to ON.".format(html.escape(chat.title), + mention_html(user.id, user.first_name)) + else: + msg.reply_text("Please enter `off` or `on`!", parse_mode=ParseMode.MARKDOWN) + return "" + else: + curr_setting = sql.welcome_mutes(chat.id) + reply = "\n Give me a setting! Choose one of: `off`/`no` or `on`/`yes` only! \nCurrent setting: `{}`" + msg.reply_text(reply.format(curr_setting), parse_mode=ParseMode.MARKDOWN) + return "" @run_async @user_admin @@ -458,6 +516,26 @@ def delete_join(bot: Bot, update: Update): if del_join: update.message.delete() +@run_async +def user_button(bot: Bot, update: Update): + chat = update.effective_chat # type: Optional[Chat] + user = update.effective_user # type: Optional[User] + query = update.callback_query # type: Optional[CallbackQuery] + match = re.match(r"user_join_\((.+?)\)", query.data) + message = update.effective_message # type: Optional[Message] + db_checks = sql.set_human_checks(user.id, chat.id) + join_user = int(match.group(1)) + + if join_user == user.id: + query.answer(text="Yus! You're a human, Unmuted!") + bot.restrict_chat_member(chat.id, user.id, can_send_messages=True, + can_send_media_messages=True, + can_send_other_messages=True, + can_add_web_page_previews=True) + bot.deleteMessage(chat.id, message.message_id) + db_checks + else: + query.answer(text="You're not allowed to do this!") WELC_HELP_TXT = "Your group's welcome/goodbye messages can be personalised in multiple ways. If you want the messages" \ " to be individually generated, like the default welcome message is, you can use *these* variables:\n" \ @@ -527,6 +605,8 @@ def __chat_settings__(chat_id, user_id): - /resetgoodbye: reset to the default goodbye message. - /cleanwelcome : On new member, try to delete the previous welcome message to avoid spamming the chat. - /rmjoin : when someone joins, try to delete the *user* joined the group message. + - /welcomemute : all users that join, get muted; a button gets added to the welcome message for them \ + to unmute themselves. This proves they aren't a bot! - /welcomehelp: view more formatting information for custom welcome/goodbye messages. """.format(WELC_HELP_TXT) @@ -542,8 +622,10 @@ def __chat_settings__(chat_id, user_id): RESET_WELCOME = CommandHandler("resetwelcome", reset_welcome, filters=Filters.group) RESET_GOODBYE = CommandHandler("resetgoodbye", reset_goodbye, filters=Filters.group) CLEAN_WELCOME = CommandHandler("cleanwelcome", clean_welcome, pass_args=True, filters=Filters.group) +WELCOMEMUTE_HANDLER = CommandHandler("welcomemute", welcomemute, pass_args=True, filters=Filters.group) DEL_JOINED = CommandHandler("rmjoin", del_joined, pass_args=True, filters=Filters.group) WELCOME_HELP = CommandHandler("welcomehelp", welcome_help) +BUTTON_VERIFY_HANDLER = CallbackQueryHandler(user_button, pattern=r"user_join_") dispatcher.add_handler(NEW_MEM_HANDLER) dispatcher.add_handler(LEFT_MEM_HANDLER) @@ -554,5 +636,7 @@ def __chat_settings__(chat_id, user_id): dispatcher.add_handler(RESET_WELCOME) dispatcher.add_handler(RESET_GOODBYE) dispatcher.add_handler(CLEAN_WELCOME) +dispatcher.add_handler(WELCOMEMUTE_HANDLER) +dispatcher.add_handler(BUTTON_VERIFY_HANDLER) dispatcher.add_handler(DEL_JOINED) dispatcher.add_handler(WELCOME_HELP)