mirror of https://github.com/nocturn9x/BotBase.git
Added /queue, /chats, /clearflood and /close (admin only). Improved general chat experience
This commit is contained in:
parent
56ec2c9860
commit
52b18b0b93
|
@ -21,6 +21,8 @@ FLOOD_PERCENTAGE = 75
|
|||
ANTIFLOOD_SENSIBILITY = 1
|
||||
# If you want the user to be notified of being flood-blocked, set this to the desired message, False to disable
|
||||
FLOOD_NOTICE = f"🤙 **Hey amico**!\n🕐 Rilassati! Sei stato bloccato per {BAN_TIME / 60:.1f} minuti"
|
||||
FLOOD_CLEARED = "♻️ Tabella antiflood svuotata"
|
||||
FLOOD_USER_CLEARED = "♻️ Tabella antiflood ripulita per `{user}`"
|
||||
DELETE_MESSAGES = True # Set this to false if you do not want the messages to be deleted after flood is detected
|
||||
|
||||
# Various options and global variables
|
||||
|
@ -38,8 +40,8 @@ WORKERS_NUM = 15 # The number of worker threads that pyrogram will spawn at st
|
|||
BOT_TOKEN = "TOKEN HERE" # Get it with t.me/BotFather
|
||||
SESSION_NAME = "BotBase" # The name of the Telegram Session that the bot will have, will be visible from Telegram
|
||||
PLUGINS_ROOT = {"root": f"BotBase/modules"} # Do not change this unless you know what you're doing
|
||||
API_ID = 1234567 # Get it at https://my.telegram.org/apps
|
||||
API_HASH = "abcdef123456" # Same as above
|
||||
API_ID = 123467 # Get it at https://my.telegram.org/apps
|
||||
API_HASH = "abcdef1234567" # Same as above
|
||||
|
||||
# Logging configuration
|
||||
# To know more about what these options mean, check https://docs.python.org/3/library/logging.html
|
||||
|
@ -92,7 +94,7 @@ from .database.query import get_user
|
|||
# Admin module configuration
|
||||
|
||||
# Edit this dict adding the ID:NAME pair of the admin that you want to add. You can add as many admins as you want
|
||||
ADMINS = {669152898: "Matt-sama :3", 836296867: "αℓѕσƓAMƐR"}
|
||||
ADMINS = {123456: "Sample Name"}
|
||||
MARKED_BUSY = "🎲 Ora sei impegnato, invia nuovamente /busy per resettare questo stato"
|
||||
UNMARKED_BUSY = "✍ Da ora riceverai nuovamente le richieste di assistenza"
|
||||
CANNOT_BAN_ADMIN = "❌ L'utente é un amministratore"
|
||||
|
@ -110,6 +112,11 @@ NAME = "tg://user?id={}"
|
|||
BYPASS_FLOOD = True # If False, admins can be flood-blocked too, otherwise the antiflood will ignore them
|
||||
USER_INFO_UPDATED = "✅ Informazioni aggiornate"
|
||||
USER_INFO_UNCHANGED = "❌ Non ho rilevato cambiamenti per questo utente"
|
||||
ADMIN_ACCEPTED_CHAT = "✅ {admin} ha preso in carico la chat con {user}"
|
||||
USER_LEFT_QUEUE = "⚠️ {user} ha lasciato la coda"
|
||||
QUEUE_LIST = "🚻 Lista utenti in attesa\n\n{queue}"
|
||||
CHATS_LIST = "💬 Lista utenti in chat\n\n{chats}"
|
||||
ADMIN_BUSY = "(Occupato)"
|
||||
USER_INFO = """**ℹ️ Informazioni**
|
||||
|
||||
🆔 **ID**: `{uid}`
|
||||
|
@ -165,10 +172,7 @@ def check_user_banned(tg_id: int):
|
|||
else:
|
||||
if not res:
|
||||
return False
|
||||
if res[-1]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return res[-1]
|
||||
|
||||
|
||||
def callback_regex(pattern: str):
|
||||
|
|
|
@ -97,7 +97,7 @@ def set_user(tg_id: int, uname: str):
|
|||
database.execute(DB_SET_USER, (None, tg_id, uname, time.strftime("%d/%m/%Y %T %p"), 0))
|
||||
return True
|
||||
except sqlite3.Error as query_error:
|
||||
logging.error(f"An error has occurred while executing DB_GET_USERS query: {query_error}")
|
||||
logging.error(f"An error has occurred while executing DB_SET_USER query: {query_error}")
|
||||
return query_error
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from ..config import ADMINS, USER_INFO, INVALID_SYNTAX, ERROR, NONNUMERIC_ID, USERS_COUNT, \
|
||||
NO_PARAMETERS, ID_MISSING, GLOBAL_MESSAGE_STATS, NAME, WHISPER_FROM, USER_INFO_UPDATED, USER_INFO_UNCHANGED, \
|
||||
USER_BANNED, USER_UNBANNED, CANNOT_BAN_ADMIN, USER_ALREADY_BANNED, USER_NOT_BANNED, YOU_ARE_BANNED, YOU_ARE_UNBANNED, \
|
||||
MARKED_BUSY, UNMARKED_BUSY, CACHE, YES, NO, NAME_MISSING, bot, WHISPER_SUCCESSFUL
|
||||
MARKED_BUSY, UNMARKED_BUSY, CACHE, YES, NO, NAME_MISSING, bot, WHISPER_SUCCESSFUL, LEAVE_CURRENT_CHAT, \
|
||||
QUEUE_LIST, CHATS_LIST, ADMIN_BUSY
|
||||
from pyrogram import Client, Filters
|
||||
from ..database.query import get_user, get_users, update_name, ban_user, unban_user, get_user_by_name
|
||||
from .antiflood import BANNED_USERS
|
||||
|
@ -226,10 +227,39 @@ def busy(client, message):
|
|||
if len(message.command) > 1:
|
||||
wrapper.send_message(message.chat.id, f"{NO_PARAMETERS.format(command='/busy')}")
|
||||
else:
|
||||
if CACHE[message.from_user.id][0] == "none":
|
||||
if CACHE[message.from_user.id][0] == "IN_CHAT" and CACHE[message.from_user.id][1] != 1234567:
|
||||
wrapper.send_message(message.from_user.id, LEAVE_CURRENT_CHAT)
|
||||
elif CACHE[message.from_user.id][0] == "none":
|
||||
wrapper.send_message(message.chat.id, MARKED_BUSY)
|
||||
CACHE[message.from_user.id] = ["IN_CHAT", 1234567]
|
||||
else:
|
||||
if message.from_user.id in CACHE:
|
||||
del CACHE[message.from_user.id]
|
||||
wrapper.send_message(message.chat.id, UNMARKED_BUSY)
|
||||
|
||||
|
||||
@Client.on_message(Filters.command("chats") & ADMINS_FILTER & Filters.private & ~BANNED_USERS & ~Filters.edited)
|
||||
def chats(client, message):
|
||||
logging.warning(f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /chats")
|
||||
if len(message.command) > 1:
|
||||
wrapper.send_message(message.chat.id, f"{NO_PARAMETERS.format(command='/chats')}")
|
||||
else:
|
||||
text = ""
|
||||
for user in CACHE:
|
||||
if CACHE[user][0] == "IN_CHAT" and user not in ADMINS:
|
||||
admin_id = CACHE[user][1]
|
||||
admin_name = ADMINS[admin_id]
|
||||
text += f"- 👤 [User]({NAME.format(user)}) -> 👨💻 [{admin_name}]({NAME.format(admin_id)})\n"
|
||||
wrapper.send_message(message.chat.id, CHATS_LIST.format(chats=text))
|
||||
|
||||
@Client.on_message(Filters.command("queue") & ADMINS_FILTER & Filters.private & ~BANNED_USERS & ~Filters.edited)
|
||||
def queue(client, message):
|
||||
logging.warning(f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /queue")
|
||||
if len(message.command) > 1:
|
||||
wrapper.send_message(message.chat.id, f"{NO_PARAMETERS.format(command='/queue')}")
|
||||
else:
|
||||
text = ""
|
||||
for user in CACHE:
|
||||
if CACHE[user][0] == "AWAITING_ADMIN":
|
||||
text += f"- 👤 [User]({NAME.format(user)})\n"
|
||||
wrapper.send_message(message.chat.id, QUEUE_LIST.format(queue=text))
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
from pyrogram import Client, Filters
|
||||
from ..config import MAX_UPDATE_THRESHOLD, ANTIFLOOD_SENSIBILITY, BAN_TIME, ADMINS, BYPASS_FLOOD, FLOOD_NOTICE, \
|
||||
FLOOD_PERCENTAGE, CACHE, PRIVATE_ONLY, DELETE_MESSAGES, bot, user_banned
|
||||
FLOOD_PERCENTAGE, CACHE, PRIVATE_ONLY, DELETE_MESSAGES, bot, user_banned, FLOOD_CLEARED, FLOOD_USER_CLEARED, \
|
||||
ERROR, NONNUMERIC_ID, check_user_banned
|
||||
from collections import defaultdict
|
||||
import logging
|
||||
import time
|
||||
from ..methods import MethodWrapper
|
||||
from ..config import check_user_banned
|
||||
|
||||
# Some variables for runtime configuration
|
||||
|
||||
MESSAGES = defaultdict(list) # Internal variable for the antiflood module
|
||||
BANNED_USERS = Filters.user() # Filters where the antiflood will put banned users
|
||||
BYPASS_USERS = Filters.user(list(ADMINS.keys())) if BYPASS_FLOOD else Filters.user()
|
||||
ADMINS = Filters.user(list(ADMINS.keys()))
|
||||
FILTER = Filters.private if PRIVATE_ONLY else ~Filters.user()
|
||||
wrapper = MethodWrapper(bot)
|
||||
|
||||
|
||||
def is_flood(updates: list):
|
||||
"""Calculates if a sequence of
|
||||
updates corresponds to a flood"""
|
||||
"""
|
||||
Calculates if a sequence of
|
||||
updates corresponds to a flood
|
||||
"""
|
||||
|
||||
genexpr = [i <= ANTIFLOOD_SENSIBILITY for i in
|
||||
((updates[i + 1] - timestamp) if i < (MAX_UPDATE_THRESHOLD - 1) else (timestamp - updates[i - 1]) for
|
||||
|
@ -40,7 +43,7 @@ def anti_flood(client, update):
|
|||
logging.warning(f"{user_id} has waited at least {BAN_TIME} seconds in {chat} and can now text again")
|
||||
BANNED_USERS.remove(user_id)
|
||||
del MESSAGES[user_id]
|
||||
elif len(MESSAGES[user_id]) >= MAX_UPDATE_THRESHOLD:
|
||||
elif len(MESSAGES[user_id]) >= MAX_UPDATE_THRESHOLD - 1: # -1 to avoid acting on the next update
|
||||
MESSAGES[user_id].append({chat: (date, message_id)})
|
||||
logging.info(f"MAX_UPDATE_THRESHOLD ({MAX_UPDATE_THRESHOLD}) Reached for {user_id}")
|
||||
user_data = MESSAGES.pop(user_id)
|
||||
|
@ -61,3 +64,21 @@ def anti_flood(client, update):
|
|||
del MESSAGES[user_id]
|
||||
else:
|
||||
MESSAGES[user_id].append({chat: (date, message_id)})
|
||||
|
||||
|
||||
@Client.on_message(FILTER & ADMINS & ~Filters.edited & Filters.command("clearflood"))
|
||||
def clear_flood(_, message):
|
||||
if len(message.command) == 1:
|
||||
global MESSAGES # Ew...
|
||||
MESSAGES = defaultdict(list)
|
||||
for user in BANNED_USERS.copy():
|
||||
BANNED_USERS.remove(user)
|
||||
wrapper.send_message(message.chat.id, FLOOD_CLEARED)
|
||||
else:
|
||||
for user in message.command[1:]:
|
||||
if not user.isdigit():
|
||||
wrapper.send_message(message.chat.id, f"{ERROR}: {NONNUMERIC_ID}")
|
||||
return
|
||||
BANNED_USERS.discard(int(user))
|
||||
MESSAGES.pop(int(user), None)
|
||||
wrapper.send_message(message.chat.id, FLOOD_USER_CLEARED.format(user=", ".join((f"{usr}" for usr in message.command[1:]))))
|
||||
|
|
|
@ -2,7 +2,8 @@ from pyrogram import Client, Filters, InlineKeyboardMarkup, InlineKeyboardButton
|
|||
from ..config import CACHE, ADMINS, ADMINS_LIST_UPDATE_DELAY, callback_regex, admin_is_chatting, \
|
||||
user_is_chatting, LIVE_CHAT_STATUSES, STATUS_BUSY, STATUS_FREE, SUPPORT_REQUEST_SENT, SUPPORT_NOTIFICATION, \
|
||||
ADMIN_JOINS_CHAT, USER_CLOSES_CHAT, JOIN_CHAT_BUTTON, USER_INFO, USER_LEAVES_CHAT, ADMIN_MESSAGE, USER_MESSAGE, \
|
||||
TOO_FAST, CHAT_BUSY, LEAVE_CURRENT_CHAT, USER_JOINS_CHAT, NAME, CANNOT_REQUEST_SUPPORT, YES, NO, user_banned, CLOSE_CHAT_BUTTON, BACK_BUTTON, UPDATE_BUTTON, bot
|
||||
TOO_FAST, CHAT_BUSY, LEAVE_CURRENT_CHAT, USER_JOINS_CHAT, NAME, CANNOT_REQUEST_SUPPORT, YES, NO, user_banned, CLOSE_CHAT_BUTTON, BACK_BUTTON, UPDATE_BUTTON, bot, \
|
||||
ADMIN_ACCEPTED_CHAT
|
||||
import time
|
||||
from ..database.query import get_user
|
||||
from .antiflood import BANNED_USERS
|
||||
|
@ -20,7 +21,7 @@ BUTTONS = InlineKeyboardMarkup(
|
|||
wrapper = MethodWrapper(bot)
|
||||
|
||||
|
||||
@Client.on_callback_query(Filters.callback_data("sos") & ~BANNED_USERS & ~user_banned())
|
||||
@Client.on_callback_query(Filters.regex("sos") & ~BANNED_USERS & ~user_banned())
|
||||
def begin_chat(client, query):
|
||||
cb_wrapper = MethodWrapper(query)
|
||||
if query.from_user.id in ADMINS:
|
||||
|
@ -53,7 +54,7 @@ def begin_chat(client, query):
|
|||
CACHE[query.from_user.id][-1].append((msg.chat.id, msg.message_id))
|
||||
|
||||
|
||||
@Client.on_callback_query(Filters.callback_data("update_admins_list") & ~BANNED_USERS & ~user_banned())
|
||||
@Client.on_callback_query(Filters.regex("update_admins_list") & ~BANNED_USERS & ~user_banned())
|
||||
def update_admins_list(_, query):
|
||||
cb_wrapper = MethodWrapper(query)
|
||||
if CACHE[query.from_user.id][0] == "AWAITING_ADMIN":
|
||||
|
@ -135,7 +136,26 @@ def close_chat(_, query):
|
|||
def forward_from_admin(client, message):
|
||||
if message.text:
|
||||
logging.warning(f"Admin {ADMINS[message.from_user.id]} [{message.from_user.id}] says to {CACHE[message.from_user.id][1]}: {message.text.html}")
|
||||
wrapper.send_message(CACHE[message.from_user.id][1],
|
||||
if message.text == "/close":
|
||||
admin_id = message.from_user.id
|
||||
user_id = CACHE[admin_id][1]
|
||||
data = CACHE[user_id][-1]
|
||||
if isinstance(data, list):
|
||||
data.append((message.from_user.id, message.message_id))
|
||||
for chatid, message_ids in data:
|
||||
wrapper.delete_messages(chatid, message_ids)
|
||||
status = CACHE[message.from_user.id][0]
|
||||
if status == "IN_CHAT":
|
||||
wrapper.send_message(message.from_user.id, USER_LEAVES_CHAT)
|
||||
admin_id, admin_name = message.from_user.id, ADMINS[message.from_user.id]
|
||||
logging.warning(f"{ADMINS[admin_id]} [{admin_id}] has terminated the chat with user {CACHE[admin_id][1]}")
|
||||
if CACHE[user_id][0] == "IN_CHAT":
|
||||
del CACHE[user_id]
|
||||
wrapper.send_message(user_id,
|
||||
USER_CLOSES_CHAT.format(user_id=NAME.format(admin_id), user_name=admin_name))
|
||||
del CACHE[message.from_user.id]
|
||||
else:
|
||||
wrapper.send_message(CACHE[message.from_user.id][1],
|
||||
ADMIN_MESSAGE.format(user_name=ADMINS[message.from_user.id],
|
||||
user_id=NAME.format(message.from_user.id),
|
||||
message=message.text.html))
|
||||
|
@ -205,6 +225,15 @@ def join_chat(_, query):
|
|||
cb_wrapper = MethodWrapper(query)
|
||||
if CACHE[query.from_user.id][0] != "IN_CHAT":
|
||||
user_id = int(query.data.split("_")[1])
|
||||
user = wrapper.get_users(user_id)
|
||||
if isinstance(user, Exception):
|
||||
user_name = "Anonymous"
|
||||
elif user.first_name:
|
||||
user_name = user.first_name
|
||||
elif user.username:
|
||||
user_name = user.username
|
||||
else:
|
||||
user_name = "Anonymous"
|
||||
if CACHE[user_id][0] != "AWAITING_ADMIN":
|
||||
cb_wrapper.answer(CHAT_BUSY)
|
||||
else:
|
||||
|
@ -215,8 +244,12 @@ def join_chat(_, query):
|
|||
message = wrapper.send_message(query.from_user.id, USER_JOINS_CHAT, reply_markup=buttons)
|
||||
admin_joins = wrapper.send_message(user_id, ADMIN_JOINS_CHAT.format(admin_name=admin_name, admin_id=NAME.format(admin_id)),
|
||||
reply_markup=buttons)
|
||||
logging.warning(f"{admin_name} [{admin_id}] has joined a chat with user {user_name} [{user_id}]")
|
||||
for chatid, message_ids in CACHE[user_id][-1]:
|
||||
wrapper.delete_messages(chatid, message_ids)
|
||||
for admin in ADMINS:
|
||||
if CACHE[admin] != "IN_CHAT" and admin != admin_id:
|
||||
wrapper.send_message(admin, ADMIN_ACCEPTED_CHAT.format(admin=f"[{admin_name}]({NAME.format(admin)})", user=f"[{user_name}]({NAME.format(user_id)})"))
|
||||
CACHE[user_id][-1].append((message.chat.id, message.message_id))
|
||||
CACHE[user_id][-1].append((admin_joins.chat.id, admin_joins.message_id))
|
||||
else:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from pyrogram import Client, Filters, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from .antiflood import BANNED_USERS
|
||||
from ..config import GREET, BUTTONS, CREDITS, CACHE, bot, VERSION, RELEASE_DATE, user_banned, BACK_BUTTON
|
||||
from ..config import GREET, BUTTONS, CREDITS, CACHE, bot, VERSION, RELEASE_DATE, user_banned, BACK_BUTTON, USER_LEFT_QUEUE, ADMINS, NAME
|
||||
from ..database.query import get_users, set_user
|
||||
import logging
|
||||
import itertools
|
||||
|
@ -33,14 +33,14 @@ def start_handler(client, message):
|
|||
)
|
||||
|
||||
|
||||
@Client.on_callback_query(Filters.callback_data("info") & ~BANNED_USERS)
|
||||
@Client.on_callback_query(Filters.regex("info") & ~BANNED_USERS)
|
||||
def bot_info(_, query):
|
||||
cb_wrapper = MethodWrapper(query)
|
||||
buttons = InlineKeyboardMarkup([[InlineKeyboardButton(BACK_BUTTON, "back_start")]])
|
||||
cb_wrapper.edit_message_text(CREDITS.format(VERSION=VERSION, RELEASE_DATE=RELEASE_DATE), reply_markup=buttons)
|
||||
|
||||
|
||||
@Client.on_callback_query(Filters.callback_data("back_start") & ~BANNED_USERS)
|
||||
@Client.on_callback_query(Filters.regex("back_start") & ~BANNED_USERS)
|
||||
def back_start(_, query):
|
||||
cb_wrapper = MethodWrapper(query)
|
||||
if query.from_user.first_name:
|
||||
|
@ -52,8 +52,12 @@ def back_start(_, query):
|
|||
if CACHE[query.from_user.id][0] == "AWAITING_ADMIN":
|
||||
data = CACHE[query.from_user.id][-1]
|
||||
if isinstance(data, list):
|
||||
for chatid, message_ids in data[:-2]:
|
||||
for chatid, message_ids in data:
|
||||
wrapper.delete_messages(chatid, message_ids)
|
||||
cb_wrapper.edit_message_text(GREET.format(mention=f"[{name}](tg://user?id={query.from_user.id})", id=query.from_user.id,
|
||||
for admin in ADMINS:
|
||||
wrapper.send_message(admin, USER_LEFT_QUEUE.format(user=f"[{name}]({NAME.format(query.from_user.id)})"))
|
||||
|
||||
wrapper.send_message(query.from_user.id, GREET.format(mention=f"[{name}](tg://user?id={query.from_user.id})", id=query.from_user.id,
|
||||
username=query.from_user.username),
|
||||
reply_markup=BUTTONS)
|
||||
del CACHE[query.from_user.id]
|
||||
|
|
Loading…
Reference in New Issue