Karma
commited on
Commit
·
c7dfe8b
1
Parent(s):
bd415c3
Add files via upload
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- Database/mongodb/db.py +6 -0
- Database/mongodb/karma_mongo.py +122 -0
- Database/mongodb/mongodb.py +75 -0
- Database/mongodb/toggle_mongo.py +50 -0
- Database/mongodb/users_db.py +102 -0
- Database/mongodb/whispers.py +19 -0
- Database/sql/__init__.py +27 -0
- Database/sql/antiflood_sql.py +145 -0
- Database/sql/approve_sql.py +61 -0
- Database/sql/blacklistusers_sql.py +69 -0
- Database/sql/connection_sql.py +204 -0
- Database/sql/cust_filters_sql.py +299 -0
- Database/sql/disable_sql.py +105 -0
- Database/sql/global_bans_sql.py +167 -0
- Database/sql/kuki_sql.py +42 -0
- Database/sql/log_channel_sql.py +156 -0
- Database/sql/rules_sql.py +58 -0
- Database/sql/userinfo_sql.py +76 -0
- Database/sql/users_sql.py +235 -0
- Database/sql/welcome_sql.py +428 -0
- Dockerfile +12 -0
- Extra/Calistoga-Regular.ttf +0 -0
- Extra/MutantAcademyStyle.ttf +0 -0
- Extra/a.jpg +0 -0
- Extra/bgg.jpg +0 -0
- Extra/default.ttf +0 -0
- Extra/profilepic.png +0 -0
- Infamous/karma.py +105 -0
- Infamous/temp.py +122 -0
- LICENSE +21 -0
- Mikobot/__init__.py +254 -0
- Mikobot/__main__.py +793 -0
- Mikobot/events.py +70 -0
- Mikobot/plugins/__init__.py +43 -0
- Mikobot/plugins/admin.py +1148 -0
- Mikobot/plugins/ai.py +142 -0
- Mikobot/plugins/alive.py +57 -0
- Mikobot/plugins/anime.py +0 -0
- Mikobot/plugins/antinsfw.py +189 -0
- Mikobot/plugins/ban.py +1045 -0
- Mikobot/plugins/botadmins.py +106 -0
- Mikobot/plugins/chatbot.py +188 -0
- Mikobot/plugins/connection.py +441 -0
- Mikobot/plugins/cosplay.py +37 -0
- Mikobot/plugins/couple.py +124 -0
- Mikobot/plugins/cust_filters.py +756 -0
- Mikobot/plugins/disable.py +376 -0
- Mikobot/plugins/extra.py +131 -0
- Mikobot/plugins/flood.py +457 -0
- Mikobot/plugins/gban.py +543 -0
Database/mongodb/db.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from motor.motor_asyncio import AsyncIOMotorClient as MongoClient
|
2 |
+
|
3 |
+
from Mikobot import DB_NAME, MONGO_DB_URI
|
4 |
+
|
5 |
+
mongo = MongoClient(MONGO_DB_URI)
|
6 |
+
dbname = mongo[DB_NAME]
|
Database/mongodb/karma_mongo.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict, Union
|
2 |
+
|
3 |
+
from pymongo import MongoClient
|
4 |
+
|
5 |
+
from Mikobot import DB_NAME, MONGO_DB_URI
|
6 |
+
|
7 |
+
client = MongoClient(MONGO_DB_URI)
|
8 |
+
db = client[DB_NAME]
|
9 |
+
|
10 |
+
coupledb = db.couple
|
11 |
+
karmadb = db.karma
|
12 |
+
|
13 |
+
|
14 |
+
async def _get_lovers(chat_id: int):
|
15 |
+
lovers = coupledb.find_one({"chat_id": chat_id})
|
16 |
+
if lovers:
|
17 |
+
lovers = lovers["couple"]
|
18 |
+
else:
|
19 |
+
lovers = {}
|
20 |
+
return lovers
|
21 |
+
|
22 |
+
|
23 |
+
async def get_couple(chat_id: int, date: str):
|
24 |
+
lovers = await _get_lovers(chat_id)
|
25 |
+
if date in lovers:
|
26 |
+
return lovers[date]
|
27 |
+
else:
|
28 |
+
return False
|
29 |
+
|
30 |
+
|
31 |
+
async def save_couple(chat_id: int, date: str, couple: dict):
|
32 |
+
lovers = await _get_lovers(chat_id)
|
33 |
+
lovers[date] = couple
|
34 |
+
coupledb.update_one({"chat_id": chat_id}, {"$set": {"couple": lovers}}, upsert=True)
|
35 |
+
|
36 |
+
|
37 |
+
async def get_karmas_count() -> dict:
|
38 |
+
chats = karmadb.find({"chat_id": {"$lt": 0}})
|
39 |
+
if not chats:
|
40 |
+
return {}
|
41 |
+
chats_count = 0
|
42 |
+
karmas_count = 0
|
43 |
+
for chat in await chats.to_list(length=1000000):
|
44 |
+
for i in chat["karma"]:
|
45 |
+
karma_ = chat["karma"][i]["karma"]
|
46 |
+
if karma_ > 0:
|
47 |
+
karmas_count += karma_
|
48 |
+
chats_count += 1
|
49 |
+
return {"chats_count": chats_count, "karmas_count": karmas_count}
|
50 |
+
|
51 |
+
|
52 |
+
async def user_global_karma(user_id) -> int:
|
53 |
+
chats = karmadb.find({"chat_id": {"$lt": 0}})
|
54 |
+
if not chats:
|
55 |
+
return 0
|
56 |
+
total_karma = 0
|
57 |
+
for chat in await chats.to_list(length=1000000):
|
58 |
+
karma = await get_karma(chat["chat_id"], await int_to_alpha(user_id))
|
59 |
+
if karma and (int(karma["karma"]) > 0):
|
60 |
+
total_karma += int(karma["karma"])
|
61 |
+
return total_karma
|
62 |
+
|
63 |
+
|
64 |
+
async def get_karmas(chat_id: int) -> Dict[str, int]:
|
65 |
+
karma = karmadb.find_one({"chat_id": chat_id})
|
66 |
+
if not karma:
|
67 |
+
return {}
|
68 |
+
return karma["karma"]
|
69 |
+
|
70 |
+
|
71 |
+
async def get_karma(chat_id: int, name: str) -> Union[bool, dict]:
|
72 |
+
name = name.lower().strip()
|
73 |
+
karmas = await get_karmas(chat_id)
|
74 |
+
if name in karmas:
|
75 |
+
return karmas[name]
|
76 |
+
|
77 |
+
|
78 |
+
async def update_karma(chat_id: int, name: str, karma: dict):
|
79 |
+
name = name.lower().strip()
|
80 |
+
karmas = await get_karmas(chat_id)
|
81 |
+
karmas[name] = karma
|
82 |
+
karmadb.update_one({"chat_id": chat_id}, {"$set": {"karma": karmas}}, upsert=True)
|
83 |
+
|
84 |
+
|
85 |
+
async def is_karma_on(chat_id: int) -> bool:
|
86 |
+
chat = karmadb.find_one({"chat_id_toggle": chat_id})
|
87 |
+
if not chat:
|
88 |
+
return True
|
89 |
+
return False
|
90 |
+
|
91 |
+
|
92 |
+
async def karma_on(chat_id: int):
|
93 |
+
is_karma = await is_karma_on(chat_id)
|
94 |
+
if is_karma:
|
95 |
+
return
|
96 |
+
return karmadb.delete_one({"chat_id_toggle": chat_id})
|
97 |
+
|
98 |
+
|
99 |
+
async def karma_off(chat_id: int):
|
100 |
+
is_karma = await is_karma_on(chat_id)
|
101 |
+
if not is_karma:
|
102 |
+
return
|
103 |
+
return karmadb.insert_one({"chat_id_toggle": chat_id})
|
104 |
+
|
105 |
+
|
106 |
+
async def int_to_alpha(user_id: int) -> str:
|
107 |
+
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
|
108 |
+
text = ""
|
109 |
+
user_id = str(user_id)
|
110 |
+
for i in user_id:
|
111 |
+
text += alphabet[int(i)]
|
112 |
+
return text
|
113 |
+
|
114 |
+
|
115 |
+
async def alpha_to_int(user_id_alphabet: str) -> int:
|
116 |
+
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
|
117 |
+
user_id = ""
|
118 |
+
for i in user_id_alphabet:
|
119 |
+
index = alphabet.index(i)
|
120 |
+
user_id += str(index)
|
121 |
+
user_id = int(user_id)
|
122 |
+
return user_id
|
Database/mongodb/mongodb.py
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sys import exit as exiter
|
2 |
+
|
3 |
+
from pymongo import MongoClient
|
4 |
+
from pymongo.errors import PyMongoError
|
5 |
+
|
6 |
+
from Mikobot import DB_NAME, LOGGER, MONGO_DB_URI
|
7 |
+
|
8 |
+
try:
|
9 |
+
Mikobot_db_client = MongoClient(MONGO_DB_URI)
|
10 |
+
except PyMongoError as f:
|
11 |
+
LOGGER.error(f"Error in Mongodb: {f}")
|
12 |
+
exiter(1)
|
13 |
+
Mikobot_main_db = Mikobot_db_client[DB_NAME]
|
14 |
+
|
15 |
+
|
16 |
+
class MongoDB:
|
17 |
+
"""Class for interacting with Bot database."""
|
18 |
+
|
19 |
+
def __init__(self, collection) -> None:
|
20 |
+
self.collection = Mikobot_main_db[collection]
|
21 |
+
|
22 |
+
# Insert one entry into collection
|
23 |
+
def insert_one(self, document):
|
24 |
+
result = self.collection.insert_one(document)
|
25 |
+
return repr(result.inserted_id)
|
26 |
+
|
27 |
+
# Find one entry from collection
|
28 |
+
def find_one(self, query):
|
29 |
+
result = self.collection.find_one(query)
|
30 |
+
if result:
|
31 |
+
return result
|
32 |
+
return False
|
33 |
+
|
34 |
+
# Find entries from collection
|
35 |
+
def find_all(self, query=None):
|
36 |
+
if query is None:
|
37 |
+
query = {}
|
38 |
+
return list(self.collection.find(query))
|
39 |
+
|
40 |
+
# Count entries from collection
|
41 |
+
def count(self, query=None):
|
42 |
+
if query is None:
|
43 |
+
query = {}
|
44 |
+
return self.collection.count_documents(query)
|
45 |
+
|
46 |
+
# Delete entry/entries from collection
|
47 |
+
def delete_one(self, query):
|
48 |
+
self.collection.delete_many(query)
|
49 |
+
return self.collection.count_documents({})
|
50 |
+
|
51 |
+
# Replace one entry in collection
|
52 |
+
def replace(self, query, new_data):
|
53 |
+
old = self.collection.find_one(query)
|
54 |
+
_id = old["_id"]
|
55 |
+
self.collection.replace_one({"_id": _id}, new_data)
|
56 |
+
new = self.collection.find_one({"_id": _id})
|
57 |
+
return old, new
|
58 |
+
|
59 |
+
# Update one entry from collection
|
60 |
+
def update(self, query, update):
|
61 |
+
result = self.collection.update_one(query, {"$set": update})
|
62 |
+
new_document = self.collection.find_one(query)
|
63 |
+
return result.modified_count, new_document
|
64 |
+
|
65 |
+
@staticmethod
|
66 |
+
def close():
|
67 |
+
return Mikobot_db_client.close()
|
68 |
+
|
69 |
+
|
70 |
+
def __connect_first():
|
71 |
+
_ = MongoDB("test")
|
72 |
+
LOGGER.info("Initialized Mongo Database!\n")
|
73 |
+
|
74 |
+
|
75 |
+
__connect_first()
|
Database/mongodb/toggle_mongo.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from Database.mongodb.db import *
|
2 |
+
|
3 |
+
dwelcomedb = dbname.dwelcome
|
4 |
+
nsfwdb = dbname.nsfw
|
5 |
+
nekomodedb = dbname.nekomode
|
6 |
+
|
7 |
+
|
8 |
+
async def is_dwelcome_on(chat_id: int) -> bool:
|
9 |
+
chat = await dwelcomedb.find_one({"chat_id_toggle": chat_id})
|
10 |
+
return not bool(chat)
|
11 |
+
|
12 |
+
|
13 |
+
async def dwelcome_on(chat_id: int):
|
14 |
+
await dwelcomedb.delete_one({"chat_id_toggle": chat_id})
|
15 |
+
|
16 |
+
|
17 |
+
async def dwelcome_off(chat_id: int):
|
18 |
+
await dwelcomedb.insert_one({"chat_id_toggle": chat_id})
|
19 |
+
|
20 |
+
|
21 |
+
async def is_nsfw_on(chat_id: int) -> bool:
|
22 |
+
chat = await nsfwdb.find_one({"chat_id": chat_id})
|
23 |
+
return chat
|
24 |
+
|
25 |
+
|
26 |
+
async def nsfw_on(chat_id: int):
|
27 |
+
is_nsfw = await is_nsfw_on(chat_id)
|
28 |
+
if is_nsfw:
|
29 |
+
return
|
30 |
+
return await nsfwdb.insert_one({"chat_id": chat_id})
|
31 |
+
|
32 |
+
|
33 |
+
async def nsfw_off(chat_id: int):
|
34 |
+
is_nsfw = await is_nsfw_on(chat_id)
|
35 |
+
if not is_nsfw:
|
36 |
+
return
|
37 |
+
return await nsfwdb.delete_one({"chat_id": chat_id})
|
38 |
+
|
39 |
+
|
40 |
+
async def is_nekomode_on(chat_id: int) -> bool:
|
41 |
+
chat = await nekomodedb.find_one({"chat_id_toggle": chat_id})
|
42 |
+
return not bool(chat)
|
43 |
+
|
44 |
+
|
45 |
+
async def nekomode_on(chat_id: int):
|
46 |
+
await nekomodedb.delete_one({"chat_id_toggle": chat_id})
|
47 |
+
|
48 |
+
|
49 |
+
async def nekomode_off(chat_id: int):
|
50 |
+
await nekomodedb.insert_one({"chat_id_toggle": chat_id})
|
Database/mongodb/users_db.py
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from threading import RLock
|
2 |
+
from time import time
|
3 |
+
|
4 |
+
from Database.mongodb.mongodb import MongoDB
|
5 |
+
from Mikobot import LOGGER
|
6 |
+
|
7 |
+
INSERTION_LOCK = RLock()
|
8 |
+
|
9 |
+
|
10 |
+
class Users(MongoDB):
|
11 |
+
"""Class to manage users for bot."""
|
12 |
+
|
13 |
+
db_name = "users"
|
14 |
+
|
15 |
+
def __init__(self, user_id: int) -> None:
|
16 |
+
super().__init__(self.db_name)
|
17 |
+
self.user_id = user_id
|
18 |
+
self.user_info = self.__ensure_in_db()
|
19 |
+
|
20 |
+
def update_user(self, name: str, username: str = None):
|
21 |
+
with INSERTION_LOCK:
|
22 |
+
if name != self.user_info["name"] or username != self.user_info["username"]:
|
23 |
+
return self.update(
|
24 |
+
{"_id": self.user_id},
|
25 |
+
{"username": username, "name": name},
|
26 |
+
)
|
27 |
+
return True
|
28 |
+
|
29 |
+
def delete_user(self):
|
30 |
+
with INSERTION_LOCK:
|
31 |
+
return self.delete_one({"_id": self.user_id})
|
32 |
+
|
33 |
+
@staticmethod
|
34 |
+
def count_users():
|
35 |
+
with INSERTION_LOCK:
|
36 |
+
collection = MongoDB(Users.db_name)
|
37 |
+
return collection.count()
|
38 |
+
|
39 |
+
def get_my_info(self):
|
40 |
+
with INSERTION_LOCK:
|
41 |
+
return self.user_info
|
42 |
+
|
43 |
+
@staticmethod
|
44 |
+
def list_users():
|
45 |
+
with INSERTION_LOCK:
|
46 |
+
collection = MongoDB(Users.db_name)
|
47 |
+
return collection.find_all()
|
48 |
+
|
49 |
+
@staticmethod
|
50 |
+
def get_user_info(user_id: int or str):
|
51 |
+
with INSERTION_LOCK:
|
52 |
+
collection = MongoDB(Users.db_name)
|
53 |
+
if isinstance(user_id, int):
|
54 |
+
curr = collection.find_one({"_id": user_id})
|
55 |
+
elif isinstance(user_id, str):
|
56 |
+
# user_id[1:] because we don't want the '@' in the username
|
57 |
+
# search!
|
58 |
+
curr = collection.find_one({"username": user_id[1:]})
|
59 |
+
else:
|
60 |
+
curr = None
|
61 |
+
|
62 |
+
if curr:
|
63 |
+
return curr
|
64 |
+
|
65 |
+
return {}
|
66 |
+
|
67 |
+
def __ensure_in_db(self):
|
68 |
+
chat_data = self.find_one({"_id": self.user_id})
|
69 |
+
if not chat_data:
|
70 |
+
new_data = {"_id": self.user_id, "username": "", "name": "unknown_till_now"}
|
71 |
+
self.insert_one(new_data)
|
72 |
+
LOGGER.info(f"Initialized User Document for {self.user_id}")
|
73 |
+
return new_data
|
74 |
+
return chat_data
|
75 |
+
|
76 |
+
@staticmethod
|
77 |
+
def load_from_db():
|
78 |
+
with INSERTION_LOCK:
|
79 |
+
collection = MongoDB(Users.db_name)
|
80 |
+
return collection.find_all()
|
81 |
+
|
82 |
+
@staticmethod
|
83 |
+
def repair_db(collection):
|
84 |
+
all_data = collection.find_all()
|
85 |
+
keys = {"username": "", "name": "unknown_till_now"}
|
86 |
+
for data in all_data:
|
87 |
+
for key, val in keys.items():
|
88 |
+
try:
|
89 |
+
_ = data[key]
|
90 |
+
except KeyError:
|
91 |
+
LOGGER.warning(
|
92 |
+
f"Repairing Users Database - setting '{key}:{val}' for {data['_id']}",
|
93 |
+
)
|
94 |
+
collection.update({"_id": data["_id"]}, {key: val})
|
95 |
+
|
96 |
+
|
97 |
+
def __pre_req_users():
|
98 |
+
start = time()
|
99 |
+
LOGGER.info("Starting Users Database Repair...")
|
100 |
+
collection = MongoDB(Users.db_name)
|
101 |
+
Users.repair_db(collection)
|
102 |
+
LOGGER.info(f"Done in {round((time() - start), 3)}s!")
|
Database/mongodb/whispers.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from Database.mongodb.db import dbname
|
2 |
+
|
3 |
+
collection = dbname["whisper"]
|
4 |
+
|
5 |
+
|
6 |
+
class Whispers:
|
7 |
+
@staticmethod
|
8 |
+
async def add_whisper(WhisperId, WhisperData):
|
9 |
+
whisper = {"WhisperId": WhisperId, "whisperData": WhisperData}
|
10 |
+
await collection.insert_one(whisper)
|
11 |
+
|
12 |
+
@staticmethod
|
13 |
+
async def del_whisper(WhisperId):
|
14 |
+
await collection.delete_one({"WhisperId": WhisperId})
|
15 |
+
|
16 |
+
@staticmethod
|
17 |
+
async def get_whisper(WhisperId):
|
18 |
+
whisper = await collection.find_one({"WhisperId": WhisperId})
|
19 |
+
return whisper["whisperData"] if whisper else None
|
Database/sql/__init__.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sqlalchemy import create_engine
|
2 |
+
from sqlalchemy.ext.declarative import declarative_base
|
3 |
+
from sqlalchemy.orm import scoped_session, sessionmaker
|
4 |
+
|
5 |
+
from Mikobot import DB_URI
|
6 |
+
from Mikobot import LOGGER as log
|
7 |
+
|
8 |
+
if DB_URI and DB_URI.startswith("postgres://"):
|
9 |
+
DB_URI = DB_URI.replace("postgres://", "postgresql://", 1)
|
10 |
+
|
11 |
+
|
12 |
+
def start() -> scoped_session:
|
13 |
+
engine = create_engine(DB_URI, client_encoding="utf8")
|
14 |
+
log.info("[PostgreSQL] Connecting to database......")
|
15 |
+
BASE.metadata.bind = engine
|
16 |
+
BASE.metadata.create_all(engine)
|
17 |
+
return scoped_session(sessionmaker(bind=engine, autoflush=False))
|
18 |
+
|
19 |
+
|
20 |
+
BASE = declarative_base()
|
21 |
+
try:
|
22 |
+
SESSION = start()
|
23 |
+
except Exception as e:
|
24 |
+
log.exception(f"[PostgreSQL] Failed to connect due to {e}")
|
25 |
+
exit()
|
26 |
+
|
27 |
+
log.info("[PostgreSQL] Connection successful, session started.")
|
Database/sql/antiflood_sql.py
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import BigInteger, Column, Integer, String, UnicodeText
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
DEF_COUNT = 1
|
8 |
+
DEF_LIMIT = 0
|
9 |
+
DEF_OBJ = (None, DEF_COUNT, DEF_LIMIT)
|
10 |
+
|
11 |
+
|
12 |
+
class FloodControl(BASE):
|
13 |
+
__tablename__ = "antiflood"
|
14 |
+
chat_id = Column(String(14), primary_key=True)
|
15 |
+
user_id = Column(BigInteger)
|
16 |
+
count = Column(Integer, default=DEF_COUNT)
|
17 |
+
limit = Column(Integer, default=DEF_LIMIT)
|
18 |
+
|
19 |
+
def __init__(self, chat_id):
|
20 |
+
self.chat_id = str(chat_id) # ensure string
|
21 |
+
|
22 |
+
def __repr__(self):
|
23 |
+
return "<flood control for %s>" % self.chat_id
|
24 |
+
|
25 |
+
|
26 |
+
class FloodSettings(BASE):
|
27 |
+
__tablename__ = "antiflood_settings"
|
28 |
+
chat_id = Column(String(14), primary_key=True)
|
29 |
+
flood_type = Column(Integer, default=1)
|
30 |
+
value = Column(UnicodeText, default="0")
|
31 |
+
|
32 |
+
def __init__(self, chat_id, flood_type=1, value="0"):
|
33 |
+
self.chat_id = str(chat_id)
|
34 |
+
self.flood_type = flood_type
|
35 |
+
self.value = value
|
36 |
+
|
37 |
+
def __repr__(self):
|
38 |
+
return "<{} will executing {} for flood.>".format(self.chat_id, self.flood_type)
|
39 |
+
|
40 |
+
|
41 |
+
FloodControl.__table__.create(checkfirst=True)
|
42 |
+
FloodSettings.__table__.create(checkfirst=True)
|
43 |
+
|
44 |
+
INSERTION_FLOOD_LOCK = threading.RLock()
|
45 |
+
INSERTION_FLOOD_SETTINGS_LOCK = threading.RLock()
|
46 |
+
|
47 |
+
CHAT_FLOOD = {}
|
48 |
+
|
49 |
+
|
50 |
+
def set_flood(chat_id, amount):
|
51 |
+
with INSERTION_FLOOD_LOCK:
|
52 |
+
flood = SESSION.query(FloodControl).get(str(chat_id))
|
53 |
+
if not flood:
|
54 |
+
flood = FloodControl(str(chat_id))
|
55 |
+
|
56 |
+
flood.user_id = None
|
57 |
+
flood.limit = amount
|
58 |
+
|
59 |
+
CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, amount)
|
60 |
+
|
61 |
+
SESSION.add(flood)
|
62 |
+
SESSION.commit()
|
63 |
+
|
64 |
+
|
65 |
+
def update_flood(chat_id: str, user_id) -> bool:
|
66 |
+
if str(chat_id) in CHAT_FLOOD:
|
67 |
+
curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ)
|
68 |
+
|
69 |
+
if limit == 0: # no antiflood
|
70 |
+
return False
|
71 |
+
|
72 |
+
if user_id != curr_user_id or user_id is None: # other user
|
73 |
+
CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT, limit)
|
74 |
+
return False
|
75 |
+
|
76 |
+
count += 1
|
77 |
+
if count > limit: # too many msgs, kick
|
78 |
+
CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit)
|
79 |
+
return True
|
80 |
+
|
81 |
+
# default -> update
|
82 |
+
CHAT_FLOOD[str(chat_id)] = (user_id, count, limit)
|
83 |
+
return False
|
84 |
+
|
85 |
+
|
86 |
+
def get_flood_limit(chat_id):
|
87 |
+
return CHAT_FLOOD.get(str(chat_id), DEF_OBJ)[2]
|
88 |
+
|
89 |
+
|
90 |
+
def set_flood_strength(chat_id, flood_type, value):
|
91 |
+
# for flood_type
|
92 |
+
# 1 = ban
|
93 |
+
# 2 = kick
|
94 |
+
# 3 = mute
|
95 |
+
# 4 = tban
|
96 |
+
# 5 = tmute
|
97 |
+
with INSERTION_FLOOD_SETTINGS_LOCK:
|
98 |
+
curr_setting = SESSION.query(FloodSettings).get(str(chat_id))
|
99 |
+
if not curr_setting:
|
100 |
+
curr_setting = FloodSettings(
|
101 |
+
chat_id,
|
102 |
+
flood_type=int(flood_type),
|
103 |
+
value=value,
|
104 |
+
)
|
105 |
+
|
106 |
+
curr_setting.flood_type = int(flood_type)
|
107 |
+
curr_setting.value = str(value)
|
108 |
+
|
109 |
+
SESSION.add(curr_setting)
|
110 |
+
SESSION.commit()
|
111 |
+
|
112 |
+
|
113 |
+
def get_flood_setting(chat_id):
|
114 |
+
try:
|
115 |
+
setting = SESSION.query(FloodSettings).get(str(chat_id))
|
116 |
+
if setting:
|
117 |
+
return setting.flood_type, setting.value
|
118 |
+
else:
|
119 |
+
return 1, "0"
|
120 |
+
|
121 |
+
finally:
|
122 |
+
SESSION.close()
|
123 |
+
|
124 |
+
|
125 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
126 |
+
with INSERTION_FLOOD_LOCK:
|
127 |
+
flood = SESSION.query(FloodControl).get(str(old_chat_id))
|
128 |
+
if flood:
|
129 |
+
CHAT_FLOOD[str(new_chat_id)] = CHAT_FLOOD.get(str(old_chat_id), DEF_OBJ)
|
130 |
+
flood.chat_id = str(new_chat_id)
|
131 |
+
SESSION.commit()
|
132 |
+
|
133 |
+
SESSION.close()
|
134 |
+
|
135 |
+
|
136 |
+
def __load_flood_settings():
|
137 |
+
global CHAT_FLOOD
|
138 |
+
try:
|
139 |
+
all_chats = SESSION.query(FloodControl).all()
|
140 |
+
CHAT_FLOOD = {chat.chat_id: (None, DEF_COUNT, chat.limit) for chat in all_chats}
|
141 |
+
finally:
|
142 |
+
SESSION.close()
|
143 |
+
|
144 |
+
|
145 |
+
__load_flood_settings()
|
Database/sql/approve_sql.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import BigInteger, Column, String
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class Approvals(BASE):
|
9 |
+
__tablename__ = "approval"
|
10 |
+
chat_id = Column(String(14), primary_key=True)
|
11 |
+
user_id = Column(BigInteger, primary_key=True)
|
12 |
+
|
13 |
+
def __init__(self, chat_id, user_id):
|
14 |
+
self.chat_id = str(chat_id) # ensure string
|
15 |
+
self.user_id = user_id
|
16 |
+
|
17 |
+
def __repr__(self):
|
18 |
+
return "<Approve %s>" % self.user_id
|
19 |
+
|
20 |
+
|
21 |
+
Approvals.__table__.create(checkfirst=True)
|
22 |
+
|
23 |
+
APPROVE_INSERTION_LOCK = threading.RLock()
|
24 |
+
|
25 |
+
|
26 |
+
def approve(chat_id, user_id):
|
27 |
+
with APPROVE_INSERTION_LOCK:
|
28 |
+
approve_user = Approvals(str(chat_id), user_id)
|
29 |
+
SESSION.add(approve_user)
|
30 |
+
SESSION.commit()
|
31 |
+
|
32 |
+
|
33 |
+
def is_approved(chat_id, user_id):
|
34 |
+
try:
|
35 |
+
return SESSION.query(Approvals).get((str(chat_id), user_id))
|
36 |
+
finally:
|
37 |
+
SESSION.close()
|
38 |
+
|
39 |
+
|
40 |
+
def disapprove(chat_id, user_id):
|
41 |
+
with APPROVE_INSERTION_LOCK:
|
42 |
+
disapprove_user = SESSION.query(Approvals).get((str(chat_id), user_id))
|
43 |
+
if disapprove_user:
|
44 |
+
SESSION.delete(disapprove_user)
|
45 |
+
SESSION.commit()
|
46 |
+
return True
|
47 |
+
else:
|
48 |
+
SESSION.close()
|
49 |
+
return False
|
50 |
+
|
51 |
+
|
52 |
+
def list_approved(chat_id):
|
53 |
+
try:
|
54 |
+
return (
|
55 |
+
SESSION.query(Approvals)
|
56 |
+
.filter(Approvals.chat_id == str(chat_id))
|
57 |
+
.order_by(Approvals.user_id.asc())
|
58 |
+
.all()
|
59 |
+
)
|
60 |
+
finally:
|
61 |
+
SESSION.close()
|
Database/sql/blacklistusers_sql.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import Column, String, UnicodeText
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class BlacklistUsers(BASE):
|
9 |
+
__tablename__ = "blacklistusers"
|
10 |
+
user_id = Column(String(14), primary_key=True)
|
11 |
+
reason = Column(UnicodeText)
|
12 |
+
|
13 |
+
def __init__(self, user_id, reason=None):
|
14 |
+
self.user_id = user_id
|
15 |
+
self.reason = reason
|
16 |
+
|
17 |
+
|
18 |
+
BlacklistUsers.__table__.create(checkfirst=True)
|
19 |
+
|
20 |
+
BLACKLIST_LOCK = threading.RLock()
|
21 |
+
BLACKLIST_USERS = set()
|
22 |
+
|
23 |
+
|
24 |
+
def blacklist_user(user_id, reason=None):
|
25 |
+
with BLACKLIST_LOCK:
|
26 |
+
user = SESSION.query(BlacklistUsers).get(str(user_id))
|
27 |
+
if not user:
|
28 |
+
user = BlacklistUsers(str(user_id), reason)
|
29 |
+
else:
|
30 |
+
user.reason = reason
|
31 |
+
|
32 |
+
SESSION.add(user)
|
33 |
+
SESSION.commit()
|
34 |
+
__load_blacklist_userid_list()
|
35 |
+
|
36 |
+
|
37 |
+
def unblacklist_user(user_id):
|
38 |
+
with BLACKLIST_LOCK:
|
39 |
+
user = SESSION.query(BlacklistUsers).get(str(user_id))
|
40 |
+
if user:
|
41 |
+
SESSION.delete(user)
|
42 |
+
|
43 |
+
SESSION.commit()
|
44 |
+
__load_blacklist_userid_list()
|
45 |
+
|
46 |
+
|
47 |
+
def get_reason(user_id):
|
48 |
+
user = SESSION.query(BlacklistUsers).get(str(user_id))
|
49 |
+
rep = ""
|
50 |
+
if user:
|
51 |
+
rep = user.reason
|
52 |
+
|
53 |
+
SESSION.close()
|
54 |
+
return rep
|
55 |
+
|
56 |
+
|
57 |
+
def is_user_blacklisted(user_id):
|
58 |
+
return user_id in BLACKLIST_USERS
|
59 |
+
|
60 |
+
|
61 |
+
def __load_blacklist_userid_list():
|
62 |
+
global BLACKLIST_USERS
|
63 |
+
try:
|
64 |
+
BLACKLIST_USERS = {int(x.user_id) for x in SESSION.query(BlacklistUsers).all()}
|
65 |
+
finally:
|
66 |
+
SESSION.close()
|
67 |
+
|
68 |
+
|
69 |
+
__load_blacklist_userid_list()
|
Database/sql/connection_sql.py
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
import time
|
3 |
+
from typing import Union
|
4 |
+
|
5 |
+
from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText
|
6 |
+
|
7 |
+
from Database.sql import BASE, SESSION
|
8 |
+
|
9 |
+
|
10 |
+
class ChatAccessConnectionSettings(BASE):
|
11 |
+
__tablename__ = "access_connection"
|
12 |
+
chat_id = Column(String(14), primary_key=True)
|
13 |
+
allow_connect_to_chat = Column(Boolean, default=True)
|
14 |
+
|
15 |
+
def __init__(self, chat_id, allow_connect_to_chat):
|
16 |
+
self.chat_id = str(chat_id)
|
17 |
+
self.allow_connect_to_chat = str(allow_connect_to_chat)
|
18 |
+
|
19 |
+
def __repr__(self):
|
20 |
+
return "<Chat access settings ({}) is {}>".format(
|
21 |
+
self.chat_id, self.allow_connect_to_chat
|
22 |
+
)
|
23 |
+
|
24 |
+
|
25 |
+
class Connection(BASE):
|
26 |
+
__tablename__ = "connection"
|
27 |
+
user_id = Column(BigInteger, primary_key=True)
|
28 |
+
chat_id = Column(String(14))
|
29 |
+
|
30 |
+
def __init__(self, user_id, chat_id):
|
31 |
+
self.user_id = user_id
|
32 |
+
self.chat_id = str(chat_id) # Ensure String
|
33 |
+
|
34 |
+
|
35 |
+
class ConnectionHistory(BASE):
|
36 |
+
__tablename__ = "connection_history"
|
37 |
+
user_id = Column(BigInteger, primary_key=True)
|
38 |
+
chat_id = Column(String(14), primary_key=True)
|
39 |
+
chat_name = Column(UnicodeText)
|
40 |
+
conn_time = Column(BigInteger)
|
41 |
+
|
42 |
+
def __init__(self, user_id, chat_id, chat_name, conn_time):
|
43 |
+
self.user_id = user_id
|
44 |
+
self.chat_id = str(chat_id)
|
45 |
+
self.chat_name = str(chat_name)
|
46 |
+
self.conn_time = int(conn_time)
|
47 |
+
|
48 |
+
def __repr__(self):
|
49 |
+
return "<connection user {} history {}>".format(self.user_id, self.chat_id)
|
50 |
+
|
51 |
+
|
52 |
+
ChatAccessConnectionSettings.__table__.create(checkfirst=True)
|
53 |
+
Connection.__table__.create(checkfirst=True)
|
54 |
+
ConnectionHistory.__table__.create(checkfirst=True)
|
55 |
+
|
56 |
+
CHAT_ACCESS_LOCK = threading.RLock()
|
57 |
+
CONNECTION_INSERTION_LOCK = threading.RLock()
|
58 |
+
CONNECTION_HISTORY_LOCK = threading.RLock()
|
59 |
+
|
60 |
+
HISTORY_CONNECT = {}
|
61 |
+
|
62 |
+
|
63 |
+
def allow_connect_to_chat(chat_id: Union[str, int]) -> bool:
|
64 |
+
try:
|
65 |
+
chat_setting = SESSION.query(ChatAccessConnectionSettings).get(str(chat_id))
|
66 |
+
if chat_setting:
|
67 |
+
return chat_setting.allow_connect_to_chat
|
68 |
+
return False
|
69 |
+
finally:
|
70 |
+
SESSION.close()
|
71 |
+
|
72 |
+
|
73 |
+
def set_allow_connect_to_chat(chat_id: Union[int, str], setting: bool):
|
74 |
+
with CHAT_ACCESS_LOCK:
|
75 |
+
chat_setting = SESSION.query(ChatAccessConnectionSettings).get(str(chat_id))
|
76 |
+
if not chat_setting:
|
77 |
+
chat_setting = ChatAccessConnectionSettings(chat_id, setting)
|
78 |
+
|
79 |
+
chat_setting.allow_connect_to_chat = setting
|
80 |
+
SESSION.add(chat_setting)
|
81 |
+
SESSION.commit()
|
82 |
+
|
83 |
+
|
84 |
+
def connect(user_id, chat_id):
|
85 |
+
with CONNECTION_INSERTION_LOCK:
|
86 |
+
prev = SESSION.query(Connection).get((int(user_id)))
|
87 |
+
if prev:
|
88 |
+
SESSION.delete(prev)
|
89 |
+
connect_to_chat = Connection(int(user_id), chat_id)
|
90 |
+
SESSION.add(connect_to_chat)
|
91 |
+
SESSION.commit()
|
92 |
+
return True
|
93 |
+
|
94 |
+
|
95 |
+
def get_connected_chat(user_id):
|
96 |
+
try:
|
97 |
+
return SESSION.query(Connection).get((int(user_id)))
|
98 |
+
finally:
|
99 |
+
SESSION.close()
|
100 |
+
|
101 |
+
|
102 |
+
def curr_connection(chat_id):
|
103 |
+
try:
|
104 |
+
return SESSION.query(Connection).get((str(chat_id)))
|
105 |
+
finally:
|
106 |
+
SESSION.close()
|
107 |
+
|
108 |
+
|
109 |
+
def disconnect(user_id):
|
110 |
+
with CONNECTION_INSERTION_LOCK:
|
111 |
+
disconnect = SESSION.query(Connection).get((int(user_id)))
|
112 |
+
if disconnect:
|
113 |
+
SESSION.delete(disconnect)
|
114 |
+
SESSION.commit()
|
115 |
+
return True
|
116 |
+
else:
|
117 |
+
SESSION.close()
|
118 |
+
return False
|
119 |
+
|
120 |
+
|
121 |
+
def add_history_conn(user_id, chat_id, chat_name):
|
122 |
+
global HISTORY_CONNECT
|
123 |
+
with CONNECTION_HISTORY_LOCK:
|
124 |
+
conn_time = int(time.time())
|
125 |
+
if HISTORY_CONNECT.get(int(user_id)):
|
126 |
+
counting = (
|
127 |
+
SESSION.query(ConnectionHistory.user_id)
|
128 |
+
.filter(ConnectionHistory.user_id == str(user_id))
|
129 |
+
.count()
|
130 |
+
)
|
131 |
+
getchat_id = {}
|
132 |
+
for x in HISTORY_CONNECT[int(user_id)]:
|
133 |
+
getchat_id[HISTORY_CONNECT[int(user_id)][x]["chat_id"]] = x
|
134 |
+
if chat_id in getchat_id:
|
135 |
+
todeltime = getchat_id[str(chat_id)]
|
136 |
+
delold = SESSION.query(ConnectionHistory).get(
|
137 |
+
(int(user_id), str(chat_id))
|
138 |
+
)
|
139 |
+
if delold:
|
140 |
+
SESSION.delete(delold)
|
141 |
+
HISTORY_CONNECT[int(user_id)].pop(todeltime)
|
142 |
+
elif counting >= 5:
|
143 |
+
todel = list(HISTORY_CONNECT[int(user_id)])
|
144 |
+
todel.reverse()
|
145 |
+
todel = todel[4:]
|
146 |
+
for x in todel:
|
147 |
+
chat_old = HISTORY_CONNECT[int(user_id)][x]["chat_id"]
|
148 |
+
delold = SESSION.query(ConnectionHistory).get(
|
149 |
+
(int(user_id), str(chat_old))
|
150 |
+
)
|
151 |
+
if delold:
|
152 |
+
SESSION.delete(delold)
|
153 |
+
HISTORY_CONNECT[int(user_id)].pop(x)
|
154 |
+
else:
|
155 |
+
HISTORY_CONNECT[int(user_id)] = {}
|
156 |
+
delold = SESSION.query(ConnectionHistory).get((int(user_id), str(chat_id)))
|
157 |
+
if delold:
|
158 |
+
SESSION.delete(delold)
|
159 |
+
history = ConnectionHistory(int(user_id), str(chat_id), chat_name, conn_time)
|
160 |
+
SESSION.add(history)
|
161 |
+
SESSION.commit()
|
162 |
+
HISTORY_CONNECT[int(user_id)][conn_time] = {
|
163 |
+
"chat_name": chat_name,
|
164 |
+
"chat_id": str(chat_id),
|
165 |
+
}
|
166 |
+
|
167 |
+
|
168 |
+
def get_history_conn(user_id):
|
169 |
+
if not HISTORY_CONNECT.get(int(user_id)):
|
170 |
+
HISTORY_CONNECT[int(user_id)] = {}
|
171 |
+
return HISTORY_CONNECT[int(user_id)]
|
172 |
+
|
173 |
+
|
174 |
+
def clear_history_conn(user_id):
|
175 |
+
global HISTORY_CONNECT
|
176 |
+
todel = list(HISTORY_CONNECT[int(user_id)])
|
177 |
+
for x in todel:
|
178 |
+
chat_old = HISTORY_CONNECT[int(user_id)][x]["chat_id"]
|
179 |
+
delold = SESSION.query(ConnectionHistory).get((int(user_id), str(chat_old)))
|
180 |
+
if delold:
|
181 |
+
SESSION.delete(delold)
|
182 |
+
HISTORY_CONNECT[int(user_id)].pop(x)
|
183 |
+
SESSION.commit()
|
184 |
+
return True
|
185 |
+
|
186 |
+
|
187 |
+
def __load_user_history():
|
188 |
+
global HISTORY_CONNECT
|
189 |
+
try:
|
190 |
+
qall = SESSION.query(ConnectionHistory).all()
|
191 |
+
HISTORY_CONNECT = {}
|
192 |
+
for x in qall:
|
193 |
+
check = HISTORY_CONNECT.get(x.user_id)
|
194 |
+
if check is None:
|
195 |
+
HISTORY_CONNECT[x.user_id] = {}
|
196 |
+
HISTORY_CONNECT[x.user_id][x.conn_time] = {
|
197 |
+
"chat_name": x.chat_name,
|
198 |
+
"chat_id": x.chat_id,
|
199 |
+
}
|
200 |
+
finally:
|
201 |
+
SESSION.close()
|
202 |
+
|
203 |
+
|
204 |
+
__load_user_history()
|
Database/sql/cust_filters_sql.py
ADDED
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import Boolean, Column, Integer, String, UnicodeText, distinct, func
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
from Mikobot.plugins.helper_funcs.msg_types import Types
|
7 |
+
|
8 |
+
|
9 |
+
class CustomFilters(BASE):
|
10 |
+
__tablename__ = "cust_filters"
|
11 |
+
chat_id = Column(String(14), primary_key=True)
|
12 |
+
keyword = Column(UnicodeText, primary_key=True, nullable=False)
|
13 |
+
reply = Column(UnicodeText, nullable=False)
|
14 |
+
reply_text = Column(UnicodeText)
|
15 |
+
file_type = Column(Integer, nullable=False, default=1)
|
16 |
+
file_id = Column(UnicodeText, default=None)
|
17 |
+
has_buttons = Column(Boolean, nullable=False, default=False)
|
18 |
+
# NOTE: Here for legacy purposes, to ensure older filters don't mess up.
|
19 |
+
has_media_spoiler = Column(Boolean, nullable=False, default=False)
|
20 |
+
|
21 |
+
def __init__(
|
22 |
+
self,
|
23 |
+
chat_id: int | str,
|
24 |
+
keyword: str,
|
25 |
+
reply: str,
|
26 |
+
reply_text: str,
|
27 |
+
has_buttons: bool,
|
28 |
+
has_media_spoiler: bool,
|
29 |
+
file_type: int,
|
30 |
+
file_id: str,
|
31 |
+
):
|
32 |
+
self.chat_id = str(chat_id) # ensure string
|
33 |
+
self.keyword = keyword
|
34 |
+
self.reply = reply
|
35 |
+
self.reply_text = reply_text
|
36 |
+
self.has_buttons = has_buttons
|
37 |
+
self.has_media_spoiler = has_media_spoiler
|
38 |
+
self.file_type = file_type
|
39 |
+
self.file_id = file_id
|
40 |
+
|
41 |
+
def __repr__(self):
|
42 |
+
return "<Filter for %s>" % self.chat_id
|
43 |
+
|
44 |
+
def __eq__(self, other):
|
45 |
+
return bool(
|
46 |
+
isinstance(other, CustomFilters)
|
47 |
+
and self.chat_id == other.chat_id
|
48 |
+
and self.keyword == other.keyword,
|
49 |
+
)
|
50 |
+
|
51 |
+
|
52 |
+
class Buttons(BASE):
|
53 |
+
__tablename__ = "cust_filter_urls"
|
54 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
55 |
+
chat_id = Column(String(14), primary_key=True)
|
56 |
+
keyword = Column(UnicodeText, primary_key=True)
|
57 |
+
name = Column(UnicodeText, nullable=False)
|
58 |
+
url = Column(UnicodeText, nullable=False)
|
59 |
+
same_line = Column(Boolean, default=False)
|
60 |
+
|
61 |
+
def __init__(self, chat_id, keyword, name, url, same_line=False):
|
62 |
+
self.chat_id = str(chat_id)
|
63 |
+
self.keyword = keyword
|
64 |
+
self.name = name
|
65 |
+
self.url = url
|
66 |
+
self.same_line = same_line
|
67 |
+
|
68 |
+
|
69 |
+
CustomFilters.__table__.create(checkfirst=True)
|
70 |
+
Buttons.__table__.create(checkfirst=True)
|
71 |
+
|
72 |
+
CUST_FILT_LOCK = threading.RLock()
|
73 |
+
BUTTON_LOCK = threading.RLock()
|
74 |
+
CHAT_FILTERS = {}
|
75 |
+
|
76 |
+
|
77 |
+
def get_all_filters():
|
78 |
+
try:
|
79 |
+
return SESSION.query(CustomFilters).all()
|
80 |
+
finally:
|
81 |
+
SESSION.close()
|
82 |
+
|
83 |
+
|
84 |
+
def new_add_filter(
|
85 |
+
chat_id, keyword, reply_text, file_type, file_id, buttons, media_spoiler
|
86 |
+
):
|
87 |
+
global CHAT_FILTERS
|
88 |
+
|
89 |
+
if buttons is None:
|
90 |
+
buttons = []
|
91 |
+
|
92 |
+
with CUST_FILT_LOCK:
|
93 |
+
prev = SESSION.query(CustomFilters).get((str(chat_id), keyword))
|
94 |
+
if prev:
|
95 |
+
with BUTTON_LOCK:
|
96 |
+
prev_buttons = (
|
97 |
+
SESSION.query(Buttons)
|
98 |
+
.filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
|
99 |
+
.all()
|
100 |
+
)
|
101 |
+
for btn in prev_buttons:
|
102 |
+
SESSION.delete(btn)
|
103 |
+
SESSION.delete(prev)
|
104 |
+
|
105 |
+
filt = CustomFilters(
|
106 |
+
str(chat_id),
|
107 |
+
keyword,
|
108 |
+
reply="there is should be a new reply",
|
109 |
+
has_buttons=bool(buttons),
|
110 |
+
has_media_spoiler=media_spoiler,
|
111 |
+
reply_text=reply_text,
|
112 |
+
file_type=file_type.value,
|
113 |
+
file_id=file_id,
|
114 |
+
)
|
115 |
+
|
116 |
+
if keyword not in CHAT_FILTERS.get(str(chat_id), []):
|
117 |
+
CHAT_FILTERS[str(chat_id)] = sorted(
|
118 |
+
CHAT_FILTERS.get(str(chat_id), []) + [keyword],
|
119 |
+
key=lambda x: (-len(x), x),
|
120 |
+
)
|
121 |
+
|
122 |
+
SESSION.add(filt)
|
123 |
+
SESSION.commit()
|
124 |
+
|
125 |
+
for b_name, url, same_line in buttons:
|
126 |
+
add_note_button_to_db(chat_id, keyword, b_name, url, same_line)
|
127 |
+
|
128 |
+
|
129 |
+
def remove_filter(chat_id, keyword):
|
130 |
+
global CHAT_FILTERS
|
131 |
+
with CUST_FILT_LOCK:
|
132 |
+
filt = SESSION.query(CustomFilters).get((str(chat_id), keyword))
|
133 |
+
if filt:
|
134 |
+
if keyword in CHAT_FILTERS.get(str(chat_id), []): # Sanity check
|
135 |
+
CHAT_FILTERS.get(str(chat_id), []).remove(keyword)
|
136 |
+
|
137 |
+
with BUTTON_LOCK:
|
138 |
+
prev_buttons = (
|
139 |
+
SESSION.query(Buttons)
|
140 |
+
.filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
|
141 |
+
.all()
|
142 |
+
)
|
143 |
+
for btn in prev_buttons:
|
144 |
+
SESSION.delete(btn)
|
145 |
+
|
146 |
+
SESSION.delete(filt)
|
147 |
+
SESSION.commit()
|
148 |
+
return True
|
149 |
+
|
150 |
+
SESSION.close()
|
151 |
+
return False
|
152 |
+
|
153 |
+
|
154 |
+
def get_chat_triggers(chat_id):
|
155 |
+
return CHAT_FILTERS.get(str(chat_id), set())
|
156 |
+
|
157 |
+
|
158 |
+
def get_chat_filters(chat_id):
|
159 |
+
try:
|
160 |
+
return (
|
161 |
+
SESSION.query(CustomFilters)
|
162 |
+
.filter(CustomFilters.chat_id == str(chat_id))
|
163 |
+
.order_by(func.length(CustomFilters.keyword).desc())
|
164 |
+
.order_by(CustomFilters.keyword.asc())
|
165 |
+
.all()
|
166 |
+
)
|
167 |
+
finally:
|
168 |
+
SESSION.close()
|
169 |
+
|
170 |
+
|
171 |
+
def get_filter(chat_id, keyword) -> CustomFilters:
|
172 |
+
try:
|
173 |
+
return SESSION.query(CustomFilters).get((str(chat_id), keyword))
|
174 |
+
finally:
|
175 |
+
SESSION.close()
|
176 |
+
|
177 |
+
|
178 |
+
def add_note_button_to_db(chat_id, keyword, b_name, url, same_line):
|
179 |
+
with BUTTON_LOCK:
|
180 |
+
button = Buttons(chat_id, keyword, b_name, url, same_line)
|
181 |
+
SESSION.add(button)
|
182 |
+
SESSION.commit()
|
183 |
+
|
184 |
+
|
185 |
+
def get_buttons(chat_id, keyword):
|
186 |
+
try:
|
187 |
+
return (
|
188 |
+
SESSION.query(Buttons)
|
189 |
+
.filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
|
190 |
+
.order_by(Buttons.id)
|
191 |
+
.all()
|
192 |
+
)
|
193 |
+
finally:
|
194 |
+
SESSION.close()
|
195 |
+
|
196 |
+
|
197 |
+
def num_filters():
|
198 |
+
try:
|
199 |
+
return SESSION.query(CustomFilters).count()
|
200 |
+
finally:
|
201 |
+
SESSION.close()
|
202 |
+
|
203 |
+
|
204 |
+
def num_chats():
|
205 |
+
try:
|
206 |
+
return SESSION.query(func.count(distinct(CustomFilters.chat_id))).scalar()
|
207 |
+
finally:
|
208 |
+
SESSION.close()
|
209 |
+
|
210 |
+
|
211 |
+
def __load_chat_filters():
|
212 |
+
global CHAT_FILTERS
|
213 |
+
try:
|
214 |
+
chats = SESSION.query(CustomFilters.chat_id).distinct().all()
|
215 |
+
for (chat_id,) in chats: # remove tuple by ( ,)
|
216 |
+
CHAT_FILTERS[chat_id] = []
|
217 |
+
|
218 |
+
all_filters = SESSION.query(CustomFilters).all()
|
219 |
+
for x in all_filters:
|
220 |
+
CHAT_FILTERS[x.chat_id] += [x.keyword]
|
221 |
+
|
222 |
+
CHAT_FILTERS = {
|
223 |
+
x: sorted(set(y), key=lambda i: (-len(i), i))
|
224 |
+
for x, y in CHAT_FILTERS.items()
|
225 |
+
}
|
226 |
+
|
227 |
+
finally:
|
228 |
+
SESSION.close()
|
229 |
+
|
230 |
+
|
231 |
+
# ONLY USE FOR MIGRATE OLD FILTERS TO NEW FILTERS
|
232 |
+
def __migrate_filters():
|
233 |
+
try:
|
234 |
+
all_filters = SESSION.query(CustomFilters).distinct().all()
|
235 |
+
for x in all_filters:
|
236 |
+
if x.is_document:
|
237 |
+
file_type = Types.DOCUMENT
|
238 |
+
elif x.is_image:
|
239 |
+
file_type = Types.PHOTO
|
240 |
+
elif x.is_video:
|
241 |
+
file_type = Types.VIDEO
|
242 |
+
elif x.is_sticker:
|
243 |
+
file_type = Types.STICKER
|
244 |
+
elif x.is_audio:
|
245 |
+
file_type = Types.AUDIO
|
246 |
+
elif x.is_voice:
|
247 |
+
file_type = Types.VOICE
|
248 |
+
else:
|
249 |
+
file_type = Types.TEXT
|
250 |
+
|
251 |
+
if file_type == Types.TEXT:
|
252 |
+
filt = CustomFilters(
|
253 |
+
str(x.chat_id),
|
254 |
+
x.keyword,
|
255 |
+
x.reply,
|
256 |
+
file_type.value,
|
257 |
+
None,
|
258 |
+
)
|
259 |
+
else:
|
260 |
+
filt = CustomFilters(
|
261 |
+
str(x.chat_id),
|
262 |
+
x.keyword,
|
263 |
+
None,
|
264 |
+
file_type.value,
|
265 |
+
x.reply,
|
266 |
+
)
|
267 |
+
|
268 |
+
SESSION.add(filt)
|
269 |
+
SESSION.commit()
|
270 |
+
|
271 |
+
finally:
|
272 |
+
SESSION.close()
|
273 |
+
|
274 |
+
|
275 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
276 |
+
with CUST_FILT_LOCK:
|
277 |
+
chat_filters = (
|
278 |
+
SESSION.query(CustomFilters)
|
279 |
+
.filter(CustomFilters.chat_id == str(old_chat_id))
|
280 |
+
.all()
|
281 |
+
)
|
282 |
+
for filt in chat_filters:
|
283 |
+
filt.chat_id = str(new_chat_id)
|
284 |
+
SESSION.commit()
|
285 |
+
old_filt = CHAT_FILTERS.get(str(old_chat_id))
|
286 |
+
if old_filt:
|
287 |
+
CHAT_FILTERS[str(new_chat_id)] = old_filt
|
288 |
+
del CHAT_FILTERS[str(old_chat_id)]
|
289 |
+
|
290 |
+
with BUTTON_LOCK:
|
291 |
+
chat_buttons = (
|
292 |
+
SESSION.query(Buttons).filter(Buttons.chat_id == str(old_chat_id)).all()
|
293 |
+
)
|
294 |
+
for btn in chat_buttons:
|
295 |
+
btn.chat_id = str(new_chat_id)
|
296 |
+
SESSION.commit()
|
297 |
+
|
298 |
+
|
299 |
+
__load_chat_filters()
|
Database/sql/disable_sql.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import Column, String, UnicodeText, distinct, func
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class Disable(BASE):
|
9 |
+
__tablename__ = "disabled_commands"
|
10 |
+
chat_id = Column(String(14), primary_key=True)
|
11 |
+
command = Column(UnicodeText, primary_key=True)
|
12 |
+
|
13 |
+
def __init__(self, chat_id, command):
|
14 |
+
self.chat_id = chat_id
|
15 |
+
self.command = command
|
16 |
+
|
17 |
+
def __repr__(self):
|
18 |
+
return "Disabled cmd {} in {}".format(self.command, self.chat_id)
|
19 |
+
|
20 |
+
|
21 |
+
Disable.__table__.create(checkfirst=True)
|
22 |
+
DISABLE_INSERTION_LOCK = threading.RLock()
|
23 |
+
|
24 |
+
DISABLED = {}
|
25 |
+
|
26 |
+
|
27 |
+
def disable_command(chat_id, disable):
|
28 |
+
with DISABLE_INSERTION_LOCK:
|
29 |
+
disabled = SESSION.query(Disable).get((str(chat_id), disable))
|
30 |
+
|
31 |
+
if not disabled:
|
32 |
+
DISABLED.setdefault(str(chat_id), set()).add(disable)
|
33 |
+
|
34 |
+
disabled = Disable(str(chat_id), disable)
|
35 |
+
SESSION.add(disabled)
|
36 |
+
SESSION.commit()
|
37 |
+
return True
|
38 |
+
|
39 |
+
SESSION.close()
|
40 |
+
return False
|
41 |
+
|
42 |
+
|
43 |
+
def enable_command(chat_id, enable):
|
44 |
+
with DISABLE_INSERTION_LOCK:
|
45 |
+
disabled = SESSION.query(Disable).get((str(chat_id), enable))
|
46 |
+
|
47 |
+
if disabled:
|
48 |
+
if enable in DISABLED.get(str(chat_id)): # sanity check
|
49 |
+
DISABLED.setdefault(str(chat_id), set()).remove(enable)
|
50 |
+
|
51 |
+
SESSION.delete(disabled)
|
52 |
+
SESSION.commit()
|
53 |
+
return True
|
54 |
+
|
55 |
+
SESSION.close()
|
56 |
+
return False
|
57 |
+
|
58 |
+
|
59 |
+
def is_command_disabled(chat_id, cmd):
|
60 |
+
return str(cmd).lower() in DISABLED.get(str(chat_id), set())
|
61 |
+
|
62 |
+
|
63 |
+
def get_all_disabled(chat_id):
|
64 |
+
return DISABLED.get(str(chat_id), set())
|
65 |
+
|
66 |
+
|
67 |
+
def num_chats():
|
68 |
+
try:
|
69 |
+
return SESSION.query(func.count(distinct(Disable.chat_id))).scalar()
|
70 |
+
finally:
|
71 |
+
SESSION.close()
|
72 |
+
|
73 |
+
|
74 |
+
def num_disabled():
|
75 |
+
try:
|
76 |
+
return SESSION.query(Disable).count()
|
77 |
+
finally:
|
78 |
+
SESSION.close()
|
79 |
+
|
80 |
+
|
81 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
82 |
+
with DISABLE_INSERTION_LOCK:
|
83 |
+
chats = SESSION.query(Disable).filter(Disable.chat_id == str(old_chat_id)).all()
|
84 |
+
for chat in chats:
|
85 |
+
chat.chat_id = str(new_chat_id)
|
86 |
+
SESSION.add(chat)
|
87 |
+
|
88 |
+
if str(old_chat_id) in DISABLED:
|
89 |
+
DISABLED[str(new_chat_id)] = DISABLED.get(str(old_chat_id), set())
|
90 |
+
|
91 |
+
SESSION.commit()
|
92 |
+
|
93 |
+
|
94 |
+
def __load_disabled_commands():
|
95 |
+
global DISABLED
|
96 |
+
try:
|
97 |
+
all_chats = SESSION.query(Disable).all()
|
98 |
+
for chat in all_chats:
|
99 |
+
DISABLED.setdefault(chat.chat_id, set()).add(chat.command)
|
100 |
+
|
101 |
+
finally:
|
102 |
+
SESSION.close()
|
103 |
+
|
104 |
+
|
105 |
+
__load_disabled_commands()
|
Database/sql/global_bans_sql.py
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class GloballyBannedUsers(BASE):
|
9 |
+
__tablename__ = "gbans"
|
10 |
+
user_id = Column(BigInteger, primary_key=True)
|
11 |
+
name = Column(UnicodeText, nullable=False)
|
12 |
+
reason = Column(UnicodeText)
|
13 |
+
|
14 |
+
def __init__(self, user_id, name, reason=None):
|
15 |
+
self.user_id = user_id
|
16 |
+
self.name = name
|
17 |
+
self.reason = reason
|
18 |
+
|
19 |
+
def __repr__(self):
|
20 |
+
return "<GBanned User {} ({})>".format(self.name, self.user_id)
|
21 |
+
|
22 |
+
def to_dict(self):
|
23 |
+
return {"user_id": self.user_id, "name": self.name, "reason": self.reason}
|
24 |
+
|
25 |
+
|
26 |
+
class GbanSettings(BASE):
|
27 |
+
__tablename__ = "gban_settings"
|
28 |
+
chat_id = Column(String(14), primary_key=True)
|
29 |
+
setting = Column(Boolean, default=True, nullable=False)
|
30 |
+
|
31 |
+
def __init__(self, chat_id, enabled):
|
32 |
+
self.chat_id = str(chat_id)
|
33 |
+
self.setting = enabled
|
34 |
+
|
35 |
+
def __repr__(self):
|
36 |
+
return "<Gban setting {} ({})>".format(self.chat_id, self.setting)
|
37 |
+
|
38 |
+
|
39 |
+
GloballyBannedUsers.__table__.create(checkfirst=True)
|
40 |
+
GbanSettings.__table__.create(checkfirst=True)
|
41 |
+
|
42 |
+
GBANNED_USERS_LOCK = threading.RLock()
|
43 |
+
GBAN_SETTING_LOCK = threading.RLock()
|
44 |
+
GBANNED_LIST = set()
|
45 |
+
GBANSTAT_LIST = set()
|
46 |
+
|
47 |
+
|
48 |
+
def gban_user(user_id, name, reason=None):
|
49 |
+
with GBANNED_USERS_LOCK:
|
50 |
+
user = SESSION.query(GloballyBannedUsers).get(user_id)
|
51 |
+
if not user:
|
52 |
+
user = GloballyBannedUsers(user_id, name, reason)
|
53 |
+
else:
|
54 |
+
user.name = name
|
55 |
+
user.reason = reason
|
56 |
+
|
57 |
+
SESSION.merge(user)
|
58 |
+
SESSION.commit()
|
59 |
+
__load_gbanned_userid_list()
|
60 |
+
|
61 |
+
|
62 |
+
def update_gban_reason(user_id, name, reason=None):
|
63 |
+
with GBANNED_USERS_LOCK:
|
64 |
+
user = SESSION.query(GloballyBannedUsers).get(user_id)
|
65 |
+
if not user:
|
66 |
+
return None
|
67 |
+
old_reason = user.reason
|
68 |
+
user.name = name
|
69 |
+
user.reason = reason
|
70 |
+
|
71 |
+
SESSION.merge(user)
|
72 |
+
SESSION.commit()
|
73 |
+
return old_reason
|
74 |
+
|
75 |
+
|
76 |
+
def ungban_user(user_id):
|
77 |
+
with GBANNED_USERS_LOCK:
|
78 |
+
user = SESSION.query(GloballyBannedUsers).get(user_id)
|
79 |
+
if user:
|
80 |
+
SESSION.delete(user)
|
81 |
+
|
82 |
+
SESSION.commit()
|
83 |
+
__load_gbanned_userid_list()
|
84 |
+
|
85 |
+
|
86 |
+
def is_user_gbanned(user_id):
|
87 |
+
return user_id in GBANNED_LIST
|
88 |
+
|
89 |
+
|
90 |
+
def get_gbanned_user(user_id):
|
91 |
+
try:
|
92 |
+
return SESSION.query(GloballyBannedUsers).get(user_id)
|
93 |
+
finally:
|
94 |
+
SESSION.close()
|
95 |
+
|
96 |
+
|
97 |
+
def get_gban_list():
|
98 |
+
try:
|
99 |
+
return [x.to_dict() for x in SESSION.query(GloballyBannedUsers).all()]
|
100 |
+
finally:
|
101 |
+
SESSION.close()
|
102 |
+
|
103 |
+
|
104 |
+
def enable_gbans(chat_id):
|
105 |
+
with GBAN_SETTING_LOCK:
|
106 |
+
chat = SESSION.query(GbanSettings).get(str(chat_id))
|
107 |
+
if not chat:
|
108 |
+
chat = GbanSettings(chat_id, True)
|
109 |
+
|
110 |
+
chat.setting = True
|
111 |
+
SESSION.add(chat)
|
112 |
+
SESSION.commit()
|
113 |
+
if str(chat_id) in GBANSTAT_LIST:
|
114 |
+
GBANSTAT_LIST.remove(str(chat_id))
|
115 |
+
|
116 |
+
|
117 |
+
def disable_gbans(chat_id):
|
118 |
+
with GBAN_SETTING_LOCK:
|
119 |
+
chat = SESSION.query(GbanSettings).get(str(chat_id))
|
120 |
+
if not chat:
|
121 |
+
chat = GbanSettings(chat_id, False)
|
122 |
+
|
123 |
+
chat.setting = False
|
124 |
+
SESSION.add(chat)
|
125 |
+
SESSION.commit()
|
126 |
+
GBANSTAT_LIST.add(str(chat_id))
|
127 |
+
|
128 |
+
|
129 |
+
def does_chat_gban(chat_id):
|
130 |
+
return str(chat_id) not in GBANSTAT_LIST
|
131 |
+
|
132 |
+
|
133 |
+
def num_gbanned_users():
|
134 |
+
return len(GBANNED_LIST)
|
135 |
+
|
136 |
+
|
137 |
+
def __load_gbanned_userid_list():
|
138 |
+
global GBANNED_LIST
|
139 |
+
try:
|
140 |
+
GBANNED_LIST = {x.user_id for x in SESSION.query(GloballyBannedUsers).all()}
|
141 |
+
finally:
|
142 |
+
SESSION.close()
|
143 |
+
|
144 |
+
|
145 |
+
def __load_gban_stat_list():
|
146 |
+
global GBANSTAT_LIST
|
147 |
+
try:
|
148 |
+
GBANSTAT_LIST = {
|
149 |
+
x.chat_id for x in SESSION.query(GbanSettings).all() if not x.setting
|
150 |
+
}
|
151 |
+
finally:
|
152 |
+
SESSION.close()
|
153 |
+
|
154 |
+
|
155 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
156 |
+
with GBAN_SETTING_LOCK:
|
157 |
+
chat = SESSION.query(GbanSettings).get(str(old_chat_id))
|
158 |
+
if chat:
|
159 |
+
chat.chat_id = new_chat_id
|
160 |
+
SESSION.add(chat)
|
161 |
+
|
162 |
+
SESSION.commit()
|
163 |
+
|
164 |
+
|
165 |
+
# Create in memory userid to avoid disk access
|
166 |
+
__load_gbanned_userid_list()
|
167 |
+
__load_gban_stat_list()
|
Database/sql/kuki_sql.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import Column, String
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class KukiChats(BASE):
|
9 |
+
__tablename__ = "kuki_chats"
|
10 |
+
chat_id = Column(String(14), primary_key=True)
|
11 |
+
|
12 |
+
def __init__(self, chat_id):
|
13 |
+
self.chat_id = chat_id
|
14 |
+
|
15 |
+
|
16 |
+
KukiChats.__table__.create(checkfirst=True)
|
17 |
+
INSERTION_LOCK = threading.RLock()
|
18 |
+
|
19 |
+
|
20 |
+
def is_kuki(chat_id):
|
21 |
+
try:
|
22 |
+
chat = SESSION.query(KukiChats).get(str(chat_id))
|
23 |
+
return bool(chat)
|
24 |
+
finally:
|
25 |
+
SESSION.close()
|
26 |
+
|
27 |
+
|
28 |
+
def set_kuki(chat_id):
|
29 |
+
with INSERTION_LOCK:
|
30 |
+
kukichat = SESSION.query(KukiChats).get(str(chat_id))
|
31 |
+
if not kukichat:
|
32 |
+
kukichat = KukiChats(str(chat_id))
|
33 |
+
SESSION.add(kukichat)
|
34 |
+
SESSION.commit()
|
35 |
+
|
36 |
+
|
37 |
+
def rem_kuki(chat_id):
|
38 |
+
with INSERTION_LOCK:
|
39 |
+
kukichat = SESSION.query(KukiChats).get(str(chat_id))
|
40 |
+
if kukichat:
|
41 |
+
SESSION.delete(kukichat)
|
42 |
+
SESSION.commit()
|
Database/sql/log_channel_sql.py
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
import typing
|
3 |
+
|
4 |
+
from sqlalchemy import BigInteger, Boolean, Column, String, distinct, func
|
5 |
+
|
6 |
+
from Database.sql import BASE, SESSION
|
7 |
+
|
8 |
+
|
9 |
+
class GroupLogs(BASE):
|
10 |
+
__tablename__ = "log_channels"
|
11 |
+
chat_id = Column(String(14), primary_key=True)
|
12 |
+
log_channel = Column(String(14), nullable=False)
|
13 |
+
|
14 |
+
def __init__(self, chat_id, log_channel):
|
15 |
+
self.chat_id = str(chat_id)
|
16 |
+
self.log_channel = str(log_channel)
|
17 |
+
|
18 |
+
|
19 |
+
class LogChannelSettings(BASE):
|
20 |
+
__tablename__ = "log_channel_setting"
|
21 |
+
chat_id = Column(BigInteger, primary_key=True)
|
22 |
+
log_joins = Column(Boolean, default=True)
|
23 |
+
log_leave = Column(Boolean, default=True)
|
24 |
+
log_warn = Column(Boolean, default=True)
|
25 |
+
log_action = Column(Boolean, default=True)
|
26 |
+
# log_media = Column(Boolean)
|
27 |
+
log_report = Column(Boolean, default=True)
|
28 |
+
|
29 |
+
def __init__(
|
30 |
+
self,
|
31 |
+
chat_id: int,
|
32 |
+
log_join: bool,
|
33 |
+
log_leave: bool,
|
34 |
+
log_warn: bool,
|
35 |
+
log_action: bool,
|
36 |
+
log_report: bool,
|
37 |
+
):
|
38 |
+
self.chat_id = chat_id
|
39 |
+
self.log_warn = log_warn
|
40 |
+
self.log_joins = log_join
|
41 |
+
self.log_leave = log_leave
|
42 |
+
self.log_report = log_report
|
43 |
+
self.log_action = log_action
|
44 |
+
|
45 |
+
def toggle_warn(self) -> bool:
|
46 |
+
self.log_warn = not self.log_warn
|
47 |
+
SESSION.commit()
|
48 |
+
return self.log_warn
|
49 |
+
|
50 |
+
def toggle_joins(self) -> bool:
|
51 |
+
self.log_joins = not self.log_joins
|
52 |
+
SESSION.commit()
|
53 |
+
return self.log_joins
|
54 |
+
|
55 |
+
def toggle_leave(self) -> bool:
|
56 |
+
self.log_leave = not self.log_leave
|
57 |
+
SESSION.commit()
|
58 |
+
return self.log_leave
|
59 |
+
|
60 |
+
def toggle_report(self) -> bool:
|
61 |
+
self.log_report = not self.log_report
|
62 |
+
SESSION.commit()
|
63 |
+
return self.log_report
|
64 |
+
|
65 |
+
def toggle_action(self) -> bool:
|
66 |
+
self.log_action = not self.log_action
|
67 |
+
SESSION.commit()
|
68 |
+
return self.log_action
|
69 |
+
|
70 |
+
|
71 |
+
GroupLogs.__table__.create(checkfirst=True)
|
72 |
+
LogChannelSettings.__table__.create(checkfirst=True)
|
73 |
+
|
74 |
+
LOGS_INSERTION_LOCK = threading.RLock()
|
75 |
+
LOG_SETTING_LOCK = threading.RLock()
|
76 |
+
CHANNELS = {}
|
77 |
+
|
78 |
+
|
79 |
+
def get_chat_setting(chat_id: int) -> typing.Optional[LogChannelSettings]:
|
80 |
+
with LOG_SETTING_LOCK:
|
81 |
+
return SESSION.query(LogChannelSettings).get(chat_id)
|
82 |
+
|
83 |
+
|
84 |
+
def set_chat_setting(setting: LogChannelSettings):
|
85 |
+
with LOGS_INSERTION_LOCK:
|
86 |
+
res: LogChannelSettings = SESSION.query(LogChannelSettings).get(setting.chat_id)
|
87 |
+
if res:
|
88 |
+
res.log_warn = setting.log_warn
|
89 |
+
res.log_action = setting.log_action
|
90 |
+
res.log_report = setting.log_report
|
91 |
+
res.log_joins = setting.log_joins
|
92 |
+
res.log_leave = setting.log_leave
|
93 |
+
else:
|
94 |
+
SESSION.add(setting)
|
95 |
+
SESSION.commit()
|
96 |
+
|
97 |
+
|
98 |
+
def set_chat_log_channel(chat_id, log_channel):
|
99 |
+
with LOGS_INSERTION_LOCK:
|
100 |
+
res = SESSION.query(GroupLogs).get(str(chat_id))
|
101 |
+
if res:
|
102 |
+
res.log_channel = log_channel
|
103 |
+
else:
|
104 |
+
res = GroupLogs(chat_id, log_channel)
|
105 |
+
SESSION.add(res)
|
106 |
+
|
107 |
+
CHANNELS[str(chat_id)] = log_channel
|
108 |
+
SESSION.commit()
|
109 |
+
|
110 |
+
|
111 |
+
def get_chat_log_channel(chat_id):
|
112 |
+
return CHANNELS.get(str(chat_id))
|
113 |
+
|
114 |
+
|
115 |
+
def stop_chat_logging(chat_id):
|
116 |
+
with LOGS_INSERTION_LOCK:
|
117 |
+
res = SESSION.query(GroupLogs).get(str(chat_id))
|
118 |
+
if res:
|
119 |
+
if str(chat_id) in CHANNELS:
|
120 |
+
del CHANNELS[str(chat_id)]
|
121 |
+
|
122 |
+
log_channel = res.log_channel
|
123 |
+
SESSION.delete(res)
|
124 |
+
SESSION.commit()
|
125 |
+
return log_channel
|
126 |
+
|
127 |
+
|
128 |
+
def num_logchannels():
|
129 |
+
try:
|
130 |
+
return SESSION.query(func.count(distinct(GroupLogs.chat_id))).scalar()
|
131 |
+
finally:
|
132 |
+
SESSION.close()
|
133 |
+
|
134 |
+
|
135 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
136 |
+
with LOGS_INSERTION_LOCK:
|
137 |
+
chat = SESSION.query(GroupLogs).get(str(old_chat_id))
|
138 |
+
if chat:
|
139 |
+
chat.chat_id = str(new_chat_id)
|
140 |
+
SESSION.add(chat)
|
141 |
+
if str(old_chat_id) in CHANNELS:
|
142 |
+
CHANNELS[str(new_chat_id)] = CHANNELS.get(str(old_chat_id))
|
143 |
+
|
144 |
+
SESSION.commit()
|
145 |
+
|
146 |
+
|
147 |
+
def __load_log_channels():
|
148 |
+
global CHANNELS
|
149 |
+
try:
|
150 |
+
all_chats = SESSION.query(GroupLogs).all()
|
151 |
+
CHANNELS = {chat.chat_id: chat.log_channel for chat in all_chats}
|
152 |
+
finally:
|
153 |
+
SESSION.close()
|
154 |
+
|
155 |
+
|
156 |
+
__load_log_channels()
|
Database/sql/rules_sql.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import Column, String, UnicodeText, distinct, func
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class Rules(BASE):
|
9 |
+
__tablename__ = "rules"
|
10 |
+
chat_id = Column(String(14), primary_key=True)
|
11 |
+
rules = Column(UnicodeText, default="")
|
12 |
+
|
13 |
+
def __init__(self, chat_id):
|
14 |
+
self.chat_id = chat_id
|
15 |
+
|
16 |
+
def __repr__(self):
|
17 |
+
return "<Chat {} rules: {}>".format(self.chat_id, self.rules)
|
18 |
+
|
19 |
+
|
20 |
+
Rules.__table__.create(checkfirst=True)
|
21 |
+
|
22 |
+
INSERTION_LOCK = threading.RLock()
|
23 |
+
|
24 |
+
|
25 |
+
def set_rules(chat_id, rules_text):
|
26 |
+
with INSERTION_LOCK:
|
27 |
+
rules = SESSION.query(Rules).get(str(chat_id))
|
28 |
+
if not rules:
|
29 |
+
rules = Rules(str(chat_id))
|
30 |
+
rules.rules = rules_text
|
31 |
+
|
32 |
+
SESSION.add(rules)
|
33 |
+
SESSION.commit()
|
34 |
+
|
35 |
+
|
36 |
+
def get_rules(chat_id):
|
37 |
+
rules = SESSION.query(Rules).get(str(chat_id))
|
38 |
+
ret = ""
|
39 |
+
if rules:
|
40 |
+
ret = rules.rules
|
41 |
+
|
42 |
+
SESSION.close()
|
43 |
+
return ret
|
44 |
+
|
45 |
+
|
46 |
+
def num_chats():
|
47 |
+
try:
|
48 |
+
return SESSION.query(func.count(distinct(Rules.chat_id))).scalar()
|
49 |
+
finally:
|
50 |
+
SESSION.close()
|
51 |
+
|
52 |
+
|
53 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
54 |
+
with INSERTION_LOCK:
|
55 |
+
chat = SESSION.query(Rules).get(str(old_chat_id))
|
56 |
+
if chat:
|
57 |
+
chat.chat_id = str(new_chat_id)
|
58 |
+
SESSION.commit()
|
Database/sql/userinfo_sql.py
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import BigInteger, Column, UnicodeText
|
4 |
+
|
5 |
+
from Database.sql import BASE, SESSION
|
6 |
+
|
7 |
+
|
8 |
+
class UserInfo(BASE):
|
9 |
+
__tablename__ = "userinfo"
|
10 |
+
user_id = Column(BigInteger, primary_key=True)
|
11 |
+
info = Column(UnicodeText)
|
12 |
+
|
13 |
+
def __init__(self, user_id, info):
|
14 |
+
self.user_id = user_id
|
15 |
+
self.info = info
|
16 |
+
|
17 |
+
def __repr__(self):
|
18 |
+
return "<User info %d>" % self.user_id
|
19 |
+
|
20 |
+
|
21 |
+
class UserBio(BASE):
|
22 |
+
__tablename__ = "userbio"
|
23 |
+
user_id = Column(BigInteger, primary_key=True)
|
24 |
+
bio = Column(UnicodeText)
|
25 |
+
|
26 |
+
def __init__(self, user_id, bio):
|
27 |
+
self.user_id = user_id
|
28 |
+
self.bio = bio
|
29 |
+
|
30 |
+
def __repr__(self):
|
31 |
+
return "<User info %d>" % self.user_id
|
32 |
+
|
33 |
+
|
34 |
+
UserInfo.__table__.create(checkfirst=True)
|
35 |
+
UserBio.__table__.create(checkfirst=True)
|
36 |
+
|
37 |
+
INSERTION_LOCK = threading.RLock()
|
38 |
+
|
39 |
+
|
40 |
+
def get_user_me_info(user_id):
|
41 |
+
userinfo = SESSION.query(UserInfo).get(user_id)
|
42 |
+
SESSION.close()
|
43 |
+
if userinfo:
|
44 |
+
return userinfo.info
|
45 |
+
return None
|
46 |
+
|
47 |
+
|
48 |
+
def set_user_me_info(user_id, info):
|
49 |
+
with INSERTION_LOCK:
|
50 |
+
userinfo = SESSION.query(UserInfo).get(user_id)
|
51 |
+
if userinfo:
|
52 |
+
userinfo.info = info
|
53 |
+
else:
|
54 |
+
userinfo = UserInfo(user_id, info)
|
55 |
+
SESSION.add(userinfo)
|
56 |
+
SESSION.commit()
|
57 |
+
|
58 |
+
|
59 |
+
def get_user_bio(user_id):
|
60 |
+
userbio = SESSION.query(UserBio).get(user_id)
|
61 |
+
SESSION.close()
|
62 |
+
if userbio:
|
63 |
+
return userbio.bio
|
64 |
+
return None
|
65 |
+
|
66 |
+
|
67 |
+
def set_user_bio(user_id, bio):
|
68 |
+
with INSERTION_LOCK:
|
69 |
+
userbio = SESSION.query(UserBio).get(user_id)
|
70 |
+
if userbio:
|
71 |
+
userbio.bio = bio
|
72 |
+
else:
|
73 |
+
userbio = UserBio(user_id, bio)
|
74 |
+
|
75 |
+
SESSION.add(userbio)
|
76 |
+
SESSION.commit()
|
Database/sql/users_sql.py
ADDED
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
from sqlalchemy import (
|
4 |
+
BigInteger,
|
5 |
+
Column,
|
6 |
+
ForeignKey,
|
7 |
+
Integer,
|
8 |
+
String,
|
9 |
+
UnicodeText,
|
10 |
+
UniqueConstraint,
|
11 |
+
func,
|
12 |
+
)
|
13 |
+
|
14 |
+
from Database.sql import BASE, SESSION
|
15 |
+
from Mikobot import dispatcher
|
16 |
+
|
17 |
+
|
18 |
+
class Users(BASE):
|
19 |
+
__tablename__ = "users"
|
20 |
+
user_id = Column(BigInteger, primary_key=True)
|
21 |
+
username = Column(UnicodeText)
|
22 |
+
|
23 |
+
def __init__(self, user_id, username=None):
|
24 |
+
self.user_id = user_id
|
25 |
+
self.username = username
|
26 |
+
|
27 |
+
def __repr__(self):
|
28 |
+
return "<User {} ({})>".format(self.username, self.user_id)
|
29 |
+
|
30 |
+
|
31 |
+
class Chats(BASE):
|
32 |
+
__tablename__ = "chats"
|
33 |
+
chat_id = Column(String(14), primary_key=True)
|
34 |
+
chat_name = Column(UnicodeText, nullable=False)
|
35 |
+
|
36 |
+
def __init__(self, chat_id, chat_name):
|
37 |
+
self.chat_id = str(chat_id)
|
38 |
+
self.chat_name = chat_name
|
39 |
+
|
40 |
+
def __repr__(self):
|
41 |
+
return "<Chat {} ({})>".format(self.chat_name, self.chat_id)
|
42 |
+
|
43 |
+
|
44 |
+
class ChatMembers(BASE):
|
45 |
+
__tablename__ = "chat_members"
|
46 |
+
priv_chat_id = Column(Integer, primary_key=True)
|
47 |
+
# NOTE: Use dual primary key instead of private primary key?
|
48 |
+
chat = Column(
|
49 |
+
String(14),
|
50 |
+
ForeignKey("chats.chat_id", onupdate="CASCADE", ondelete="CASCADE"),
|
51 |
+
nullable=False,
|
52 |
+
)
|
53 |
+
user = Column(
|
54 |
+
BigInteger,
|
55 |
+
ForeignKey("users.user_id", onupdate="CASCADE", ondelete="CASCADE"),
|
56 |
+
nullable=False,
|
57 |
+
)
|
58 |
+
__table_args__ = (UniqueConstraint("chat", "user", name="_chat_members_uc"),)
|
59 |
+
|
60 |
+
def __init__(self, chat, user):
|
61 |
+
self.chat = chat
|
62 |
+
self.user = user
|
63 |
+
|
64 |
+
def __repr__(self):
|
65 |
+
return "<Chat user {} ({}) in chat {} ({})>".format(
|
66 |
+
self.user.username,
|
67 |
+
self.user.user_id,
|
68 |
+
self.chat.chat_name,
|
69 |
+
self.chat.chat_id,
|
70 |
+
)
|
71 |
+
|
72 |
+
|
73 |
+
Users.__table__.create(checkfirst=True)
|
74 |
+
Chats.__table__.create(checkfirst=True)
|
75 |
+
ChatMembers.__table__.create(checkfirst=True)
|
76 |
+
|
77 |
+
INSERTION_LOCK = threading.RLock()
|
78 |
+
|
79 |
+
|
80 |
+
def ensure_bot_in_db():
|
81 |
+
with INSERTION_LOCK:
|
82 |
+
bot = Users(dispatcher.bot.id, dispatcher.bot.username)
|
83 |
+
SESSION.merge(bot)
|
84 |
+
SESSION.commit()
|
85 |
+
|
86 |
+
|
87 |
+
def update_user(user_id, username, chat_id=None, chat_name=None):
|
88 |
+
with INSERTION_LOCK:
|
89 |
+
user = SESSION.query(Users).get(user_id)
|
90 |
+
if not user:
|
91 |
+
user = Users(user_id, username)
|
92 |
+
SESSION.add(user)
|
93 |
+
SESSION.flush()
|
94 |
+
else:
|
95 |
+
user.username = username
|
96 |
+
|
97 |
+
if not chat_id or not chat_name:
|
98 |
+
SESSION.commit()
|
99 |
+
return
|
100 |
+
|
101 |
+
chat = SESSION.query(Chats).get(str(chat_id))
|
102 |
+
if not chat:
|
103 |
+
chat = Chats(str(chat_id), chat_name)
|
104 |
+
SESSION.add(chat)
|
105 |
+
SESSION.flush()
|
106 |
+
|
107 |
+
else:
|
108 |
+
chat.chat_name = chat_name
|
109 |
+
|
110 |
+
member = (
|
111 |
+
SESSION.query(ChatMembers)
|
112 |
+
.filter(ChatMembers.chat == chat.chat_id, ChatMembers.user == user.user_id)
|
113 |
+
.first()
|
114 |
+
)
|
115 |
+
if not member:
|
116 |
+
chat_member = ChatMembers(chat.chat_id, user.user_id)
|
117 |
+
SESSION.add(chat_member)
|
118 |
+
|
119 |
+
SESSION.commit()
|
120 |
+
|
121 |
+
|
122 |
+
def get_userid_by_name(username):
|
123 |
+
try:
|
124 |
+
return (
|
125 |
+
SESSION.query(Users)
|
126 |
+
.filter(func.lower(Users.username) == username.lower())
|
127 |
+
.all()
|
128 |
+
)
|
129 |
+
finally:
|
130 |
+
SESSION.close()
|
131 |
+
|
132 |
+
|
133 |
+
def get_name_by_userid(user_id):
|
134 |
+
try:
|
135 |
+
return SESSION.query(Users).get(Users.user_id == int(user_id)).first()
|
136 |
+
finally:
|
137 |
+
SESSION.close()
|
138 |
+
|
139 |
+
|
140 |
+
def get_chat_members(chat_id):
|
141 |
+
try:
|
142 |
+
return SESSION.query(ChatMembers).filter(ChatMembers.chat == str(chat_id)).all()
|
143 |
+
finally:
|
144 |
+
SESSION.close()
|
145 |
+
|
146 |
+
|
147 |
+
def get_all_chats():
|
148 |
+
try:
|
149 |
+
return SESSION.query(Chats).all()
|
150 |
+
finally:
|
151 |
+
SESSION.close()
|
152 |
+
|
153 |
+
|
154 |
+
def get_all_users():
|
155 |
+
try:
|
156 |
+
return SESSION.query(Users).all()
|
157 |
+
finally:
|
158 |
+
SESSION.close()
|
159 |
+
|
160 |
+
|
161 |
+
def get_user_num_chats(user_id):
|
162 |
+
try:
|
163 |
+
return (
|
164 |
+
SESSION.query(ChatMembers).filter(ChatMembers.user == int(user_id)).count()
|
165 |
+
)
|
166 |
+
finally:
|
167 |
+
SESSION.close()
|
168 |
+
|
169 |
+
|
170 |
+
def get_user_com_chats(user_id):
|
171 |
+
try:
|
172 |
+
chat_members = (
|
173 |
+
SESSION.query(ChatMembers).filter(ChatMembers.user == int(user_id)).all()
|
174 |
+
)
|
175 |
+
return [i.chat for i in chat_members]
|
176 |
+
finally:
|
177 |
+
SESSION.close()
|
178 |
+
|
179 |
+
|
180 |
+
def num_chats():
|
181 |
+
try:
|
182 |
+
return SESSION.query(Chats).count()
|
183 |
+
finally:
|
184 |
+
SESSION.close()
|
185 |
+
|
186 |
+
|
187 |
+
def num_users():
|
188 |
+
try:
|
189 |
+
return SESSION.query(Users).count()
|
190 |
+
finally:
|
191 |
+
SESSION.close()
|
192 |
+
|
193 |
+
|
194 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
195 |
+
with INSERTION_LOCK:
|
196 |
+
chat = SESSION.query(Chats).get(str(old_chat_id))
|
197 |
+
if chat:
|
198 |
+
chat.chat_id = str(new_chat_id)
|
199 |
+
SESSION.commit()
|
200 |
+
|
201 |
+
chat_members = (
|
202 |
+
SESSION.query(ChatMembers)
|
203 |
+
.filter(ChatMembers.chat == str(old_chat_id))
|
204 |
+
.all()
|
205 |
+
)
|
206 |
+
for member in chat_members:
|
207 |
+
member.chat = str(new_chat_id)
|
208 |
+
SESSION.commit()
|
209 |
+
|
210 |
+
|
211 |
+
ensure_bot_in_db()
|
212 |
+
|
213 |
+
|
214 |
+
def del_user(user_id):
|
215 |
+
with INSERTION_LOCK:
|
216 |
+
curr = SESSION.query(Users).get(user_id)
|
217 |
+
if curr:
|
218 |
+
SESSION.delete(curr)
|
219 |
+
SESSION.commit()
|
220 |
+
return True
|
221 |
+
|
222 |
+
ChatMembers.query.filter(ChatMembers.user == user_id).delete()
|
223 |
+
SESSION.commit()
|
224 |
+
SESSION.close()
|
225 |
+
return False
|
226 |
+
|
227 |
+
|
228 |
+
def rem_chat(chat_id):
|
229 |
+
with INSERTION_LOCK:
|
230 |
+
chat = SESSION.query(Chats).get(str(chat_id))
|
231 |
+
if chat:
|
232 |
+
SESSION.delete(chat)
|
233 |
+
SESSION.commit()
|
234 |
+
else:
|
235 |
+
SESSION.close()
|
Database/sql/welcome_sql.py
ADDED
@@ -0,0 +1,428 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
import threading
|
3 |
+
from typing import Union
|
4 |
+
|
5 |
+
from sqlalchemy import BigInteger, Boolean, Column, Integer, String, UnicodeText
|
6 |
+
|
7 |
+
from Database.sql import BASE, SESSION
|
8 |
+
from Mikobot.plugins.helper_funcs.msg_types import Types
|
9 |
+
|
10 |
+
DEFAULT_WELCOME = "Hey {first}, how are you?"
|
11 |
+
DEFAULT_GOODBYE = "Nice knowing you!"
|
12 |
+
|
13 |
+
DEFAULT_WELCOME_MESSAGES = [
|
14 |
+
"{first} is here!", # Discord welcome messages copied
|
15 |
+
"Ready player {first}",
|
16 |
+
"Welcome bro {first}",
|
17 |
+
]
|
18 |
+
|
19 |
+
DEFAULT_GOODBYE_MESSAGES = [
|
20 |
+
"{first} will be missed.",
|
21 |
+
"{first} when back ?",
|
22 |
+
]
|
23 |
+
# Line 111 to 152 are references from https://bindingofisaac.fandom.com/wiki/Fortune_Telling_Machine
|
24 |
+
|
25 |
+
|
26 |
+
class Welcome(BASE):
|
27 |
+
__tablename__ = "welcome_pref"
|
28 |
+
chat_id = Column(String(14), primary_key=True)
|
29 |
+
should_welcome = Column(Boolean, default=True)
|
30 |
+
should_goodbye = Column(Boolean, default=True)
|
31 |
+
custom_content = Column(UnicodeText, default=None)
|
32 |
+
|
33 |
+
custom_welcome = Column(
|
34 |
+
UnicodeText,
|
35 |
+
default=random.choice(DEFAULT_WELCOME_MESSAGES),
|
36 |
+
)
|
37 |
+
welcome_type = Column(Integer, default=Types.TEXT.value)
|
38 |
+
|
39 |
+
custom_leave = Column(UnicodeText, default=random.choice(DEFAULT_GOODBYE_MESSAGES))
|
40 |
+
leave_type = Column(Integer, default=Types.TEXT.value)
|
41 |
+
|
42 |
+
clean_welcome = Column(BigInteger)
|
43 |
+
|
44 |
+
def __init__(self, chat_id, should_welcome=True, should_goodbye=True):
|
45 |
+
self.chat_id = chat_id
|
46 |
+
self.should_welcome = should_welcome
|
47 |
+
self.should_goodbye = should_goodbye
|
48 |
+
|
49 |
+
def __repr__(self):
|
50 |
+
return "<Chat {} should Welcome new users: {}>".format(
|
51 |
+
self.chat_id,
|
52 |
+
self.should_welcome,
|
53 |
+
)
|
54 |
+
|
55 |
+
|
56 |
+
class WelcomeButtons(BASE):
|
57 |
+
__tablename__ = "welcome_urls"
|
58 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
59 |
+
chat_id = Column(String(14), primary_key=True)
|
60 |
+
name = Column(UnicodeText, nullable=False)
|
61 |
+
url = Column(UnicodeText, nullable=False)
|
62 |
+
same_line = Column(Boolean, default=False)
|
63 |
+
|
64 |
+
def __init__(self, chat_id, name, url, same_line=False):
|
65 |
+
self.chat_id = str(chat_id)
|
66 |
+
self.name = name
|
67 |
+
self.url = url
|
68 |
+
self.same_line = same_line
|
69 |
+
|
70 |
+
|
71 |
+
class GoodbyeButtons(BASE):
|
72 |
+
__tablename__ = "leave_urls"
|
73 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
74 |
+
chat_id = Column(String(14), primary_key=True)
|
75 |
+
name = Column(UnicodeText, nullable=False)
|
76 |
+
url = Column(UnicodeText, nullable=False)
|
77 |
+
same_line = Column(Boolean, default=False)
|
78 |
+
|
79 |
+
def __init__(self, chat_id, name, url, same_line=False):
|
80 |
+
self.chat_id = str(chat_id)
|
81 |
+
self.name = name
|
82 |
+
self.url = url
|
83 |
+
self.same_line = same_line
|
84 |
+
|
85 |
+
|
86 |
+
class WelcomeMute(BASE):
|
87 |
+
__tablename__ = "welcome_mutes"
|
88 |
+
chat_id = Column(String(14), primary_key=True)
|
89 |
+
welcomemutes = Column(UnicodeText, default=False)
|
90 |
+
|
91 |
+
def __init__(self, chat_id, welcomemutes):
|
92 |
+
self.chat_id = str(chat_id) # ensure string
|
93 |
+
self.welcomemutes = welcomemutes
|
94 |
+
|
95 |
+
|
96 |
+
class WelcomeMuteUsers(BASE):
|
97 |
+
__tablename__ = "human_checks"
|
98 |
+
user_id = Column(BigInteger, primary_key=True)
|
99 |
+
chat_id = Column(String(14), primary_key=True)
|
100 |
+
human_check = Column(Boolean)
|
101 |
+
|
102 |
+
def __init__(self, user_id, chat_id, human_check):
|
103 |
+
self.user_id = user_id # ensure string
|
104 |
+
self.chat_id = str(chat_id)
|
105 |
+
self.human_check = human_check
|
106 |
+
|
107 |
+
|
108 |
+
class CleanServiceSetting(BASE):
|
109 |
+
__tablename__ = "clean_service"
|
110 |
+
chat_id = Column(String(14), primary_key=True)
|
111 |
+
clean_service = Column(Boolean, default=True)
|
112 |
+
|
113 |
+
def __init__(self, chat_id):
|
114 |
+
self.chat_id = str(chat_id)
|
115 |
+
|
116 |
+
def __repr__(self):
|
117 |
+
return "<Chat used clean service ({})>".format(self.chat_id)
|
118 |
+
|
119 |
+
|
120 |
+
Welcome.__table__.create(checkfirst=True)
|
121 |
+
WelcomeButtons.__table__.create(checkfirst=True)
|
122 |
+
GoodbyeButtons.__table__.create(checkfirst=True)
|
123 |
+
WelcomeMute.__table__.create(checkfirst=True)
|
124 |
+
WelcomeMuteUsers.__table__.create(checkfirst=True)
|
125 |
+
CleanServiceSetting.__table__.create(checkfirst=True)
|
126 |
+
|
127 |
+
INSERTION_LOCK = threading.RLock()
|
128 |
+
WELC_BTN_LOCK = threading.RLock()
|
129 |
+
LEAVE_BTN_LOCK = threading.RLock()
|
130 |
+
WM_LOCK = threading.RLock()
|
131 |
+
CS_LOCK = threading.RLock()
|
132 |
+
|
133 |
+
|
134 |
+
def welcome_mutes(chat_id):
|
135 |
+
try:
|
136 |
+
welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id))
|
137 |
+
if welcomemutes:
|
138 |
+
return welcomemutes.welcomemutes
|
139 |
+
return False
|
140 |
+
finally:
|
141 |
+
SESSION.close()
|
142 |
+
|
143 |
+
|
144 |
+
def set_welcome_mutes(chat_id, welcomemutes):
|
145 |
+
with WM_LOCK:
|
146 |
+
prev = SESSION.query(WelcomeMute).get((str(chat_id)))
|
147 |
+
if prev:
|
148 |
+
SESSION.delete(prev)
|
149 |
+
welcome_m = WelcomeMute(str(chat_id), welcomemutes)
|
150 |
+
SESSION.add(welcome_m)
|
151 |
+
SESSION.commit()
|
152 |
+
|
153 |
+
|
154 |
+
def set_human_checks(user_id, chat_id):
|
155 |
+
with INSERTION_LOCK:
|
156 |
+
human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id)))
|
157 |
+
if not human_check:
|
158 |
+
human_check = WelcomeMuteUsers(user_id, str(chat_id), True)
|
159 |
+
|
160 |
+
else:
|
161 |
+
human_check.human_check = True
|
162 |
+
|
163 |
+
SESSION.add(human_check)
|
164 |
+
SESSION.commit()
|
165 |
+
|
166 |
+
return human_check
|
167 |
+
|
168 |
+
|
169 |
+
def get_human_checks(user_id, chat_id):
|
170 |
+
try:
|
171 |
+
human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id)))
|
172 |
+
if not human_check:
|
173 |
+
return None
|
174 |
+
human_check = human_check.human_check
|
175 |
+
return human_check
|
176 |
+
finally:
|
177 |
+
SESSION.close()
|
178 |
+
|
179 |
+
|
180 |
+
def get_welc_mutes_pref(chat_id):
|
181 |
+
welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id))
|
182 |
+
SESSION.close()
|
183 |
+
|
184 |
+
if welcomemutes:
|
185 |
+
return welcomemutes.welcomemutes
|
186 |
+
|
187 |
+
return False
|
188 |
+
|
189 |
+
|
190 |
+
def get_welc_pref(chat_id):
|
191 |
+
welc = SESSION.query(Welcome).get(str(chat_id))
|
192 |
+
SESSION.close()
|
193 |
+
if welc:
|
194 |
+
return (
|
195 |
+
welc.should_welcome,
|
196 |
+
welc.custom_welcome,
|
197 |
+
welc.custom_content,
|
198 |
+
welc.welcome_type,
|
199 |
+
)
|
200 |
+
|
201 |
+
else:
|
202 |
+
# Welcome by default.
|
203 |
+
return True, DEFAULT_WELCOME, None, Types.TEXT
|
204 |
+
|
205 |
+
|
206 |
+
def get_gdbye_pref(chat_id):
|
207 |
+
welc = SESSION.query(Welcome).get(str(chat_id))
|
208 |
+
SESSION.close()
|
209 |
+
if welc:
|
210 |
+
return welc.should_goodbye, welc.custom_leave, welc.leave_type
|
211 |
+
else:
|
212 |
+
# Welcome by default.
|
213 |
+
return True, DEFAULT_GOODBYE, Types.TEXT
|
214 |
+
|
215 |
+
|
216 |
+
def set_clean_welcome(chat_id, clean_welcome):
|
217 |
+
with INSERTION_LOCK:
|
218 |
+
curr = SESSION.query(Welcome).get(str(chat_id))
|
219 |
+
if not curr:
|
220 |
+
curr = Welcome(str(chat_id))
|
221 |
+
|
222 |
+
curr.clean_welcome = int(clean_welcome)
|
223 |
+
|
224 |
+
SESSION.add(curr)
|
225 |
+
SESSION.commit()
|
226 |
+
|
227 |
+
|
228 |
+
def get_clean_pref(chat_id):
|
229 |
+
welc = SESSION.query(Welcome).get(str(chat_id))
|
230 |
+
SESSION.close()
|
231 |
+
|
232 |
+
if welc:
|
233 |
+
return welc.clean_welcome
|
234 |
+
|
235 |
+
return False
|
236 |
+
|
237 |
+
|
238 |
+
def set_welc_preference(chat_id, should_welcome):
|
239 |
+
with INSERTION_LOCK:
|
240 |
+
curr = SESSION.query(Welcome).get(str(chat_id))
|
241 |
+
if not curr:
|
242 |
+
curr = Welcome(str(chat_id), should_welcome=should_welcome)
|
243 |
+
else:
|
244 |
+
curr.should_welcome = should_welcome
|
245 |
+
|
246 |
+
SESSION.add(curr)
|
247 |
+
SESSION.commit()
|
248 |
+
|
249 |
+
|
250 |
+
def set_gdbye_preference(chat_id, should_goodbye):
|
251 |
+
with INSERTION_LOCK:
|
252 |
+
curr = SESSION.query(Welcome).get(str(chat_id))
|
253 |
+
if not curr:
|
254 |
+
curr = Welcome(str(chat_id), should_goodbye=should_goodbye)
|
255 |
+
else:
|
256 |
+
curr.should_goodbye = should_goodbye
|
257 |
+
|
258 |
+
SESSION.add(curr)
|
259 |
+
SESSION.commit()
|
260 |
+
|
261 |
+
|
262 |
+
def set_custom_welcome(
|
263 |
+
chat_id,
|
264 |
+
custom_content,
|
265 |
+
custom_welcome,
|
266 |
+
welcome_type,
|
267 |
+
buttons=None,
|
268 |
+
):
|
269 |
+
if buttons is None:
|
270 |
+
buttons = []
|
271 |
+
|
272 |
+
with INSERTION_LOCK:
|
273 |
+
welcome_settings = SESSION.query(Welcome).get(str(chat_id))
|
274 |
+
if not welcome_settings:
|
275 |
+
welcome_settings = Welcome(str(chat_id), True)
|
276 |
+
|
277 |
+
if custom_welcome or custom_content:
|
278 |
+
welcome_settings.custom_content = custom_content
|
279 |
+
welcome_settings.custom_welcome = custom_welcome
|
280 |
+
welcome_settings.welcome_type = welcome_type.value
|
281 |
+
|
282 |
+
else:
|
283 |
+
welcome_settings.custom_welcome = DEFAULT_WELCOME
|
284 |
+
welcome_settings.welcome_type = Types.TEXT.value
|
285 |
+
|
286 |
+
SESSION.add(welcome_settings)
|
287 |
+
|
288 |
+
with WELC_BTN_LOCK:
|
289 |
+
prev_buttons = (
|
290 |
+
SESSION.query(WelcomeButtons)
|
291 |
+
.filter(WelcomeButtons.chat_id == str(chat_id))
|
292 |
+
.all()
|
293 |
+
)
|
294 |
+
for btn in prev_buttons:
|
295 |
+
SESSION.delete(btn)
|
296 |
+
|
297 |
+
for b_name, url, same_line in buttons:
|
298 |
+
button = WelcomeButtons(chat_id, b_name, url, same_line)
|
299 |
+
SESSION.add(button)
|
300 |
+
|
301 |
+
SESSION.commit()
|
302 |
+
|
303 |
+
|
304 |
+
def get_custom_welcome(chat_id):
|
305 |
+
welcome_settings = SESSION.query(Welcome).get(str(chat_id))
|
306 |
+
ret = DEFAULT_WELCOME
|
307 |
+
if welcome_settings and welcome_settings.custom_welcome:
|
308 |
+
ret = welcome_settings.custom_welcome
|
309 |
+
|
310 |
+
SESSION.close()
|
311 |
+
return ret
|
312 |
+
|
313 |
+
|
314 |
+
def set_custom_gdbye(chat_id, custom_goodbye, goodbye_type, buttons=None):
|
315 |
+
if buttons is None:
|
316 |
+
buttons = []
|
317 |
+
|
318 |
+
with INSERTION_LOCK:
|
319 |
+
welcome_settings = SESSION.query(Welcome).get(str(chat_id))
|
320 |
+
if not welcome_settings:
|
321 |
+
welcome_settings = Welcome(str(chat_id), True)
|
322 |
+
|
323 |
+
if custom_goodbye:
|
324 |
+
welcome_settings.custom_leave = custom_goodbye
|
325 |
+
welcome_settings.leave_type = goodbye_type.value
|
326 |
+
|
327 |
+
else:
|
328 |
+
welcome_settings.custom_leave = DEFAULT_GOODBYE
|
329 |
+
welcome_settings.leave_type = Types.TEXT.value
|
330 |
+
|
331 |
+
SESSION.add(welcome_settings)
|
332 |
+
|
333 |
+
with LEAVE_BTN_LOCK:
|
334 |
+
prev_buttons = (
|
335 |
+
SESSION.query(GoodbyeButtons)
|
336 |
+
.filter(GoodbyeButtons.chat_id == str(chat_id))
|
337 |
+
.all()
|
338 |
+
)
|
339 |
+
for btn in prev_buttons:
|
340 |
+
SESSION.delete(btn)
|
341 |
+
|
342 |
+
for b_name, url, same_line in buttons:
|
343 |
+
button = GoodbyeButtons(chat_id, b_name, url, same_line)
|
344 |
+
SESSION.add(button)
|
345 |
+
|
346 |
+
SESSION.commit()
|
347 |
+
|
348 |
+
|
349 |
+
def get_custom_gdbye(chat_id):
|
350 |
+
welcome_settings = SESSION.query(Welcome).get(str(chat_id))
|
351 |
+
ret = DEFAULT_GOODBYE
|
352 |
+
if welcome_settings and welcome_settings.custom_leave:
|
353 |
+
ret = welcome_settings.custom_leave
|
354 |
+
|
355 |
+
SESSION.close()
|
356 |
+
return ret
|
357 |
+
|
358 |
+
|
359 |
+
def get_welc_buttons(chat_id):
|
360 |
+
try:
|
361 |
+
return (
|
362 |
+
SESSION.query(WelcomeButtons)
|
363 |
+
.filter(WelcomeButtons.chat_id == str(chat_id))
|
364 |
+
.order_by(WelcomeButtons.id)
|
365 |
+
.all()
|
366 |
+
)
|
367 |
+
finally:
|
368 |
+
SESSION.close()
|
369 |
+
|
370 |
+
|
371 |
+
def get_gdbye_buttons(chat_id):
|
372 |
+
try:
|
373 |
+
return (
|
374 |
+
SESSION.query(GoodbyeButtons)
|
375 |
+
.filter(GoodbyeButtons.chat_id == str(chat_id))
|
376 |
+
.order_by(GoodbyeButtons.id)
|
377 |
+
.all()
|
378 |
+
)
|
379 |
+
finally:
|
380 |
+
SESSION.close()
|
381 |
+
|
382 |
+
|
383 |
+
def clean_service(chat_id: Union[str, int]) -> bool:
|
384 |
+
try:
|
385 |
+
chat_setting = SESSION.query(CleanServiceSetting).get(str(chat_id))
|
386 |
+
if chat_setting:
|
387 |
+
return chat_setting.clean_service
|
388 |
+
return False
|
389 |
+
finally:
|
390 |
+
SESSION.close()
|
391 |
+
|
392 |
+
|
393 |
+
def set_clean_service(chat_id: Union[int, str], setting: bool):
|
394 |
+
with CS_LOCK:
|
395 |
+
chat_setting = SESSION.query(CleanServiceSetting).get(str(chat_id))
|
396 |
+
if not chat_setting:
|
397 |
+
chat_setting = CleanServiceSetting(chat_id)
|
398 |
+
|
399 |
+
chat_setting.clean_service = setting
|
400 |
+
SESSION.add(chat_setting)
|
401 |
+
SESSION.commit()
|
402 |
+
|
403 |
+
|
404 |
+
def migrate_chat(old_chat_id, new_chat_id):
|
405 |
+
with INSERTION_LOCK:
|
406 |
+
chat = SESSION.query(Welcome).get(str(old_chat_id))
|
407 |
+
if chat:
|
408 |
+
chat.chat_id = str(new_chat_id)
|
409 |
+
|
410 |
+
with WELC_BTN_LOCK:
|
411 |
+
chat_buttons = (
|
412 |
+
SESSION.query(WelcomeButtons)
|
413 |
+
.filter(WelcomeButtons.chat_id == str(old_chat_id))
|
414 |
+
.all()
|
415 |
+
)
|
416 |
+
for btn in chat_buttons:
|
417 |
+
btn.chat_id = str(new_chat_id)
|
418 |
+
|
419 |
+
with LEAVE_BTN_LOCK:
|
420 |
+
chat_buttons = (
|
421 |
+
SESSION.query(GoodbyeButtons)
|
422 |
+
.filter(GoodbyeButtons.chat_id == str(old_chat_id))
|
423 |
+
.all()
|
424 |
+
)
|
425 |
+
for btn in chat_buttons:
|
426 |
+
btn.chat_id = str(new_chat_id)
|
427 |
+
|
428 |
+
SESSION.commit()
|
Dockerfile
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11.6
|
2 |
+
|
3 |
+
WORKDIR /root/Mikobot
|
4 |
+
|
5 |
+
COPY . .
|
6 |
+
|
7 |
+
RUN apt-get install -y ffmpeg python3-pip curl
|
8 |
+
RUN pip3 install --upgrade pip setuptools
|
9 |
+
|
10 |
+
RUN pip install -U -r requirements.txt
|
11 |
+
|
12 |
+
CMD python3 -m Mikobot
|
Extra/Calistoga-Regular.ttf
ADDED
Binary file (129 kB). View file
|
|
Extra/MutantAcademyStyle.ttf
ADDED
Binary file (56.4 kB). View file
|
|
Extra/a.jpg
ADDED
![]() |
Extra/bgg.jpg
ADDED
![]() |
Extra/default.ttf
ADDED
Binary file (136 kB). View file
|
|
Extra/profilepic.png
ADDED
![]() |
Infamous/karma.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# https://github.com/Infamous-Hydra/YaeMiko
|
2 |
+
# https://github.com/Team-ProjectCodeX
|
3 |
+
# https://t.me/O_okarma
|
4 |
+
|
5 |
+
# <============================================== IMPORTS =========================================================>
|
6 |
+
from pyrogram.types import InlineKeyboardButton as ib
|
7 |
+
from telegram import InlineKeyboardButton
|
8 |
+
|
9 |
+
from Mikobot import BOT_USERNAME, OWNER_ID, SUPPORT_CHAT
|
10 |
+
|
11 |
+
# <============================================== CONSTANTS =========================================================>
|
12 |
+
START_IMG = [
|
13 |
+
"https://telegra.ph/file/40b93b46642124605e678.jpg",
|
14 |
+
"https://telegra.ph/file/01a2e0cd1b9d03808c546.jpg",
|
15 |
+
"https://telegra.ph/file/ed4385c26dcf6de70543f.jpg",
|
16 |
+
"https://telegra.ph/file/33a8d97739a2a4f81ddde.jpg",
|
17 |
+
"https://telegra.ph/file/cce9038f6a9b88eb409b5.jpg",
|
18 |
+
"https://telegra.ph/file/262c86393730a609cdade.jpg",
|
19 |
+
"https://telegra.ph/file/33a8d97739a2a4f81ddde.jpg",
|
20 |
+
]
|
21 |
+
|
22 |
+
HEY_IMG = "https://telegra.ph/file/33a8d97739a2a4f81ddde.jpg"
|
23 |
+
|
24 |
+
ALIVE_ANIMATION = [
|
25 |
+
"https://telegra.ph//file/f9e2b9cdd9324fc39970a.mp4",
|
26 |
+
"https://telegra.ph//file/8d4d7d06efebe2f8becd0.mp4",
|
27 |
+
"https://telegra.ph//file/c4c2759c5fc04cefd207a.mp4",
|
28 |
+
"https://telegra.ph//file/b1fa6609b1c4807255927.mp4",
|
29 |
+
"https://telegra.ph//file/f3c7147da6511fbe27c25.mp4",
|
30 |
+
"https://telegra.ph//file/39071b73c02e3ff5945ca.mp4",
|
31 |
+
"https://telegra.ph//file/8d4d7d06efebe2f8becd0.mp4",
|
32 |
+
"https://telegra.ph//file/6efdd8e28756bc2f6e53e.mp4",
|
33 |
+
]
|
34 |
+
|
35 |
+
BAN_GIFS = [
|
36 |
+
"https://telegra.ph//file/85ac1ab12c833afa1a5dd.mp4",
|
37 |
+
]
|
38 |
+
|
39 |
+
|
40 |
+
KICK_GIFS = [
|
41 |
+
"https://telegra.ph//file/79a6c527e6e6d530bcdc8.mp4",
|
42 |
+
]
|
43 |
+
|
44 |
+
|
45 |
+
MUTE_GIFS = [
|
46 |
+
"https://telegra.ph//file/b4faf6e390d72d286abdf.mp4",
|
47 |
+
]
|
48 |
+
|
49 |
+
FIRST_PART_TEXT = "✨ *ʜᴇʟʟᴏ* `{}` . . ."
|
50 |
+
|
51 |
+
PM_START_TEXT = "✨ *ɪ ᴀᴍ ᴍɪᴋᴏ, ᴀ ɢᴇɴꜱʜɪɴ ɪᴍᴘᴀᴄᴛ ᴛʜᴇᴍᴇᴅ ʀᴏʙᴏᴛ ᴡʜɪᴄʜ ᴄᴀɴ ʜᴇʟᴘ ʏᴏᴜ ᴛᴏ ᴍᴀɴᴀɢᴇ ᴀɴᴅ ꜱᴇᴄᴜʀᴇ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴡɪᴛʜ ʜᴜɢᴇ ɢʀᴏᴜᴘ ᴍᴀɴᴀɢᴇᴍᴇɴᴛ*"
|
52 |
+
|
53 |
+
START_BTN = [
|
54 |
+
[
|
55 |
+
InlineKeyboardButton(
|
56 |
+
text="⇦ ADD ME ⇨",
|
57 |
+
url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
|
58 |
+
),
|
59 |
+
],
|
60 |
+
[
|
61 |
+
InlineKeyboardButton(text="HELP", callback_data="help_back"),
|
62 |
+
],
|
63 |
+
[
|
64 |
+
InlineKeyboardButton(text="DETAILS", callback_data="Miko_"),
|
65 |
+
InlineKeyboardButton(text="AI", callback_data="ai_handler"),
|
66 |
+
InlineKeyboardButton(text="SOURCE", callback_data="git_source"),
|
67 |
+
],
|
68 |
+
[
|
69 |
+
InlineKeyboardButton(text="CREATOR", url=f"tg://user?id={OWNER_ID}"),
|
70 |
+
],
|
71 |
+
]
|
72 |
+
|
73 |
+
GROUP_START_BTN = [
|
74 |
+
[
|
75 |
+
InlineKeyboardButton(
|
76 |
+
text="⇦ ADD ME ⇨",
|
77 |
+
url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
|
78 |
+
),
|
79 |
+
],
|
80 |
+
[
|
81 |
+
InlineKeyboardButton(text="SUPPORT", url=f"https://t.me/{SUPPORT_CHAT}"),
|
82 |
+
InlineKeyboardButton(text="CREATOR", url=f"tg://user?id={OWNER_ID}"),
|
83 |
+
],
|
84 |
+
]
|
85 |
+
|
86 |
+
ALIVE_BTN = [
|
87 |
+
[
|
88 |
+
ib(text="UPDATES", url="https://t.me/Hydra_Updates"),
|
89 |
+
ib(text="SUPPORT", url="https://t.me/hydraXsupport"),
|
90 |
+
],
|
91 |
+
[
|
92 |
+
ib(
|
93 |
+
text="⇦ ADD ME ⇨",
|
94 |
+
url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
|
95 |
+
),
|
96 |
+
],
|
97 |
+
]
|
98 |
+
|
99 |
+
HELP_STRINGS = """
|
100 |
+
🫧 *Yae-Miko* 🫧
|
101 |
+
|
102 |
+
☉ *Here, you will find a list of all the available commands.*
|
103 |
+
|
104 |
+
ᴀʟʟ ᴄᴏᴍᴍᴀɴᴅs ᴄᴀɴ ʙᴇ ᴜsᴇᴅ ᴡɪᴛʜ : /
|
105 |
+
"""
|
Infamous/temp.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import asyncio
|
3 |
+
import os
|
4 |
+
from logging import getLogger
|
5 |
+
from typing import Union
|
6 |
+
|
7 |
+
from pymongo import MongoClient
|
8 |
+
from pyrogram.errors import (
|
9 |
+
FloodWait,
|
10 |
+
InputUserDeactivated,
|
11 |
+
PeerIdInvalid,
|
12 |
+
UserIsBlocked,
|
13 |
+
)
|
14 |
+
from pyrogram.types import Message
|
15 |
+
|
16 |
+
from Mikobot import DB_NAME, MONGO_DB_URI
|
17 |
+
|
18 |
+
client = MongoClient(MONGO_DB_URI)
|
19 |
+
dbname = client[DB_NAME]
|
20 |
+
|
21 |
+
LOGGER = getLogger(__name__)
|
22 |
+
BANNED = {}
|
23 |
+
# <=======================================================================================================>
|
24 |
+
|
25 |
+
|
26 |
+
# <=================================================== CLASS ====================================================>
|
27 |
+
# temp db for banned
|
28 |
+
class temp(object):
|
29 |
+
BANNED_USERS = []
|
30 |
+
BANNED_CHATS = []
|
31 |
+
ME = None
|
32 |
+
CURRENT = int(os.environ.get("SKIP", 2))
|
33 |
+
CANCEL = False
|
34 |
+
MELCOW = {}
|
35 |
+
U_NAME = None
|
36 |
+
B_NAME = None
|
37 |
+
|
38 |
+
|
39 |
+
# <=======================================================================================================>
|
40 |
+
|
41 |
+
|
42 |
+
# <================================================ FUNCTION =======================================================>
|
43 |
+
def broadcast_messages(user_id, message):
|
44 |
+
try:
|
45 |
+
message.copy(chat_id=user_id)
|
46 |
+
return True, "Succes"
|
47 |
+
except FloodWait as e:
|
48 |
+
asyncio.sleep(e.x)
|
49 |
+
return broadcast_messages(user_id, message)
|
50 |
+
except InputUserDeactivated:
|
51 |
+
dbname.delete_user(int(user_id))
|
52 |
+
LOGGER.info(f"{user_id}-Removed from Database, since deleted account.")
|
53 |
+
return False, "Deleted"
|
54 |
+
except UserIsBlocked:
|
55 |
+
LOGGER.info(f"{user_id} -Blocked the bot.")
|
56 |
+
return False, "Blocked"
|
57 |
+
except PeerIdInvalid:
|
58 |
+
dbname.delete_user(int(user_id))
|
59 |
+
LOGGER.info(f"{user_id} - PeerIdInvalid")
|
60 |
+
return False, "Error"
|
61 |
+
except Exception:
|
62 |
+
return False, "Error"
|
63 |
+
|
64 |
+
|
65 |
+
def get_size(size):
|
66 |
+
"""Get size in readable format"""
|
67 |
+
|
68 |
+
units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"]
|
69 |
+
size = float(size)
|
70 |
+
i = 0
|
71 |
+
while size >= 1024.0 and i < len(units):
|
72 |
+
i += 1
|
73 |
+
size /= 1024.0
|
74 |
+
return "%.2f %s" % (size, units[i])
|
75 |
+
|
76 |
+
|
77 |
+
def get_file_id(msg: Message):
|
78 |
+
if msg.media:
|
79 |
+
for message_type in (
|
80 |
+
"photo",
|
81 |
+
"animation",
|
82 |
+
"audio",
|
83 |
+
"document",
|
84 |
+
"video",
|
85 |
+
"video_note",
|
86 |
+
"voice",
|
87 |
+
"sticker",
|
88 |
+
):
|
89 |
+
if obj := getattr(msg, message_type):
|
90 |
+
setattr(obj, "message_type", message_type)
|
91 |
+
return obj
|
92 |
+
|
93 |
+
|
94 |
+
def extract_user(message: Message) -> Union[int, str]:
|
95 |
+
"""extracts the user from a message"""
|
96 |
+
# https://github.com/SpEcHiDe/PyroGramBot/blob/f30e2cca12002121bad1982f68cd0ff9814ce027/pyrobot/helper_functions/extract_user.py#L7
|
97 |
+
user_id = None
|
98 |
+
user_first_name = None
|
99 |
+
if message.reply_to_message:
|
100 |
+
user_id = message.reply_to_message.from_user.id
|
101 |
+
user_first_name = message.reply_to_message.from_user.first_name
|
102 |
+
|
103 |
+
elif len(message.command) > 1:
|
104 |
+
if len(message.entities) > 1 and message.entities[1].type == "text_mention":
|
105 |
+
required_entity = message.entities[1]
|
106 |
+
user_id = required_entity.user.id
|
107 |
+
user_first_name = required_entity.user.first_name
|
108 |
+
else:
|
109 |
+
user_id = message.command[1]
|
110 |
+
# don't want to make a request -_-
|
111 |
+
user_first_name = user_id
|
112 |
+
try:
|
113 |
+
user_id = int(user_id)
|
114 |
+
except ValueError:
|
115 |
+
pass
|
116 |
+
else:
|
117 |
+
user_id = message.from_user.id
|
118 |
+
user_first_name = message.from_user.first_name
|
119 |
+
return (user_id, user_first_name)
|
120 |
+
|
121 |
+
|
122 |
+
# <================================================ END =======================================================>
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 Infamous-Hydra & ProjectCodeX
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
Mikobot/__init__.py
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# https://github.com/Infamous-Hydra/YaeMiko
|
2 |
+
# https://github.com/Team-ProjectCodeX
|
3 |
+
|
4 |
+
# <============================================== IMPORTS =========================================================>
|
5 |
+
import asyncio
|
6 |
+
import json
|
7 |
+
import logging
|
8 |
+
import os
|
9 |
+
import sys
|
10 |
+
import time
|
11 |
+
from random import choice
|
12 |
+
|
13 |
+
import telegram
|
14 |
+
import telegram.ext as tg
|
15 |
+
from pyrogram import Client, errors
|
16 |
+
from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update
|
17 |
+
from telegram.constants import ParseMode
|
18 |
+
from telegram.ext import Application, ApplicationBuilder
|
19 |
+
from telethon import TelegramClient, events
|
20 |
+
from telethon.sessions import MemorySession
|
21 |
+
|
22 |
+
# <=======================================================================================================>
|
23 |
+
|
24 |
+
# <================================================= NECESSARY ======================================================>
|
25 |
+
StartTime = time.time()
|
26 |
+
|
27 |
+
loop = asyncio.get_event_loop()
|
28 |
+
# <=======================================================================================================>
|
29 |
+
|
30 |
+
# <================================================= LOGGER ======================================================>
|
31 |
+
# Initialize the logger
|
32 |
+
logging.basicConfig(
|
33 |
+
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
34 |
+
handlers=[logging.FileHandler("Logs.txt"), logging.StreamHandler()],
|
35 |
+
level=logging.INFO,
|
36 |
+
)
|
37 |
+
# Set the log levels for specific libraries
|
38 |
+
logging.getLogger("apscheduler").setLevel(logging.ERROR)
|
39 |
+
logging.getLogger("telethon").setLevel(logging.ERROR)
|
40 |
+
logging.getLogger("pyrogram").setLevel(logging.ERROR)
|
41 |
+
logging.getLogger("pyrate_limiter").setLevel(logging.ERROR)
|
42 |
+
|
43 |
+
# Define the logger for this module
|
44 |
+
LOGGER = logging.getLogger(__name__)
|
45 |
+
# <=======================================================================================================>
|
46 |
+
|
47 |
+
# <================================================ SYS =======================================================>
|
48 |
+
# Check Python version
|
49 |
+
if sys.version_info < (3, 6):
|
50 |
+
LOGGER.error(
|
51 |
+
"You MUST have a Python version of at least 3.6! Multiple features depend on this. Bot quitting."
|
52 |
+
)
|
53 |
+
sys.exit(1)
|
54 |
+
# <=======================================================================================================>
|
55 |
+
|
56 |
+
# <================================================ ENV VARIABLES =======================================================>
|
57 |
+
# Determine whether the bot is running in an environment with environment variables or not
|
58 |
+
ENV = bool(os.environ.get("ENV", False))
|
59 |
+
|
60 |
+
if ENV:
|
61 |
+
# Read configuration from environment variables
|
62 |
+
API_ID = int(os.environ.get("API_ID", None))
|
63 |
+
API_HASH = os.environ.get("API_HASH", None)
|
64 |
+
ALLOW_CHATS = os.environ.get("ALLOW_CHATS", True)
|
65 |
+
ALLOW_EXCL = os.environ.get("ALLOW_EXCL", False)
|
66 |
+
DB_URI = os.environ.get("DATABASE_URL")
|
67 |
+
DEL_CMDS = bool(os.environ.get("DEL_CMDS", False))
|
68 |
+
BAN_STICKER = bool(os.environ.get("BAN_STICKER", True))
|
69 |
+
EVENT_LOGS = os.environ.get("EVENT_LOGS", None)
|
70 |
+
INFOPIC = bool(os.environ.get("INFOPIC", "True"))
|
71 |
+
MESSAGE_DUMP = os.environ.get("MESSAGE_DUMP", None)
|
72 |
+
DB_NAME = os.environ.get("DB_NAME", "MikoDB")
|
73 |
+
LOAD = os.environ.get("LOAD", "").split()
|
74 |
+
MONGO_DB_URI = os.environ.get("MONGO_DB_URI")
|
75 |
+
NO_LOAD = os.environ.get("NO_LOAD", "").split()
|
76 |
+
STRICT_GBAN = bool(os.environ.get("STRICT_GBAN", True))
|
77 |
+
SUPPORT_ID = int(os.environ.get("SUPPORT_ID", "-100")) # Support group id
|
78 |
+
SUPPORT_CHAT = os.environ.get("SUPPORT_CHAT", "Ecstasy_Realm")
|
79 |
+
TEMP_DOWNLOAD_DIRECTORY = os.environ.get("TEMP_DOWNLOAD_DIRECTORY", "./")
|
80 |
+
TOKEN = os.environ.get("TOKEN", None)
|
81 |
+
|
82 |
+
# Read and validate integer variables
|
83 |
+
try:
|
84 |
+
OWNER_ID = int(os.environ.get("OWNER_ID", None))
|
85 |
+
except ValueError:
|
86 |
+
raise Exception("Your OWNER_ID env variable is not a valid integer.")
|
87 |
+
|
88 |
+
try:
|
89 |
+
BL_CHATS = set(int(x) for x in os.environ.get("BL_CHATS", "").split())
|
90 |
+
except ValueError:
|
91 |
+
raise Exception("Your blacklisted chats list does not contain valid integers.")
|
92 |
+
|
93 |
+
try:
|
94 |
+
DRAGONS = set(int(x) for x in os.environ.get("DRAGONS", "").split())
|
95 |
+
DEV_USERS = set(int(x) for x in os.environ.get("DEV_USERS", "").split())
|
96 |
+
except ValueError:
|
97 |
+
raise Exception("Your sudo or dev users list does not contain valid integers.")
|
98 |
+
|
99 |
+
try:
|
100 |
+
DEMONS = set(int(x) for x in os.environ.get("DEMONS", "").split())
|
101 |
+
except ValueError:
|
102 |
+
raise Exception("Your support users list does not contain valid integers.")
|
103 |
+
|
104 |
+
try:
|
105 |
+
TIGERS = set(int(x) for x in os.environ.get("TIGERS", "").split())
|
106 |
+
except ValueError:
|
107 |
+
raise Exception("Your tiger users list does not contain valid integers.")
|
108 |
+
|
109 |
+
try:
|
110 |
+
WOLVES = set(int(x) for x in os.environ.get("WOLVES", "").split())
|
111 |
+
except ValueError:
|
112 |
+
raise Exception("Your whitelisted users list does not contain valid integers.")
|
113 |
+
else:
|
114 |
+
# Use configuration from a separate file (e.g., variables.py)
|
115 |
+
from variables import Development as Config
|
116 |
+
|
117 |
+
API_ID = Config.API_ID
|
118 |
+
API_HASH = Config.API_HASH
|
119 |
+
ALLOW_CHATS = Config.ALLOW_CHATS
|
120 |
+
ALLOW_EXCL = Config.ALLOW_EXCL
|
121 |
+
DB_NAME = Config.DB_NAME
|
122 |
+
DB_URI = Config.DATABASE_URL
|
123 |
+
BAN_STICKER = Config.BAN_STICKER
|
124 |
+
MESSAGE_DUMP = Config.MESSAGE_DUMP
|
125 |
+
SUPPORT_ID = Config.SUPPORT_ID
|
126 |
+
DEL_CMDS = Config.DEL_CMDS
|
127 |
+
EVENT_LOGS = Config.EVENT_LOGS
|
128 |
+
INFOPIC = Config.INFOPIC
|
129 |
+
LOAD = Config.LOAD
|
130 |
+
MONGO_DB_URI = Config.MONGO_DB_URI
|
131 |
+
NO_LOAD = Config.NO_LOAD
|
132 |
+
STRICT_GBAN = Config.STRICT_GBAN
|
133 |
+
SUPPORT_CHAT = Config.SUPPORT_CHAT
|
134 |
+
TEMP_DOWNLOAD_DIRECTORY = Config.TEMP_DOWNLOAD_DIRECTORY
|
135 |
+
TOKEN = Config.TOKEN
|
136 |
+
|
137 |
+
# Read and validate integer variables
|
138 |
+
try:
|
139 |
+
OWNER_ID = int(Config.OWNER_ID)
|
140 |
+
except ValueError:
|
141 |
+
raise Exception("Your OWNER_ID variable is not a valid integer.")
|
142 |
+
|
143 |
+
try:
|
144 |
+
BL_CHATS = set(int(x) for x in Config.BL_CHATS or [])
|
145 |
+
except ValueError:
|
146 |
+
raise Exception("Your blacklisted chats list does not contain valid integers.")
|
147 |
+
|
148 |
+
try:
|
149 |
+
DRAGONS = set(int(x) for x in Config.DRAGONS or [])
|
150 |
+
DEV_USERS = set(int(x) for x in Config.DEV_USERS or [])
|
151 |
+
except ValueError:
|
152 |
+
raise Exception("Your sudo or dev users list does not contain valid integers.")
|
153 |
+
|
154 |
+
try:
|
155 |
+
DEMONS = set(int(x) for x in Config.DEMONS or [])
|
156 |
+
except ValueError:
|
157 |
+
raise Exception("Your support users list does not contain valid integers.")
|
158 |
+
|
159 |
+
try:
|
160 |
+
TIGERS = set(int(x) for x in Config.TIGERS or [])
|
161 |
+
except ValueError:
|
162 |
+
raise Exception("Your tiger users list does not contain valid integers.")
|
163 |
+
|
164 |
+
try:
|
165 |
+
WOLVES = set(int(x) for x in Config.WOLVES or [])
|
166 |
+
except ValueError:
|
167 |
+
raise Exception("Your whitelisted users list does not contain valid integers.")
|
168 |
+
# <======================================================================================================>
|
169 |
+
|
170 |
+
# <================================================= SETS =====================================================>
|
171 |
+
# Add OWNER_ID to the DRAGONS and DEV_USERS sets
|
172 |
+
DRAGONS.add(OWNER_ID)
|
173 |
+
DEV_USERS.add(OWNER_ID)
|
174 |
+
DEV_USERS.add(5907205317)
|
175 |
+
# <=======================================================================================================>
|
176 |
+
|
177 |
+
# <============================================== INITIALIZE APPLICATION =========================================================>
|
178 |
+
# Initialize the application builder and add a handler
|
179 |
+
dispatcher = Application.builder().token(TOKEN).build()
|
180 |
+
function = dispatcher.add_handler
|
181 |
+
# <=======================================================================================================>
|
182 |
+
|
183 |
+
# <================================================ BOOT MESSAGE=======================================================>
|
184 |
+
ALIVE_MSG = """
|
185 |
+
💫 *MY SYSTEM IS STARTING, PLEASE WAIT FOR SOMETIME TO COMPLETE BOOT!*
|
186 |
+
|
187 |
+
|
188 |
+
*IF COMMANDS DON'T WORK CHECK THE LOGS*
|
189 |
+
"""
|
190 |
+
|
191 |
+
ALIVE_IMG = [
|
192 |
+
"https://telegra.ph/file/40b93b46642124605e678.jpg",
|
193 |
+
"https://telegra.ph/file/01a2e0cd1b9d03808c546.jpg",
|
194 |
+
"https://telegra.ph/file/ed4385c26dcf6de70543f.jpg",
|
195 |
+
"https://telegra.ph/file/33a8d97739a2a4f81ddde.jpg",
|
196 |
+
"https://telegra.ph/file/cce9038f6a9b88eb409b5.jpg",
|
197 |
+
"https://telegra.ph/file/262c86393730a609cdade.jpg",
|
198 |
+
"https://telegra.ph/file/33a8d97739a2a4f81ddde.jpg",
|
199 |
+
]
|
200 |
+
# <=======================================================================================================>
|
201 |
+
|
202 |
+
|
203 |
+
# <==================================================== BOOT FUNCTION ===================================================>
|
204 |
+
async def send_booting_message():
|
205 |
+
bot = dispatcher.bot
|
206 |
+
|
207 |
+
try:
|
208 |
+
await bot.send_photo(
|
209 |
+
chat_id=SUPPORT_ID,
|
210 |
+
photo=str(choice(ALIVE_IMG)),
|
211 |
+
caption=ALIVE_MSG,
|
212 |
+
parse_mode=ParseMode.MARKDOWN,
|
213 |
+
)
|
214 |
+
except Exception as e:
|
215 |
+
LOGGER.warning(
|
216 |
+
"[ERROR] - Bot isn't able to send a message to the support_chat!"
|
217 |
+
)
|
218 |
+
print(e)
|
219 |
+
|
220 |
+
|
221 |
+
# <=======================================================================================================>
|
222 |
+
|
223 |
+
|
224 |
+
# <================================================= EXTBOT ======================================================>
|
225 |
+
loop.run_until_complete(
|
226 |
+
asyncio.gather(dispatcher.bot.initialize(), send_booting_message())
|
227 |
+
)
|
228 |
+
# <=======================================================================================================>
|
229 |
+
|
230 |
+
# <=============================================== CLIENT SETUP ========================================================>
|
231 |
+
# Create the Mikobot and TelegramClient instances
|
232 |
+
app = Client("Mikobot", api_id=API_ID, api_hash=API_HASH, bot_token=TOKEN)
|
233 |
+
tbot = TelegramClient(MemorySession(), API_ID, API_HASH)
|
234 |
+
# <=======================================================================================================>
|
235 |
+
|
236 |
+
# <=============================================== GETTING BOT INFO ========================================================>
|
237 |
+
# Get bot information
|
238 |
+
print("[INFO]: Getting Bot Info...")
|
239 |
+
BOT_ID = dispatcher.bot.id
|
240 |
+
BOT_NAME = dispatcher.bot.first_name
|
241 |
+
BOT_USERNAME = dispatcher.bot.username
|
242 |
+
# <=======================================================================================================>
|
243 |
+
|
244 |
+
# <================================================== CONVERT LISTS =====================================================>
|
245 |
+
# Convert sets to lists for further use
|
246 |
+
SUPPORT_STAFF = (
|
247 |
+
[int(OWNER_ID)] + list(DRAGONS) + list(WOLVES) + list(DEMONS) + list(DEV_USERS)
|
248 |
+
)
|
249 |
+
DRAGONS = list(DRAGONS) + list(DEV_USERS)
|
250 |
+
DEV_USERS = list(DEV_USERS)
|
251 |
+
WOLVES = list(WOLVES)
|
252 |
+
DEMONS = list(DEMONS)
|
253 |
+
TIGERS = list(TIGERS)
|
254 |
+
# <==================================================== END ===================================================>
|
Mikobot/__main__.py
ADDED
@@ -0,0 +1,793 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# https://github.com/Infamous-Hydra/YaeMiko
|
2 |
+
# https://github.com/Team-ProjectCodeX
|
3 |
+
|
4 |
+
# <============================================== IMPORTS =========================================================>
|
5 |
+
import asyncio
|
6 |
+
import contextlib
|
7 |
+
import importlib
|
8 |
+
import json
|
9 |
+
import re
|
10 |
+
import time
|
11 |
+
import traceback
|
12 |
+
from platform import python_version
|
13 |
+
from random import choice
|
14 |
+
|
15 |
+
import psutil
|
16 |
+
import pyrogram
|
17 |
+
import telegram
|
18 |
+
import telethon
|
19 |
+
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
20 |
+
from telegram.constants import ParseMode
|
21 |
+
from telegram.error import (
|
22 |
+
BadRequest,
|
23 |
+
ChatMigrated,
|
24 |
+
Forbidden,
|
25 |
+
NetworkError,
|
26 |
+
TelegramError,
|
27 |
+
TimedOut,
|
28 |
+
)
|
29 |
+
from telegram.ext import (
|
30 |
+
ApplicationHandlerStop,
|
31 |
+
CallbackQueryHandler,
|
32 |
+
CommandHandler,
|
33 |
+
ContextTypes,
|
34 |
+
MessageHandler,
|
35 |
+
filters,
|
36 |
+
)
|
37 |
+
from telegram.helpers import escape_markdown
|
38 |
+
|
39 |
+
import Database.sql.users_sql as sql
|
40 |
+
from Infamous.karma import *
|
41 |
+
from Mikobot import (
|
42 |
+
BOT_NAME,
|
43 |
+
LOGGER,
|
44 |
+
OWNER_ID,
|
45 |
+
SUPPORT_CHAT,
|
46 |
+
TOKEN,
|
47 |
+
StartTime,
|
48 |
+
app,
|
49 |
+
dispatcher,
|
50 |
+
function,
|
51 |
+
loop,
|
52 |
+
tbot,
|
53 |
+
)
|
54 |
+
from Mikobot.plugins import ALL_MODULES
|
55 |
+
from Mikobot.plugins.helper_funcs.chat_status import is_user_admin
|
56 |
+
from Mikobot.plugins.helper_funcs.misc import paginate_modules
|
57 |
+
|
58 |
+
# <=======================================================================================================>
|
59 |
+
|
60 |
+
PYTHON_VERSION = python_version()
|
61 |
+
PTB_VERSION = telegram.__version__
|
62 |
+
PYROGRAM_VERSION = pyrogram.__version__
|
63 |
+
TELETHON_VERSION = telethon.__version__
|
64 |
+
|
65 |
+
|
66 |
+
# <============================================== FUNCTIONS =========================================================>
|
67 |
+
async def ai_handler_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
68 |
+
query = update.callback_query
|
69 |
+
if query.data == "ai_handler":
|
70 |
+
await query.answer()
|
71 |
+
await query.message.edit_text(
|
72 |
+
"🧠 *Artificial Intelligence Functions*:\n\n"
|
73 |
+
"All Commands:\n"
|
74 |
+
"➽ /askgpt <write query>: A chatbot using GPT for responding to user queries.\n\n"
|
75 |
+
"➽ /palm <write prompt>: Performs a Palm search using a chatbot.\n\n"
|
76 |
+
"➽ /upscale <reply to image>: Upscales your image quality.",
|
77 |
+
parse_mode=ParseMode.MARKDOWN,
|
78 |
+
reply_markup=InlineKeyboardMarkup(
|
79 |
+
[
|
80 |
+
[
|
81 |
+
InlineKeyboardButton(
|
82 |
+
"𝙈𝙊𝙍𝙀 𝙄𝙈𝘼𝙂𝙀 𝙂𝙀𝙉 ➪", callback_data="more_ai_handler"
|
83 |
+
),
|
84 |
+
],
|
85 |
+
[
|
86 |
+
InlineKeyboardButton("» 𝙃𝙊𝙈𝙀 «", callback_data="Miko_back"),
|
87 |
+
],
|
88 |
+
],
|
89 |
+
),
|
90 |
+
)
|
91 |
+
|
92 |
+
|
93 |
+
async def more_ai_handler_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
94 |
+
query = update.callback_query
|
95 |
+
if query.data == "more_ai_handler":
|
96 |
+
await query.answer()
|
97 |
+
await query.message.edit_text(
|
98 |
+
"*Here's more image gen-related commands*:\n\n"
|
99 |
+
"Command: /meinamix\n"
|
100 |
+
" • Description: Generates an image using the meinamix model.\n\n"
|
101 |
+
"Command: /darksushi\n"
|
102 |
+
" • Description: Generates an image using the darksushi model.\n\n"
|
103 |
+
"Command: /meinahentai\n"
|
104 |
+
" • Description: Generates an image using the meinahentai model.\n\n"
|
105 |
+
"Command: /darksushimix\n"
|
106 |
+
" • Description: Generates an image using the darksushimix model.\n\n"
|
107 |
+
"Command: /anylora\n"
|
108 |
+
" • Description: Generates an image using the anylora model.\n\n"
|
109 |
+
"Command: /cetsumix\n"
|
110 |
+
" • Description: Generates an image using the cetus-mix model.\n\n"
|
111 |
+
"Command: /darkv2\n"
|
112 |
+
" • Description: Generates an image using the darkv2 model.\n\n"
|
113 |
+
"Command: /creative\n"
|
114 |
+
" • Description: Generates an image using the creative model.",
|
115 |
+
parse_mode=ParseMode.MARKDOWN,
|
116 |
+
reply_markup=InlineKeyboardMarkup(
|
117 |
+
[
|
118 |
+
[
|
119 |
+
InlineKeyboardButton("⇦ 𝘽𝘼𝘾𝙆", callback_data="ai_handler"),
|
120 |
+
],
|
121 |
+
],
|
122 |
+
),
|
123 |
+
)
|
124 |
+
|
125 |
+
|
126 |
+
def get_readable_time(seconds: int) -> str:
|
127 |
+
count = 0
|
128 |
+
ping_time = ""
|
129 |
+
time_list = []
|
130 |
+
time_suffix_list = ["s", "m", "h", "days"]
|
131 |
+
|
132 |
+
while count < 4:
|
133 |
+
count += 1
|
134 |
+
remainder, result = divmod(seconds, 60) if count < 3 else divmod(seconds, 24)
|
135 |
+
if seconds == 0 and remainder == 0:
|
136 |
+
break
|
137 |
+
time_list.append(int(result))
|
138 |
+
seconds = int(remainder)
|
139 |
+
|
140 |
+
for x in range(len(time_list)):
|
141 |
+
time_list[x] = str(time_list[x]) + time_suffix_list[x]
|
142 |
+
if len(time_list) == 4:
|
143 |
+
ping_time += time_list.pop() + ", "
|
144 |
+
|
145 |
+
time_list.reverse()
|
146 |
+
ping_time += ":".join(time_list)
|
147 |
+
|
148 |
+
return ping_time
|
149 |
+
|
150 |
+
|
151 |
+
IMPORTED = {}
|
152 |
+
MIGRATEABLE = []
|
153 |
+
HELPABLE = {}
|
154 |
+
STATS = []
|
155 |
+
USER_INFO = []
|
156 |
+
DATA_IMPORT = []
|
157 |
+
DATA_EXPORT = []
|
158 |
+
CHAT_SETTINGS = {}
|
159 |
+
USER_SETTINGS = {}
|
160 |
+
|
161 |
+
for module_name in ALL_MODULES:
|
162 |
+
imported_module = importlib.import_module("Mikobot.plugins." + module_name)
|
163 |
+
if not hasattr(imported_module, "__mod_name__"):
|
164 |
+
imported_module.__mod_name__ = imported_module.__name__
|
165 |
+
|
166 |
+
if imported_module.__mod_name__.lower() not in IMPORTED:
|
167 |
+
IMPORTED[imported_module.__mod_name__.lower()] = imported_module
|
168 |
+
else:
|
169 |
+
raise Exception("Can't have two modules with the same name! Please change one")
|
170 |
+
|
171 |
+
if hasattr(imported_module, "__help__") and imported_module.__help__:
|
172 |
+
HELPABLE[imported_module.__mod_name__.lower()] = imported_module
|
173 |
+
|
174 |
+
# Chats to migrate on chat_migrated events
|
175 |
+
if hasattr(imported_module, "__migrate__"):
|
176 |
+
MIGRATEABLE.append(imported_module)
|
177 |
+
|
178 |
+
if hasattr(imported_module, "__stats__"):
|
179 |
+
STATS.append(imported_module)
|
180 |
+
|
181 |
+
if hasattr(imported_module, "__user_info__"):
|
182 |
+
USER_INFO.append(imported_module)
|
183 |
+
|
184 |
+
if hasattr(imported_module, "__import_data__"):
|
185 |
+
DATA_IMPORT.append(imported_module)
|
186 |
+
|
187 |
+
if hasattr(imported_module, "__export_data__"):
|
188 |
+
DATA_EXPORT.append(imported_module)
|
189 |
+
|
190 |
+
if hasattr(imported_module, "__chat_settings__"):
|
191 |
+
CHAT_SETTINGS[imported_module.__mod_name__.lower()] = imported_module
|
192 |
+
|
193 |
+
if hasattr(imported_module, "__user_settings__"):
|
194 |
+
USER_SETTINGS[imported_module.__mod_name__.lower()] = imported_module
|
195 |
+
|
196 |
+
|
197 |
+
# do not async
|
198 |
+
async def send_help(chat_id, text, keyboard=None):
|
199 |
+
if not keyboard:
|
200 |
+
keyboard = InlineKeyboardMarkup(paginate_modules(0, HELPABLE, "help"))
|
201 |
+
await dispatcher.bot.send_message(
|
202 |
+
chat_id=chat_id,
|
203 |
+
text=text,
|
204 |
+
parse_mode=ParseMode.MARKDOWN,
|
205 |
+
disable_web_page_preview=True,
|
206 |
+
reply_markup=keyboard,
|
207 |
+
)
|
208 |
+
|
209 |
+
|
210 |
+
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
211 |
+
args = context.args
|
212 |
+
message = update.effective_message
|
213 |
+
uptime = get_readable_time((time.time() - StartTime))
|
214 |
+
if update.effective_chat.type == "private":
|
215 |
+
if len(args) >= 1:
|
216 |
+
if args[0].lower() == "help":
|
217 |
+
await send_help(update.effective_chat.id, HELP_STRINGS)
|
218 |
+
elif args[0].lower().startswith("ghelp_"):
|
219 |
+
mod = args[0].lower().split("_", 1)[1]
|
220 |
+
if not HELPABLE.get(mod, False):
|
221 |
+
return
|
222 |
+
await send_help(
|
223 |
+
update.effective_chat.id,
|
224 |
+
HELPABLE[mod].__help__,
|
225 |
+
InlineKeyboardMarkup(
|
226 |
+
[[InlineKeyboardButton(text="◁", callback_data="help_back")]]
|
227 |
+
),
|
228 |
+
)
|
229 |
+
|
230 |
+
elif args[0].lower() == "markdownhelp":
|
231 |
+
IMPORTED["exᴛʀᴀs"].markdown_help_sender(update)
|
232 |
+
elif args[0].lower().startswith("stngs_"):
|
233 |
+
match = re.match("stngs_(.*)", args[0].lower())
|
234 |
+
chat = dispatcher.bot.getChat(match.group(1))
|
235 |
+
|
236 |
+
if is_user_admin(chat, update.effective_user.id):
|
237 |
+
send_settings(match.group(1), update.effective_user.id, False)
|
238 |
+
else:
|
239 |
+
send_settings(match.group(1), update.effective_user.id, True)
|
240 |
+
|
241 |
+
elif args[0][1:].isdigit() and "rules" in IMPORTED:
|
242 |
+
await IMPORTED["rules"].send_rules(update, args[0], from_pm=True)
|
243 |
+
|
244 |
+
else:
|
245 |
+
first_name = update.effective_user.first_name
|
246 |
+
lol = await message.reply_photo(
|
247 |
+
photo=str(choice(START_IMG)),
|
248 |
+
caption=FIRST_PART_TEXT.format(escape_markdown(first_name)),
|
249 |
+
parse_mode=ParseMode.MARKDOWN,
|
250 |
+
)
|
251 |
+
await asyncio.sleep(0.2)
|
252 |
+
guu = await update.effective_message.reply_text("🐾")
|
253 |
+
await asyncio.sleep(1.8)
|
254 |
+
await guu.delete() # Await this line
|
255 |
+
await update.effective_message.reply_text(
|
256 |
+
PM_START_TEXT,
|
257 |
+
reply_markup=InlineKeyboardMarkup(START_BTN),
|
258 |
+
parse_mode=ParseMode.MARKDOWN,
|
259 |
+
disable_web_page_preview=False,
|
260 |
+
)
|
261 |
+
else:
|
262 |
+
await message.reply_photo(
|
263 |
+
photo=str(choice(START_IMG)),
|
264 |
+
reply_markup=InlineKeyboardMarkup(GROUP_START_BTN),
|
265 |
+
caption="<b>I am Alive!</b>\n\n<b>Since:</b> <code>{}</code>".format(
|
266 |
+
uptime
|
267 |
+
),
|
268 |
+
parse_mode=ParseMode.HTML,
|
269 |
+
)
|
270 |
+
|
271 |
+
|
272 |
+
async def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
273 |
+
"""Log the error and send a telegram message to notify the developer."""
|
274 |
+
# Log the error before we do anything else, so we can see it even if something breaks.
|
275 |
+
LOGGER.error(msg="Exception while handling an update:", exc_info=context.error)
|
276 |
+
|
277 |
+
# traceback.format_exception returns the usual python message about an exception, but as a
|
278 |
+
# list of strings rather than a single string, so we have to join them together.
|
279 |
+
tb_list = traceback.format_exception(
|
280 |
+
None, context.error, context.error.__traceback__
|
281 |
+
)
|
282 |
+
tb = "".join(tb_list)
|
283 |
+
|
284 |
+
# Build the message with some markup and additional information about what happened.
|
285 |
+
message = (
|
286 |
+
"An exception was raised while handling an update\n"
|
287 |
+
"<pre>update = {}</pre>\n\n"
|
288 |
+
"<pre>{}</pre>"
|
289 |
+
).format(
|
290 |
+
html.escape(json.dumps(update.to_dict(), indent=2, ensure_ascii=False)),
|
291 |
+
html.escape(tb),
|
292 |
+
)
|
293 |
+
|
294 |
+
if len(message) >= 4096:
|
295 |
+
message = message[:4096]
|
296 |
+
# Finally, send the message
|
297 |
+
await context.bot.send_message(
|
298 |
+
chat_id=OWNER_ID, text=message, parse_mode=ParseMode.HTML
|
299 |
+
)
|
300 |
+
|
301 |
+
|
302 |
+
# for test purposes
|
303 |
+
async def error_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
304 |
+
error = context.error
|
305 |
+
try:
|
306 |
+
raise error
|
307 |
+
except Forbidden:
|
308 |
+
print("no nono1")
|
309 |
+
print(error)
|
310 |
+
# remove update.message.chat_id from conversation list
|
311 |
+
except BadRequest:
|
312 |
+
print("no nono2")
|
313 |
+
print("BadRequest caught")
|
314 |
+
print(error)
|
315 |
+
|
316 |
+
# handle malformed requests - read more below!
|
317 |
+
except TimedOut:
|
318 |
+
print("no nono3")
|
319 |
+
# handle slow connection problems
|
320 |
+
except NetworkError:
|
321 |
+
print("no nono4")
|
322 |
+
# handle other connection problems
|
323 |
+
except ChatMigrated as err:
|
324 |
+
print("no nono5")
|
325 |
+
print(err)
|
326 |
+
# the chat_id of a group has changed, use e.new_chat_id instead
|
327 |
+
except TelegramError:
|
328 |
+
print(error)
|
329 |
+
# handle all other telegram related errors
|
330 |
+
|
331 |
+
|
332 |
+
async def help_button(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
333 |
+
query = update.callback_query
|
334 |
+
mod_match = re.match(r"help_module\((.+?)\)", query.data)
|
335 |
+
prev_match = re.match(r"help_prev\((.+?)\)", query.data)
|
336 |
+
next_match = re.match(r"help_next\((.+?)\)", query.data)
|
337 |
+
back_match = re.match(r"help_back", query.data)
|
338 |
+
|
339 |
+
print(query.message.chat.id)
|
340 |
+
|
341 |
+
try:
|
342 |
+
if mod_match:
|
343 |
+
module = mod_match.group(1)
|
344 |
+
text = (
|
345 |
+
"➲ *HELP SECTION OF* *{}* :\n".format(HELPABLE[module].__mod_name__)
|
346 |
+
+ HELPABLE[module].__help__
|
347 |
+
)
|
348 |
+
await query.message.edit_text(
|
349 |
+
text=text,
|
350 |
+
parse_mode=ParseMode.MARKDOWN,
|
351 |
+
disable_web_page_preview=True,
|
352 |
+
reply_markup=InlineKeyboardMarkup(
|
353 |
+
[[InlineKeyboardButton(text="◁", callback_data="help_back")]]
|
354 |
+
),
|
355 |
+
)
|
356 |
+
|
357 |
+
elif prev_match:
|
358 |
+
curr_page = int(prev_match.group(1))
|
359 |
+
await query.message.edit_text(
|
360 |
+
text=HELP_STRINGS,
|
361 |
+
parse_mode=ParseMode.MARKDOWN,
|
362 |
+
reply_markup=InlineKeyboardMarkup(
|
363 |
+
paginate_modules(curr_page - 1, HELPABLE, "help")
|
364 |
+
),
|
365 |
+
)
|
366 |
+
|
367 |
+
elif next_match:
|
368 |
+
next_page = int(next_match.group(1))
|
369 |
+
await query.message.edit_text(
|
370 |
+
text=HELP_STRINGS,
|
371 |
+
parse_mode=ParseMode.MARKDOWN,
|
372 |
+
reply_markup=InlineKeyboardMarkup(
|
373 |
+
paginate_modules(next_page + 1, HELPABLE, "help")
|
374 |
+
),
|
375 |
+
)
|
376 |
+
|
377 |
+
elif back_match:
|
378 |
+
await query.message.edit_text(
|
379 |
+
text=HELP_STRINGS,
|
380 |
+
parse_mode=ParseMode.MARKDOWN,
|
381 |
+
reply_markup=InlineKeyboardMarkup(
|
382 |
+
paginate_modules(0, HELPABLE, "help")
|
383 |
+
),
|
384 |
+
)
|
385 |
+
|
386 |
+
await context.bot.answer_callback_query(query.id)
|
387 |
+
|
388 |
+
except BadRequest:
|
389 |
+
pass
|
390 |
+
|
391 |
+
|
392 |
+
async def stats_back(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
393 |
+
query = update.callback_query
|
394 |
+
if query.data == "insider_":
|
395 |
+
uptime = get_readable_time((time.time() - StartTime))
|
396 |
+
cpu = psutil.cpu_percent(interval=0.5)
|
397 |
+
mem = psutil.virtual_memory().percent
|
398 |
+
disk = psutil.disk_usage("/").percent
|
399 |
+
text = f"""
|
400 |
+
𝙎𝙮𝙨𝙩𝙚𝙢 𝙨𝙩𝙖𝙩𝙨@𝙔𝙖𝙚𝙈𝙞𝙠𝙤_𝙍𝙤𝙭𝙗𝙤𝙩
|
401 |
+
➖➖➖➖➖➖
|
402 |
+
UPTIME ➼ {uptime}
|
403 |
+
CPU ➼ {cpu}%
|
404 |
+
RAM ➼ {mem}%
|
405 |
+
DISK ➼ {disk}%
|
406 |
+
|
407 |
+
PYTHON ➼ {PYTHON_VERSION}
|
408 |
+
|
409 |
+
PTB ➼ {PTB_VERSION}
|
410 |
+
TELETHON ➼ {TELETHON_VERSION}
|
411 |
+
PYROGRAM ➼ {PYROGRAM_VERSION}
|
412 |
+
"""
|
413 |
+
await query.answer(text=text, show_alert=True)
|
414 |
+
|
415 |
+
|
416 |
+
async def gitsource_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
417 |
+
query = update.callback_query
|
418 |
+
await query.answer()
|
419 |
+
|
420 |
+
if query.data == "git_source":
|
421 |
+
source_link = "https://github.com/Infamous-Hydra/YaeMiko"
|
422 |
+
message_text = (
|
423 |
+
f"*Here is the link for the public source repo*:\n\n{source_link}"
|
424 |
+
)
|
425 |
+
|
426 |
+
# Adding the inline button
|
427 |
+
keyboard = [[InlineKeyboardButton(text="◁", callback_data="Miko_back")]]
|
428 |
+
reply_markup = InlineKeyboardMarkup(keyboard)
|
429 |
+
|
430 |
+
await query.edit_message_text(
|
431 |
+
message_text,
|
432 |
+
parse_mode=ParseMode.MARKDOWN,
|
433 |
+
disable_web_page_preview=False,
|
434 |
+
reply_markup=reply_markup,
|
435 |
+
)
|
436 |
+
|
437 |
+
|
438 |
+
async def Miko_about_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
439 |
+
query = update.callback_query
|
440 |
+
if query.data == "Miko_":
|
441 |
+
uptime = get_readable_time((time.time() - StartTime))
|
442 |
+
message_text = (
|
443 |
+
f"➲ <b>Ai integration.</b>"
|
444 |
+
f"\n➲ <b>Advance management capability.</b>"
|
445 |
+
f"\n➲ <b>Anime bot functionality.</b>"
|
446 |
+
f"\n\n<b>USERS</b> » {sql.num_users()}"
|
447 |
+
f"\n<b>CHATS</b> » {sql.num_chats()}"
|
448 |
+
f"\n\n<b>Click on the buttons below for getting help and info about</b> {BOT_NAME}."
|
449 |
+
)
|
450 |
+
await query.message.edit_text(
|
451 |
+
text=message_text,
|
452 |
+
disable_web_page_preview=True,
|
453 |
+
parse_mode=ParseMode.HTML,
|
454 |
+
reply_markup=InlineKeyboardMarkup(
|
455 |
+
[
|
456 |
+
[
|
457 |
+
InlineKeyboardButton(
|
458 |
+
text="ABOUT", callback_data="Miko_support"
|
459 |
+
),
|
460 |
+
InlineKeyboardButton(text="COMMAND", callback_data="help_back"),
|
461 |
+
],
|
462 |
+
[
|
463 |
+
InlineKeyboardButton(text="INSIDER", callback_data="insider_"),
|
464 |
+
],
|
465 |
+
[
|
466 |
+
InlineKeyboardButton(text="◁", callback_data="Miko_back"),
|
467 |
+
],
|
468 |
+
]
|
469 |
+
),
|
470 |
+
)
|
471 |
+
elif query.data == "Miko_support":
|
472 |
+
message_text = (
|
473 |
+
"*Our bot leverages SQL, MongoDB, Telegram, MTProto for secure and efficient operations. It resides on a high-speed server, integrates numerous APIs, ensuring quick and versatile responses to user queries.*"
|
474 |
+
f"\n\n*If you find any bug in {BOT_NAME} Please report it at the support chat.*"
|
475 |
+
)
|
476 |
+
await query.message.edit_text(
|
477 |
+
text=message_text,
|
478 |
+
parse_mode=ParseMode.MARKDOWN,
|
479 |
+
disable_web_page_preview=True,
|
480 |
+
reply_markup=InlineKeyboardMarkup(
|
481 |
+
[
|
482 |
+
[
|
483 |
+
InlineKeyboardButton(
|
484 |
+
text="SUPPORT", url=f"https://t.me/{SUPPORT_CHAT}"
|
485 |
+
),
|
486 |
+
InlineKeyboardButton(
|
487 |
+
text="DEVELOPER", url=f"tg://user?id={OWNER_ID}"
|
488 |
+
),
|
489 |
+
],
|
490 |
+
[
|
491 |
+
InlineKeyboardButton(text="◁", callback_data="Miko_"),
|
492 |
+
],
|
493 |
+
]
|
494 |
+
),
|
495 |
+
)
|
496 |
+
elif query.data == "Miko_back":
|
497 |
+
first_name = update.effective_user.first_name
|
498 |
+
await query.message.edit_text(
|
499 |
+
PM_START_TEXT.format(escape_markdown(first_name), BOT_NAME),
|
500 |
+
reply_markup=InlineKeyboardMarkup(START_BTN),
|
501 |
+
parse_mode=ParseMode.MARKDOWN,
|
502 |
+
disable_web_page_preview=True,
|
503 |
+
)
|
504 |
+
|
505 |
+
|
506 |
+
async def get_help(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
507 |
+
chat = update.effective_chat # type: Optional[Chat]
|
508 |
+
args = update.effective_message.text.split(None, 1)
|
509 |
+
|
510 |
+
# ONLY send help in PM
|
511 |
+
if chat.type != chat.PRIVATE:
|
512 |
+
if len(args) >= 2 and any(args[1].lower() == x for x in HELPABLE):
|
513 |
+
module = args[1].lower()
|
514 |
+
await update.effective_message.reply_text(
|
515 |
+
f"Contact me in PM to get help of {module.capitalize()}",
|
516 |
+
reply_markup=InlineKeyboardMarkup(
|
517 |
+
[
|
518 |
+
[
|
519 |
+
InlineKeyboardButton(
|
520 |
+
text="HELP",
|
521 |
+
url="https://t.me/{}?start=ghelp_{}".format(
|
522 |
+
context.bot.username, module
|
523 |
+
),
|
524 |
+
)
|
525 |
+
]
|
526 |
+
]
|
527 |
+
),
|
528 |
+
)
|
529 |
+
return
|
530 |
+
await update.effective_message.reply_text(
|
531 |
+
"» Choose an option for getting help.",
|
532 |
+
reply_markup=InlineKeyboardMarkup(
|
533 |
+
[
|
534 |
+
[
|
535 |
+
InlineKeyboardButton(
|
536 |
+
text="OPEN IN PM",
|
537 |
+
url="https://t.me/{}?start=help".format(
|
538 |
+
context.bot.username
|
539 |
+
),
|
540 |
+
)
|
541 |
+
],
|
542 |
+
[
|
543 |
+
InlineKeyboardButton(
|
544 |
+
text="OPEN HERE",
|
545 |
+
callback_data="help_back",
|
546 |
+
)
|
547 |
+
],
|
548 |
+
]
|
549 |
+
),
|
550 |
+
)
|
551 |
+
return
|
552 |
+
|
553 |
+
elif len(args) >= 2 and any(args[1].lower() == x for x in HELPABLE):
|
554 |
+
module = args[1].lower()
|
555 |
+
text = (
|
556 |
+
"Here is the available help for the *{}* module:\n".format(
|
557 |
+
HELPABLE[module].__mod_name__
|
558 |
+
)
|
559 |
+
+ HELPABLE[module].__help__
|
560 |
+
)
|
561 |
+
await send_help(
|
562 |
+
chat.id,
|
563 |
+
text,
|
564 |
+
InlineKeyboardMarkup(
|
565 |
+
[[InlineKeyboardButton(text="◁", callback_data="help_back")]]
|
566 |
+
),
|
567 |
+
)
|
568 |
+
|
569 |
+
else:
|
570 |
+
await send_help(chat.id, HELP_STRINGS)
|
571 |
+
|
572 |
+
|
573 |
+
async def send_settings(chat_id, user_id, user=False):
|
574 |
+
if user:
|
575 |
+
if USER_SETTINGS:
|
576 |
+
settings = "\n\n".join(
|
577 |
+
"*{}*:\n{}".format(mod.__mod_name__, mod.__user_settings__(user_id))
|
578 |
+
for mod in USER_SETTINGS.values()
|
579 |
+
)
|
580 |
+
await dispatcher.bot.send_message(
|
581 |
+
user_id,
|
582 |
+
"These are your current settings:" + "\n\n" + settings,
|
583 |
+
parse_mode=ParseMode.MARKDOWN,
|
584 |
+
)
|
585 |
+
|
586 |
+
else:
|
587 |
+
await dispatcher.bot.send_message(
|
588 |
+
user_id,
|
589 |
+
"Seems like there aren't any user specific settings available :'(",
|
590 |
+
parse_mode=ParseMode.MARKDOWN,
|
591 |
+
)
|
592 |
+
else:
|
593 |
+
if CHAT_SETTINGS:
|
594 |
+
chat_name = dispatcher.bot.getChat(chat_id).title
|
595 |
+
await dispatcher.bot.send_message(
|
596 |
+
user_id,
|
597 |
+
text="Which module would you like to check {}'s settings for?".format(
|
598 |
+
chat_name
|
599 |
+
),
|
600 |
+
reply_markup=InlineKeyboardMarkup(
|
601 |
+
paginate_modules(0, CHAT_SETTINGS, "stngs", chat=chat_id)
|
602 |
+
),
|
603 |
+
)
|
604 |
+
else:
|
605 |
+
await dispatcher.bot.send_message(
|
606 |
+
user_id,
|
607 |
+
"Seems like there aren't any chat settings available :'(\nSend this "
|
608 |
+
"in a group chat you're admin in to find its current settings!",
|
609 |
+
parse_mode=ParseMode.MARKDOWN,
|
610 |
+
)
|
611 |
+
|
612 |
+
|
613 |
+
async def settings_button(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
614 |
+
query = update.callback_query
|
615 |
+
user = update.effective_user
|
616 |
+
bot = context.bot
|
617 |
+
mod_match = re.match(r"stngs_module\((.+?),(.+?)\)", query.data)
|
618 |
+
prev_match = re.match(r"stngs_prev\((.+?),(.+?)\)", query.data)
|
619 |
+
next_match = re.match(r"stngs_next\((.+?),(.+?)\)", query.data)
|
620 |
+
back_match = re.match(r"stngs_back\((.+?)\)", query.data)
|
621 |
+
try:
|
622 |
+
if mod_match:
|
623 |
+
chat_id = mod_match.group(1)
|
624 |
+
module = mod_match.group(2)
|
625 |
+
chat = bot.get_chat(chat_id)
|
626 |
+
text = "*{}* has the following settings for the *{}* module:\n\n".format(
|
627 |
+
escape_markdown(chat.title), CHAT_SETTINGS[module].__mod_name__
|
628 |
+
) + CHAT_SETTINGS[module].__chat_settings__(chat_id, user.id)
|
629 |
+
await query.message.reply_text(
|
630 |
+
text=text,
|
631 |
+
parse_mode=ParseMode.MARKDOWN,
|
632 |
+
reply_markup=InlineKeyboardMarkup(
|
633 |
+
[
|
634 |
+
[
|
635 |
+
InlineKeyboardButton(
|
636 |
+
text="◁",
|
637 |
+
callback_data="stngs_back({})".format(chat_id),
|
638 |
+
)
|
639 |
+
]
|
640 |
+
]
|
641 |
+
),
|
642 |
+
)
|
643 |
+
|
644 |
+
elif prev_match:
|
645 |
+
chat_id = prev_match.group(1)
|
646 |
+
curr_page = int(prev_match.group(2))
|
647 |
+
chat = bot.get_chat(chat_id)
|
648 |
+
await query.message.reply_text(
|
649 |
+
"Hi there! There are quite a few settings for {} - go ahead and pick what "
|
650 |
+
"you're interested in.".format(chat.title),
|
651 |
+
reply_markup=InlineKeyboardMarkup(
|
652 |
+
paginate_modules(
|
653 |
+
curr_page - 1, CHAT_SETTINGS, "stngs", chat=chat_id
|
654 |
+
)
|
655 |
+
),
|
656 |
+
)
|
657 |
+
|
658 |
+
elif next_match:
|
659 |
+
chat_id = next_match.group(1)
|
660 |
+
next_page = int(next_match.group(2))
|
661 |
+
chat = bot.get_chat(chat_id)
|
662 |
+
await query.message.reply_text(
|
663 |
+
"Hi there! There are quite a few settings for {} - go ahead and pick what "
|
664 |
+
"you're interested in.".format(chat.title),
|
665 |
+
reply_markup=InlineKeyboardMarkup(
|
666 |
+
paginate_modules(
|
667 |
+
next_page + 1, CHAT_SETTINGS, "stngs", chat=chat_id
|
668 |
+
)
|
669 |
+
),
|
670 |
+
)
|
671 |
+
|
672 |
+
elif back_match:
|
673 |
+
chat_id = back_match.group(1)
|
674 |
+
chat = bot.get_chat(chat_id)
|
675 |
+
await query.message.reply_text(
|
676 |
+
text="Hi there! There are quite a few settings for {} - go ahead and pick what "
|
677 |
+
"you're interested in.".format(escape_markdown(chat.title)),
|
678 |
+
parse_mode=ParseMode.MARKDOWN,
|
679 |
+
reply_markup=InlineKeyboardMarkup(
|
680 |
+
paginate_modules(0, CHAT_SETTINGS, "stngs", chat=chat_id)
|
681 |
+
),
|
682 |
+
)
|
683 |
+
|
684 |
+
# ensure no spinny white circle
|
685 |
+
bot.answer_callback_query(query.id)
|
686 |
+
await query.message.delete()
|
687 |
+
except BadRequest as excp:
|
688 |
+
if excp.message not in [
|
689 |
+
"Message is not modified",
|
690 |
+
"Query_id_invalid",
|
691 |
+
"Message can't be deleted",
|
692 |
+
]:
|
693 |
+
LOGGER.exception("Exception in settings buttons. %s", str(query.data))
|
694 |
+
|
695 |
+
|
696 |
+
async def get_settings(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
697 |
+
chat = update.effective_chat # type: Optional[Chat]
|
698 |
+
user = update.effective_user # type: Optional[User]
|
699 |
+
msg = update.effective_message # type: Optional[Message]
|
700 |
+
|
701 |
+
# ONLY send settings in PM
|
702 |
+
if chat.type != chat.PRIVATE:
|
703 |
+
if is_user_admin(chat, user.id):
|
704 |
+
text = "Click here to get this chat's settings, as well as yours."
|
705 |
+
await msg.reply_text(
|
706 |
+
text,
|
707 |
+
reply_markup=InlineKeyboardMarkup(
|
708 |
+
[
|
709 |
+
[
|
710 |
+
InlineKeyboardButton(
|
711 |
+
text="SETTINGS",
|
712 |
+
url="t.me/{}?start=stngs_{}".format(
|
713 |
+
context.bot.username, chat.id
|
714 |
+
),
|
715 |
+
)
|
716 |
+
]
|
717 |
+
]
|
718 |
+
),
|
719 |
+
)
|
720 |
+
else:
|
721 |
+
text = "Click here to check your settings."
|
722 |
+
|
723 |
+
else:
|
724 |
+
await send_settings(chat.id, user.id, True)
|
725 |
+
|
726 |
+
|
727 |
+
async def migrate_chats(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
728 |
+
msg = update.effective_message # type: Optional[Message]
|
729 |
+
if msg.migrate_to_chat_id:
|
730 |
+
old_chat = update.effective_chat.id
|
731 |
+
new_chat = msg.migrate_to_chat_id
|
732 |
+
elif msg.migrate_from_chat_id:
|
733 |
+
old_chat = msg.migrate_from_chat_id
|
734 |
+
new_chat = update.effective_chat.id
|
735 |
+
else:
|
736 |
+
return
|
737 |
+
|
738 |
+
LOGGER.info("Migrating from %s, ᴛᴏ %s", str(old_chat), str(new_chat))
|
739 |
+
for mod in MIGRATEABLE:
|
740 |
+
with contextlib.suppress(KeyError, AttributeError):
|
741 |
+
mod.__migrate__(old_chat, new_chat)
|
742 |
+
|
743 |
+
LOGGER.info("Successfully Migrated!")
|
744 |
+
raise ApplicationHandlerStop
|
745 |
+
|
746 |
+
|
747 |
+
# <=======================================================================================================>
|
748 |
+
|
749 |
+
|
750 |
+
# <=================================================== MAIN ====================================================>
|
751 |
+
def main():
|
752 |
+
function(CommandHandler("start", start))
|
753 |
+
|
754 |
+
function(CommandHandler("help", get_help))
|
755 |
+
function(CallbackQueryHandler(help_button, pattern=r"help_.*"))
|
756 |
+
|
757 |
+
function(CommandHandler("settings", get_settings))
|
758 |
+
function(CallbackQueryHandler(settings_button, pattern=r"stngs_"))
|
759 |
+
|
760 |
+
function(CallbackQueryHandler(Miko_about_callback, pattern=r"Miko_"))
|
761 |
+
function(CallbackQueryHandler(gitsource_callback, pattern=r"git_source"))
|
762 |
+
function(CallbackQueryHandler(stats_back, pattern=r"insider_"))
|
763 |
+
function(CallbackQueryHandler(ai_handler_callback, pattern=r"ai_handler"))
|
764 |
+
function(CallbackQueryHandler(more_ai_handler_callback, pattern=r"more_ai_handler"))
|
765 |
+
function(MessageHandler(filters.StatusUpdate.MIGRATE, migrate_chats))
|
766 |
+
|
767 |
+
dispatcher.add_error_handler(error_callback)
|
768 |
+
|
769 |
+
LOGGER.info("Mikobot is starting >> Using long polling.")
|
770 |
+
dispatcher.run_polling(timeout=15, drop_pending_updates=True)
|
771 |
+
|
772 |
+
|
773 |
+
if __name__ == "__main__":
|
774 |
+
try:
|
775 |
+
LOGGER.info("Successfully loaded modules: " + str(ALL_MODULES))
|
776 |
+
tbot.start(bot_token=TOKEN)
|
777 |
+
app.start()
|
778 |
+
main()
|
779 |
+
except KeyboardInterrupt:
|
780 |
+
pass
|
781 |
+
except Exception:
|
782 |
+
err = traceback.format_exc()
|
783 |
+
LOGGER.info(err)
|
784 |
+
finally:
|
785 |
+
try:
|
786 |
+
if loop.is_running():
|
787 |
+
loop.stop()
|
788 |
+
finally:
|
789 |
+
loop.close()
|
790 |
+
LOGGER.info(
|
791 |
+
"------------------------ Stopped Services ------------------------"
|
792 |
+
)
|
793 |
+
# <==================================================== END ===================================================>
|
Mikobot/events.py
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
from telethon import events
|
3 |
+
|
4 |
+
from Mikobot import tbot
|
5 |
+
|
6 |
+
|
7 |
+
# <============================================== FUNCTIONS =========================================================>
|
8 |
+
def register(**args):
|
9 |
+
"""Registers a new message."""
|
10 |
+
pattern = args.get("pattern")
|
11 |
+
|
12 |
+
r_pattern = r"^[/!]"
|
13 |
+
|
14 |
+
if pattern is not None and not pattern.startswith("(?i)"):
|
15 |
+
args["pattern"] = f"(?i){pattern}"
|
16 |
+
|
17 |
+
args["pattern"] = pattern.replace("^/", r_pattern, 1)
|
18 |
+
|
19 |
+
def decorator(func):
|
20 |
+
tbot.add_event_handler(func, events.NewMessage(**args))
|
21 |
+
return func
|
22 |
+
|
23 |
+
return decorator
|
24 |
+
|
25 |
+
|
26 |
+
def chataction(**args):
|
27 |
+
"""Registers chat actions."""
|
28 |
+
|
29 |
+
def decorator(func):
|
30 |
+
tbot.add_event_handler(func, events.ChatAction(**args))
|
31 |
+
return func
|
32 |
+
|
33 |
+
return decorator
|
34 |
+
|
35 |
+
|
36 |
+
def userupdate(**args):
|
37 |
+
"""Registers user updates."""
|
38 |
+
|
39 |
+
def decorator(func):
|
40 |
+
tbot.add_event_handler(func, events.UserUpdate(**args))
|
41 |
+
return func
|
42 |
+
|
43 |
+
return decorator
|
44 |
+
|
45 |
+
|
46 |
+
def inlinequery(**args):
|
47 |
+
"""Registers inline query."""
|
48 |
+
pattern = args.get("pattern")
|
49 |
+
|
50 |
+
if pattern is not None and not pattern.startswith("(?i)"):
|
51 |
+
args["pattern"] = f"(?i){pattern}"
|
52 |
+
|
53 |
+
def decorator(func):
|
54 |
+
tbot.add_event_handler(func, events.InlineQuery(**args))
|
55 |
+
return func
|
56 |
+
|
57 |
+
return decorator
|
58 |
+
|
59 |
+
|
60 |
+
def callbackquery(**args):
|
61 |
+
"""Registers inline query."""
|
62 |
+
|
63 |
+
def decorator(func):
|
64 |
+
tbot.add_event_handler(func, events.CallbackQuery(**args))
|
65 |
+
return func
|
66 |
+
|
67 |
+
return decorator
|
68 |
+
|
69 |
+
|
70 |
+
# <==================================================== END ===================================================>
|
Mikobot/plugins/__init__.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from Mikobot import LOAD, LOGGER, NO_LOAD
|
2 |
+
|
3 |
+
|
4 |
+
def __list_all_modules():
|
5 |
+
import glob
|
6 |
+
from os.path import basename, dirname, isfile
|
7 |
+
|
8 |
+
# This generates a list of modules in this folder for the * in __main__ to work.
|
9 |
+
mod_paths = glob.glob(dirname(__file__) + "/*.py")
|
10 |
+
all_modules = [
|
11 |
+
basename(f)[:-3]
|
12 |
+
for f in mod_paths
|
13 |
+
if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py")
|
14 |
+
]
|
15 |
+
|
16 |
+
if LOAD or NO_LOAD:
|
17 |
+
to_load = LOAD
|
18 |
+
if to_load:
|
19 |
+
if not all(
|
20 |
+
any(mod == module_name for module_name in all_modules)
|
21 |
+
for mod in to_load
|
22 |
+
):
|
23 |
+
LOGGER.error("Invalid loadorder names, Quitting...")
|
24 |
+
quit(1)
|
25 |
+
|
26 |
+
all_modules = sorted(set(all_modules) - set(to_load))
|
27 |
+
to_load = list(all_modules) + to_load
|
28 |
+
|
29 |
+
else:
|
30 |
+
to_load = all_modules
|
31 |
+
|
32 |
+
if NO_LOAD:
|
33 |
+
LOGGER.info("Not loading: {}".format(NO_LOAD))
|
34 |
+
return [item for item in to_load if item not in NO_LOAD]
|
35 |
+
|
36 |
+
return to_load
|
37 |
+
|
38 |
+
return all_modules
|
39 |
+
|
40 |
+
|
41 |
+
ALL_MODULES = __list_all_modules()
|
42 |
+
LOGGER.info("Modules to load: %s", str(ALL_MODULES))
|
43 |
+
__all__ = ALL_MODULES + ["ALL_MODULES"]
|
Mikobot/plugins/admin.py
ADDED
@@ -0,0 +1,1148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import html
|
3 |
+
|
4 |
+
from telegram import (
|
5 |
+
ChatMemberAdministrator,
|
6 |
+
InlineKeyboardButton,
|
7 |
+
InlineKeyboardMarkup,
|
8 |
+
Update,
|
9 |
+
)
|
10 |
+
from telegram.constants import ChatID, ChatMemberStatus, ChatType, ParseMode
|
11 |
+
from telegram.error import BadRequest
|
12 |
+
from telegram.ext import CallbackQueryHandler, CommandHandler, ContextTypes, filters
|
13 |
+
from telegram.helpers import mention_html
|
14 |
+
|
15 |
+
from Mikobot import DRAGONS, function
|
16 |
+
from Mikobot.plugins.disable import DisableAbleCommandHandler
|
17 |
+
from Mikobot.plugins.helper_funcs.alternate import send_message
|
18 |
+
from Mikobot.plugins.helper_funcs.chat_status import (
|
19 |
+
ADMIN_CACHE,
|
20 |
+
check_admin,
|
21 |
+
connection_status,
|
22 |
+
)
|
23 |
+
from Mikobot.plugins.helper_funcs.extraction import extract_user, extract_user_and_text
|
24 |
+
from Mikobot.plugins.log_channel import loggable
|
25 |
+
|
26 |
+
# <=======================================================================================================>
|
27 |
+
|
28 |
+
|
29 |
+
# <================================================ FUNCTION =======================================================>
|
30 |
+
@connection_status
|
31 |
+
@loggable
|
32 |
+
@check_admin(permission="can_promote_members", is_both=True)
|
33 |
+
async def promote(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
34 |
+
bot = context.bot
|
35 |
+
args = context.args
|
36 |
+
|
37 |
+
message = update.effective_message
|
38 |
+
chat = update.effective_chat
|
39 |
+
user = update.effective_user
|
40 |
+
|
41 |
+
user_id = await extract_user(message, context, args)
|
42 |
+
await chat.get_member(user.id)
|
43 |
+
|
44 |
+
if message.from_user.id == ChatID.ANONYMOUS_ADMIN:
|
45 |
+
await message.reply_text(
|
46 |
+
text="You are an anonymous admin.",
|
47 |
+
reply_markup=InlineKeyboardMarkup(
|
48 |
+
[
|
49 |
+
[
|
50 |
+
InlineKeyboardButton(
|
51 |
+
text="Click to promote admin.",
|
52 |
+
callback_data=f"admin_=promote={user_id}",
|
53 |
+
),
|
54 |
+
],
|
55 |
+
],
|
56 |
+
),
|
57 |
+
)
|
58 |
+
|
59 |
+
return
|
60 |
+
|
61 |
+
if not user_id:
|
62 |
+
await message.reply_text(
|
63 |
+
"You don't seem to be referring to a user, or the ID specified is incorrect.",
|
64 |
+
)
|
65 |
+
return
|
66 |
+
|
67 |
+
try:
|
68 |
+
user_member = await chat.get_member(user_id)
|
69 |
+
except:
|
70 |
+
return
|
71 |
+
|
72 |
+
if (
|
73 |
+
user_member.status == ChatMemberStatus.ADMINISTRATOR
|
74 |
+
or user_member.status == ChatMemberStatus.OWNER
|
75 |
+
):
|
76 |
+
await message.reply_text("How can I promote someone who is already an admin?")
|
77 |
+
return
|
78 |
+
|
79 |
+
if user_id == bot.id:
|
80 |
+
await message.reply_text(
|
81 |
+
"I can't promote myself! Get an admin to do it for me."
|
82 |
+
)
|
83 |
+
return
|
84 |
+
|
85 |
+
# Set the same permissions as the bot - the bot can't assign higher permissions than itself!
|
86 |
+
bot_member = await chat.get_member(bot.id)
|
87 |
+
|
88 |
+
if isinstance(bot_member, ChatMemberAdministrator):
|
89 |
+
try:
|
90 |
+
await bot.promoteChatMember(
|
91 |
+
chat.id,
|
92 |
+
user_id,
|
93 |
+
can_change_info=bot_member.can_change_info,
|
94 |
+
can_post_messages=bot_member.can_post_messages,
|
95 |
+
can_edit_messages=bot_member.can_edit_messages,
|
96 |
+
can_delete_messages=bot_member.can_delete_messages,
|
97 |
+
can_invite_users=bot_member.can_invite_users,
|
98 |
+
can_restrict_members=bot_member.can_restrict_members,
|
99 |
+
can_pin_messages=bot_member.can_pin_messages,
|
100 |
+
can_manage_chat=bot_member.can_manage_chat,
|
101 |
+
can_manage_video_chats=bot_member.can_manage_video_chats,
|
102 |
+
can_manage_topics=bot_member.can_manage_topics,
|
103 |
+
)
|
104 |
+
except BadRequest as err:
|
105 |
+
if err.message == "User_not_mutual_contact":
|
106 |
+
await message.reply_text(
|
107 |
+
"I can't promote someone who isn't in the group."
|
108 |
+
)
|
109 |
+
else:
|
110 |
+
await message.reply_text("An error occurred while promoting.")
|
111 |
+
return
|
112 |
+
|
113 |
+
await bot.sendMessage(
|
114 |
+
chat.id,
|
115 |
+
f"Successfully promoted {user_member.user.first_name or user_id}!",
|
116 |
+
parse_mode=ParseMode.HTML,
|
117 |
+
message_thread_id=message.message_thread_id if chat.is_forum else None,
|
118 |
+
)
|
119 |
+
|
120 |
+
log_message = (
|
121 |
+
f"{html.escape(chat.title)}:\n"
|
122 |
+
"#Promoted\n"
|
123 |
+
f"ADMIN: {mention_html(user.id, user.first_name)}\n"
|
124 |
+
f"USER: {mention_html(user_member.user.id, user_member.user.first_name)}"
|
125 |
+
)
|
126 |
+
|
127 |
+
return log_message
|
128 |
+
|
129 |
+
|
130 |
+
@connection_status
|
131 |
+
@loggable
|
132 |
+
@check_admin(permission="can_promote_members", is_both=True)
|
133 |
+
async def fullpromote(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
134 |
+
bot = context.bot
|
135 |
+
args = context.args
|
136 |
+
|
137 |
+
message = update.effective_message
|
138 |
+
chat = update.effective_chat
|
139 |
+
user = update.effective_user
|
140 |
+
|
141 |
+
user_id = await extract_user(message, context, args)
|
142 |
+
await chat.get_member(user.id)
|
143 |
+
|
144 |
+
if message.from_user.id == ChatID.ANONYMOUS_ADMIN:
|
145 |
+
await message.reply_text(
|
146 |
+
text="You are an anonymous admin.",
|
147 |
+
reply_markup=InlineKeyboardMarkup(
|
148 |
+
[
|
149 |
+
[
|
150 |
+
InlineKeyboardButton(
|
151 |
+
text="Click to promote admin.",
|
152 |
+
callback_data=f"admin_=promote={user_id}",
|
153 |
+
),
|
154 |
+
],
|
155 |
+
],
|
156 |
+
),
|
157 |
+
)
|
158 |
+
|
159 |
+
return
|
160 |
+
|
161 |
+
if not user_id:
|
162 |
+
await message.reply_text(
|
163 |
+
"You don't seem to be referring to a user, or the ID specified is incorrect.",
|
164 |
+
)
|
165 |
+
return
|
166 |
+
|
167 |
+
try:
|
168 |
+
user_member = await chat.get_member(user_id)
|
169 |
+
except:
|
170 |
+
return
|
171 |
+
|
172 |
+
if (
|
173 |
+
user_member.status == ChatMemberStatus.ADMINISTRATOR
|
174 |
+
or user_member.status == ChatMemberStatus.OWNER
|
175 |
+
):
|
176 |
+
await message.reply_text("How can I promote someone who is already an admin?")
|
177 |
+
return
|
178 |
+
|
179 |
+
if user_id == bot.id:
|
180 |
+
await message.reply_text(
|
181 |
+
"I can't promote myself! Get an admin to do it for me."
|
182 |
+
)
|
183 |
+
return
|
184 |
+
|
185 |
+
# Set the same permissions as the bot - the bot can't assign higher perms than itself!
|
186 |
+
bot_member = await chat.get_member(bot.id)
|
187 |
+
|
188 |
+
if isinstance(bot_member, ChatMemberAdministrator):
|
189 |
+
try:
|
190 |
+
await bot.promoteChatMember(
|
191 |
+
chat.id,
|
192 |
+
user_id,
|
193 |
+
can_change_info=bot_member.can_change_info,
|
194 |
+
can_post_messages=bot_member.can_post_messages,
|
195 |
+
can_edit_messages=bot_member.can_edit_messages,
|
196 |
+
can_delete_messages=bot_member.can_delete_messages,
|
197 |
+
can_invite_users=bot_member.can_invite_users,
|
198 |
+
can_promote_members=bot_member.can_promote_members,
|
199 |
+
can_restrict_members=bot_member.can_restrict_members,
|
200 |
+
can_pin_messages=bot_member.can_pin_messages,
|
201 |
+
can_manage_chat=bot_member.can_manage_chat,
|
202 |
+
can_manage_video_chats=bot_member.can_manage_video_chats,
|
203 |
+
can_manage_topics=bot_member.can_manage_topics,
|
204 |
+
)
|
205 |
+
except BadRequest as err:
|
206 |
+
if err.message == "User_not_mutual_contact":
|
207 |
+
await message.reply_text(
|
208 |
+
"I can't promote someone who isn't in the group."
|
209 |
+
)
|
210 |
+
else:
|
211 |
+
await message.reply_text("An error occurred while promoting.")
|
212 |
+
return
|
213 |
+
|
214 |
+
await bot.sendMessage(
|
215 |
+
chat.id,
|
216 |
+
f"Successfully promoted {user_member.user.first_name or user_id}!",
|
217 |
+
parse_mode=ParseMode.HTML,
|
218 |
+
message_thread_id=message.message_thread_id if chat.is_forum else None,
|
219 |
+
)
|
220 |
+
|
221 |
+
log_message = (
|
222 |
+
f"{html.escape(chat.title)}:\n"
|
223 |
+
"#FULLPROMOTED\n"
|
224 |
+
f"ADMIN: {mention_html(user.id, user.first_name)}\n"
|
225 |
+
f"USER: {mention_html(user_member.user.id, user_member.user.first_name)}"
|
226 |
+
)
|
227 |
+
|
228 |
+
return log_message
|
229 |
+
|
230 |
+
|
231 |
+
@connection_status
|
232 |
+
@loggable
|
233 |
+
@check_admin(permission="can_promote_members", is_both=True)
|
234 |
+
async def demote(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
235 |
+
bot = context.bot
|
236 |
+
args = context.args
|
237 |
+
|
238 |
+
chat = update.effective_chat
|
239 |
+
message = update.effective_message
|
240 |
+
user = update.effective_user
|
241 |
+
|
242 |
+
user_id = await extract_user(message, context, args)
|
243 |
+
await chat.get_member(user.id)
|
244 |
+
|
245 |
+
if message.from_user.id == ChatID.ANONYMOUS_ADMIN:
|
246 |
+
await message.reply_text(
|
247 |
+
text="You are an anonymous admin.",
|
248 |
+
reply_markup=InlineKeyboardMarkup(
|
249 |
+
[
|
250 |
+
[
|
251 |
+
InlineKeyboardButton(
|
252 |
+
text="Click to prove admin.",
|
253 |
+
callback_data=f"admin_=demote={user_id}",
|
254 |
+
),
|
255 |
+
],
|
256 |
+
],
|
257 |
+
),
|
258 |
+
)
|
259 |
+
|
260 |
+
return
|
261 |
+
|
262 |
+
if not user_id:
|
263 |
+
await message.reply_text(
|
264 |
+
"You don't seem to be referring to a user or the id specified is incorrect..",
|
265 |
+
)
|
266 |
+
return
|
267 |
+
|
268 |
+
try:
|
269 |
+
user_member = await chat.get_member(user_id)
|
270 |
+
except:
|
271 |
+
return
|
272 |
+
|
273 |
+
if user_member.status == ChatMemberStatus.OWNER:
|
274 |
+
await message.reply_text(
|
275 |
+
"This person created the chat, How could i demote him?"
|
276 |
+
)
|
277 |
+
return
|
278 |
+
|
279 |
+
if not user_member.status == ChatMemberStatus.ADMINISTRATOR:
|
280 |
+
await message.reply_text("Can't demote who isn't promoted!")
|
281 |
+
return
|
282 |
+
|
283 |
+
if user_id == bot.id:
|
284 |
+
await message.reply_text("I can't demote myself!.")
|
285 |
+
return
|
286 |
+
|
287 |
+
try:
|
288 |
+
await bot.promote_chat_member(
|
289 |
+
chat.id,
|
290 |
+
user_id,
|
291 |
+
can_change_info=False,
|
292 |
+
can_post_messages=False,
|
293 |
+
can_edit_messages=False,
|
294 |
+
can_delete_messages=False,
|
295 |
+
can_invite_users=False,
|
296 |
+
can_restrict_members=False,
|
297 |
+
can_pin_messages=False,
|
298 |
+
can_promote_members=False,
|
299 |
+
can_manage_chat=False,
|
300 |
+
can_manage_video_chats=False,
|
301 |
+
can_manage_topics=False,
|
302 |
+
)
|
303 |
+
|
304 |
+
await bot.sendMessage(
|
305 |
+
chat.id,
|
306 |
+
f"SUCCESSFULLY DEMOTED <b>{user_member.user.first_name or user_id}</b>!",
|
307 |
+
parse_mode=ParseMode.HTML,
|
308 |
+
message_thread_id=message.message_thread_id if chat.is_forum else None,
|
309 |
+
)
|
310 |
+
|
311 |
+
log_message = (
|
312 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
313 |
+
f"#DEMOTED\n"
|
314 |
+
f"<b>ADMIN:</b> {mention_html(user.id, user.first_name)}\n"
|
315 |
+
f"<b>USER:</b> {mention_html(user_member.user.id, user_member.user.first_name)}"
|
316 |
+
)
|
317 |
+
|
318 |
+
return log_message
|
319 |
+
except BadRequest:
|
320 |
+
await message.reply_text(
|
321 |
+
"Could not demote. I might not be admin or the admin status was appointed by another"
|
322 |
+
"Its a User, So I can't act upon them!",
|
323 |
+
)
|
324 |
+
raise
|
325 |
+
|
326 |
+
|
327 |
+
@check_admin(is_user=True)
|
328 |
+
async def refresh_admin(update, _):
|
329 |
+
try:
|
330 |
+
ADMIN_CACHE.pop(update.effective_chat.id)
|
331 |
+
except KeyError:
|
332 |
+
pass
|
333 |
+
|
334 |
+
await update.effective_message.reply_text("Admins cache refreshed!")
|
335 |
+
|
336 |
+
|
337 |
+
@connection_status
|
338 |
+
@check_admin(permission="can_promote_members", is_both=True)
|
339 |
+
async def set_title(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
340 |
+
bot = context.bot
|
341 |
+
args = context.args
|
342 |
+
|
343 |
+
chat = update.effective_chat
|
344 |
+
message = update.effective_message
|
345 |
+
|
346 |
+
user_id, title = await extract_user_and_text(message, context, args)
|
347 |
+
|
348 |
+
if message.from_user.id == 1087968824:
|
349 |
+
await message.reply_text(
|
350 |
+
text="You are an anonymous admin.",
|
351 |
+
reply_markup=InlineKeyboardMarkup(
|
352 |
+
[
|
353 |
+
[
|
354 |
+
InlineKeyboardButton(
|
355 |
+
text="Click to prove admin.",
|
356 |
+
callback_data=f"admin_=title={user_id}={title}",
|
357 |
+
),
|
358 |
+
],
|
359 |
+
],
|
360 |
+
),
|
361 |
+
)
|
362 |
+
|
363 |
+
return
|
364 |
+
|
365 |
+
try:
|
366 |
+
user_member = await chat.get_member(user_id)
|
367 |
+
except:
|
368 |
+
return
|
369 |
+
|
370 |
+
if not user_id:
|
371 |
+
await message.reply_text(
|
372 |
+
"You don't seem to be referring to a user or the ID specified is incorrect..",
|
373 |
+
)
|
374 |
+
return
|
375 |
+
|
376 |
+
if user_member.status == ChatMemberStatus.OWNER:
|
377 |
+
await message.reply_text(
|
378 |
+
"This person CREATED the chat, how can I set custom title for him?",
|
379 |
+
)
|
380 |
+
return
|
381 |
+
|
382 |
+
if user_member.status != ChatMemberStatus.ADMINISTRATOR:
|
383 |
+
await message.reply_text(
|
384 |
+
"Can't set title for non-admins!\nPromote them first to set custom title!",
|
385 |
+
)
|
386 |
+
return
|
387 |
+
|
388 |
+
if user_id == bot.id:
|
389 |
+
await message.reply_text(
|
390 |
+
"I can't set my own title myself! Get the one who made me admin to do it for me.",
|
391 |
+
)
|
392 |
+
return
|
393 |
+
|
394 |
+
if not title:
|
395 |
+
await message.reply_text("Setting a blank title doesn't do anything!")
|
396 |
+
return
|
397 |
+
|
398 |
+
if len(title) > 16:
|
399 |
+
await message.reply_text(
|
400 |
+
"The title length is longer than 16 characters.\nTruncating it to 16 characters.",
|
401 |
+
)
|
402 |
+
|
403 |
+
try:
|
404 |
+
await bot.setChatAdministratorCustomTitle(chat.id, user_id, title)
|
405 |
+
except BadRequest:
|
406 |
+
await message.reply_text(
|
407 |
+
"Either they aren't promoted by me or you set a title text that is impossible to set."
|
408 |
+
)
|
409 |
+
raise
|
410 |
+
|
411 |
+
await bot.sendMessage(
|
412 |
+
chat.id,
|
413 |
+
f"Successfully set title for <code>{user_member.user.first_name or user_id}</code> "
|
414 |
+
f"to <code>{html.escape(title[:16])}</code>!",
|
415 |
+
parse_mode=ParseMode.HTML,
|
416 |
+
message_thread_id=message.message_thread_id if chat.is_forum else None,
|
417 |
+
)
|
418 |
+
|
419 |
+
|
420 |
+
@loggable
|
421 |
+
@check_admin(permission="can_pin_messages", is_both=True)
|
422 |
+
async def pin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
423 |
+
bot = context.bot
|
424 |
+
args = context.args
|
425 |
+
|
426 |
+
user = update.effective_user
|
427 |
+
chat = update.effective_chat
|
428 |
+
message = update.effective_message
|
429 |
+
|
430 |
+
is_group = chat.type != "private" and chat.type != "channel"
|
431 |
+
prev_message = update.effective_message.reply_to_message
|
432 |
+
|
433 |
+
is_silent = True
|
434 |
+
if len(args) >= 1:
|
435 |
+
is_silent = not (
|
436 |
+
args[0].lower() == "notify"
|
437 |
+
or args[0].lower() == "loud"
|
438 |
+
or args[0].lower() == "violent"
|
439 |
+
)
|
440 |
+
|
441 |
+
if not prev_message:
|
442 |
+
await message.reply_text("Please reply to message which you want to pin.")
|
443 |
+
return
|
444 |
+
|
445 |
+
if message.from_user.id == 1087968824:
|
446 |
+
await message.reply_text(
|
447 |
+
text="You are an anonymous admin.",
|
448 |
+
reply_markup=InlineKeyboardMarkup(
|
449 |
+
[
|
450 |
+
[
|
451 |
+
InlineKeyboardButton(
|
452 |
+
text="Click to prove admin.",
|
453 |
+
callback_data=f"admin_=pin={prev_message.message_id}={is_silent}",
|
454 |
+
),
|
455 |
+
],
|
456 |
+
],
|
457 |
+
),
|
458 |
+
)
|
459 |
+
|
460 |
+
return
|
461 |
+
|
462 |
+
if prev_message and is_group:
|
463 |
+
try:
|
464 |
+
await bot.pinChatMessage(
|
465 |
+
chat.id,
|
466 |
+
prev_message.message_id,
|
467 |
+
disable_notification=is_silent,
|
468 |
+
)
|
469 |
+
except BadRequest as excp:
|
470 |
+
if excp.message == "Chat_not_modified":
|
471 |
+
pass
|
472 |
+
else:
|
473 |
+
raise
|
474 |
+
log_message = (
|
475 |
+
f"{chat.title}:\n"
|
476 |
+
"#PINNED\n"
|
477 |
+
f"Admin: {mention_html(user.id, user.first_name)}"
|
478 |
+
)
|
479 |
+
|
480 |
+
return log_message
|
481 |
+
|
482 |
+
|
483 |
+
@loggable
|
484 |
+
@check_admin(permission="can_pin_messages", is_both=True)
|
485 |
+
async def unpin(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
486 |
+
bot = context.bot
|
487 |
+
chat = update.effective_chat
|
488 |
+
user = update.effective_user
|
489 |
+
message = update.effective_message
|
490 |
+
|
491 |
+
if message.from_user.id == 1087968824:
|
492 |
+
await message.reply_text(
|
493 |
+
text="You are an anonymous admin.",
|
494 |
+
reply_markup=InlineKeyboardMarkup(
|
495 |
+
[
|
496 |
+
[
|
497 |
+
InlineKeyboardButton(
|
498 |
+
text="Click to prove Admin.",
|
499 |
+
callback_data=f"admin_=unpin",
|
500 |
+
),
|
501 |
+
],
|
502 |
+
],
|
503 |
+
),
|
504 |
+
)
|
505 |
+
|
506 |
+
return
|
507 |
+
|
508 |
+
try:
|
509 |
+
await bot.unpinChatMessage(chat.id)
|
510 |
+
except BadRequest as excp:
|
511 |
+
if excp.message == "Chat_not_modified":
|
512 |
+
pass
|
513 |
+
elif excp.message == "Message to unpin not found":
|
514 |
+
await message.reply_text("No pinned message found")
|
515 |
+
return
|
516 |
+
else:
|
517 |
+
raise
|
518 |
+
|
519 |
+
log_message = (
|
520 |
+
f"{chat.title}:\n"
|
521 |
+
"#UNPINNED\n"
|
522 |
+
f"Admin: {mention_html(user.id, user.first_name)}"
|
523 |
+
)
|
524 |
+
|
525 |
+
return log_message
|
526 |
+
|
527 |
+
|
528 |
+
@loggable
|
529 |
+
@check_admin(permission="can_pin_messages", is_both=True)
|
530 |
+
async def unpinall(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
531 |
+
bot = context.bot
|
532 |
+
chat = update.effective_chat
|
533 |
+
user = update.effective_user
|
534 |
+
message = update.effective_message
|
535 |
+
admin_member = await chat.get_member(user.id)
|
536 |
+
|
537 |
+
if message.from_user.id == 1087968824:
|
538 |
+
await message.reply_text(
|
539 |
+
text="You are an anonymous admin.",
|
540 |
+
reply_markup=InlineKeyboardMarkup(
|
541 |
+
[
|
542 |
+
[
|
543 |
+
InlineKeyboardButton(
|
544 |
+
text="Click to prove admin.",
|
545 |
+
callback_data=f"admin_=unpinall",
|
546 |
+
),
|
547 |
+
],
|
548 |
+
],
|
549 |
+
),
|
550 |
+
)
|
551 |
+
|
552 |
+
return
|
553 |
+
elif not admin_member.status == ChatMemberStatus.OWNER and user.id not in DRAGONS:
|
554 |
+
await message.reply_text("Only chat OWNER can unpin all messages.")
|
555 |
+
return
|
556 |
+
|
557 |
+
try:
|
558 |
+
if chat.is_forum:
|
559 |
+
await bot.unpin_all_forum_topic_messages(chat.id, message.message_thread_id)
|
560 |
+
else:
|
561 |
+
await bot.unpin_all_chat_messages(chat.id)
|
562 |
+
except BadRequest as excp:
|
563 |
+
if excp.message == "Chat_not_modified":
|
564 |
+
pass
|
565 |
+
else:
|
566 |
+
raise
|
567 |
+
|
568 |
+
log_message = (
|
569 |
+
f"{chat.title}:\n"
|
570 |
+
"#UNPINNED_ALL\n"
|
571 |
+
f"Admin: {mention_html(user.id, user.first_name)}"
|
572 |
+
)
|
573 |
+
|
574 |
+
return log_message
|
575 |
+
|
576 |
+
|
577 |
+
@connection_status
|
578 |
+
@check_admin(permission="can_invite_users", is_bot=True)
|
579 |
+
async def invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
580 |
+
bot = context.bot
|
581 |
+
chat = update.effective_chat
|
582 |
+
|
583 |
+
if chat.username:
|
584 |
+
await update.effective_message.reply_text(f"https://t.me/{chat.username}")
|
585 |
+
elif chat.type in [ChatType.SUPERGROUP, ChatType.CHANNEL]:
|
586 |
+
bot_member = await chat.get_member(bot.id)
|
587 |
+
if (
|
588 |
+
bot_member.can_invite_users
|
589 |
+
if isinstance(bot_member, ChatMemberAdministrator)
|
590 |
+
else None
|
591 |
+
):
|
592 |
+
invitelink = await bot.exportChatInviteLink(chat.id)
|
593 |
+
await update.effective_message.reply_text(invitelink)
|
594 |
+
else:
|
595 |
+
await update.effective_message.reply_text(
|
596 |
+
"I don't have access to the invite link, try changing my permissions!",
|
597 |
+
)
|
598 |
+
else:
|
599 |
+
await update.effective_message.reply_text(
|
600 |
+
"I can only give you invite links for supergroups and channels, sorry!",
|
601 |
+
)
|
602 |
+
|
603 |
+
|
604 |
+
@connection_status
|
605 |
+
async def adminlist(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
606 |
+
chat = update.effective_chat # type: Optional[Chat]
|
607 |
+
user = update.effective_user # type: Optional[User]
|
608 |
+
args = context.args
|
609 |
+
bot = context.bot
|
610 |
+
if update.effective_message.chat.type == "private":
|
611 |
+
await send_message(
|
612 |
+
update.effective_message, "This command only works in Groups."
|
613 |
+
)
|
614 |
+
return
|
615 |
+
chat = update.effective_chat
|
616 |
+
chat_id = update.effective_chat.id
|
617 |
+
chat_name = update.effective_message.chat.title
|
618 |
+
try:
|
619 |
+
msg = await update.effective_message.reply_text(
|
620 |
+
"Fetching group admins...", parse_mode=ParseMode.HTML
|
621 |
+
)
|
622 |
+
except BadRequest:
|
623 |
+
msg = await update.effective_message.reply_text(
|
624 |
+
"Fetching group admins...", quote=False, parse_mode=ParseMode.HTML
|
625 |
+
)
|
626 |
+
administrators = await bot.get_chat_administrators(chat_id)
|
627 |
+
administrators_list = list(administrators) # Convert to a list
|
628 |
+
text = "「 𝗔𝗗𝗠𝗜𝗡𝗦 𝗜𝗡 <b>{}</b>:".format(html.escape(update.effective_chat.title))
|
629 |
+
bot_admin_list = []
|
630 |
+
for admin in administrators_list:
|
631 |
+
user = admin.user
|
632 |
+
status = admin.status
|
633 |
+
custom_title = admin.custom_title
|
634 |
+
if user.first_name == "":
|
635 |
+
name = "☠ Deleted Account"
|
636 |
+
else:
|
637 |
+
name = "{}".format(
|
638 |
+
mention_html(
|
639 |
+
user.id, html.escape(user.first_name + " " + (user.last_name or ""))
|
640 |
+
)
|
641 |
+
)
|
642 |
+
if user.is_bot:
|
643 |
+
bot_admin_list.append(name)
|
644 |
+
administrators_list.remove(admin)
|
645 |
+
continue
|
646 |
+
if status == "creator":
|
647 |
+
text += "\n\n 👑 <b>Creator:</b>"
|
648 |
+
text += "\n<code> ╰─➽ </code>{}\n".format(name)
|
649 |
+
if custom_title:
|
650 |
+
text += f"<code> ┗━ {html.escape(custom_title)}</code>\n"
|
651 |
+
text += "\n🚓 <b>Admins:</b>"
|
652 |
+
custom_admin_list = {}
|
653 |
+
normal_admin_list = []
|
654 |
+
for admin in administrators_list:
|
655 |
+
user = admin.user
|
656 |
+
status = admin.status
|
657 |
+
custom_title = admin.custom_title
|
658 |
+
if user.first_name == "":
|
659 |
+
name = "☠ Deleted Account"
|
660 |
+
else:
|
661 |
+
name = "{}".format(
|
662 |
+
mention_html(
|
663 |
+
user.id, html.escape(user.first_name + " " + (user.last_name or ""))
|
664 |
+
)
|
665 |
+
)
|
666 |
+
if status == "administrator":
|
667 |
+
if custom_title:
|
668 |
+
try:
|
669 |
+
custom_admin_list[custom_title].append(name)
|
670 |
+
except KeyError:
|
671 |
+
custom_admin_list.update({custom_title: [name]})
|
672 |
+
else:
|
673 |
+
normal_admin_list.append(name)
|
674 |
+
for admin in normal_admin_list:
|
675 |
+
text += "\n<code> ╰─➽ </code>{}".format(admin)
|
676 |
+
for admin_group in custom_admin_list.copy():
|
677 |
+
if len(custom_admin_list[admin_group]) == 1:
|
678 |
+
text += "\n<code> ╰─➽ </code>{} | <code>{}</code>".format(
|
679 |
+
custom_admin_list[admin_group][0], html.escape(admin_group)
|
680 |
+
)
|
681 |
+
custom_admin_list.pop(admin_group)
|
682 |
+
text += "\n"
|
683 |
+
for admin_group in custom_admin_list:
|
684 |
+
text += "\n🚨 <code>{}</code>".format(admin_group)
|
685 |
+
for admin in custom_admin_list[admin_group]:
|
686 |
+
text += "\n<code> ╰─➽ </code>{}".format(admin)
|
687 |
+
text += "\n"
|
688 |
+
text += "\n🤖 <b>Bots:</b>"
|
689 |
+
for each_bot in bot_admin_list:
|
690 |
+
text += "\n<code> ╰─➽ </code>{}".format(each_bot)
|
691 |
+
try:
|
692 |
+
await msg.edit_text(text, parse_mode=ParseMode.HTML)
|
693 |
+
except BadRequest: # if the original message is deleted
|
694 |
+
return
|
695 |
+
|
696 |
+
|
697 |
+
@loggable
|
698 |
+
async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
699 |
+
query = update.callback_query
|
700 |
+
bot = context.bot
|
701 |
+
message = update.effective_message
|
702 |
+
chat = update.effective_chat
|
703 |
+
admin_user = query.from_user
|
704 |
+
|
705 |
+
splitter = query.data.replace("admin_", "").split("=")
|
706 |
+
|
707 |
+
if splitter[1] == "promote":
|
708 |
+
promoter = await chat.get_member(admin_user.id)
|
709 |
+
|
710 |
+
if (
|
711 |
+
not (
|
712 |
+
promoter.can_promote_members
|
713 |
+
if isinstance(promoter, ChatMemberAdministrator)
|
714 |
+
else None or promoter.status == ChatMemberStatus.OWNER
|
715 |
+
)
|
716 |
+
and admin_user.id not in DRAGONS
|
717 |
+
):
|
718 |
+
await query.answer(
|
719 |
+
"You don't have the necessary rights to do that!", show_alert=True
|
720 |
+
)
|
721 |
+
return
|
722 |
+
|
723 |
+
try:
|
724 |
+
user_id = int(splitter[2])
|
725 |
+
except ValueError:
|
726 |
+
user_id = splitter[2]
|
727 |
+
await message.edit_text(
|
728 |
+
"You don't seem to be referring to a user or the ID specified is incorrect..."
|
729 |
+
)
|
730 |
+
return
|
731 |
+
|
732 |
+
try:
|
733 |
+
user_member = await chat.get_member(user_id)
|
734 |
+
except:
|
735 |
+
return
|
736 |
+
|
737 |
+
if (
|
738 |
+
user_member.status == ChatMemberStatus.ADMINISTRATOR
|
739 |
+
or user_member.status == ChatMemberStatus.OWNER
|
740 |
+
):
|
741 |
+
await message.edit_text(
|
742 |
+
"How am I meant to promote someone that's already an admin?"
|
743 |
+
)
|
744 |
+
return
|
745 |
+
|
746 |
+
bot_member = await chat.get_member(bot.id)
|
747 |
+
|
748 |
+
if isinstance(bot_member, ChatMemberAdministrator):
|
749 |
+
try:
|
750 |
+
await bot.promoteChatMember(
|
751 |
+
chat.id,
|
752 |
+
user_id,
|
753 |
+
can_change_info=bot_member.can_change_info,
|
754 |
+
can_post_messages=bot_member.can_post_messages,
|
755 |
+
can_edit_messages=bot_member.can_edit_messages,
|
756 |
+
can_delete_messages=bot_member.can_delete_messages,
|
757 |
+
can_invite_users=bot_member.can_invite_users,
|
758 |
+
can_restrict_members=bot_member.can_restrict_members,
|
759 |
+
can_pin_messages=bot_member.can_pin_messages,
|
760 |
+
can_manage_chat=bot_member.can_manage_chat,
|
761 |
+
can_manage_video_chats=bot_member.can_manage_video_chats,
|
762 |
+
)
|
763 |
+
except BadRequest as err:
|
764 |
+
if err.message == "User_not_mutual_contact":
|
765 |
+
await message.edit_text(
|
766 |
+
"I can't promote someone who isn't in the group"
|
767 |
+
)
|
768 |
+
else:
|
769 |
+
await message.edit_text("An error occurred while promoting.")
|
770 |
+
return
|
771 |
+
|
772 |
+
await message.edit_text(
|
773 |
+
f"Successfully promoted <b>{user_member.user.first_name or user_id}</b>!",
|
774 |
+
parse_mode=ParseMode.HTML,
|
775 |
+
)
|
776 |
+
await query.answer("Done")
|
777 |
+
|
778 |
+
log_message = (
|
779 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
780 |
+
f"#PROMOTED\n"
|
781 |
+
f"<b>Admin:</b> {mention_html(admin_user.id, admin_user.first_name)}\n"
|
782 |
+
f"<b>User:</b> {mention_html(user_member.user.id, user_member.user.first_name)}"
|
783 |
+
)
|
784 |
+
|
785 |
+
return log_message
|
786 |
+
|
787 |
+
elif splitter[1] == "demote":
|
788 |
+
demoter = await chat.get_member(admin_user.id)
|
789 |
+
|
790 |
+
if not (
|
791 |
+
demoter.can_promote_members
|
792 |
+
if isinstance(demoter, ChatMemberAdministrator)
|
793 |
+
else None or demoter.status == ChatMemberStatus.OWNER
|
794 |
+
):
|
795 |
+
await query.answer(
|
796 |
+
"You don't have the necessary rights to do that!", show_alert=True
|
797 |
+
)
|
798 |
+
return
|
799 |
+
|
800 |
+
try:
|
801 |
+
user_id = int(splitter[2])
|
802 |
+
except:
|
803 |
+
user_id = splitter[2]
|
804 |
+
await message.edit_text(
|
805 |
+
"You don't seem to be referring to a user or the ID specified is incorrect.."
|
806 |
+
)
|
807 |
+
return
|
808 |
+
|
809 |
+
try:
|
810 |
+
user_member = await chat.get_member(user_id)
|
811 |
+
except:
|
812 |
+
return
|
813 |
+
|
814 |
+
if user_member.status == ChatMemberStatus.OWNER:
|
815 |
+
await message.edit_text(
|
816 |
+
"This person CREATED the chat, how would I demote them?"
|
817 |
+
)
|
818 |
+
return
|
819 |
+
|
820 |
+
if not user_member.status == ChatMemberStatus.ADMINISTRATOR:
|
821 |
+
await message.edit_text("Can't demote what wasn't promoted!")
|
822 |
+
return
|
823 |
+
|
824 |
+
if user_id == bot.id:
|
825 |
+
await message.edit_text(
|
826 |
+
"I can't demote myself!, get an admin to do it for me."
|
827 |
+
)
|
828 |
+
return
|
829 |
+
|
830 |
+
try:
|
831 |
+
await bot.promoteChatMember(
|
832 |
+
chat.id,
|
833 |
+
user_id,
|
834 |
+
can_change_info=False,
|
835 |
+
can_post_messages=False,
|
836 |
+
can_edit_messages=False,
|
837 |
+
can_delete_messages=False,
|
838 |
+
can_invite_users=False,
|
839 |
+
can_restrict_members=False,
|
840 |
+
can_pin_messages=False,
|
841 |
+
can_promote_members=False,
|
842 |
+
can_manage_chat=False,
|
843 |
+
can_manage_video_chats=False,
|
844 |
+
)
|
845 |
+
|
846 |
+
await message.edit_text(
|
847 |
+
f"Successfully demoted <b>{user_member.user.first_name or user_id}</b>!",
|
848 |
+
parse_mode=ParseMode.HTML,
|
849 |
+
)
|
850 |
+
await query.answer("Done")
|
851 |
+
|
852 |
+
log_message = (
|
853 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
854 |
+
f"#DEMOTE\n"
|
855 |
+
f"<b>Admin:</b> {mention_html(admin_user.id, admin_user.first_name)}\n"
|
856 |
+
f"<b>User:</b> {mention_html(user_member.user.id, user_member.user.first_name)}"
|
857 |
+
)
|
858 |
+
|
859 |
+
return log_message
|
860 |
+
except BadRequest:
|
861 |
+
await message.edit_text(
|
862 |
+
"Could not demote. I might not be admin, or the admin status was appointed by another"
|
863 |
+
" user, so I can't act upon them!"
|
864 |
+
)
|
865 |
+
return
|
866 |
+
|
867 |
+
elif splitter[1] == "title":
|
868 |
+
title = splitter[3]
|
869 |
+
|
870 |
+
admin_member = await chat.get_member(admin_user.id)
|
871 |
+
|
872 |
+
if (
|
873 |
+
not (
|
874 |
+
(
|
875 |
+
admin_member.can_promote_members
|
876 |
+
if isinstance(admin_member, ChatMemberAdministrator)
|
877 |
+
else None
|
878 |
+
)
|
879 |
+
or admin_member.status == ChatMemberStatus.OWNER
|
880 |
+
)
|
881 |
+
and admin_user.id not in DRAGONS
|
882 |
+
):
|
883 |
+
await query.answer("You don't have the necessary rights to do that!")
|
884 |
+
return
|
885 |
+
|
886 |
+
try:
|
887 |
+
user_id = int(splitter[2])
|
888 |
+
except:
|
889 |
+
await message.edit_text(
|
890 |
+
"You don't seem to be referring to a user or the ID specified is incorrect...",
|
891 |
+
)
|
892 |
+
return
|
893 |
+
|
894 |
+
try:
|
895 |
+
user_member = await chat.get_member(user_id)
|
896 |
+
except:
|
897 |
+
return
|
898 |
+
|
899 |
+
if user_member.status == ChatMemberStatus.OWNER:
|
900 |
+
await message.edit_text(
|
901 |
+
"This person CREATED the chat, how can I set a custom title for him?",
|
902 |
+
)
|
903 |
+
return
|
904 |
+
|
905 |
+
if user_member.status != ChatMemberStatus.ADMINISTRATOR:
|
906 |
+
await message.edit_text(
|
907 |
+
"Can't set a title for non-admins! Promote them first to set a custom title!",
|
908 |
+
)
|
909 |
+
return
|
910 |
+
|
911 |
+
if user_id == bot.id:
|
912 |
+
await message.edit_text(
|
913 |
+
"I can't set my own title myself! Get the one who made me admin to do it for me.",
|
914 |
+
)
|
915 |
+
return
|
916 |
+
|
917 |
+
if not title:
|
918 |
+
await message.edit_text("Setting a blank title doesn't do anything!")
|
919 |
+
return
|
920 |
+
|
921 |
+
if len(title) > 16:
|
922 |
+
await message.edit_text(
|
923 |
+
"The title length is longer than 16 characters. Truncating it to 16 characters.",
|
924 |
+
)
|
925 |
+
|
926 |
+
try:
|
927 |
+
await bot.setChatAdministratorCustomTitle(chat.id, user_id, title)
|
928 |
+
except BadRequest:
|
929 |
+
await message.edit_text(
|
930 |
+
"Either they aren't promoted by me or you set a title text that is impossible to set."
|
931 |
+
)
|
932 |
+
return
|
933 |
+
|
934 |
+
await message.edit_text(
|
935 |
+
text=f"Successfully set title for <code>{user_member.user.first_name or user_id}</code> "
|
936 |
+
f"to <code>{html.escape(title[:16])}</code>!",
|
937 |
+
parse_mode=ParseMode.HTML,
|
938 |
+
)
|
939 |
+
|
940 |
+
elif splitter[1] == "pin":
|
941 |
+
admin_member = await chat.get_member(admin_user.id)
|
942 |
+
|
943 |
+
if (
|
944 |
+
not (
|
945 |
+
(
|
946 |
+
admin_member.can_pin_messages
|
947 |
+
if isinstance(admin_member, ChatMemberAdministrator)
|
948 |
+
else None
|
949 |
+
)
|
950 |
+
or admin_member.status == ChatMemberStatus.OWNER
|
951 |
+
)
|
952 |
+
and admin_user.id not in DRAGONS
|
953 |
+
):
|
954 |
+
await query.answer(
|
955 |
+
"You don't have the necessary rights to do that!", show_alert=True
|
956 |
+
)
|
957 |
+
return
|
958 |
+
|
959 |
+
try:
|
960 |
+
message_id = int(splitter[2])
|
961 |
+
except:
|
962 |
+
return
|
963 |
+
|
964 |
+
is_silent = bool(splitter[3])
|
965 |
+
is_group = chat.type != "private" and chat.type != "channel"
|
966 |
+
|
967 |
+
if is_group:
|
968 |
+
try:
|
969 |
+
await bot.pinChatMessage(
|
970 |
+
chat.id,
|
971 |
+
message_id,
|
972 |
+
disable_notification=is_silent,
|
973 |
+
)
|
974 |
+
except BadRequest as excp:
|
975 |
+
if excp.message == "Chat_not_modified":
|
976 |
+
pass
|
977 |
+
else:
|
978 |
+
raise
|
979 |
+
|
980 |
+
await message.edit_text("Done Pinned.")
|
981 |
+
|
982 |
+
log_message = (
|
983 |
+
f"<b>{html.escape(chat.title)}</b>\n"
|
984 |
+
f"#PINNED\n"
|
985 |
+
f"<b>Admin:</b> {mention_html(admin_user.id, html.escape(admin_user.first_name))}"
|
986 |
+
)
|
987 |
+
|
988 |
+
return log_message
|
989 |
+
|
990 |
+
elif splitter[1] == "unpin":
|
991 |
+
admin_member = await chat.get_member(admin_user.id)
|
992 |
+
|
993 |
+
if (
|
994 |
+
not (
|
995 |
+
(
|
996 |
+
admin_member.can_pin_messages
|
997 |
+
if isinstance(admin_member, ChatMemberAdministrator)
|
998 |
+
else None
|
999 |
+
)
|
1000 |
+
or admin_member.status == ChatMemberStatus.OWNER
|
1001 |
+
)
|
1002 |
+
and admin_user.id not in DRAGONS
|
1003 |
+
):
|
1004 |
+
await query.answer(
|
1005 |
+
"You don't have the necessary rights to do that!",
|
1006 |
+
show_alert=True,
|
1007 |
+
)
|
1008 |
+
return
|
1009 |
+
|
1010 |
+
try:
|
1011 |
+
await bot.unpinChatMessage(chat.id)
|
1012 |
+
except BadRequest as excp:
|
1013 |
+
if excp.message == "Chat_not_modified":
|
1014 |
+
pass
|
1015 |
+
elif excp.message == "Message_to_unpin_not_found":
|
1016 |
+
await message.edit_text("No pinned message found")
|
1017 |
+
return
|
1018 |
+
else:
|
1019 |
+
raise
|
1020 |
+
|
1021 |
+
log_message = (
|
1022 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
1023 |
+
f"#UNPINNED\n"
|
1024 |
+
f"<b>Admin:</b> {mention_html(admin_user.id, html.escape(admin_user.first_name))}"
|
1025 |
+
)
|
1026 |
+
|
1027 |
+
return log_message
|
1028 |
+
|
1029 |
+
elif splitter[1] == "unpinall":
|
1030 |
+
admin_member = await chat.get_member(admin_user.id)
|
1031 |
+
|
1032 |
+
if (
|
1033 |
+
not admin_member.status == ChatMemberStatus.OWNER
|
1034 |
+
and admin_user.id not in DRAGONS
|
1035 |
+
):
|
1036 |
+
await query.answer("Only chat OWNER can unpin all messages.")
|
1037 |
+
return
|
1038 |
+
|
1039 |
+
try:
|
1040 |
+
if chat.is_forum:
|
1041 |
+
await bot.unpin_all_forum_topic_messages(
|
1042 |
+
chat.id, message.message_thread_id
|
1043 |
+
)
|
1044 |
+
else:
|
1045 |
+
await bot.unpin_all_chat_messages(chat.id)
|
1046 |
+
except BadRequest as excp:
|
1047 |
+
if excp.message == "Chat_not_modified":
|
1048 |
+
pass
|
1049 |
+
else:
|
1050 |
+
raise
|
1051 |
+
|
1052 |
+
await message.edit_text("Done unpinning all messages.")
|
1053 |
+
log_message = (
|
1054 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
1055 |
+
f"#UNPINNED-ALL\n"
|
1056 |
+
f"<b>ADMIN:</b> {mention_html(admin_user.id, html.escape(admin_user.first_name))}"
|
1057 |
+
)
|
1058 |
+
|
1059 |
+
return log_message
|
1060 |
+
|
1061 |
+
|
1062 |
+
# <=================================================== HELP ====================================================>
|
1063 |
+
|
1064 |
+
|
1065 |
+
__help__ = """
|
1066 |
+
» /adminlist: List of admins in the chat.
|
1067 |
+
|
1068 |
+
➠ *Admins only:*
|
1069 |
+
|
1070 |
+
» /pin: Silently pins the message replied to. Add 'loud' or 'notify' to give notifications to users.
|
1071 |
+
|
1072 |
+
» /unpin: Unpins the currently pinned message.
|
1073 |
+
|
1074 |
+
» /unpinall: Unpins all the pinned messages. Works in topics too (only OWNER can do this).
|
1075 |
+
|
1076 |
+
» /invitelink: Get an invite link.
|
1077 |
+
|
1078 |
+
» /promote: Promotes the user replied to.
|
1079 |
+
|
1080 |
+
» /fullpromote: FullPromotes the user replied to.
|
1081 |
+
|
1082 |
+
» /demote: Demotes the user replied to.
|
1083 |
+
|
1084 |
+
» /title <Title here>: Sets a custom title for an admin that the bot promoted.
|
1085 |
+
|
1086 |
+
» /admincache: Force refresh the admins list.
|
1087 |
+
"""
|
1088 |
+
|
1089 |
+
# <================================================ HANDLER =======================================================>
|
1090 |
+
ADMINLIST_HANDLER = DisableAbleCommandHandler("adminlist", adminlist, block=False)
|
1091 |
+
|
1092 |
+
PIN_HANDLER = CommandHandler("pin", pin, filters=filters.ChatType.GROUPS, block=False)
|
1093 |
+
UNPIN_HANDLER = CommandHandler(
|
1094 |
+
"unpin", unpin, filters=filters.ChatType.GROUPS, block=False
|
1095 |
+
)
|
1096 |
+
UNPINALL_HANDLER = CommandHandler(
|
1097 |
+
"unpinall", unpinall, filters=filters.ChatType.GROUPS, block=False
|
1098 |
+
)
|
1099 |
+
|
1100 |
+
INVITE_HANDLER = DisableAbleCommandHandler("invitelink", invite, block=False)
|
1101 |
+
|
1102 |
+
PROMOTE_HANDLER = DisableAbleCommandHandler("promote", promote, block=False)
|
1103 |
+
FULLPROMOTE_HANDLER = DisableAbleCommandHandler("fullpromote", fullpromote, block=False)
|
1104 |
+
DEMOTE_HANDLER = DisableAbleCommandHandler("demote", demote, block=False)
|
1105 |
+
|
1106 |
+
SET_TITLE_HANDLER = CommandHandler("title", set_title, block=False)
|
1107 |
+
ADMIN_REFRESH_HANDLER = CommandHandler(
|
1108 |
+
"admincache", refresh_admin, filters=filters.ChatType.GROUPS, block=False
|
1109 |
+
)
|
1110 |
+
ADMIN_CALLBACK_HANDLER = CallbackQueryHandler(
|
1111 |
+
admin_callback, block=False, pattern=r"admin_"
|
1112 |
+
)
|
1113 |
+
|
1114 |
+
function(ADMINLIST_HANDLER)
|
1115 |
+
function(PIN_HANDLER)
|
1116 |
+
function(UNPIN_HANDLER)
|
1117 |
+
function(UNPINALL_HANDLER)
|
1118 |
+
function(INVITE_HANDLER)
|
1119 |
+
function(PROMOTE_HANDLER)
|
1120 |
+
function(FULLPROMOTE_HANDLER)
|
1121 |
+
function(DEMOTE_HANDLER)
|
1122 |
+
function(SET_TITLE_HANDLER)
|
1123 |
+
function(ADMIN_REFRESH_HANDLER)
|
1124 |
+
function(ADMIN_CALLBACK_HANDLER)
|
1125 |
+
|
1126 |
+
__mod_name__ = "ADMIN"
|
1127 |
+
__command_list__ = [
|
1128 |
+
"adminlist",
|
1129 |
+
"admins",
|
1130 |
+
"invitelink",
|
1131 |
+
"promote",
|
1132 |
+
"demote",
|
1133 |
+
"admincache",
|
1134 |
+
"fullpromote",
|
1135 |
+
"setgpic",
|
1136 |
+
"delgpic",
|
1137 |
+
]
|
1138 |
+
__handlers__ = [
|
1139 |
+
ADMINLIST_HANDLER,
|
1140 |
+
PIN_HANDLER,
|
1141 |
+
UNPIN_HANDLER,
|
1142 |
+
INVITE_HANDLER,
|
1143 |
+
PROMOTE_HANDLER,
|
1144 |
+
DEMOTE_HANDLER,
|
1145 |
+
SET_TITLE_HANDLER,
|
1146 |
+
ADMIN_REFRESH_HANDLER,
|
1147 |
+
]
|
1148 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/ai.py
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# CREATED BY: https://t.me/O_oKarma
|
2 |
+
# API CREDITS: @Qewertyy
|
3 |
+
# PROVIDED BY: https://github.com/Team-ProjectCodeX
|
4 |
+
|
5 |
+
# <============================================== IMPORTS =========================================================>
|
6 |
+
import base64
|
7 |
+
|
8 |
+
from telegram import Update
|
9 |
+
from telegram.constants import ParseMode
|
10 |
+
from telegram.ext import CommandHandler, ContextTypes
|
11 |
+
|
12 |
+
from Mikobot import LOGGER as logger
|
13 |
+
from Mikobot import function
|
14 |
+
from Mikobot.state import state
|
15 |
+
|
16 |
+
# <=======================================================================================================>
|
17 |
+
|
18 |
+
# <================================================ CONSTANTS =====================================================>
|
19 |
+
PALM_API_URL = "https://lexica.qewertyy.me/models"
|
20 |
+
GPT_API_URL = "https://lexica.qewertyy.me/models"
|
21 |
+
PALM_MODEL_ID = 0
|
22 |
+
GPT_MODEL_ID = 5
|
23 |
+
|
24 |
+
# <================================================ FUNCTIONS =====================================================>
|
25 |
+
|
26 |
+
|
27 |
+
async def get_api_response(model_id, api_params, api_url):
|
28 |
+
try:
|
29 |
+
response = await state.post(api_url, params=api_params)
|
30 |
+
if response.status_code == 200:
|
31 |
+
data = response.json()
|
32 |
+
return data.get(
|
33 |
+
"content", f"Error: Empty response received from the {model_id} API."
|
34 |
+
)
|
35 |
+
else:
|
36 |
+
return f"Error: Request failed with status code {response.status_code}."
|
37 |
+
except state.RequestError as e:
|
38 |
+
return f"Error: An error occurred while calling the {model_id} API. {e}"
|
39 |
+
|
40 |
+
|
41 |
+
async def palm_chatbot(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
42 |
+
args = context.args
|
43 |
+
if not args:
|
44 |
+
await context.bot.send_message(
|
45 |
+
chat_id=update.effective_chat.id,
|
46 |
+
text="Error: Missing input text after /palm command.",
|
47 |
+
)
|
48 |
+
return
|
49 |
+
|
50 |
+
input_text = " ".join(args)
|
51 |
+
|
52 |
+
result_msg = await context.bot.send_message(
|
53 |
+
chat_id=update.effective_chat.id, text="🌴"
|
54 |
+
)
|
55 |
+
|
56 |
+
api_params = {"model_id": PALM_MODEL_ID, "prompt": input_text}
|
57 |
+
api_response = await get_api_response("PALM", api_params, PALM_API_URL)
|
58 |
+
|
59 |
+
await result_msg.delete()
|
60 |
+
await context.bot.send_message(chat_id=update.effective_chat.id, text=api_response)
|
61 |
+
|
62 |
+
|
63 |
+
async def gpt_chatbot(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
64 |
+
args = context.args
|
65 |
+
if not args:
|
66 |
+
await context.bot.send_message(
|
67 |
+
chat_id=update.effective_chat.id,
|
68 |
+
text="Error: Missing input text after /askgpt command.",
|
69 |
+
)
|
70 |
+
return
|
71 |
+
|
72 |
+
input_text = " ".join(args)
|
73 |
+
|
74 |
+
result_msg = await context.bot.send_message(
|
75 |
+
chat_id=update.effective_chat.id, text="💬"
|
76 |
+
)
|
77 |
+
|
78 |
+
api_params = {"model_id": GPT_MODEL_ID, "prompt": input_text}
|
79 |
+
api_response = await get_api_response("GPT", api_params, GPT_API_URL)
|
80 |
+
|
81 |
+
await result_msg.delete()
|
82 |
+
await context.bot.send_message(chat_id=update.effective_chat.id, text=api_response)
|
83 |
+
|
84 |
+
|
85 |
+
# Define the upscale_image function
|
86 |
+
async def upscale_image(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
87 |
+
try:
|
88 |
+
# Check if the replied message contains a photo
|
89 |
+
if update.message.reply_to_message and update.message.reply_to_message.photo:
|
90 |
+
# Send a message indicating upscaling is in progress
|
91 |
+
progress_msg = await update.message.reply_text(
|
92 |
+
"Upscaling your image, please wait..."
|
93 |
+
)
|
94 |
+
|
95 |
+
# Access the image file_id from the replied message
|
96 |
+
image = await update.message.reply_to_message.photo[-1].get_file()
|
97 |
+
|
98 |
+
# Download the image and save it
|
99 |
+
image_path = await image.download_to_drive()
|
100 |
+
|
101 |
+
with open(image_path, "rb") as image_file:
|
102 |
+
f = image_file.read()
|
103 |
+
|
104 |
+
b = base64.b64encode(f).decode("utf-8")
|
105 |
+
|
106 |
+
response = await state.post(
|
107 |
+
"https://lexica.qewertyy.me/upscale",
|
108 |
+
data={"image_data": b},
|
109 |
+
)
|
110 |
+
|
111 |
+
# Save the upscaled image
|
112 |
+
upscaled_file_path = "upscaled_image.png"
|
113 |
+
with open(upscaled_file_path, "wb") as output_file:
|
114 |
+
output_file.write(response.content)
|
115 |
+
|
116 |
+
# Delete the progress message
|
117 |
+
await context.bot.delete_message(
|
118 |
+
chat_id=update.message.chat_id, message_id=progress_msg.message_id
|
119 |
+
)
|
120 |
+
|
121 |
+
# Send the upscaled image as a PNG file
|
122 |
+
await update.message.reply_document(
|
123 |
+
document=open(upscaled_file_path, "rb"),
|
124 |
+
caption=f"<b>Upscaled your image.</b>\n<b>Generated By:</b> @{context.bot.username}",
|
125 |
+
parse_mode=ParseMode.HTML,
|
126 |
+
)
|
127 |
+
else:
|
128 |
+
await update.message.reply_text("Please reply to an image to upscale it.")
|
129 |
+
|
130 |
+
except Exception as e:
|
131 |
+
logger.error(f"Failed to upscale the image: {e}")
|
132 |
+
await update.message.reply_text(
|
133 |
+
"Failed to upscale the image. Please try again later."
|
134 |
+
)
|
135 |
+
|
136 |
+
|
137 |
+
# <================================================ HANDLER =======================================================>
|
138 |
+
# Register the upscale_image command handler
|
139 |
+
function(CommandHandler("upscale", upscale_image, block=False))
|
140 |
+
function(CommandHandler("palm", palm_chatbot, block=False))
|
141 |
+
function(CommandHandler("askgpt", gpt_chatbot, block=False))
|
142 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/alive.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# SOURCE https://github.com/Team-ProjectCodeX
|
2 |
+
# CREATED BY https://t.me/O_okarma
|
3 |
+
# PROVIDED BY https://t.me/ProjectCodeX
|
4 |
+
|
5 |
+
# <============================================== IMPORTS =========================================================>
|
6 |
+
import random
|
7 |
+
from sys import version_info
|
8 |
+
|
9 |
+
import pyrogram
|
10 |
+
import telegram
|
11 |
+
import telethon
|
12 |
+
from pyrogram import filters
|
13 |
+
from pyrogram.types import InlineKeyboardMarkup, Message
|
14 |
+
|
15 |
+
from Infamous.karma import ALIVE_ANIMATION, ALIVE_BTN
|
16 |
+
from Mikobot import BOT_NAME, app
|
17 |
+
|
18 |
+
# <=======================================================================================================>
|
19 |
+
|
20 |
+
|
21 |
+
# <================================================ FUNCTION =======================================================>
|
22 |
+
@app.on_message(filters.command("alive"))
|
23 |
+
async def alive(_, message: Message):
|
24 |
+
library_versions = {
|
25 |
+
"PTB": telegram.__version__,
|
26 |
+
"TELETHON": telethon.__version__,
|
27 |
+
"PYROGRAM": pyrogram.__version__,
|
28 |
+
}
|
29 |
+
|
30 |
+
library_versions_text = "\n".join(
|
31 |
+
[f"➲ **{key}:** `{value}`" for key, value in library_versions.items()]
|
32 |
+
)
|
33 |
+
|
34 |
+
caption = f"""**HEY, I AM {BOT_NAME}**
|
35 |
+
|
36 |
+
━━━━━━ 🌟✿🌟 ━━━━━━
|
37 |
+
✪ **CREATOR:** [🄺🄰🅁🄼🄰](https://t.me/anime_Freakz)
|
38 |
+
|
39 |
+
{library_versions_text}
|
40 |
+
|
41 |
+
➲ **PYTHON:** `{version_info[0]}.{version_info[1]}.{version_info[2]}`
|
42 |
+
➲ **BOT VERSION:** `2.0`
|
43 |
+
━━━━━━ 🌟✿🌟 ━━━━━━"""
|
44 |
+
|
45 |
+
await message.reply_animation(
|
46 |
+
random.choice(ALIVE_ANIMATION),
|
47 |
+
caption=caption,
|
48 |
+
reply_markup=InlineKeyboardMarkup(ALIVE_BTN),
|
49 |
+
)
|
50 |
+
|
51 |
+
|
52 |
+
# <=======================================================================================================>
|
53 |
+
|
54 |
+
|
55 |
+
# <================================================ NAME =======================================================>
|
56 |
+
__mod_name__ = "ALIVE"
|
57 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/anime.py
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Mikobot/plugins/antinsfw.py
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
from os import remove
|
3 |
+
|
4 |
+
from pyrogram import filters
|
5 |
+
|
6 |
+
from Database.mongodb.toggle_mongo import is_nsfw_on, nsfw_off, nsfw_on
|
7 |
+
from Mikobot import BOT_USERNAME, DRAGONS, app
|
8 |
+
from Mikobot.state import arq
|
9 |
+
from Mikobot.utils.can_restrict import can_restrict
|
10 |
+
from Mikobot.utils.errors import capture_err
|
11 |
+
|
12 |
+
# <=======================================================================================================>
|
13 |
+
|
14 |
+
|
15 |
+
# <================================================ FUNCTION =======================================================>
|
16 |
+
async def get_file_id_from_message(message):
|
17 |
+
file_id = None
|
18 |
+
if message.document:
|
19 |
+
if int(message.document.file_size) > 3145728:
|
20 |
+
return
|
21 |
+
mime_type = message.document.mime_type
|
22 |
+
if mime_type not in ("image/png", "image/jpeg"):
|
23 |
+
return
|
24 |
+
file_id = message.document.file_id
|
25 |
+
|
26 |
+
if message.sticker:
|
27 |
+
if message.sticker.is_animated:
|
28 |
+
if not message.sticker.thumbs:
|
29 |
+
return
|
30 |
+
file_id = message.sticker.thumbs[0].file_id
|
31 |
+
else:
|
32 |
+
file_id = message.sticker.file_id
|
33 |
+
|
34 |
+
if message.photo:
|
35 |
+
file_id = message.photo.file_id
|
36 |
+
|
37 |
+
if message.animation:
|
38 |
+
if not message.animation.thumbs:
|
39 |
+
return
|
40 |
+
file_id = message.animation.thumbs[0].file_id
|
41 |
+
|
42 |
+
if message.video:
|
43 |
+
if not message.video.thumbs:
|
44 |
+
return
|
45 |
+
file_id = message.video.thumbs[0].file_id
|
46 |
+
return file_id
|
47 |
+
|
48 |
+
|
49 |
+
@app.on_message(
|
50 |
+
(
|
51 |
+
filters.document
|
52 |
+
| filters.photo
|
53 |
+
| filters.sticker
|
54 |
+
| filters.animation
|
55 |
+
| filters.video
|
56 |
+
)
|
57 |
+
& ~filters.private,
|
58 |
+
group=8,
|
59 |
+
)
|
60 |
+
@capture_err
|
61 |
+
async def detect_nsfw(_, message):
|
62 |
+
if not await is_nsfw_on(message.chat.id):
|
63 |
+
return
|
64 |
+
if not message.from_user:
|
65 |
+
return
|
66 |
+
file_id = await get_file_id_from_message(message)
|
67 |
+
if not file_id:
|
68 |
+
return
|
69 |
+
file = await _.download_media(file_id)
|
70 |
+
try:
|
71 |
+
results = await arq.nsfw_scan(file=file)
|
72 |
+
except Exception:
|
73 |
+
return
|
74 |
+
if not results.ok:
|
75 |
+
return
|
76 |
+
results = results.result
|
77 |
+
remove(file)
|
78 |
+
nsfw = results.is_nsfw
|
79 |
+
if message.from_user.id in DRAGONS:
|
80 |
+
return
|
81 |
+
if not nsfw:
|
82 |
+
return
|
83 |
+
try:
|
84 |
+
await message.delete()
|
85 |
+
except Exception:
|
86 |
+
return
|
87 |
+
await message.reply_text(
|
88 |
+
f"""
|
89 |
+
**🔞 NSFW Image Detected & Deleted Successfully!**
|
90 |
+
|
91 |
+
**✪ User:** {message.from_user.mention} [`{message.from_user.id}`]
|
92 |
+
**✪ Safe:** `{results.neutral} %`
|
93 |
+
**✪ Porn:** `{results.porn} %`
|
94 |
+
**✪ Adult:** `{results.sexy} %`
|
95 |
+
**✪ Hentai:** `{results.hentai} %`
|
96 |
+
**✪ Drawings:** `{results.drawings} %`
|
97 |
+
"""
|
98 |
+
)
|
99 |
+
|
100 |
+
|
101 |
+
@app.on_message(filters.command(["nsfwscan", f"nsfwscan@{BOT_USERNAME}"]))
|
102 |
+
@capture_err
|
103 |
+
async def nsfw_scan_command(_, message):
|
104 |
+
if not message.reply_to_message:
|
105 |
+
await message.reply_text(
|
106 |
+
"Reply to an image/document/sticker/animation to scan it."
|
107 |
+
)
|
108 |
+
return
|
109 |
+
reply = message.reply_to_message
|
110 |
+
if (
|
111 |
+
not reply.document
|
112 |
+
and not reply.photo
|
113 |
+
and not reply.sticker
|
114 |
+
and not reply.animation
|
115 |
+
and not reply.video
|
116 |
+
):
|
117 |
+
await message.reply_text(
|
118 |
+
"Reply to an image/document/sticker/animation to scan it."
|
119 |
+
)
|
120 |
+
return
|
121 |
+
m = await message.reply_text("Scanning")
|
122 |
+
file_id = await get_file_id_from_message(reply)
|
123 |
+
if not file_id:
|
124 |
+
return await m.edit("Something wrong happened.")
|
125 |
+
file = await _.download_media(file_id)
|
126 |
+
try:
|
127 |
+
results = await arq.nsfw_scan(file=file)
|
128 |
+
except Exception:
|
129 |
+
return
|
130 |
+
remove(file)
|
131 |
+
if not results.ok:
|
132 |
+
return await m.edit(results.result)
|
133 |
+
results = results.result
|
134 |
+
await m.edit(
|
135 |
+
f"""
|
136 |
+
**➢ Neutral:** `{results.neutral} %`
|
137 |
+
**➢ Porn:** `{results.porn} %`
|
138 |
+
**➢ Hentai:** `{results.hentai} %`
|
139 |
+
**➢ Sexy:** `{results.sexy} %`
|
140 |
+
**➢ Drawings:** `{results.drawings} %`
|
141 |
+
**➢ NSFW:** `{results.is_nsfw}`
|
142 |
+
"""
|
143 |
+
)
|
144 |
+
|
145 |
+
|
146 |
+
@app.on_message(
|
147 |
+
filters.command(["antinsfw", f"antinsfw@{BOT_USERNAME}"]) & ~filters.private
|
148 |
+
)
|
149 |
+
@can_restrict
|
150 |
+
async def nsfw_enable_disable(_, message):
|
151 |
+
if len(message.command) != 2:
|
152 |
+
await message.reply_text("Usage: /antinsfw [on/off]")
|
153 |
+
return
|
154 |
+
status = message.text.split(None, 1)[1].strip()
|
155 |
+
status = status.lower()
|
156 |
+
chat_id = message.chat.id
|
157 |
+
if status in ("on", "yes"):
|
158 |
+
if await is_nsfw_on(chat_id):
|
159 |
+
await message.reply_text("Antinsfw is already enabled.")
|
160 |
+
return
|
161 |
+
await nsfw_on(chat_id)
|
162 |
+
await message.reply_text(
|
163 |
+
"Enabled AntiNSFW System. I will Delete Messages Containing Inappropriate Content."
|
164 |
+
)
|
165 |
+
elif status in ("off", "no"):
|
166 |
+
if not await is_nsfw_on(chat_id):
|
167 |
+
await message.reply_text("Antinsfw is already disabled.")
|
168 |
+
return
|
169 |
+
await nsfw_off(chat_id)
|
170 |
+
await message.reply_text("Disabled AntiNSFW System.")
|
171 |
+
else:
|
172 |
+
await message.reply_text("Unknown Suffix, Use /antinsfw [on/off]")
|
173 |
+
|
174 |
+
|
175 |
+
# <=================================================== HELP ====================================================>
|
176 |
+
|
177 |
+
|
178 |
+
__mod_name__ = "ANTI-NSFW"
|
179 |
+
|
180 |
+
__help__ = """
|
181 |
+
*🔞 Helps in detecting NSFW material and removing it*.
|
182 |
+
|
183 |
+
➠ *Usage:*
|
184 |
+
|
185 |
+
» /antinsfw [on/off]: Enables Anti-NSFW system.
|
186 |
+
|
187 |
+
» /nsfwscan <reply to message>: Scans the file replied to.
|
188 |
+
"""
|
189 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/ban.py
ADDED
@@ -0,0 +1,1045 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
from random import choice
|
3 |
+
from traceback import format_exc
|
4 |
+
|
5 |
+
from pyrogram import enums
|
6 |
+
from pyrogram.errors import (
|
7 |
+
ChatAdminRequired,
|
8 |
+
PeerIdInvalid,
|
9 |
+
RightForbidden,
|
10 |
+
RPCError,
|
11 |
+
UserAdminInvalid,
|
12 |
+
)
|
13 |
+
from pyrogram.filters import regex
|
14 |
+
from pyrogram.types import (
|
15 |
+
CallbackQuery,
|
16 |
+
InlineKeyboardButton,
|
17 |
+
InlineKeyboardMarkup,
|
18 |
+
Message,
|
19 |
+
)
|
20 |
+
|
21 |
+
from Infamous.karma import BAN_GIFS, KICK_GIFS
|
22 |
+
from Mikobot import BOT_ID, LOGGER, MESSAGE_DUMP, OWNER_ID, SUPPORT_STAFF, app
|
23 |
+
from Mikobot.utils.caching import ADMIN_CACHE, admin_cache_reload
|
24 |
+
from Mikobot.utils.custom_filters import command, restrict_filter
|
25 |
+
from Mikobot.utils.extract_user import extract_user
|
26 |
+
from Mikobot.utils.parser import mention_html
|
27 |
+
from Mikobot.utils.string import extract_time
|
28 |
+
|
29 |
+
# <=======================================================================================================>
|
30 |
+
|
31 |
+
|
32 |
+
# <================================================ FUNCTION =======================================================>
|
33 |
+
@app.on_message(command("tban") & restrict_filter)
|
34 |
+
async def tban_usr(c: app, m: Message):
|
35 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
36 |
+
await m.reply_text(text="I can't ban nothing!")
|
37 |
+
await m.stop_propagation()
|
38 |
+
|
39 |
+
try:
|
40 |
+
user_id, user_first_name, _ = await extract_user(c, m)
|
41 |
+
except Exception:
|
42 |
+
return
|
43 |
+
|
44 |
+
if not user_id:
|
45 |
+
await m.reply_text("Cannot find user to ban")
|
46 |
+
return
|
47 |
+
if user_id == BOT_ID:
|
48 |
+
await m.reply_text("WTF?? Why would I ban myself?")
|
49 |
+
await m.stop_propagation()
|
50 |
+
|
51 |
+
if user_id in SUPPORT_STAFF:
|
52 |
+
await m.reply_text(
|
53 |
+
text="This user is in my support staff, cannot restrict them."
|
54 |
+
)
|
55 |
+
LOGGER.info(
|
56 |
+
f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
57 |
+
)
|
58 |
+
await m.stop_propagation()
|
59 |
+
|
60 |
+
r_id = m.reply_to_message.id if m.reply_to_message else m.id
|
61 |
+
|
62 |
+
if m.reply_to_message and len(m.text.split()) >= 2:
|
63 |
+
reason = m.text.split(None, 1)[1]
|
64 |
+
elif not m.reply_to_message and len(m.text.split()) >= 3:
|
65 |
+
reason = m.text.split(None, 2)[2]
|
66 |
+
else:
|
67 |
+
await m.reply_text("Read /help !!")
|
68 |
+
return
|
69 |
+
|
70 |
+
if not reason:
|
71 |
+
await m.reply_text("You haven't specified a time to ban this user for!")
|
72 |
+
return
|
73 |
+
|
74 |
+
split_reason = reason.split(None, 1)
|
75 |
+
time_val = split_reason[0].lower()
|
76 |
+
reason = split_reason[1] if len(split_reason) > 1 else ""
|
77 |
+
|
78 |
+
bantime = await extract_time(m, time_val)
|
79 |
+
|
80 |
+
if not bantime:
|
81 |
+
return
|
82 |
+
|
83 |
+
try:
|
84 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
85 |
+
except KeyError:
|
86 |
+
admins_group = await admin_cache_reload(m, "ban")
|
87 |
+
|
88 |
+
if user_id in admins_group:
|
89 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
90 |
+
await m.stop_propagation()
|
91 |
+
|
92 |
+
try:
|
93 |
+
admin = await mention_html(m.from_user.first_name, m.from_user.id)
|
94 |
+
banned = await mention_html(user_first_name, user_id)
|
95 |
+
chat_title = m.chat.title
|
96 |
+
LOGGER.info(f"{m.from_user.id} tbanned {user_id} in {m.chat.id}")
|
97 |
+
await m.chat.ban_member(user_id, until_date=bantime)
|
98 |
+
t_t = (f"{admin} banned {banned} in <b>{chat_title}</b>!",)
|
99 |
+
txt = t_t
|
100 |
+
if type(t_t) is tuple:
|
101 |
+
txt = t_t[
|
102 |
+
0
|
103 |
+
] # Done this bcuz idk why t_t is tuple type data. SO now if it is tuple this will get text from it
|
104 |
+
if reason:
|
105 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
106 |
+
else:
|
107 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
108 |
+
if time_val:
|
109 |
+
txt += f"\n<b>Banned for</b>:{time_val}"
|
110 |
+
keyboard = InlineKeyboardMarkup(
|
111 |
+
[
|
112 |
+
[
|
113 |
+
InlineKeyboardButton(
|
114 |
+
"UNBAN",
|
115 |
+
callback_data=f"unban_={user_id}",
|
116 |
+
),
|
117 |
+
],
|
118 |
+
],
|
119 |
+
)
|
120 |
+
anim = choice(BAN_GIFS)
|
121 |
+
try:
|
122 |
+
await m.reply_animation(
|
123 |
+
reply_to_message_id=r_id,
|
124 |
+
animation=str(anim),
|
125 |
+
caption=txt,
|
126 |
+
reply_markup=keyboard,
|
127 |
+
parse_mode=enums.ParseMode.HTML,
|
128 |
+
)
|
129 |
+
except Exception:
|
130 |
+
await m.reply_text(
|
131 |
+
reply_to_message_id=r_id,
|
132 |
+
text=txt,
|
133 |
+
reply_markup=keyboard,
|
134 |
+
parse_mode=enums.ParseMode.HTML,
|
135 |
+
)
|
136 |
+
await c.send_message(MESSAGE_DUMP, f"#REMOVE from BAN_GFIS\n{anim}")
|
137 |
+
# await m.reply_text(txt, reply_markup=keyboard,
|
138 |
+
# reply_to_message_id=r_id)
|
139 |
+
except ChatAdminRequired:
|
140 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
141 |
+
except PeerIdInvalid:
|
142 |
+
await m.reply_text(
|
143 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
144 |
+
)
|
145 |
+
except UserAdminInvalid:
|
146 |
+
await m.reply_text(
|
147 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
148 |
+
)
|
149 |
+
except RightForbidden:
|
150 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
151 |
+
except RPCError as ef:
|
152 |
+
await m.reply_text(
|
153 |
+
(
|
154 |
+
f"""Some error occured, report it using `/bug`
|
155 |
+
|
156 |
+
<b>Error:</b> <code>{ef}</code>"""
|
157 |
+
)
|
158 |
+
)
|
159 |
+
LOGGER.error(ef)
|
160 |
+
LOGGER.error(format_exc())
|
161 |
+
return
|
162 |
+
|
163 |
+
|
164 |
+
@app.on_message(command("stban") & restrict_filter)
|
165 |
+
async def stban_usr(c: app, m: Message):
|
166 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
167 |
+
await m.reply_text(text="I can't ban nothing!")
|
168 |
+
await m.stop_propagation()
|
169 |
+
|
170 |
+
try:
|
171 |
+
user_id, _, _ = await extract_user(c, m)
|
172 |
+
except Exception:
|
173 |
+
return
|
174 |
+
|
175 |
+
if not user_id:
|
176 |
+
await m.reply_text("Cannot find user to ban")
|
177 |
+
return
|
178 |
+
if user_id == BOT_ID:
|
179 |
+
await m.reply_text("What the heck? Why would I ban myself?")
|
180 |
+
await m.stop_propagation()
|
181 |
+
|
182 |
+
if user_id in SUPPORT_STAFF:
|
183 |
+
await m.reply_text(
|
184 |
+
text="This user is in my support staff, cannot restrict them."
|
185 |
+
)
|
186 |
+
LOGGER.info(
|
187 |
+
f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
188 |
+
)
|
189 |
+
await m.stop_propagation()
|
190 |
+
|
191 |
+
if m.reply_to_message and len(m.text.split()) >= 2:
|
192 |
+
reason = m.text.split(None, 1)[1]
|
193 |
+
elif not m.reply_to_message and len(m.text.split()) >= 3:
|
194 |
+
reason = m.text.split(None, 2)[2]
|
195 |
+
else:
|
196 |
+
await m.reply_text("Read /help !!")
|
197 |
+
return
|
198 |
+
|
199 |
+
if not reason:
|
200 |
+
await m.reply_text("You haven't specified a time to ban this user for!")
|
201 |
+
return
|
202 |
+
|
203 |
+
split_reason = reason.split(None, 1)
|
204 |
+
time_val = split_reason[0].lower()
|
205 |
+
reason = split_reason[1] if len(split_reason) > 1 else ""
|
206 |
+
|
207 |
+
bantime = await extract_time(m, time_val)
|
208 |
+
|
209 |
+
if not bantime:
|
210 |
+
return
|
211 |
+
|
212 |
+
try:
|
213 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
214 |
+
except KeyError:
|
215 |
+
admins_group = await admin_cache_reload(m, "ban")
|
216 |
+
|
217 |
+
if user_id in admins_group:
|
218 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
219 |
+
await m.stop_propagation()
|
220 |
+
|
221 |
+
try:
|
222 |
+
LOGGER.info(f"{m.from_user.id} stbanned {user_id} in {m.chat.id}")
|
223 |
+
await m.chat.ban_member(user_id, until_date=bantime)
|
224 |
+
await m.delete()
|
225 |
+
if m.reply_to_message:
|
226 |
+
await m.reply_to_message.delete()
|
227 |
+
return
|
228 |
+
return
|
229 |
+
except ChatAdminRequired:
|
230 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
231 |
+
except PeerIdInvalid:
|
232 |
+
await m.reply_text(
|
233 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
234 |
+
)
|
235 |
+
except UserAdminInvalid:
|
236 |
+
await m.reply_text(
|
237 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
238 |
+
)
|
239 |
+
except RightForbidden:
|
240 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
241 |
+
except RPCError as ef:
|
242 |
+
await m.reply_text(
|
243 |
+
text=f"""Some error occured, report it using `/bug`
|
244 |
+
|
245 |
+
<b>Error:</b> <code>{ef}</code>"""
|
246 |
+
)
|
247 |
+
LOGGER.error(ef)
|
248 |
+
LOGGER.error(format_exc())
|
249 |
+
return
|
250 |
+
|
251 |
+
|
252 |
+
@app.on_message(command("dtban") & restrict_filter)
|
253 |
+
async def dtban_usr(c: app, m: Message):
|
254 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
255 |
+
await m.reply_text(text="I can't ban nothing!")
|
256 |
+
await m.stop_propagation()
|
257 |
+
|
258 |
+
if not m.reply_to_message:
|
259 |
+
await m.reply_text(
|
260 |
+
"Reply to a message with this command to temp ban and delete the message.",
|
261 |
+
)
|
262 |
+
await m.stop_propagation()
|
263 |
+
|
264 |
+
user_id = m.reply_to_message.from_user.id
|
265 |
+
user_first_name = m.reply_to_message.from_user.first_name
|
266 |
+
|
267 |
+
if not user_id:
|
268 |
+
await m.reply_text("Cannot find user to ban")
|
269 |
+
return
|
270 |
+
if user_id == BOT_ID:
|
271 |
+
await m.reply_text("Huh, why would I ban myself?")
|
272 |
+
await m.stop_propagation()
|
273 |
+
|
274 |
+
if user_id in SUPPORT_STAFF:
|
275 |
+
await m.reply_text(text="I am not going to ban one of my support staff")
|
276 |
+
LOGGER.info(
|
277 |
+
f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
278 |
+
)
|
279 |
+
await m.stop_propagation()
|
280 |
+
|
281 |
+
if m.reply_to_message and len(m.text.split()) >= 2:
|
282 |
+
reason = m.text.split(None, 1)[1]
|
283 |
+
elif not m.reply_to_message and len(m.text.split()) >= 3:
|
284 |
+
reason = m.text.split(None, 2)[2]
|
285 |
+
else:
|
286 |
+
await m.reply_text("Read /help !!")
|
287 |
+
return
|
288 |
+
|
289 |
+
if not reason:
|
290 |
+
await m.reply_text("You haven't specified a time to ban this user for!")
|
291 |
+
return
|
292 |
+
|
293 |
+
split_reason = reason.split(None, 1)
|
294 |
+
time_val = split_reason[0].lower()
|
295 |
+
reason = split_reason[1] if len(split_reason) > 1 else ""
|
296 |
+
|
297 |
+
bantime = await extract_time(m, time_val)
|
298 |
+
|
299 |
+
if not bantime:
|
300 |
+
return
|
301 |
+
|
302 |
+
try:
|
303 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
304 |
+
except KeyError:
|
305 |
+
admins_group = await admin_cache_reload(m, "ban")
|
306 |
+
|
307 |
+
if user_id in admins_group:
|
308 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
309 |
+
await m.stop_propagation()
|
310 |
+
|
311 |
+
try:
|
312 |
+
admin = await mention_html(m.from_user.first_name, m.from_user.id)
|
313 |
+
banned = await mention_html(user_first_name, user_id)
|
314 |
+
chat_title = m.chat.title
|
315 |
+
LOGGER.info(f"{m.from_user.id} dtbanned {user_id} in {m.chat.id}")
|
316 |
+
await m.chat.ban_member(user_id, until_date=bantime)
|
317 |
+
await m.reply_to_message.delete()
|
318 |
+
txt = f"{admin} banned {banned} in <b>{chat_title}</b>!"
|
319 |
+
if reason:
|
320 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
321 |
+
else:
|
322 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
323 |
+
|
324 |
+
if bantime:
|
325 |
+
txt += f"\n<b>Banned for</b>: {time_val}"
|
326 |
+
keyboard = InlineKeyboardMarkup(
|
327 |
+
[
|
328 |
+
[
|
329 |
+
InlineKeyboardButton(
|
330 |
+
"UNBAN",
|
331 |
+
callback_data=f"unban_={user_id}",
|
332 |
+
),
|
333 |
+
],
|
334 |
+
],
|
335 |
+
)
|
336 |
+
anim = choice(BAN_GIFS)
|
337 |
+
try:
|
338 |
+
await m.reply_animation(
|
339 |
+
animation=str(anim),
|
340 |
+
caption=txt,
|
341 |
+
reply_markup=keyboard,
|
342 |
+
parse_mode=enums.ParseMode.HTML,
|
343 |
+
)
|
344 |
+
except Exception:
|
345 |
+
await m.reply_text(
|
346 |
+
txt,
|
347 |
+
reply_markup=keyboard,
|
348 |
+
parse_mode=enums.ParseMode.HTML,
|
349 |
+
)
|
350 |
+
await c.send_message(MESSAGE_DUMP, f"#REMOVE from BAN_GFIS\n{anim}")
|
351 |
+
# await c.send_message(m.chat.id, txt, reply_markup=keyboard)
|
352 |
+
except ChatAdminRequired:
|
353 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
354 |
+
except PeerIdInvalid:
|
355 |
+
await m.reply_text(
|
356 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
357 |
+
)
|
358 |
+
except UserAdminInvalid:
|
359 |
+
await m.reply_text(
|
360 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
361 |
+
)
|
362 |
+
except RightForbidden:
|
363 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
364 |
+
except RPCError as ef:
|
365 |
+
await m.reply_text(
|
366 |
+
text=f"""Some error occured, report it using `/bug`
|
367 |
+
|
368 |
+
<b>Error:</b> <code>{ef}</code>"""
|
369 |
+
)
|
370 |
+
LOGGER.error(ef)
|
371 |
+
LOGGER.error(format_exc())
|
372 |
+
return
|
373 |
+
|
374 |
+
|
375 |
+
@app.on_message(command("kick") & restrict_filter)
|
376 |
+
async def kick_usr(c: app, m: Message):
|
377 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
378 |
+
await m.reply_text(text="I can't kick nothing!")
|
379 |
+
return
|
380 |
+
|
381 |
+
reason = None
|
382 |
+
|
383 |
+
if m.reply_to_message:
|
384 |
+
r_id = m.reply_to_message.id
|
385 |
+
if len(m.text.split()) >= 2:
|
386 |
+
reason = m.text.split(None, 1)[1]
|
387 |
+
else:
|
388 |
+
r_id = m.id
|
389 |
+
if len(m.text.split()) >= 3:
|
390 |
+
reason = m.text.split(None, 2)[2]
|
391 |
+
try:
|
392 |
+
user_id, user_first_name, _ = await extract_user(c, m)
|
393 |
+
except Exception:
|
394 |
+
return
|
395 |
+
|
396 |
+
if not user_id:
|
397 |
+
await m.reply_text("Cannot find user to kick")
|
398 |
+
return
|
399 |
+
|
400 |
+
if user_id == BOT_ID:
|
401 |
+
await m.reply_text("Huh, why would I kick myself?")
|
402 |
+
await m.stop_propagation()
|
403 |
+
|
404 |
+
if user_id in SUPPORT_STAFF:
|
405 |
+
await m.reply_text(
|
406 |
+
text="This user is in my support staff, cannot restrict them."
|
407 |
+
)
|
408 |
+
LOGGER.info(
|
409 |
+
f"{m.from_user.id} trying to kick {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
410 |
+
)
|
411 |
+
await m.stop_propagation()
|
412 |
+
|
413 |
+
try:
|
414 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
415 |
+
except KeyError:
|
416 |
+
admins_group = await admin_cache_reload(m, "kick")
|
417 |
+
|
418 |
+
if user_id in admins_group:
|
419 |
+
await m.reply_text(text="This user is an admin, I cannot kick them!")
|
420 |
+
await m.stop_propagation()
|
421 |
+
|
422 |
+
try:
|
423 |
+
admin = await mention_html(m.from_user.first_name, m.from_user.id)
|
424 |
+
kicked = await mention_html(user_first_name, user_id)
|
425 |
+
chat_title = m.chat.title
|
426 |
+
LOGGER.info(f"{m.from_user.id} kicked {user_id} in {m.chat.id}")
|
427 |
+
await m.chat.ban_member(user_id)
|
428 |
+
txt = f"{admin} kicked {kicked} in <b>{chat_title}</b>!"
|
429 |
+
if reason:
|
430 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
431 |
+
else:
|
432 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
433 |
+
# await m.reply_text(txt, reply_to_message_id=r_id)
|
434 |
+
kickk = choice(KICK_GIFS)
|
435 |
+
try:
|
436 |
+
await m.reply_animation(
|
437 |
+
reply_to_message_id=r_id,
|
438 |
+
animation=str(kickk),
|
439 |
+
caption=txt,
|
440 |
+
parse_mode=enums.ParseMode.HTML,
|
441 |
+
)
|
442 |
+
except:
|
443 |
+
await m.reply_text(
|
444 |
+
reply_to_message_id=r_id,
|
445 |
+
text=txt,
|
446 |
+
parse_mode=enums.ParseMode.HTML,
|
447 |
+
)
|
448 |
+
await c.send_message(MESSAGE_DUMP, f"#REMOVE from KICK_GFIS\n{kickk}")
|
449 |
+
await m.chat.unban_member(user_id)
|
450 |
+
except ChatAdminRequired:
|
451 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
452 |
+
except PeerIdInvalid:
|
453 |
+
await m.reply_text(
|
454 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
455 |
+
)
|
456 |
+
except UserAdminInvalid:
|
457 |
+
await m.reply_text(
|
458 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
459 |
+
)
|
460 |
+
except RightForbidden:
|
461 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
462 |
+
except RPCError as ef:
|
463 |
+
await m.reply_text(
|
464 |
+
text=f"""Some error occured, report it using `/bug`
|
465 |
+
|
466 |
+
<b>Error:</b> <code>{ef}</code>"""
|
467 |
+
)
|
468 |
+
LOGGER.error(ef)
|
469 |
+
LOGGER.error(format_exc())
|
470 |
+
|
471 |
+
return
|
472 |
+
|
473 |
+
|
474 |
+
@app.on_message(command("skick") & restrict_filter)
|
475 |
+
async def skick_usr(c: app, m: Message):
|
476 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
477 |
+
await m.reply_text(text="I can't kick nothing!")
|
478 |
+
return
|
479 |
+
|
480 |
+
try:
|
481 |
+
user_id, _, _ = await extract_user(c, m)
|
482 |
+
except Exception:
|
483 |
+
return
|
484 |
+
|
485 |
+
if not user_id:
|
486 |
+
await m.reply_text("Cannot find user to kick")
|
487 |
+
return
|
488 |
+
|
489 |
+
if user_id == BOT_ID:
|
490 |
+
await m.reply_text("Huh, why would I kick myself?")
|
491 |
+
await m.stop_propagation()
|
492 |
+
|
493 |
+
if user_id in SUPPORT_STAFF:
|
494 |
+
await m.reply_text(
|
495 |
+
text="This user is in my support staff, cannot restrict them."
|
496 |
+
)
|
497 |
+
LOGGER.info(
|
498 |
+
f"{m.from_user.id} trying to skick {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
499 |
+
)
|
500 |
+
await m.stop_propagation()
|
501 |
+
|
502 |
+
try:
|
503 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
504 |
+
except KeyError:
|
505 |
+
admins_group = await admin_cache_reload(m, "kick")
|
506 |
+
|
507 |
+
if user_id in admins_group:
|
508 |
+
await m.reply_text(text="This user is an admin, I cannot kick them!")
|
509 |
+
await m.stop_propagation()
|
510 |
+
|
511 |
+
try:
|
512 |
+
LOGGER.info(f"{m.from_user.id} skicked {user_id} in {m.chat.id}")
|
513 |
+
await m.chat.ban_member(user_id)
|
514 |
+
await m.delete()
|
515 |
+
if m.reply_to_message:
|
516 |
+
await m.reply_to_message.delete()
|
517 |
+
await m.chat.unban_member(user_id)
|
518 |
+
except ChatAdminRequired:
|
519 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
520 |
+
except PeerIdInvalid:
|
521 |
+
await m.reply_text(
|
522 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
523 |
+
)
|
524 |
+
except UserAdminInvalid:
|
525 |
+
await m.reply_text(
|
526 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
527 |
+
)
|
528 |
+
except RightForbidden:
|
529 |
+
await m.reply_text(text="I don't have enough rights to kick this user.")
|
530 |
+
except RPCError as ef:
|
531 |
+
await m.reply_text(
|
532 |
+
text=f"""Some error occured, report it using `/bug`
|
533 |
+
|
534 |
+
<b>Error:</b> <code>{ef}</code>"""
|
535 |
+
)
|
536 |
+
LOGGER.error(ef)
|
537 |
+
LOGGER.error(format_exc())
|
538 |
+
|
539 |
+
return
|
540 |
+
|
541 |
+
|
542 |
+
@app.on_message(command("dkick") & restrict_filter)
|
543 |
+
async def dkick_usr(c: app, m: Message):
|
544 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
545 |
+
await m.reply_text(text="I can't ban nothing!")
|
546 |
+
return
|
547 |
+
if not m.reply_to_message:
|
548 |
+
return await m.reply_text("Reply to a message to delete it and kick the user!")
|
549 |
+
|
550 |
+
reason = None
|
551 |
+
|
552 |
+
user_id = m.reply_to_message.from_user.id
|
553 |
+
user_first_name = m.reply_to_message.from_user.first_name
|
554 |
+
|
555 |
+
if not user_id:
|
556 |
+
await m.reply_text("Cannot find user to kick")
|
557 |
+
return
|
558 |
+
|
559 |
+
if user_id == BOT_ID:
|
560 |
+
await m.reply_text("Huh, why would I kick myself?")
|
561 |
+
await m.stop_propagation()
|
562 |
+
|
563 |
+
if user_id in SUPPORT_STAFF:
|
564 |
+
await m.reply_text(
|
565 |
+
text="This user is in my support staff, cannot restrict them."
|
566 |
+
)
|
567 |
+
LOGGER.info(
|
568 |
+
f"{m.from_user.id} trying to dkick {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
569 |
+
)
|
570 |
+
await m.stop_propagation()
|
571 |
+
|
572 |
+
try:
|
573 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
574 |
+
except KeyError:
|
575 |
+
admins_group = await admin_cache_reload(m, "kick")
|
576 |
+
|
577 |
+
if user_id in admins_group:
|
578 |
+
await m.reply_text(text="This user is an admin, I cannot kick them!")
|
579 |
+
await m.stop_propagation()
|
580 |
+
|
581 |
+
try:
|
582 |
+
LOGGER.info(f"{m.from_user.id} dkicked {user_id} in {m.chat.id}")
|
583 |
+
await m.reply_to_message.delete()
|
584 |
+
await m.chat.ban_member(user_id)
|
585 |
+
admin = await mention_html(m.from_user.first_name, m.from_user.id)
|
586 |
+
kicked = await mention_html(user_first_name, user_id)
|
587 |
+
chat_title = m.chat.title
|
588 |
+
txt = f"{admin} kicked {kicked} in <b>{chat_title}</b>!"
|
589 |
+
if reason:
|
590 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
591 |
+
else:
|
592 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
593 |
+
kickk = choice(KICK_GIFS)
|
594 |
+
try:
|
595 |
+
await m.reply_animation(
|
596 |
+
animation=str(kickk),
|
597 |
+
caption=txt,
|
598 |
+
parse_mode=enums.ParseMode.HTML,
|
599 |
+
)
|
600 |
+
except:
|
601 |
+
await m.reply_text(
|
602 |
+
txt,
|
603 |
+
parse_mode=enums.ParseMode.HTML,
|
604 |
+
)
|
605 |
+
await c.send_message(MESSAGE_DUMP, f"#REMOVE from KICK_GFIS\n{kickk}")
|
606 |
+
await m.chat.unban_member(user_id)
|
607 |
+
except ChatAdminRequired:
|
608 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
609 |
+
except PeerIdInvalid:
|
610 |
+
await m.reply_text(
|
611 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
612 |
+
)
|
613 |
+
except UserAdminInvalid:
|
614 |
+
await m.reply_text(
|
615 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
616 |
+
)
|
617 |
+
except RightForbidden:
|
618 |
+
await m.reply_text(text="I don't have enough rights to kick this user.")
|
619 |
+
except RPCError as ef:
|
620 |
+
await m.reply_text(
|
621 |
+
text=f"""Some error occured, report it using `/bug`
|
622 |
+
|
623 |
+
<b>Error:</b> <code>{ef}</code>"""
|
624 |
+
)
|
625 |
+
LOGGER.error(ef)
|
626 |
+
LOGGER.error(format_exc())
|
627 |
+
|
628 |
+
return
|
629 |
+
|
630 |
+
|
631 |
+
@app.on_message(command("unban") & restrict_filter)
|
632 |
+
async def unban_usr(c: app, m: Message):
|
633 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
634 |
+
await m.reply_text(text="I can't unban nothing!")
|
635 |
+
await m.stop_propagation()
|
636 |
+
|
637 |
+
if m.reply_to_message and not m.reply_to_message.from_user:
|
638 |
+
user_id, user_first_name = (
|
639 |
+
m.reply_to_message.sender_chat.id,
|
640 |
+
m.reply_to_message.sender_chat.title,
|
641 |
+
)
|
642 |
+
else:
|
643 |
+
try:
|
644 |
+
user_id, user_first_name, _ = await extract_user(c, m)
|
645 |
+
except Exception:
|
646 |
+
return
|
647 |
+
|
648 |
+
if m.reply_to_message and len(m.text.split()) >= 2:
|
649 |
+
reason = m.text.split(None, 2)[1]
|
650 |
+
elif not m.reply_to_message and len(m.text.split()) >= 3:
|
651 |
+
reason = m.text.split(None, 2)[2]
|
652 |
+
else:
|
653 |
+
reason = None
|
654 |
+
|
655 |
+
try:
|
656 |
+
statu = (await m.chat.get_member(user_id)).status
|
657 |
+
if statu not in [
|
658 |
+
enums.ChatMemberStatus.BANNED,
|
659 |
+
enums.ChatMemberStatus.RESTRICTED,
|
660 |
+
]:
|
661 |
+
await m.reply_text(
|
662 |
+
"User is not banned in this chat\nOr using this command as reply to his message"
|
663 |
+
)
|
664 |
+
return
|
665 |
+
except Exception as e:
|
666 |
+
LOGGER.error(e)
|
667 |
+
LOGGER.exception(format_exc())
|
668 |
+
try:
|
669 |
+
await m.chat.unban_member(user_id)
|
670 |
+
admin = m.from_user.mention
|
671 |
+
unbanned = await mention_html(user_first_name, user_id)
|
672 |
+
chat_title = (m.chat.title,)
|
673 |
+
txt = f"{admin} unbanned {unbanned} in chat <b>{chat_title}</b>!"
|
674 |
+
if reason:
|
675 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
676 |
+
else:
|
677 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
678 |
+
await m.reply_text(txt)
|
679 |
+
except ChatAdminRequired:
|
680 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
681 |
+
except RightForbidden:
|
682 |
+
await m.reply_text(text="I don't have enough rights to unban this user.")
|
683 |
+
except RPCError as ef:
|
684 |
+
await m.reply_text(
|
685 |
+
text=f"""Some error occured, report it using `/bug`
|
686 |
+
|
687 |
+
<b>Error:</b> <code>{ef}</code>"""
|
688 |
+
)
|
689 |
+
LOGGER.error(ef)
|
690 |
+
LOGGER.error(format_exc())
|
691 |
+
|
692 |
+
return
|
693 |
+
|
694 |
+
|
695 |
+
@app.on_message(command("sban") & restrict_filter)
|
696 |
+
async def sban_usr(c: app, m: Message):
|
697 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
698 |
+
await m.reply_text(text="I can't ban nothing!")
|
699 |
+
await m.stop_propagation()
|
700 |
+
|
701 |
+
if m.reply_to_message and not m.reply_to_message.from_user:
|
702 |
+
user_id = m.reply_to_message.sender_chat.id
|
703 |
+
else:
|
704 |
+
try:
|
705 |
+
user_id, _, _ = await extract_user(c, m)
|
706 |
+
except Exception:
|
707 |
+
return
|
708 |
+
|
709 |
+
if not user_id:
|
710 |
+
await m.reply_text("Cannot find user to ban")
|
711 |
+
return
|
712 |
+
if user_id == m.chat.id:
|
713 |
+
await m.reply_text("That's an admin!")
|
714 |
+
await m.stop_propagation()
|
715 |
+
if user_id == BOT_ID:
|
716 |
+
await m.reply_text("Huh, why would I ban myself?")
|
717 |
+
await m.stop_propagation()
|
718 |
+
|
719 |
+
if user_id in SUPPORT_STAFF:
|
720 |
+
await m.reply_text(
|
721 |
+
text="This user is in my support staff, cannot restrict them."
|
722 |
+
)
|
723 |
+
LOGGER.info(
|
724 |
+
f"{m.from_user.id} trying to sban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
725 |
+
)
|
726 |
+
await m.stop_propagation()
|
727 |
+
|
728 |
+
try:
|
729 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
730 |
+
except KeyError:
|
731 |
+
admins_group = await admin_cache_reload(m, "ban")
|
732 |
+
|
733 |
+
if user_id in admins_group:
|
734 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
735 |
+
await m.stop_propagation()
|
736 |
+
|
737 |
+
try:
|
738 |
+
LOGGER.info(f"{m.from_user.id} sbanned {user_id} in {m.chat.id}")
|
739 |
+
await m.chat.ban_member(user_id)
|
740 |
+
await m.delete()
|
741 |
+
if m.reply_to_message:
|
742 |
+
await m.reply_to_message.delete()
|
743 |
+
except ChatAdminRequired:
|
744 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
745 |
+
except PeerIdInvalid:
|
746 |
+
await m.reply_text(
|
747 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
748 |
+
)
|
749 |
+
except UserAdminInvalid:
|
750 |
+
await m.reply_text(
|
751 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
752 |
+
)
|
753 |
+
except RightForbidden:
|
754 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
755 |
+
except RPCError as ef:
|
756 |
+
await m.reply_text(
|
757 |
+
text=f"""Some error occured, report it using `/bug`
|
758 |
+
|
759 |
+
<b>Error:</b> <code>{ef}</code>"""
|
760 |
+
)
|
761 |
+
LOGGER.error(ef)
|
762 |
+
LOGGER.error(format_exc())
|
763 |
+
return
|
764 |
+
|
765 |
+
|
766 |
+
@app.on_message(command("dban") & restrict_filter)
|
767 |
+
async def dban_usr(c: app, m: Message):
|
768 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
769 |
+
await m.reply_text(text="I can't ban nothing!")
|
770 |
+
await m.stop_propagation()
|
771 |
+
|
772 |
+
if not m.reply_to_message:
|
773 |
+
return await m.reply_text("Reply to a message to delete it and ban the user!")
|
774 |
+
|
775 |
+
if m.reply_to_message and not m.reply_to_message.from_user:
|
776 |
+
user_id, user_first_name = (
|
777 |
+
m.reply_to_message.sender_chat.id,
|
778 |
+
m.reply_to_message.sender_chat.title,
|
779 |
+
)
|
780 |
+
else:
|
781 |
+
user_id, user_first_name = (
|
782 |
+
m.reply_to_message.from_user.id,
|
783 |
+
m.reply_to_message.from_user.first_name,
|
784 |
+
)
|
785 |
+
|
786 |
+
if not user_id:
|
787 |
+
await m.reply_text("Cannot find user to ban")
|
788 |
+
return
|
789 |
+
if user_id == m.chat.id:
|
790 |
+
await m.reply_text("That's an admin!")
|
791 |
+
await m.stop_propagation()
|
792 |
+
if user_id == BOT_ID:
|
793 |
+
await m.reply_text("Huh, why would I ban myself?")
|
794 |
+
await m.stop_propagation()
|
795 |
+
|
796 |
+
if user_id in SUPPORT_STAFF:
|
797 |
+
await m.reply_text(
|
798 |
+
text="This user is in my support staff, cannot restrict them."
|
799 |
+
)
|
800 |
+
LOGGER.info(
|
801 |
+
f"{m.from_user.id} trying to dban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
802 |
+
)
|
803 |
+
await m.stop_propagation()
|
804 |
+
|
805 |
+
try:
|
806 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
807 |
+
except KeyError:
|
808 |
+
admins_group = await admin_cache_reload(m, "ban")
|
809 |
+
|
810 |
+
if user_id in admins_group:
|
811 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
812 |
+
await m.stop_propagation()
|
813 |
+
|
814 |
+
reason = None
|
815 |
+
if len(m.text.split()) >= 2:
|
816 |
+
reason = m.text.split(None, 1)[1]
|
817 |
+
|
818 |
+
try:
|
819 |
+
LOGGER.info(f"{m.from_user.id} dbanned {user_id} in {m.chat.id}")
|
820 |
+
await m.reply_to_message.delete()
|
821 |
+
await m.chat.ban_member(user_id)
|
822 |
+
txt = f"{m.from_user.mention} banned {m.reply_to_message.from_user.mention} in <b>{m.chat.title}</b>!"
|
823 |
+
if reason:
|
824 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
825 |
+
else:
|
826 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
827 |
+
keyboard = InlineKeyboardMarkup(
|
828 |
+
[
|
829 |
+
[
|
830 |
+
InlineKeyboardButton(
|
831 |
+
"UNBAN",
|
832 |
+
callback_data=f"unban_={user_id}",
|
833 |
+
),
|
834 |
+
],
|
835 |
+
],
|
836 |
+
)
|
837 |
+
animm = choice(BAN_GIFS)
|
838 |
+
try:
|
839 |
+
await c.send_animation(
|
840 |
+
m.chat.id, animation=str(animm), caption=txt, reply_markup=keyboard
|
841 |
+
)
|
842 |
+
except Exception:
|
843 |
+
await c.send_message(
|
844 |
+
m.chat.id, txt, enums.ParseMode.HTML, reply_markup=keyboard
|
845 |
+
)
|
846 |
+
await c.send_messagea(MESSAGE_DUMP, f"#REMOVE from BAN_GIFS\n{animm}")
|
847 |
+
except ChatAdminRequired:
|
848 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
849 |
+
except PeerIdInvalid:
|
850 |
+
await m.reply_text(
|
851 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
852 |
+
)
|
853 |
+
except UserAdminInvalid:
|
854 |
+
await m.reply_text(
|
855 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
856 |
+
)
|
857 |
+
except RightForbidden:
|
858 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
859 |
+
except RPCError as ef:
|
860 |
+
await m.reply_text(
|
861 |
+
text=f"""Some error occured, report it using `/bug`
|
862 |
+
|
863 |
+
<b>Error:</b> <code>{ef}</code>"""
|
864 |
+
)
|
865 |
+
LOGGER.error(ef)
|
866 |
+
LOGGER.error(format_exc())
|
867 |
+
return
|
868 |
+
|
869 |
+
|
870 |
+
@app.on_message(command("ban") & restrict_filter)
|
871 |
+
async def ban_usr(c: app, m: Message):
|
872 |
+
if len(m.text.split()) == 1 and not m.reply_to_message:
|
873 |
+
await m.reply_text(text="I can't ban nothing!")
|
874 |
+
await m.stop_propagation()
|
875 |
+
|
876 |
+
if m.reply_to_message and not m.reply_to_message.from_user:
|
877 |
+
user_id, user_first_name = (
|
878 |
+
m.reply_to_message.sender_chat.id,
|
879 |
+
m.reply_to_message.sender_chat.title,
|
880 |
+
)
|
881 |
+
else:
|
882 |
+
try:
|
883 |
+
user_id, user_first_name, _ = await extract_user(c, m)
|
884 |
+
except Exception:
|
885 |
+
return
|
886 |
+
|
887 |
+
if not user_id:
|
888 |
+
await m.reply_text("Cannot find user to ban")
|
889 |
+
await m.stop_propagation()
|
890 |
+
if user_id == m.chat.id:
|
891 |
+
await m.reply_text("That's an admin!")
|
892 |
+
await m.stop_propagation()
|
893 |
+
if user_id == BOT_ID:
|
894 |
+
await m.reply_text("Huh, why would I ban myself?")
|
895 |
+
await m.stop_propagation()
|
896 |
+
|
897 |
+
if user_id in SUPPORT_STAFF:
|
898 |
+
await m.reply_text(
|
899 |
+
text="This user is in my support staff, cannot restrict them."
|
900 |
+
)
|
901 |
+
LOGGER.info(
|
902 |
+
f"{m.from_user.id} trying to ban {user_id} (SUPPORT_STAFF) in {m.chat.id}",
|
903 |
+
)
|
904 |
+
await m.stop_propagation()
|
905 |
+
|
906 |
+
try:
|
907 |
+
admins_group = {i[0] for i in ADMIN_CACHE[m.chat.id]}
|
908 |
+
except KeyError:
|
909 |
+
admins_group = await admin_cache_reload(m, "ban")
|
910 |
+
|
911 |
+
if user_id in admins_group:
|
912 |
+
await m.reply_text(text="This user is an admin, I cannot ban them!")
|
913 |
+
await m.stop_propagation()
|
914 |
+
|
915 |
+
reason = None
|
916 |
+
if m.reply_to_message:
|
917 |
+
r_id = m.reply_to_message.id
|
918 |
+
if len(m.text.split()) >= 2:
|
919 |
+
reason = m.text.split(None, 1)[1]
|
920 |
+
else:
|
921 |
+
r_id = m.id
|
922 |
+
if len(m.text.split()) >= 3:
|
923 |
+
reason = m.text.split(None, 2)[2]
|
924 |
+
|
925 |
+
try:
|
926 |
+
LOGGER.info(f"{m.from_user.id} banned {user_id} in {m.chat.id}")
|
927 |
+
await m.chat.ban_member(user_id)
|
928 |
+
banned = await mention_html(user_first_name, user_id)
|
929 |
+
txt = f"{m.from_user.mention} banned {banned} in <b>{m.chat.title}</b>!"
|
930 |
+
if reason:
|
931 |
+
txt += f"\n<b>Reason</b>: {reason}"
|
932 |
+
else:
|
933 |
+
txt += "\n<b>Reason</b>: Not Specified"
|
934 |
+
keyboard = InlineKeyboardMarkup(
|
935 |
+
[
|
936 |
+
[
|
937 |
+
InlineKeyboardButton(
|
938 |
+
"UNBAN",
|
939 |
+
callback_data=f"unban_={user_id}",
|
940 |
+
),
|
941 |
+
],
|
942 |
+
],
|
943 |
+
)
|
944 |
+
anim = choice(BAN_GIFS)
|
945 |
+
try:
|
946 |
+
await m.reply_animation(
|
947 |
+
reply_to_message_id=r_id,
|
948 |
+
animation=str(anim),
|
949 |
+
caption=txt,
|
950 |
+
reply_markup=keyboard,
|
951 |
+
parse_mode=enums.ParseMode.HTML,
|
952 |
+
)
|
953 |
+
except Exception:
|
954 |
+
await m.reply_text(
|
955 |
+
reply_to_message_id=r_id,
|
956 |
+
text=txt,
|
957 |
+
reply_markup=keyboard,
|
958 |
+
parse_mode=enums.ParseMode.HTML,
|
959 |
+
)
|
960 |
+
await c.send_message(MESSAGE_DUMP, f"#REMOVE from BAN_GFIS\n{anim}")
|
961 |
+
except ChatAdminRequired:
|
962 |
+
await m.reply_text(text="I'm not admin or I don't have rights.")
|
963 |
+
except PeerIdInvalid:
|
964 |
+
await m.reply_text(
|
965 |
+
"I have not seen this user yet...!\nMind forwarding one of their message so I can recognize them?",
|
966 |
+
)
|
967 |
+
except UserAdminInvalid:
|
968 |
+
await m.reply_text(
|
969 |
+
text="Cannot act on this user, maybe I wasn't the one who changed their permissions."
|
970 |
+
)
|
971 |
+
except RightForbidden:
|
972 |
+
await m.reply_text(text="I don't have enough rights to ban this user.")
|
973 |
+
except RPCError as ef:
|
974 |
+
await m.reply_text(
|
975 |
+
text=f"""Some error occured, report it using `/bug`
|
976 |
+
|
977 |
+
<b>Error:</b> <code>{ef}</code>"""
|
978 |
+
)
|
979 |
+
LOGGER.error(ef)
|
980 |
+
LOGGER.error(format_exc())
|
981 |
+
return
|
982 |
+
|
983 |
+
|
984 |
+
@app.on_callback_query(regex("^unban_"))
|
985 |
+
async def unbanbutton(c: app, q: CallbackQuery):
|
986 |
+
splitter = (str(q.data).replace("unban_", "")).split("=")
|
987 |
+
user_id = int(splitter[1])
|
988 |
+
user = await q.message.chat.get_member(q.from_user.id)
|
989 |
+
|
990 |
+
if not user:
|
991 |
+
await q.answer(
|
992 |
+
"You don't have enough permission to do this!\nStay in your limits!",
|
993 |
+
show_alert=True,
|
994 |
+
)
|
995 |
+
return
|
996 |
+
|
997 |
+
if not user.privileges.can_restrict_members and q.from_user.id != OWNER_ID:
|
998 |
+
await q.answer(
|
999 |
+
"You don't have enough permission to do this!\nStay in your limits!",
|
1000 |
+
show_alert=True,
|
1001 |
+
)
|
1002 |
+
return
|
1003 |
+
whoo = await c.get_chat(user_id)
|
1004 |
+
doneto = whoo.first_name if whoo.first_name else whoo.title
|
1005 |
+
try:
|
1006 |
+
await q.message.chat.unban_member(user_id)
|
1007 |
+
except RPCError as e:
|
1008 |
+
await q.message.edit_text(f"Error: {e}")
|
1009 |
+
return
|
1010 |
+
await q.message.edit_text(f"{q.from_user.mention} unbanned {doneto}!")
|
1011 |
+
return
|
1012 |
+
|
1013 |
+
|
1014 |
+
# <=================================================== HELP ====================================================>
|
1015 |
+
|
1016 |
+
|
1017 |
+
__help__ = """
|
1018 |
+
➠ *Admin only:*
|
1019 |
+
|
1020 |
+
» /kick: Kick the user replied or tagged.
|
1021 |
+
|
1022 |
+
» /skick: Kick the user replied or tagged and delete your messsage.
|
1023 |
+
|
1024 |
+
» /dkick: Kick the user replied and delete their message.
|
1025 |
+
|
1026 |
+
» /ban: Bans the user replied to or tagged.
|
1027 |
+
|
1028 |
+
» /sban: Bans the user replied or tagged and delete your messsage.
|
1029 |
+
|
1030 |
+
» /dban: Bans the user replied and delete their message.
|
1031 |
+
|
1032 |
+
» /tban <userhandle> x(m/h/d): Bans a user for x time. (via handle, or reply). m = minutes, h = hours, d = days.
|
1033 |
+
|
1034 |
+
» /stban <userhandle> x(m/h/d): Silently bans a user for x time. (via handle, or reply). m = minutes, h = hours, d = days.
|
1035 |
+
|
1036 |
+
» /dtban <userhandle> x(m/h/d): Silently bans a user for x time and delete the replied message. (via reply). m = minutes, h = hours, d = days.
|
1037 |
+
|
1038 |
+
» /unban: Unbans the user replied to or tagged.
|
1039 |
+
|
1040 |
+
|
1041 |
+
➠ **Example:**
|
1042 |
+
» `/ban @username`: this bans a user in the chat."""
|
1043 |
+
|
1044 |
+
__mod_name__ = "BANS"
|
1045 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/botadmins.py
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# SOURCE https://github.com/Team-ProjectCodeX
|
2 |
+
# CREATED BY https://t.me/O_okarma
|
3 |
+
# PROVIDED BY https://t.me/ProjectCodeX
|
4 |
+
|
5 |
+
# <============================================== IMPORTS =========================================================>
|
6 |
+
|
7 |
+
from telegram import Update
|
8 |
+
from telegram.constants import ParseMode
|
9 |
+
from telegram.error import TelegramError
|
10 |
+
from telegram.ext import CommandHandler, ContextTypes
|
11 |
+
|
12 |
+
from Mikobot import DEMONS, DEV_USERS, DRAGONS, LOGGER, OWNER_ID, WOLVES, function
|
13 |
+
from Mikobot.plugins.helper_funcs.chat_status import check_admin
|
14 |
+
from Mikobot.utils.parser import mention_html
|
15 |
+
|
16 |
+
# <=======================================================================================================>
|
17 |
+
|
18 |
+
|
19 |
+
# <================================================ FUNCTION =======================================================>
|
20 |
+
async def get_chat_member(context: ContextTypes.DEFAULT_TYPE, user_id):
|
21 |
+
try:
|
22 |
+
return await context.bot.get_chat_member(user_id, user_id)
|
23 |
+
except TelegramError as e:
|
24 |
+
LOGGER.error(f"Error getting chat member {user_id}: {e}")
|
25 |
+
return None
|
26 |
+
|
27 |
+
|
28 |
+
async def get_user_info(context: ContextTypes.DEFAULT_TYPE, user_id):
|
29 |
+
user_info = await get_chat_member(context, user_id)
|
30 |
+
return user_info.user.first_name if user_info else "Unknown User"
|
31 |
+
|
32 |
+
|
33 |
+
async def get_users_info(context: ContextTypes.DEFAULT_TYPE, user_ids):
|
34 |
+
return [(await get_user_info(context, user_id), user_id) for user_id in user_ids]
|
35 |
+
|
36 |
+
|
37 |
+
async def get_users_list(context: ContextTypes.DEFAULT_TYPE, user_ids):
|
38 |
+
return [
|
39 |
+
f"• {await mention_html(name, user_id)} (<code>{user_id}</code>)"
|
40 |
+
for name, user_id in await get_users_info(context, user_ids)
|
41 |
+
]
|
42 |
+
|
43 |
+
|
44 |
+
@check_admin(only_dev=True)
|
45 |
+
async def botstaff(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
46 |
+
try:
|
47 |
+
owner = await get_chat_member(context, OWNER_ID)
|
48 |
+
owner_info = await mention_html(owner.user.first_name, owner.user.id)
|
49 |
+
reply = f"✪ <b>CREATOR :</b> {owner_info} (<code>{OWNER_ID}</code>)\n"
|
50 |
+
except TelegramError as e:
|
51 |
+
LOGGER.error(f"Error getting owner information: {e}")
|
52 |
+
reply = ""
|
53 |
+
|
54 |
+
true_dev = list(set(DEV_USERS) - {OWNER_ID})
|
55 |
+
reply += "\n\n➪ <b>SPECIAL GRADE USERS :</b>\n"
|
56 |
+
reply += "\n".join(await get_users_list(context, true_dev)) or "No Dev Users"
|
57 |
+
|
58 |
+
true_sudo = list(set(DRAGONS) - set(DEV_USERS))
|
59 |
+
reply += "\n\n➪ <b>A GRADE USERS :</b>\n"
|
60 |
+
reply += "\n".join(await get_users_list(context, true_sudo)) or "No Sudo Users"
|
61 |
+
|
62 |
+
reply += "\n\n➪ <b>B GRADE USERS :</b>\n"
|
63 |
+
reply += "\n".join(await get_users_list(context, DEMONS)) or "No Demon Users"
|
64 |
+
|
65 |
+
reply += "\n\n➪ <b>NORMAL GRADE USERS :</b>\n"
|
66 |
+
reply += (
|
67 |
+
"\n".join(await get_users_list(context, WOLVES))
|
68 |
+
or "No additional whitelisted users"
|
69 |
+
)
|
70 |
+
|
71 |
+
await update.message.reply_text(reply, parse_mode=ParseMode.HTML)
|
72 |
+
LOGGER.info(
|
73 |
+
f"{update.message.from_user.id} fetched botstaff in {update.message.chat.id}"
|
74 |
+
)
|
75 |
+
|
76 |
+
|
77 |
+
# <================================================ HANDLER =======================================================>
|
78 |
+
function(CommandHandler("botadmins", botstaff, block=False))
|
79 |
+
# <================================================ END =======================================================>
|
80 |
+
|
81 |
+
|
82 |
+
# <=================================================== HELP ====================================================>
|
83 |
+
__help__ = """
|
84 |
+
➠ *BOT ADMINS ONLY:*
|
85 |
+
|
86 |
+
» /stats: Shows bot stats.
|
87 |
+
|
88 |
+
» /gban: Global ban.
|
89 |
+
|
90 |
+
» /gbanlist: Shows gban list.
|
91 |
+
|
92 |
+
» /botadmins: Opens Bot admin lists.
|
93 |
+
|
94 |
+
» /gcast: Advance broadcast system. Just reply to any message.
|
95 |
+
|
96 |
+
➠ *Write with text message*
|
97 |
+
|
98 |
+
» /broadcastall
|
99 |
+
|
100 |
+
» /broadcastusers
|
101 |
+
|
102 |
+
» /broadcastgroups
|
103 |
+
"""
|
104 |
+
|
105 |
+
__mod_name__ = "BOT-ADMIN"
|
106 |
+
# <================================================ HANDLER =======================================================>
|
Mikobot/plugins/chatbot.py
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import asyncio
|
3 |
+
import html
|
4 |
+
import json
|
5 |
+
import re
|
6 |
+
from typing import Optional
|
7 |
+
|
8 |
+
import requests
|
9 |
+
from telegram import (
|
10 |
+
CallbackQuery,
|
11 |
+
Chat,
|
12 |
+
InlineKeyboardButton,
|
13 |
+
InlineKeyboardMarkup,
|
14 |
+
Update,
|
15 |
+
User,
|
16 |
+
)
|
17 |
+
from telegram.constants import ParseMode
|
18 |
+
from telegram.error import BadRequest, Forbidden, RetryAfter
|
19 |
+
from telegram.ext import (
|
20 |
+
CallbackQueryHandler,
|
21 |
+
CommandHandler,
|
22 |
+
ContextTypes,
|
23 |
+
MessageHandler,
|
24 |
+
filters,
|
25 |
+
)
|
26 |
+
from telegram.helpers import mention_html
|
27 |
+
|
28 |
+
import Database.sql.kuki_sql as sql
|
29 |
+
from Mikobot import function
|
30 |
+
from Mikobot.plugins.log_channel import gloggable
|
31 |
+
|
32 |
+
# <=======================================================================================================>
|
33 |
+
|
34 |
+
|
35 |
+
# <================================================ FUNCTION =======================================================>
|
36 |
+
@gloggable
|
37 |
+
async def kukirm(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
38 |
+
query: Optional[CallbackQuery] = update.callback_query
|
39 |
+
user: Optional[User] = update.effective_user
|
40 |
+
if match := re.match(r"rm_chat\((.+?)\)", query.data):
|
41 |
+
user_id = match[1]
|
42 |
+
chat: Optional[Chat] = update.effective_chat
|
43 |
+
if is_kuki := sql.rem_kuki(chat.id):
|
44 |
+
sql.rem_kuki(user_id)
|
45 |
+
return (
|
46 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
47 |
+
f"AI_DISABLED\n"
|
48 |
+
f"<b>Admin:</b> {mention_html(user.id, html.escape(user.first_name))}\n"
|
49 |
+
)
|
50 |
+
else:
|
51 |
+
await update.effective_message.edit_text(
|
52 |
+
f"Chatbot disable by {mention_html(user.id, user.first_name)}.",
|
53 |
+
parse_mode=ParseMode.HTML,
|
54 |
+
)
|
55 |
+
|
56 |
+
return ""
|
57 |
+
|
58 |
+
|
59 |
+
@gloggable
|
60 |
+
async def kukiadd(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
61 |
+
query: Optional[CallbackQuery] = update.callback_query
|
62 |
+
user: Optional[User] = update.effective_user
|
63 |
+
if match := re.match(r"add_chat\((.+?)\)", query.data):
|
64 |
+
user_id = match[1]
|
65 |
+
chat: Optional[Chat] = update.effective_chat
|
66 |
+
if is_kuki := sql.set_kuki(chat.id):
|
67 |
+
sql.set_kuki(user_id)
|
68 |
+
return (
|
69 |
+
f"<b>{html.escape(chat.title)}:</b>\n"
|
70 |
+
f"AI_ENABLE\n"
|
71 |
+
f"<b>Admin:</b> {mention_html(user.id, html.escape(user.first_name))}\n"
|
72 |
+
)
|
73 |
+
else:
|
74 |
+
await update.effective_message.edit_text(
|
75 |
+
f"Hey Darling Chatbot enable by {mention_html(user.id, user.first_name)}.",
|
76 |
+
parse_mode=ParseMode.HTML,
|
77 |
+
)
|
78 |
+
|
79 |
+
return ""
|
80 |
+
|
81 |
+
|
82 |
+
@gloggable
|
83 |
+
async def kuki(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
84 |
+
update.effective_user
|
85 |
+
message = update.effective_message
|
86 |
+
msg = "Choose an option"
|
87 |
+
keyboard = InlineKeyboardMarkup(
|
88 |
+
[
|
89 |
+
[InlineKeyboardButton(text="Enable", callback_data="add_chat({})")],
|
90 |
+
[InlineKeyboardButton(text="Disable", callback_data="rm_chat({})")],
|
91 |
+
]
|
92 |
+
)
|
93 |
+
await message.reply_text(
|
94 |
+
msg,
|
95 |
+
reply_markup=keyboard,
|
96 |
+
parse_mode=ParseMode.HTML,
|
97 |
+
)
|
98 |
+
|
99 |
+
|
100 |
+
async def kuki_message(context: ContextTypes.DEFAULT_TYPE, message):
|
101 |
+
reply_message = message.reply_to_message
|
102 |
+
if message.text.lower() == "kuki":
|
103 |
+
return True
|
104 |
+
if reply_message:
|
105 |
+
if reply_message.from_user.id == (await context.bot.get_me()).id:
|
106 |
+
return True
|
107 |
+
else:
|
108 |
+
return False
|
109 |
+
|
110 |
+
|
111 |
+
async def chatbot(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
112 |
+
update.effective_user
|
113 |
+
message = update.effective_message
|
114 |
+
chat_id = update.effective_chat.id
|
115 |
+
bot = context.bot
|
116 |
+
is_kuki = sql.is_kuki(chat_id)
|
117 |
+
if not is_kuki:
|
118 |
+
return
|
119 |
+
|
120 |
+
if message.text and not message.document:
|
121 |
+
if not await kuki_message(context, message):
|
122 |
+
return
|
123 |
+
Message = message.text
|
124 |
+
await bot.send_chat_action(chat_id, action="typing")
|
125 |
+
kukiurl = requests.get(
|
126 |
+
f"http://api.brainshop.ai/get?bid=176809&key=lbMN8CXTGzhn1NKG&uid=[user]&msg={Message}"
|
127 |
+
)
|
128 |
+
|
129 |
+
Kuki = json.loads(kukiurl.text)
|
130 |
+
kuki = Kuki["cnt"]
|
131 |
+
|
132 |
+
await asyncio.sleep(0.3)
|
133 |
+
await message.reply_text(kuki)
|
134 |
+
|
135 |
+
|
136 |
+
async def list_all_chats(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
137 |
+
chats = sql.get_all_kuki_chats()
|
138 |
+
text = "<b>Neko Enabled Chats</b>\n"
|
139 |
+
for chat in chats:
|
140 |
+
try:
|
141 |
+
x = await context.bot.get_chat(int(*chat))
|
142 |
+
name = x.title or x.first_name
|
143 |
+
text += f"• <code>{name}</code>\n"
|
144 |
+
except (BadRequest, Forbidden):
|
145 |
+
sql.rem_kuki(*chat)
|
146 |
+
except RetryAfter as e:
|
147 |
+
await asyncio.sleep(e.retry_after)
|
148 |
+
await update.effective_message.reply_text(text, parse_mode="HTML")
|
149 |
+
|
150 |
+
|
151 |
+
# <=================================================== HELP ====================================================>
|
152 |
+
|
153 |
+
|
154 |
+
__help__ = """
|
155 |
+
➠ *Admins only command*:
|
156 |
+
|
157 |
+
» `/Chatbot`*:* shows chatbot panel.
|
158 |
+
"""
|
159 |
+
|
160 |
+
__mod_name__ = "CHATBOT"
|
161 |
+
|
162 |
+
|
163 |
+
# <================================================ HANDLER =======================================================>
|
164 |
+
CHATBOTK_HANDLER = CommandHandler("chatbot", kuki, block=False)
|
165 |
+
ADD_CHAT_HANDLER = CallbackQueryHandler(kukiadd, pattern=r"add_chat", block=False)
|
166 |
+
RM_CHAT_HANDLER = CallbackQueryHandler(kukirm, pattern=r"rm_chat", block=False)
|
167 |
+
CHATBOT_HANDLER = MessageHandler(
|
168 |
+
filters.TEXT
|
169 |
+
& (~filters.Regex(r"^#[^\s]+") & ~filters.Regex(r"^!") & ~filters.Regex(r"^\/")),
|
170 |
+
chatbot,
|
171 |
+
block=False,
|
172 |
+
)
|
173 |
+
LIST_ALL_CHATS_HANDLER = CommandHandler("allchats", list_all_chats, block=False)
|
174 |
+
|
175 |
+
function(ADD_CHAT_HANDLER)
|
176 |
+
function(CHATBOTK_HANDLER)
|
177 |
+
function(RM_CHAT_HANDLER)
|
178 |
+
function(LIST_ALL_CHATS_HANDLER)
|
179 |
+
function(CHATBOT_HANDLER)
|
180 |
+
|
181 |
+
__handlers__ = [
|
182 |
+
ADD_CHAT_HANDLER,
|
183 |
+
CHATBOTK_HANDLER,
|
184 |
+
RM_CHAT_HANDLER,
|
185 |
+
LIST_ALL_CHATS_HANDLER,
|
186 |
+
CHATBOT_HANDLER,
|
187 |
+
]
|
188 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/connection.py
ADDED
@@ -0,0 +1,441 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import re
|
3 |
+
import time
|
4 |
+
|
5 |
+
from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update
|
6 |
+
from telegram.constants import ParseMode
|
7 |
+
from telegram.error import BadRequest, Forbidden
|
8 |
+
from telegram.ext import CallbackQueryHandler, CommandHandler, ContextTypes
|
9 |
+
|
10 |
+
import Database.sql.connection_sql as sql
|
11 |
+
from Mikobot import DEV_USERS, DRAGONS, dispatcher, function
|
12 |
+
from Mikobot.plugins.helper_funcs import chat_status
|
13 |
+
from Mikobot.plugins.helper_funcs.alternate import send_message, typing_action
|
14 |
+
|
15 |
+
# <=======================================================================================================>
|
16 |
+
|
17 |
+
check_admin = chat_status.check_admin
|
18 |
+
|
19 |
+
|
20 |
+
# <================================================ FUNCTION =======================================================>
|
21 |
+
@check_admin(is_user=True)
|
22 |
+
@typing_action
|
23 |
+
async def allow_connections(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
24 |
+
chat = update.effective_chat
|
25 |
+
args = context.args
|
26 |
+
|
27 |
+
if chat.type != chat.PRIVATE:
|
28 |
+
if len(args) >= 1:
|
29 |
+
var = args[0]
|
30 |
+
if var == "no":
|
31 |
+
sql.set_allow_connect_to_chat(chat.id, False)
|
32 |
+
await send_message(
|
33 |
+
update.effective_message,
|
34 |
+
"Connection has been disabled for this chat.",
|
35 |
+
)
|
36 |
+
elif var == "yes":
|
37 |
+
sql.set_allow_connect_to_chat(chat.id, True)
|
38 |
+
await send_message(
|
39 |
+
update.effective_message,
|
40 |
+
"Connection has been enabled for this chat.",
|
41 |
+
)
|
42 |
+
else:
|
43 |
+
await send_message(
|
44 |
+
update.effective_message,
|
45 |
+
"Please enter 'yes' or 'no'!",
|
46 |
+
parse_mode=ParseMode.MARKDOWN,
|
47 |
+
)
|
48 |
+
else:
|
49 |
+
get_settings = sql.allow_connect_to_chat(chat.id)
|
50 |
+
if get_settings:
|
51 |
+
await send_message(
|
52 |
+
update.effective_message,
|
53 |
+
"Connections to this group are *allowed* for members!",
|
54 |
+
parse_mode=ParseMode.MARKDOWN,
|
55 |
+
)
|
56 |
+
else:
|
57 |
+
await send_message(
|
58 |
+
update.effective_message,
|
59 |
+
"Connection to this group is *not allowed* for members!",
|
60 |
+
parse_mode=ParseMode.MARKDOWN,
|
61 |
+
)
|
62 |
+
else:
|
63 |
+
await send_message(
|
64 |
+
update.effective_message,
|
65 |
+
"This command is for groups only, not in PM!",
|
66 |
+
)
|
67 |
+
|
68 |
+
|
69 |
+
@typing_action
|
70 |
+
async def connection_chat(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
71 |
+
chat = update.effective_chat
|
72 |
+
user = update.effective_user
|
73 |
+
|
74 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=True)
|
75 |
+
|
76 |
+
if conn:
|
77 |
+
chat = await dispatcher.bot.getChat(conn)
|
78 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
79 |
+
chat_name = chat_obj.title
|
80 |
+
else:
|
81 |
+
if update.effective_message.chat.type != "private":
|
82 |
+
return
|
83 |
+
chat = update.effective_chat
|
84 |
+
chat_name = update.effective_message.chat.title
|
85 |
+
|
86 |
+
if conn:
|
87 |
+
message = "You are currently connected to {}.\n".format(chat_name)
|
88 |
+
else:
|
89 |
+
message = "You are currently not connected in any group.\n"
|
90 |
+
await send_message(update.effective_message, message, parse_mode="markdown")
|
91 |
+
|
92 |
+
|
93 |
+
@typing_action
|
94 |
+
async def connect_chat(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
95 |
+
chat = update.effective_chat
|
96 |
+
user = update.effective_user
|
97 |
+
args = context.args
|
98 |
+
|
99 |
+
if update.effective_chat.type == "private":
|
100 |
+
if args and len(args) >= 1:
|
101 |
+
try:
|
102 |
+
connect_chat = int(args[0])
|
103 |
+
getstatusadmin = await context.bot.get_chat_member(
|
104 |
+
connect_chat,
|
105 |
+
update.effective_message.from_user.id,
|
106 |
+
)
|
107 |
+
except ValueError:
|
108 |
+
try:
|
109 |
+
connect_chat = str(args[0])
|
110 |
+
get_chat = await context.bot.getChat(connect_chat)
|
111 |
+
connect_chat = get_chat.id
|
112 |
+
getstatusadmin = await context.bot.get_chat_member(
|
113 |
+
connect_chat,
|
114 |
+
update.effective_message.from_user.id,
|
115 |
+
)
|
116 |
+
except BadRequest:
|
117 |
+
await send_message(update.effective_message, "Invalid Chat ID!")
|
118 |
+
return
|
119 |
+
except BadRequest:
|
120 |
+
await send_message(update.effective_message, "Invalid Chat ID!")
|
121 |
+
return
|
122 |
+
|
123 |
+
isadmin = getstatusadmin.status in ("administrator", "creator")
|
124 |
+
ismember = getstatusadmin.status in ("member")
|
125 |
+
isallow = sql.allow_connect_to_chat(connect_chat)
|
126 |
+
|
127 |
+
if (isadmin) or (isallow and ismember) or (user.id in DRAGONS):
|
128 |
+
connection_status = sql.connect(
|
129 |
+
update.effective_message.from_user.id,
|
130 |
+
connect_chat,
|
131 |
+
)
|
132 |
+
if connection_status:
|
133 |
+
conn = await connected(
|
134 |
+
context.bot, update, chat, user.id, need_admin=False
|
135 |
+
)
|
136 |
+
conn_chat = await dispatcher.bot.getChat(conn)
|
137 |
+
chat_name = conn_chat.title
|
138 |
+
await send_message(
|
139 |
+
update.effective_message,
|
140 |
+
"Successfully connected to *{}*. Use /helpconnect to check available commands.".format(
|
141 |
+
chat_name,
|
142 |
+
),
|
143 |
+
parse_mode=ParseMode.MARKDOWN,
|
144 |
+
)
|
145 |
+
sql.add_history_conn(user.id, str(conn_chat.id), chat_name)
|
146 |
+
else:
|
147 |
+
await send_message(update.effective_message, "Connection failed!")
|
148 |
+
else:
|
149 |
+
await send_message(
|
150 |
+
update.effective_message,
|
151 |
+
"Connection to this chat is not allowed!",
|
152 |
+
)
|
153 |
+
else:
|
154 |
+
gethistory = sql.get_history_conn(user.id)
|
155 |
+
if gethistory:
|
156 |
+
buttons = [
|
157 |
+
InlineKeyboardButton(
|
158 |
+
text="❎ Close Button",
|
159 |
+
callback_data="connect_close",
|
160 |
+
),
|
161 |
+
InlineKeyboardButton(
|
162 |
+
text="🧹 Clear History",
|
163 |
+
callback_data="connect_clear",
|
164 |
+
),
|
165 |
+
]
|
166 |
+
else:
|
167 |
+
buttons = []
|
168 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=False)
|
169 |
+
if conn:
|
170 |
+
connectedchat = await dispatcher.bot.getChat(conn)
|
171 |
+
text = "You are currently connected to *{}* (`{}`)".format(
|
172 |
+
connectedchat.title,
|
173 |
+
conn,
|
174 |
+
)
|
175 |
+
buttons.append(
|
176 |
+
InlineKeyboardButton(
|
177 |
+
text="🔌 Disconnect",
|
178 |
+
callback_data="connect_disconnect",
|
179 |
+
),
|
180 |
+
)
|
181 |
+
else:
|
182 |
+
text = "Write the chat ID or tag to connect!"
|
183 |
+
if gethistory:
|
184 |
+
text += "\n\n*Connection History:*\n"
|
185 |
+
text += "╒═══「 *Info* 」\n"
|
186 |
+
text += "│ Sorted: `Newest`\n"
|
187 |
+
text += "│\n"
|
188 |
+
buttons = [buttons]
|
189 |
+
for x in sorted(gethistory.keys(), reverse=True):
|
190 |
+
htime = time.strftime("%d/%m/%Y", time.localtime(x))
|
191 |
+
text += "╞═「 *{}* 」\n│ `{}`\n│ `{}`\n".format(
|
192 |
+
gethistory[x]["chat_name"],
|
193 |
+
gethistory[x]["chat_id"],
|
194 |
+
htime,
|
195 |
+
)
|
196 |
+
text += "│\n"
|
197 |
+
buttons.append(
|
198 |
+
[
|
199 |
+
InlineKeyboardButton(
|
200 |
+
text=gethistory[x]["chat_name"],
|
201 |
+
callback_data="connect({})".format(
|
202 |
+
gethistory[x]["chat_id"],
|
203 |
+
),
|
204 |
+
),
|
205 |
+
],
|
206 |
+
)
|
207 |
+
text += "╘══「 Total {} Chats 」".format(
|
208 |
+
str(len(gethistory)) + " (max)"
|
209 |
+
if len(gethistory) == 5
|
210 |
+
else str(len(gethistory)),
|
211 |
+
)
|
212 |
+
conn_hist = InlineKeyboardMarkup(buttons)
|
213 |
+
elif buttons:
|
214 |
+
conn_hist = InlineKeyboardMarkup([buttons])
|
215 |
+
else:
|
216 |
+
conn_hist = None
|
217 |
+
await send_message(
|
218 |
+
update.effective_message,
|
219 |
+
text,
|
220 |
+
parse_mode="markdown",
|
221 |
+
reply_markup=conn_hist,
|
222 |
+
)
|
223 |
+
|
224 |
+
else:
|
225 |
+
getstatusadmin = await context.bot.get_chat_member(
|
226 |
+
chat.id,
|
227 |
+
update.effective_message.from_user.id,
|
228 |
+
)
|
229 |
+
isadmin = getstatusadmin.status in ("administrator", "creator")
|
230 |
+
ismember = getstatusadmin.status in ("member")
|
231 |
+
isallow = sql.allow_connect_to_chat(chat.id)
|
232 |
+
if (isadmin) or (isallow and ismember) or (user.id in DRAGONS):
|
233 |
+
connection_status = sql.connect(
|
234 |
+
update.effective_message.from_user.id,
|
235 |
+
chat.id,
|
236 |
+
)
|
237 |
+
if connection_status:
|
238 |
+
chat_obj = await dispatcher.bot.getChat(chat.id)
|
239 |
+
chat_name = chat_obj.title
|
240 |
+
await send_message(
|
241 |
+
update.effective_message,
|
242 |
+
"Successfully connected to *{}*.".format(chat_name),
|
243 |
+
parse_mode=ParseMode.MARKDOWN,
|
244 |
+
)
|
245 |
+
try:
|
246 |
+
sql.add_history_conn(user.id, str(chat.id), chat_name)
|
247 |
+
await context.bot.send_message(
|
248 |
+
update.effective_message.from_user.id,
|
249 |
+
"You are connected to *{}*. \nUse `/helpconnect` to check available commands.".format(
|
250 |
+
chat_name,
|
251 |
+
),
|
252 |
+
parse_mode="markdown",
|
253 |
+
)
|
254 |
+
except BadRequest:
|
255 |
+
pass
|
256 |
+
except Forbidden:
|
257 |
+
pass
|
258 |
+
else:
|
259 |
+
await send_message(update.effective_message, "ᴄᴏɴɴᴇᴄᴛɪᴏɴ ғᴀɪʟᴇᴅ!")
|
260 |
+
else:
|
261 |
+
await send_message(
|
262 |
+
update.effective_message,
|
263 |
+
"Connection to this chat is not allowed!",
|
264 |
+
)
|
265 |
+
|
266 |
+
|
267 |
+
async def disconnect_chat(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
268 |
+
if update.effective_chat.type == "private":
|
269 |
+
disconnection_status = sql.disconnect(update.effective_message.from_user.id)
|
270 |
+
if disconnection_status:
|
271 |
+
sql.disconnected_chat = await send_message(
|
272 |
+
update.effective_message,
|
273 |
+
"Disconnected from chat!",
|
274 |
+
)
|
275 |
+
else:
|
276 |
+
await send_message(update.effective_message, "You're not connected!")
|
277 |
+
else:
|
278 |
+
await send_message(
|
279 |
+
update.effective_message, "This command is only available in PM."
|
280 |
+
)
|
281 |
+
|
282 |
+
|
283 |
+
async def connected(bot: Bot, update: Update, chat, user_id, need_admin=True):
|
284 |
+
user = update.effective_user
|
285 |
+
|
286 |
+
if chat.type == chat.PRIVATE and sql.get_connected_chat(user_id):
|
287 |
+
conn_id = sql.get_connected_chat(user_id).chat_id
|
288 |
+
getstatusadmin = await bot.get_chat_member(
|
289 |
+
conn_id,
|
290 |
+
update.effective_message.from_user.id,
|
291 |
+
)
|
292 |
+
isadmin = getstatusadmin.status in ("administrator", "creator")
|
293 |
+
ismember = getstatusadmin.status in ("member")
|
294 |
+
isallow = sql.allow_connect_to_chat(conn_id)
|
295 |
+
|
296 |
+
if (
|
297 |
+
(isadmin)
|
298 |
+
or (isallow and ismember)
|
299 |
+
or (user.id in DRAGONS)
|
300 |
+
or (user.id in DEV_USERS)
|
301 |
+
):
|
302 |
+
if need_admin is True:
|
303 |
+
if (
|
304 |
+
getstatusadmin.status in ("administrator", "creator")
|
305 |
+
or user_id in DRAGONS
|
306 |
+
or user.id in DEV_USERS
|
307 |
+
):
|
308 |
+
return conn_id
|
309 |
+
else:
|
310 |
+
await send_message(
|
311 |
+
update.effective_message,
|
312 |
+
"You must be an admin in the connected group!",
|
313 |
+
)
|
314 |
+
else:
|
315 |
+
return conn_id
|
316 |
+
else:
|
317 |
+
await send_message(
|
318 |
+
update.effective_message,
|
319 |
+
"The group changed the connection rights or you are no longer an admin.\nI've disconnected you.",
|
320 |
+
)
|
321 |
+
disconnect_chat(update, bot)
|
322 |
+
else:
|
323 |
+
return False
|
324 |
+
|
325 |
+
|
326 |
+
CONN_HELP = """
|
327 |
+
Actions are available with connected groups:
|
328 |
+
• View and edit Notes.
|
329 |
+
• View and edit Filters.
|
330 |
+
• Get invite link of chat.
|
331 |
+
• Set and control AntiFlood settings.
|
332 |
+
• Set and control Blacklist settings.
|
333 |
+
• Set Locks and Unlocks in chat.
|
334 |
+
• Enable and Disable commands in chat.
|
335 |
+
• Export and Imports of chat backup.
|
336 |
+
"""
|
337 |
+
|
338 |
+
|
339 |
+
async def help_connect_chat(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
340 |
+
context.args
|
341 |
+
|
342 |
+
if update.effective_message.chat.type != "private":
|
343 |
+
await send_message(
|
344 |
+
update.effective_message, "PM me with that command to get help."
|
345 |
+
)
|
346 |
+
return
|
347 |
+
else:
|
348 |
+
await send_message(update.effective_message, CONN_HELP, parse_mode="markdown")
|
349 |
+
|
350 |
+
|
351 |
+
async def connect_button(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
352 |
+
query = update.callback_query
|
353 |
+
chat = update.effective_chat
|
354 |
+
user = update.effective_user
|
355 |
+
|
356 |
+
connect_match = re.match(r"connect\((.+?)\)", query.data)
|
357 |
+
disconnect_match = query.data == "connect_disconnect"
|
358 |
+
clear_match = query.data == "connect_clear"
|
359 |
+
connect_close = query.data == "connect_close"
|
360 |
+
|
361 |
+
if connect_match:
|
362 |
+
target_chat = connect_match.group(1)
|
363 |
+
getstatusadmin = await context.bot.get_chat_member(
|
364 |
+
target_chat, query.from_user.id
|
365 |
+
)
|
366 |
+
isadmin = getstatusadmin.status in ("administrator", "creator")
|
367 |
+
ismember = getstatusadmin.status in ("member")
|
368 |
+
isallow = sql.allow_connect_to_chat(target_chat)
|
369 |
+
|
370 |
+
if (isadmin) or (isallow and ismember) or (user.id in DRAGONS):
|
371 |
+
connection_status = sql.connect(query.from_user.id, target_chat)
|
372 |
+
|
373 |
+
if connection_status:
|
374 |
+
conn = await connected(
|
375 |
+
context.bot, update, chat, user.id, need_admin=False
|
376 |
+
)
|
377 |
+
conn_chat = await dispatcher.bot.getChat(conn)
|
378 |
+
chat_name = conn_chat.title
|
379 |
+
await query.message.edit_text(
|
380 |
+
"Successfully connected to *{}*. Use `/helpconnect` to check available commands.".format(
|
381 |
+
chat_name,
|
382 |
+
),
|
383 |
+
parse_mode=ParseMode.MARKDOWN,
|
384 |
+
)
|
385 |
+
sql.add_history_conn(user.id, str(conn_chat.id), chat_name)
|
386 |
+
else:
|
387 |
+
await query.message.edit_text("Connection failed!")
|
388 |
+
else:
|
389 |
+
await context.bot.answer_callback_query(
|
390 |
+
query.id,
|
391 |
+
"Connection to this chat is not allowed!",
|
392 |
+
show_alert=True,
|
393 |
+
)
|
394 |
+
elif disconnect_match:
|
395 |
+
disconnection_status = sql.disconnect(query.from_user.id)
|
396 |
+
if disconnection_status:
|
397 |
+
sql.disconnected_chat = await query.message.edit_text(
|
398 |
+
"Disconnected from chat!"
|
399 |
+
)
|
400 |
+
else:
|
401 |
+
await context.bot.answer_callback_query(
|
402 |
+
query.id,
|
403 |
+
"You're not connected!",
|
404 |
+
show_alert=True,
|
405 |
+
)
|
406 |
+
elif clear_match:
|
407 |
+
sql.clear_history_conn(query.from_user.id)
|
408 |
+
await query.message.edit_text("History connected has been cleared!")
|
409 |
+
elif connect_close:
|
410 |
+
await query.message.edit_text("Closed. To open again, type /connect")
|
411 |
+
else:
|
412 |
+
connect_chat(update, context)
|
413 |
+
|
414 |
+
|
415 |
+
# <=================================================== HELP ====================================================>
|
416 |
+
__mod_name__ = "CONNECT"
|
417 |
+
|
418 |
+
__help__ = """
|
419 |
+
➠ *Sometimes, you just want to add some notes and filters to a group chat, but you don't want everyone to see; this is where connections come in. This allows you to connect to a chat's database and add things to it without the commands appearing in chat! For obvious reasons, you need to be an admin to add things, but any member in the group can view your data.*
|
420 |
+
|
421 |
+
» /connect: Connects to chat (can be done in a group by /connect or /connect <chat id> in PM)
|
422 |
+
|
423 |
+
» /connection: List connected chats
|
424 |
+
|
425 |
+
» /disconnect: Disconnect from a chat
|
426 |
+
|
427 |
+
» /helpconnect: List available commands that can be used remotely
|
428 |
+
|
429 |
+
➠ *Admin Only:*
|
430 |
+
|
431 |
+
» /allowconnect <yes/no>: Allow a user to connect to a chat
|
432 |
+
"""
|
433 |
+
|
434 |
+
# <================================================ HANDLER =======================================================>
|
435 |
+
function(CommandHandler("connect", connect_chat, block=False))
|
436 |
+
function(CommandHandler("connection", connection_chat, block=False))
|
437 |
+
function(CommandHandler("disconnect", disconnect_chat, block=False))
|
438 |
+
function(CommandHandler("allowconnect", allow_connections, block=False))
|
439 |
+
function(CommandHandler("helpconnect", help_connect_chat, block=False))
|
440 |
+
function(CallbackQueryHandler(connect_button, pattern=r"connect", block=False))
|
441 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/cosplay.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# SOURCE https://github.com/Team-ProjectCodeX
|
2 |
+
# CREATED BY https://t.me/O_okarma
|
3 |
+
# API BY https://www.github.com/SOME-1HING
|
4 |
+
# PROVIDED BY https://t.me/ProjectCodeX
|
5 |
+
|
6 |
+
# <============================================== IMPORTS =========================================================>
|
7 |
+
from telegram import Update
|
8 |
+
from telegram.ext import CommandHandler, ContextTypes
|
9 |
+
|
10 |
+
from Mikobot import function
|
11 |
+
from Mikobot.state import state
|
12 |
+
|
13 |
+
# <=======================================================================================================>
|
14 |
+
|
15 |
+
|
16 |
+
# <================================================ FUNCTIONS =====================================================>
|
17 |
+
async def get_cosplay_data():
|
18 |
+
cosplay_url = "https://sugoi-api.vercel.app/cosplay"
|
19 |
+
response = await state.get(cosplay_url)
|
20 |
+
return response.json()
|
21 |
+
|
22 |
+
|
23 |
+
async def cosplay(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
24 |
+
try:
|
25 |
+
data = await get_cosplay_data()
|
26 |
+
photo_url = data.get("url") # Corrected key: "url" instead of "cosplay_url"
|
27 |
+
if photo_url:
|
28 |
+
await update.message.reply_photo(photo=photo_url)
|
29 |
+
else:
|
30 |
+
await update.message.reply_text("Could not fetch photo URL.")
|
31 |
+
except state.FetchError:
|
32 |
+
await update.message.reply_text("Unable to fetch data.")
|
33 |
+
|
34 |
+
|
35 |
+
# <================================================ HANDLER =======================================================>
|
36 |
+
function(CommandHandler("cosplay", cosplay, block=False))
|
37 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/couple.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import random
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
from pyrogram import filters
|
6 |
+
|
7 |
+
from Database.mongodb.karma_mongo import get_couple, save_couple
|
8 |
+
from Mikobot import app
|
9 |
+
|
10 |
+
# <=======================================================================================================>
|
11 |
+
|
12 |
+
|
13 |
+
# <================================================ FUNCTION =======================================================>
|
14 |
+
def dt():
|
15 |
+
now = datetime.now()
|
16 |
+
dt_string = now.strftime("%d/%m/%Y %H:%M")
|
17 |
+
dt_list = dt_string.split(" ")
|
18 |
+
return dt_list
|
19 |
+
|
20 |
+
|
21 |
+
def dt_tom():
|
22 |
+
a = (
|
23 |
+
str(int(dt()[0].split("/")[0]) + 1)
|
24 |
+
+ "/"
|
25 |
+
+ dt()[0].split("/")[1]
|
26 |
+
+ "/"
|
27 |
+
+ dt()[0].split("/")[2]
|
28 |
+
)
|
29 |
+
return a
|
30 |
+
|
31 |
+
|
32 |
+
tomorrow = str(dt_tom())
|
33 |
+
today = str(dt()[0])
|
34 |
+
|
35 |
+
COUPLES_PIC = "https://telegra.ph/file/c6d0c884f559b9ed8a54e.jpg"
|
36 |
+
C = """
|
37 |
+
✧ 𝗖𝗢𝗨𝗣𝗟𝗘𝗦 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 ✧
|
38 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
39 |
+
{} + ( PGM🎀😶 (https://t.me/Chalnayaaaaaarr) + 花火 (https://t.me/zd_sr07) + ゼロツー (https://t.me/wewewe_x) ) = 💞
|
40 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
41 |
+
𝗡𝗘𝗪 𝗖𝗢𝗨𝗣𝗟𝗘 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 𝗖𝗔𝗡 𝗕𝗘 𝗖𝗛𝗢𝗦𝗘𝗡 𝗔𝗧 12AM {}
|
42 |
+
"""
|
43 |
+
CAP = """
|
44 |
+
✧ 𝗖𝗢𝗨𝗣𝗟𝗘𝗦 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 ✧
|
45 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
46 |
+
{} + {} = 💞
|
47 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
48 |
+
𝗡𝗘𝗪 𝗖𝗢𝗨𝗣𝗟𝗘 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 𝗖𝗔𝗡 𝗕𝗘 𝗖𝗛𝗢𝗦𝗘𝗡 𝗔𝗧 12AM {}
|
49 |
+
"""
|
50 |
+
|
51 |
+
CAP2 = """
|
52 |
+
✧ 𝗖𝗢𝗨𝗣𝗟𝗘𝗦 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 ✧
|
53 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
54 |
+
{} (tg://openmessage?user_id={}) + {} (tg://openmessage?user_id={}) = 💞\n
|
55 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
56 |
+
𝗡𝗘𝗪 𝗖𝗢𝗨𝗣𝗟𝗘 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 𝗖𝗔𝗡 𝗕𝗘 𝗖𝗛𝗢𝗦𝗘𝗡 𝗔𝗧 12AM {}
|
57 |
+
"""
|
58 |
+
|
59 |
+
|
60 |
+
@app.on_message(filters.command(["couple", "couples", "shipping"]) & ~filters.private)
|
61 |
+
async def nibba_nibbi(_, message):
|
62 |
+
if message.from_user.id == 5540249238:
|
63 |
+
my_ = await _.get_users("rfxtuv")
|
64 |
+
me = await _.get_users(5540249238)
|
65 |
+
await message.reply_photo(
|
66 |
+
photo=COUPLES_PIC, caption=C.format(me.mention, tomorrow)
|
67 |
+
)
|
68 |
+
else:
|
69 |
+
try:
|
70 |
+
chat_id = message.chat.id
|
71 |
+
is_selected = await get_couple(chat_id, today)
|
72 |
+
if not is_selected:
|
73 |
+
list_of_users = []
|
74 |
+
async for i in _.get_chat_members(message.chat.id, limit=50):
|
75 |
+
if not i.user.is_bot:
|
76 |
+
list_of_users.append(i.user.id)
|
77 |
+
if len(list_of_users) < 2:
|
78 |
+
return await message.reply_text("ɴᴏᴛ ᴇɴᴏᴜɢʜ ᴜsᴇʀs ɪɴ ᴛʜɪs ɢʀᴏᴜᴘ.")
|
79 |
+
c1_id = random.choice(list_of_users)
|
80 |
+
c2_id = random.choice(list_of_users)
|
81 |
+
while c1_id == c2_id:
|
82 |
+
c1_id = random.choice(list_of_users)
|
83 |
+
c1_mention = (await _.get_users(c1_id)).mention
|
84 |
+
c2_mention = (await _.get_users(c2_id)).mention
|
85 |
+
await _.send_photo(
|
86 |
+
message.chat.id,
|
87 |
+
photo=COUPLES_PIC,
|
88 |
+
caption=CAP.format(c1_mention, c2_mention, tomorrow),
|
89 |
+
)
|
90 |
+
|
91 |
+
couple = {"c1_id": c1_id, "c2_id": c2_id}
|
92 |
+
await save_couple(chat_id, today, couple)
|
93 |
+
|
94 |
+
elif is_selected:
|
95 |
+
c1_id = int(is_selected["c1_id"])
|
96 |
+
c2_id = int(is_selected["c2_id"])
|
97 |
+
|
98 |
+
c1_name = (await _.get_users(c1_id)).first_name
|
99 |
+
c2_name = (await _.get_users(c2_id)).first_name
|
100 |
+
print(c1_id, c2_id, c1_name, c2_name)
|
101 |
+
couple_selection_message = f"""✧ 𝗖𝗢𝗨𝗣𝗟𝗘𝗦 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 ✧
|
102 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
103 |
+
[{c1_name}](tg://openmessage?user_id={c1_id}) + [{c2_name}](tg://openmessage?user_id={c2_id}) = 💞
|
104 |
+
➖➖➖➖➖➖➖➖➖➖➖➖
|
105 |
+
𝗡𝗘𝗪 𝗖𝗢𝗨𝗣𝗟𝗘 𝗢𝗙 𝗧𝗛𝗘 𝗗𝗔𝗬 𝗖𝗔𝗡 𝗕𝗘 𝗖𝗛𝗢𝗦𝗘𝗡 𝗔𝗧 12AM {tomorrow}"""
|
106 |
+
await _.send_photo(
|
107 |
+
message.chat.id, photo=COUPLES_PIC, caption=couple_selection_message
|
108 |
+
)
|
109 |
+
except Exception as e:
|
110 |
+
print(e)
|
111 |
+
await message.reply_text(str(e))
|
112 |
+
|
113 |
+
|
114 |
+
# <=================================================== HELP ====================================================>
|
115 |
+
|
116 |
+
|
117 |
+
__help__ = """
|
118 |
+
💘 *Choose couples in your chat*
|
119 |
+
|
120 |
+
» /couple, /couples, /shipping *:* Choose 2 users and send their names as couples in your chat.
|
121 |
+
"""
|
122 |
+
|
123 |
+
__mod_name__ = "COUPLE"
|
124 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/cust_filters.py
ADDED
@@ -0,0 +1,756 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import random
|
3 |
+
import re
|
4 |
+
from html import escape
|
5 |
+
|
6 |
+
from pyrate_limiter import BucketFullException, Duration, InMemoryBucket, Limiter, Rate
|
7 |
+
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
8 |
+
from telegram.constants import ChatMemberStatus, MessageLimit, ParseMode
|
9 |
+
from telegram.error import BadRequest
|
10 |
+
from telegram.ext import (
|
11 |
+
ApplicationHandlerStop,
|
12 |
+
CallbackQueryHandler,
|
13 |
+
CommandHandler,
|
14 |
+
ContextTypes,
|
15 |
+
MessageHandler,
|
16 |
+
)
|
17 |
+
from telegram.ext import filters as filters_module
|
18 |
+
from telegram.helpers import escape_markdown, mention_html
|
19 |
+
|
20 |
+
from Database.sql import cust_filters_sql as sql
|
21 |
+
from Mikobot import DEV_USERS, DRAGONS, LOGGER, dispatcher, function
|
22 |
+
from Mikobot.plugins.connection import connected
|
23 |
+
from Mikobot.plugins.disable import DisableAbleCommandHandler
|
24 |
+
from Mikobot.plugins.helper_funcs.alternate import send_message, typing_action
|
25 |
+
from Mikobot.plugins.helper_funcs.chat_status import check_admin
|
26 |
+
from Mikobot.plugins.helper_funcs.extraction import extract_text
|
27 |
+
from Mikobot.plugins.helper_funcs.misc import build_keyboard_parser
|
28 |
+
from Mikobot.plugins.helper_funcs.msg_types import get_filter_type
|
29 |
+
from Mikobot.plugins.helper_funcs.string_handling import (
|
30 |
+
button_markdown_parser,
|
31 |
+
escape_invalid_curly_brackets,
|
32 |
+
markdown_to_html,
|
33 |
+
split_quotes,
|
34 |
+
)
|
35 |
+
|
36 |
+
# <=======================================================================================================>
|
37 |
+
|
38 |
+
HANDLER_GROUP = 10
|
39 |
+
|
40 |
+
ENUM_FUNC_MAP = {
|
41 |
+
sql.Types.TEXT.value: dispatcher.bot.send_message,
|
42 |
+
sql.Types.BUTTON_TEXT.value: dispatcher.bot.send_message,
|
43 |
+
sql.Types.STICKER.value: dispatcher.bot.send_sticker,
|
44 |
+
sql.Types.DOCUMENT.value: dispatcher.bot.send_document,
|
45 |
+
sql.Types.PHOTO.value: dispatcher.bot.send_photo,
|
46 |
+
sql.Types.AUDIO.value: dispatcher.bot.send_audio,
|
47 |
+
sql.Types.VOICE.value: dispatcher.bot.send_voice,
|
48 |
+
sql.Types.VIDEO.value: dispatcher.bot.send_video,
|
49 |
+
}
|
50 |
+
|
51 |
+
|
52 |
+
class AntiSpam:
|
53 |
+
def __init__(self):
|
54 |
+
self.whitelist = (DEV_USERS or []) + (DRAGONS or [])
|
55 |
+
# Values are HIGHLY experimental, its recommended you pay attention to our commits as we will be adjusting the values over time with what suits best.
|
56 |
+
Duration.CUSTOM = 15 # Custom duration, 15 seconds
|
57 |
+
self.sec_limit = Rate(6, Duration.CUSTOM) # 6 / Per 15 Seconds
|
58 |
+
self.min_limit = Rate(20, Duration.MINUTE) # 20 / Per minute
|
59 |
+
self.hour_limit = Rate(100, Duration.HOUR) # 100 / Per hour
|
60 |
+
self.daily_limit = Rate(1000, Duration.DAY) # 1000 / Per day
|
61 |
+
self.limiter = Limiter(
|
62 |
+
InMemoryBucket(
|
63 |
+
[self.sec_limit, self.min_limit, self.hour_limit, self.daily_limit]
|
64 |
+
)
|
65 |
+
)
|
66 |
+
|
67 |
+
def check_user(self, user):
|
68 |
+
"""
|
69 |
+
Return True if user is to be ignored else False
|
70 |
+
"""
|
71 |
+
if user in self.whitelist:
|
72 |
+
return False
|
73 |
+
try:
|
74 |
+
self.limiter.consume(user)
|
75 |
+
return False
|
76 |
+
except BucketFullException:
|
77 |
+
return True
|
78 |
+
|
79 |
+
|
80 |
+
MessageHandlerChecker = AntiSpam()
|
81 |
+
|
82 |
+
|
83 |
+
# <================================================ FUNCTION =======================================================>
|
84 |
+
@typing_action
|
85 |
+
async def list_handlers(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
86 |
+
chat = update.effective_chat
|
87 |
+
user = update.effective_user
|
88 |
+
|
89 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=False)
|
90 |
+
if not conn is False:
|
91 |
+
chat_id = conn
|
92 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
93 |
+
chat_name = chat_obj.title
|
94 |
+
filter_list = "*Filter in {}:*\n"
|
95 |
+
else:
|
96 |
+
chat_id = update.effective_chat.id
|
97 |
+
if chat.type == "private":
|
98 |
+
chat_name = "Local filters"
|
99 |
+
filter_list = "*local filters:*\n"
|
100 |
+
else:
|
101 |
+
chat_name = chat.title
|
102 |
+
filter_list = "*Filters in {}*:\n"
|
103 |
+
|
104 |
+
all_handlers = sql.get_chat_triggers(chat_id)
|
105 |
+
|
106 |
+
if not all_handlers:
|
107 |
+
await send_message(
|
108 |
+
update.effective_message,
|
109 |
+
"No filters saved in {}!".format(chat_name),
|
110 |
+
)
|
111 |
+
return
|
112 |
+
|
113 |
+
for keyword in all_handlers:
|
114 |
+
entry = " • `{}`\n".format(escape_markdown(keyword))
|
115 |
+
if len(entry) + len(filter_list) > MessageLimit.MAX_TEXT_LENGTH:
|
116 |
+
await send_message(
|
117 |
+
update.effective_message,
|
118 |
+
filter_list.format(chat_name),
|
119 |
+
parse_mode=ParseMode.MARKDOWN,
|
120 |
+
)
|
121 |
+
filter_list = entry
|
122 |
+
else:
|
123 |
+
filter_list += entry
|
124 |
+
|
125 |
+
await send_message(
|
126 |
+
update.effective_message,
|
127 |
+
filter_list.format(chat_name),
|
128 |
+
parse_mode=ParseMode.MARKDOWN,
|
129 |
+
)
|
130 |
+
|
131 |
+
|
132 |
+
@typing_action
|
133 |
+
@check_admin(is_user=True)
|
134 |
+
async def filters(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
135 |
+
chat = update.effective_chat
|
136 |
+
user = update.effective_user
|
137 |
+
msg = update.effective_message
|
138 |
+
args = msg.text.split(
|
139 |
+
None, 1
|
140 |
+
) # use python's maxsplit to separate Cmd, keyword, and reply_text
|
141 |
+
|
142 |
+
buttons = None
|
143 |
+
conn = await connected(context.bot, update, chat, user.id)
|
144 |
+
if not conn is False:
|
145 |
+
chat_id = conn
|
146 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
147 |
+
chat_name = chat_obj.title
|
148 |
+
else:
|
149 |
+
chat_id = update.effective_chat.id
|
150 |
+
if chat.type == "private":
|
151 |
+
chat_name = "local filters"
|
152 |
+
else:
|
153 |
+
chat_name = chat.title
|
154 |
+
|
155 |
+
if not msg.reply_to_message and len(args) < 2:
|
156 |
+
await send_message(
|
157 |
+
update.effective_message,
|
158 |
+
"Please provide keyboard keyword for this filter to reply with!",
|
159 |
+
)
|
160 |
+
return
|
161 |
+
|
162 |
+
if msg.reply_to_message and not msg.reply_to_message.forum_topic_created:
|
163 |
+
if len(args) < 2:
|
164 |
+
await send_message(
|
165 |
+
update.effective_message,
|
166 |
+
"Please provide keyword for this filter to reply with!",
|
167 |
+
)
|
168 |
+
return
|
169 |
+
else:
|
170 |
+
keyword = args[1]
|
171 |
+
else:
|
172 |
+
extracted = split_quotes(args[1])
|
173 |
+
if len(extracted) < 1:
|
174 |
+
return
|
175 |
+
# set trigger -> lower, so as to avoid adding duplicate filters with different cases
|
176 |
+
keyword = extracted[0].lower()
|
177 |
+
|
178 |
+
# Add the filter
|
179 |
+
# Note: perhaps handlers can be removed somehow using sql.get_chat_filters
|
180 |
+
for handler in dispatcher.handlers.get(HANDLER_GROUP, []):
|
181 |
+
if handler.filters == (keyword, chat_id):
|
182 |
+
dispatcher.remove_handler(handler, HANDLER_GROUP)
|
183 |
+
|
184 |
+
text, file_type, file_id, media_spoiler = get_filter_type(msg)
|
185 |
+
if not msg.reply_to_message and len(extracted) >= 2:
|
186 |
+
offset = len(extracted[1]) - len(
|
187 |
+
msg.text,
|
188 |
+
) # set correct offset relative to command + notename
|
189 |
+
text, buttons = button_markdown_parser(
|
190 |
+
extracted[1],
|
191 |
+
entities=msg.parse_entities(),
|
192 |
+
offset=offset,
|
193 |
+
)
|
194 |
+
text = text.strip()
|
195 |
+
if not text:
|
196 |
+
await send_message(
|
197 |
+
update.effective_message,
|
198 |
+
"There is no note message - You can't JUST have buttons, you need a message to go with it!",
|
199 |
+
)
|
200 |
+
return
|
201 |
+
|
202 |
+
if len(args) >= 2:
|
203 |
+
if msg.reply_to_message:
|
204 |
+
if msg.reply_to_message.forum_topic_created:
|
205 |
+
offset = len(extracted[1]) - len(msg.text)
|
206 |
+
|
207 |
+
text, buttons = button_markdown_parser(
|
208 |
+
extracted[1], entities=msg.parse_entities(), offset=offset
|
209 |
+
)
|
210 |
+
|
211 |
+
text = text.strip()
|
212 |
+
if not text:
|
213 |
+
await send_message(
|
214 |
+
update.effective_message,
|
215 |
+
"There is no note message - You can't JUST have buttons, you need a message to go with it!",
|
216 |
+
)
|
217 |
+
return
|
218 |
+
else:
|
219 |
+
pass
|
220 |
+
|
221 |
+
elif msg.reply_to_message and len(args) >= 1:
|
222 |
+
if msg.reply_to_message.text:
|
223 |
+
text_to_parsing = msg.reply_to_message.text
|
224 |
+
elif msg.reply_to_message.caption:
|
225 |
+
text_to_parsing = msg.reply_to_message.caption
|
226 |
+
else:
|
227 |
+
text_to_parsing = ""
|
228 |
+
offset = len(
|
229 |
+
text_to_parsing,
|
230 |
+
) # set correct offset relative to command + notename
|
231 |
+
text, buttons = button_markdown_parser(
|
232 |
+
text_to_parsing,
|
233 |
+
entities=msg.parse_entities(),
|
234 |
+
offset=offset,
|
235 |
+
)
|
236 |
+
text = text.strip()
|
237 |
+
|
238 |
+
elif not text and not file_type:
|
239 |
+
await send_message(
|
240 |
+
update.effective_message,
|
241 |
+
"Please provide keyword for this filter reply with!",
|
242 |
+
)
|
243 |
+
return
|
244 |
+
|
245 |
+
elif msg.reply_to_message:
|
246 |
+
if msg.reply_to_message.forum_topic_created:
|
247 |
+
return
|
248 |
+
|
249 |
+
if msg.reply_to_message.text:
|
250 |
+
text_to_parsing = msg.reply_to_message.text
|
251 |
+
elif msg.reply_to_message.caption:
|
252 |
+
text_to_parsing = msg.reply_to_message.caption
|
253 |
+
else:
|
254 |
+
text_to_parsing = ""
|
255 |
+
offset = len(
|
256 |
+
text_to_parsing,
|
257 |
+
) # set correct offset relative to command + notename
|
258 |
+
text, buttons = button_markdown_parser(
|
259 |
+
text_to_parsing,
|
260 |
+
entities=msg.parse_entities(),
|
261 |
+
offset=offset,
|
262 |
+
)
|
263 |
+
text = text.strip()
|
264 |
+
if (msg.reply_to_message.text or msg.reply_to_message.caption) and not text:
|
265 |
+
await send_message(
|
266 |
+
update.effective_message,
|
267 |
+
"There is no note message - You can't JUST have buttons, you need a message to go with it!",
|
268 |
+
)
|
269 |
+
return
|
270 |
+
|
271 |
+
else:
|
272 |
+
await send_message(update.effective_message, "Invalid filter!")
|
273 |
+
return
|
274 |
+
|
275 |
+
add = await addnew_filter(
|
276 |
+
update, chat_id, keyword, text, file_type, file_id, buttons, media_spoiler
|
277 |
+
)
|
278 |
+
# This is an old method
|
279 |
+
# sql.add_filter(chat_id, keyword, content, is_sticker, is_document, is_image, is_audio, is_voice, is_video, buttons)
|
280 |
+
|
281 |
+
if add is True:
|
282 |
+
await send_message(
|
283 |
+
update.effective_message,
|
284 |
+
"Saved filter '{}' in *{}*!".format(keyword, chat_name),
|
285 |
+
parse_mode=ParseMode.MARKDOWN,
|
286 |
+
)
|
287 |
+
raise ApplicationHandlerStop
|
288 |
+
|
289 |
+
|
290 |
+
@typing_action
|
291 |
+
@check_admin(is_user=True)
|
292 |
+
async def stop_filter(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
293 |
+
chat = update.effective_chat
|
294 |
+
user = update.effective_user
|
295 |
+
args = update.effective_message.text.split(None, 1)
|
296 |
+
|
297 |
+
conn = await connected(context.bot, update, chat, user.id)
|
298 |
+
if not conn is False:
|
299 |
+
chat_id = conn
|
300 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
301 |
+
chat_name = chat_obj.title
|
302 |
+
else:
|
303 |
+
chat_id = update.effective_chat.id
|
304 |
+
if chat.type == "private":
|
305 |
+
chat_name = "Local filters"
|
306 |
+
else:
|
307 |
+
chat_name = chat.title
|
308 |
+
|
309 |
+
if len(args) < 2:
|
310 |
+
await send_message(update.effective_message, "What should i stop?")
|
311 |
+
return
|
312 |
+
|
313 |
+
chat_filters = sql.get_chat_triggers(chat_id)
|
314 |
+
|
315 |
+
if not chat_filters:
|
316 |
+
await send_message(update.effective_message, "No filters active here!")
|
317 |
+
return
|
318 |
+
|
319 |
+
for keyword in chat_filters:
|
320 |
+
if keyword == args[1]:
|
321 |
+
sql.remove_filter(chat_id, args[1])
|
322 |
+
await send_message(
|
323 |
+
update.effective_message,
|
324 |
+
"Okay, I'll stop replying to that filter in *{}*.".format(chat_name),
|
325 |
+
parse_mode=ParseMode.MARKDOWN,
|
326 |
+
)
|
327 |
+
raise ApplicationHandlerStop
|
328 |
+
|
329 |
+
await send_message(
|
330 |
+
update.effective_message,
|
331 |
+
"That's not a filter - Click: /filters to get currently active filters.",
|
332 |
+
)
|
333 |
+
|
334 |
+
|
335 |
+
async def reply_filter(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
336 |
+
chat = update.effective_chat
|
337 |
+
message = update.effective_message
|
338 |
+
|
339 |
+
if not update.effective_user or update.effective_user.id == 777000:
|
340 |
+
return
|
341 |
+
to_match = await extract_text(message)
|
342 |
+
if not to_match:
|
343 |
+
return
|
344 |
+
|
345 |
+
chat_filters = sql.get_chat_triggers(chat.id)
|
346 |
+
for keyword in chat_filters:
|
347 |
+
pattern = r"( |^|[^\w])" + re.escape(keyword) + r"( |$|[^\w])"
|
348 |
+
if re.search(pattern, to_match, flags=re.IGNORECASE):
|
349 |
+
if MessageHandlerChecker.check_user(update.effective_user.id):
|
350 |
+
return
|
351 |
+
filt = sql.get_filter(chat.id, keyword)
|
352 |
+
if filt.reply == "there is should be a new reply":
|
353 |
+
buttons = sql.get_buttons(chat.id, filt.keyword)
|
354 |
+
keyb = build_keyboard_parser(context.bot, chat.id, buttons)
|
355 |
+
keyboard = InlineKeyboardMarkup(keyb)
|
356 |
+
|
357 |
+
VALID_WELCOME_FORMATTERS = [
|
358 |
+
"first",
|
359 |
+
"last",
|
360 |
+
"fullname",
|
361 |
+
"username",
|
362 |
+
"id",
|
363 |
+
"chatname",
|
364 |
+
"mention",
|
365 |
+
]
|
366 |
+
if filt.reply_text:
|
367 |
+
if "%%%" in filt.reply_text:
|
368 |
+
split = filt.reply_text.split("%%%")
|
369 |
+
if all(split):
|
370 |
+
text = random.choice(split)
|
371 |
+
else:
|
372 |
+
text = filt.reply_text
|
373 |
+
else:
|
374 |
+
text = filt.reply_text
|
375 |
+
if text.startswith("~!") and text.endswith("!~"):
|
376 |
+
sticker_id = text.replace("~!", "").replace("!~", "")
|
377 |
+
try:
|
378 |
+
await context.bot.send_sticker(
|
379 |
+
chat.id,
|
380 |
+
sticker_id,
|
381 |
+
reply_to_message_id=message.message_id,
|
382 |
+
message_thread_id=message.message_thread_id
|
383 |
+
if chat.is_forum
|
384 |
+
else None,
|
385 |
+
)
|
386 |
+
return
|
387 |
+
except BadRequest as excp:
|
388 |
+
if (
|
389 |
+
excp.message
|
390 |
+
== "Wrong remote file identifier specified: wrong padding in the string"
|
391 |
+
):
|
392 |
+
await context.bot.send_message(
|
393 |
+
chat.id,
|
394 |
+
"Message couldn't be sent, Is the sticker id valid?",
|
395 |
+
message_thread_id=message.message_thread_id
|
396 |
+
if chat.is_forum
|
397 |
+
else None,
|
398 |
+
)
|
399 |
+
return
|
400 |
+
else:
|
401 |
+
LOGGER.exception("Error in filters: " + excp.message)
|
402 |
+
return
|
403 |
+
valid_format = escape_invalid_curly_brackets(
|
404 |
+
text,
|
405 |
+
VALID_WELCOME_FORMATTERS,
|
406 |
+
)
|
407 |
+
if valid_format:
|
408 |
+
filtext = valid_format.format(
|
409 |
+
first=escape(message.from_user.first_name),
|
410 |
+
last=escape(
|
411 |
+
message.from_user.last_name
|
412 |
+
or message.from_user.first_name,
|
413 |
+
),
|
414 |
+
fullname=" ".join(
|
415 |
+
[
|
416 |
+
escape(message.from_user.first_name),
|
417 |
+
escape(message.from_user.last_name),
|
418 |
+
]
|
419 |
+
if message.from_user.last_name
|
420 |
+
else [escape(message.from_user.first_name)],
|
421 |
+
),
|
422 |
+
username="@" + escape(message.from_user.username)
|
423 |
+
if message.from_user.username
|
424 |
+
else mention_html(
|
425 |
+
message.from_user.id,
|
426 |
+
message.from_user.first_name,
|
427 |
+
),
|
428 |
+
mention=mention_html(
|
429 |
+
message.from_user.id,
|
430 |
+
message.from_user.first_name,
|
431 |
+
),
|
432 |
+
chatname=escape(message.chat.title)
|
433 |
+
if message.chat.type != "private"
|
434 |
+
else escape(message.from_user.first_name),
|
435 |
+
id=message.from_user.id,
|
436 |
+
)
|
437 |
+
else:
|
438 |
+
filtext = ""
|
439 |
+
else:
|
440 |
+
filtext = ""
|
441 |
+
|
442 |
+
if filt.file_type in (sql.Types.BUTTON_TEXT, sql.Types.TEXT):
|
443 |
+
try:
|
444 |
+
await message.reply_text(
|
445 |
+
markdown_to_html(filtext),
|
446 |
+
parse_mode=ParseMode.HTML,
|
447 |
+
disable_web_page_preview=True,
|
448 |
+
reply_markup=keyboard,
|
449 |
+
)
|
450 |
+
except BadRequest as excp:
|
451 |
+
LOGGER.exception("Error in filters: " + excp.message)
|
452 |
+
try:
|
453 |
+
await send_message(
|
454 |
+
update.effective_message,
|
455 |
+
get_exception(excp, filt, chat),
|
456 |
+
)
|
457 |
+
except BadRequest as excp:
|
458 |
+
LOGGER.exception(
|
459 |
+
"Failed to send message: " + excp.message,
|
460 |
+
)
|
461 |
+
else:
|
462 |
+
try:
|
463 |
+
if filt.file_type not in [
|
464 |
+
sql.Types.PHOTO.value,
|
465 |
+
sql.Types.VIDEO,
|
466 |
+
]:
|
467 |
+
await ENUM_FUNC_MAP[filt.file_type](
|
468 |
+
chat.id,
|
469 |
+
filt.file_id,
|
470 |
+
reply_markup=keyboard,
|
471 |
+
reply_to_message_id=message.message_id,
|
472 |
+
message_thread_id=message.message_thread_id
|
473 |
+
if chat.is_forum
|
474 |
+
else None,
|
475 |
+
)
|
476 |
+
else:
|
477 |
+
await ENUM_FUNC_MAP[filt.file_type](
|
478 |
+
chat.id,
|
479 |
+
filt.file_id,
|
480 |
+
reply_markup=keyboard,
|
481 |
+
caption=filt.reply_text,
|
482 |
+
reply_to_message_id=message.message_id,
|
483 |
+
message_thread_id=message.message_thread_id
|
484 |
+
if chat.is_forum
|
485 |
+
else None,
|
486 |
+
has_spoiler=filt.has_media_spoiler,
|
487 |
+
)
|
488 |
+
except BadRequest:
|
489 |
+
await send_message(
|
490 |
+
message,
|
491 |
+
"I don't have the permission to send the content of the filter.",
|
492 |
+
)
|
493 |
+
break
|
494 |
+
else:
|
495 |
+
if filt.is_sticker:
|
496 |
+
await message.reply_sticker(filt.reply)
|
497 |
+
elif filt.is_document:
|
498 |
+
await message.reply_document(filt.reply)
|
499 |
+
elif filt.is_image:
|
500 |
+
await message.reply_photo(
|
501 |
+
filt.reply, has_spoiler=filt.has_media_spoiler
|
502 |
+
)
|
503 |
+
elif filt.is_audio:
|
504 |
+
await message.reply_audio(filt.reply)
|
505 |
+
elif filt.is_voice:
|
506 |
+
await message.reply_voice(filt.reply)
|
507 |
+
elif filt.is_video:
|
508 |
+
await message.reply_video(
|
509 |
+
filt.reply, has_spoiler=filt.has_media_spoiler
|
510 |
+
)
|
511 |
+
elif filt.has_buttons:
|
512 |
+
buttons = sql.get_buttons(chat.id, filt.keyword)
|
513 |
+
keyb = build_keyboard_parser(context.bot, chat.id, buttons)
|
514 |
+
keyboard = InlineKeyboardMarkup(keyb)
|
515 |
+
|
516 |
+
try:
|
517 |
+
await context.bot.send_message(
|
518 |
+
chat.id,
|
519 |
+
markdown_to_html(filt.reply),
|
520 |
+
parse_mode=ParseMode.HTML,
|
521 |
+
disable_web_page_preview=True,
|
522 |
+
reply_markup=keyboard,
|
523 |
+
message_thread_id=message.message_thread_id
|
524 |
+
if chat.is_forum
|
525 |
+
else None,
|
526 |
+
)
|
527 |
+
except BadRequest as excp:
|
528 |
+
if excp.message == "Unsupported url protocol":
|
529 |
+
try:
|
530 |
+
await send_message(
|
531 |
+
update.effective_message,
|
532 |
+
"You seem to be trying to use an unsupported url protocol. "
|
533 |
+
"Telegram doesn't support buttons for some protocols, such as tg://. Please try "
|
534 |
+
"again...",
|
535 |
+
)
|
536 |
+
except BadRequest as excp:
|
537 |
+
LOGGER.exception("Error in filters: " + excp.message)
|
538 |
+
else:
|
539 |
+
try:
|
540 |
+
await send_message(
|
541 |
+
update.effective_message,
|
542 |
+
"This message couldn't be sent as it's incorrectly formatted.",
|
543 |
+
)
|
544 |
+
except BadRequest as excp:
|
545 |
+
LOGGER.exception("Error in filters: " + excp.message)
|
546 |
+
LOGGER.warning(
|
547 |
+
"Message %s could not be parsed",
|
548 |
+
str(filt.reply),
|
549 |
+
)
|
550 |
+
LOGGER.exception(
|
551 |
+
"Could not parse filter %s in chat %s",
|
552 |
+
str(filt.keyword),
|
553 |
+
str(chat.id),
|
554 |
+
)
|
555 |
+
|
556 |
+
else:
|
557 |
+
# LEGACY - all new filters will have has_markdown set to True.
|
558 |
+
try:
|
559 |
+
await context.bot.send_message(
|
560 |
+
chat.id,
|
561 |
+
filt.reply,
|
562 |
+
message_thread_id=message.message_thread_id
|
563 |
+
if chat.is_forum
|
564 |
+
else None,
|
565 |
+
)
|
566 |
+
except BadRequest as excp:
|
567 |
+
LOGGER.exception("Error in filters: " + excp.message)
|
568 |
+
break
|
569 |
+
|
570 |
+
|
571 |
+
async def rmall_filters(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
572 |
+
chat = update.effective_chat
|
573 |
+
user = update.effective_user
|
574 |
+
member = await chat.get_member(user.id)
|
575 |
+
if member.status != ChatMemberStatus.OWNER and user.id not in DRAGONS:
|
576 |
+
await update.effective_message.reply_text(
|
577 |
+
"Only the chat owner can clear all notes at once.",
|
578 |
+
)
|
579 |
+
else:
|
580 |
+
buttons = InlineKeyboardMarkup(
|
581 |
+
[
|
582 |
+
[
|
583 |
+
InlineKeyboardButton(
|
584 |
+
text="STOP ALL FILTERS",
|
585 |
+
callback_data="filters_rmall",
|
586 |
+
),
|
587 |
+
],
|
588 |
+
[InlineKeyboardButton(text="CANCEL", callback_data="filters_cancel")],
|
589 |
+
],
|
590 |
+
)
|
591 |
+
await update.effective_message.reply_text(
|
592 |
+
f"Are you sure you would like to stop ALL filters in {chat.title}? This action cannot be undone.",
|
593 |
+
reply_markup=buttons,
|
594 |
+
parse_mode=ParseMode.MARKDOWN,
|
595 |
+
)
|
596 |
+
|
597 |
+
|
598 |
+
async def rmall_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
599 |
+
query = update.callback_query
|
600 |
+
chat = update.effective_chat
|
601 |
+
msg = update.effective_message
|
602 |
+
member = await chat.get_member(query.from_user.id)
|
603 |
+
if query.data == "filters_rmall":
|
604 |
+
if member.status == "creator" or query.from_user.id in DRAGONS:
|
605 |
+
allfilters = sql.get_chat_triggers(chat.id)
|
606 |
+
if not allfilters:
|
607 |
+
await msg.edit_text("No filters in this chat, nothing to stop!")
|
608 |
+
return
|
609 |
+
|
610 |
+
count = 0
|
611 |
+
filterlist = []
|
612 |
+
for x in allfilters:
|
613 |
+
count += 1
|
614 |
+
filterlist.append(x)
|
615 |
+
|
616 |
+
for i in filterlist:
|
617 |
+
sql.remove_filter(chat.id, i)
|
618 |
+
|
619 |
+
await msg.edit_text(f"Cleaned {count} filters in {chat.title}")
|
620 |
+
|
621 |
+
if member.status == "administrator":
|
622 |
+
await query.answer("Only owner of the chat can do this.")
|
623 |
+
|
624 |
+
if member.status == "member":
|
625 |
+
await query.answer("You need to be admin to do this.")
|
626 |
+
elif query.data == "filters_cancel":
|
627 |
+
if member.status == "creator" or query.from_user.id in DRAGONS:
|
628 |
+
await msg.edit_text("Clearing of all filters has been cancelled.")
|
629 |
+
return await query.answer()
|
630 |
+
if member.status == "administrator":
|
631 |
+
await query.answer("Only owner of the chat can do this.")
|
632 |
+
if member.status == "member":
|
633 |
+
await query.answer("You need to be admin to do this.")
|
634 |
+
|
635 |
+
|
636 |
+
# NOT ASYNC NOT A HANDLER
|
637 |
+
def get_exception(excp, filt, chat):
|
638 |
+
if excp.message == "Unsupported url protocol":
|
639 |
+
return "You seem to be trying to use the URL protocol which is not supported. Telegram does not support key for multiple protocols, such as tg: //. Please try again!"
|
640 |
+
elif excp.message == "Reply message not found":
|
641 |
+
return "noreply"
|
642 |
+
else:
|
643 |
+
LOGGER.warning("Message %s could not be parsed", str(filt.reply))
|
644 |
+
LOGGER.exception(
|
645 |
+
"Could not parse filter %s in chat %s",
|
646 |
+
str(filt.keyword),
|
647 |
+
str(chat.id),
|
648 |
+
)
|
649 |
+
return "This data could not be sent because it is incorrectly formatted."
|
650 |
+
|
651 |
+
|
652 |
+
# NOT ASYNC NOT A HANDLER
|
653 |
+
async def addnew_filter(
|
654 |
+
update, chat_id, keyword, text, file_type, file_id, buttons, has_spoiler
|
655 |
+
):
|
656 |
+
msg = update.effective_message
|
657 |
+
totalfilt = sql.get_chat_triggers(chat_id)
|
658 |
+
if len(totalfilt) >= 150: # Idk why i made this like function....
|
659 |
+
await msg.reply_text("This group has reached its max filters limit of 150.")
|
660 |
+
return False
|
661 |
+
else:
|
662 |
+
sql.new_add_filter(
|
663 |
+
chat_id, keyword, text, file_type, file_id, buttons, has_spoiler
|
664 |
+
)
|
665 |
+
return True
|
666 |
+
|
667 |
+
|
668 |
+
def __stats__():
|
669 |
+
return "• {} filters, across {} chats.".format(sql.num_filters(), sql.num_chats())
|
670 |
+
|
671 |
+
|
672 |
+
async def __import_data__(chat_id, data, message):
|
673 |
+
# set chat filters
|
674 |
+
filters = data.get("filters", {})
|
675 |
+
for trigger in filters:
|
676 |
+
sql.add_to_blacklist(chat_id, trigger)
|
677 |
+
|
678 |
+
|
679 |
+
def __migrate__(old_chat_id, new_chat_id):
|
680 |
+
sql.migrate_chat(old_chat_id, new_chat_id)
|
681 |
+
|
682 |
+
|
683 |
+
def __chat_settings__(chat_id, user_id):
|
684 |
+
cust_filters = sql.get_chat_triggers(chat_id)
|
685 |
+
return "There are `{}` custom filters here.".format(len(cust_filters))
|
686 |
+
|
687 |
+
|
688 |
+
# <=================================================== HELP ====================================================>
|
689 |
+
|
690 |
+
|
691 |
+
__help__ = """
|
692 |
+
» `/filters`*:* List all active filters saved in the chat.
|
693 |
+
|
694 |
+
➠ *Admin only:*
|
695 |
+
|
696 |
+
» `/filter <keyword> <reply message>`*:* Add a filter to this chat. The bot will now reply that message whenever 'keyword'\
|
697 |
+
is mentioned. If you reply to a sticker with a keyword, the bot will reply with that sticker. NOTE: all filter \
|
698 |
+
keywords are in lowercase. If you want your keyword to be a sentence, use quotes. eg: /filter "hey there" How you \
|
699 |
+
doin?
|
700 |
+
|
701 |
+
➠ Separate diff replies by `%%%` to get random replies
|
702 |
+
➠ *Example:*
|
703 |
+
|
704 |
+
» `/filter "filtername"
|
705 |
+
Reply 1
|
706 |
+
%%%
|
707 |
+
Reply 2
|
708 |
+
%%%
|
709 |
+
Reply 3`
|
710 |
+
|
711 |
+
» `/stop <filter keyword>`*:* Stop that filter.
|
712 |
+
|
713 |
+
➠ *Chat creator only:*
|
714 |
+
» `/removeallfilters`*:* Remove all chat filters at once.
|
715 |
+
|
716 |
+
➠ *Note*: Filters also support markdown formatters like: {first}, {last} etc.. and buttons.
|
717 |
+
➠ Now Supports media spoilers too, and media caption.
|
718 |
+
"""
|
719 |
+
|
720 |
+
__mod_name__ = "FILTERS"
|
721 |
+
|
722 |
+
# <================================================ HANDLER =======================================================>
|
723 |
+
FILTER_HANDLER = CommandHandler("filter", filters, block=False)
|
724 |
+
STOP_HANDLER = CommandHandler("stop", stop_filter, block=False)
|
725 |
+
RMALLFILTER_HANDLER = CommandHandler(
|
726 |
+
"removeallfilters",
|
727 |
+
rmall_filters,
|
728 |
+
filters=filters_module.ChatType.GROUPS,
|
729 |
+
block=False,
|
730 |
+
)
|
731 |
+
RMALLFILTER_CALLBACK = CallbackQueryHandler(
|
732 |
+
rmall_callback, pattern=r"filters_.*", block=False
|
733 |
+
)
|
734 |
+
LIST_HANDLER = DisableAbleCommandHandler(
|
735 |
+
"filters", list_handlers, admin_ok=True, block=False
|
736 |
+
)
|
737 |
+
CUST_FILTER_HANDLER = MessageHandler(
|
738 |
+
filters_module.TEXT & ~filters_module.UpdateType.EDITED_MESSAGE,
|
739 |
+
reply_filter,
|
740 |
+
block=False,
|
741 |
+
)
|
742 |
+
|
743 |
+
function(FILTER_HANDLER)
|
744 |
+
function(STOP_HANDLER)
|
745 |
+
function(LIST_HANDLER)
|
746 |
+
function(CUST_FILTER_HANDLER, HANDLER_GROUP)
|
747 |
+
function(RMALLFILTER_HANDLER)
|
748 |
+
function(RMALLFILTER_CALLBACK)
|
749 |
+
|
750 |
+
__handlers__ = [
|
751 |
+
FILTER_HANDLER,
|
752 |
+
STOP_HANDLER,
|
753 |
+
LIST_HANDLER,
|
754 |
+
(CUST_FILTER_HANDLER, HANDLER_GROUP, RMALLFILTER_HANDLER),
|
755 |
+
]
|
756 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/disable.py
ADDED
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import importlib
|
3 |
+
import re
|
4 |
+
from typing import Dict, List, Optional, Tuple, Union
|
5 |
+
|
6 |
+
from future.utils import string_types
|
7 |
+
from telegram import Update
|
8 |
+
from telegram.constants import ParseMode
|
9 |
+
from telegram.ext import CommandHandler, ContextTypes, MessageHandler
|
10 |
+
from telegram.ext import filters as filters_module
|
11 |
+
from telegram.helpers import escape_markdown
|
12 |
+
|
13 |
+
from Mikobot import function
|
14 |
+
from Mikobot.plugins.helper_funcs.misc import is_module_loaded
|
15 |
+
from Mikobot.utils.cmdprefix import CMD_STARTERS
|
16 |
+
|
17 |
+
# <=======================================================================================================>
|
18 |
+
|
19 |
+
FILENAME = __name__.rsplit(".", 1)[-1]
|
20 |
+
|
21 |
+
# If module is due to be loaded, then setup all the magical handlers
|
22 |
+
if is_module_loaded(FILENAME):
|
23 |
+
from Database.sql import disable_sql as sql
|
24 |
+
from Mikobot.plugins.helper_funcs.chat_status import (
|
25 |
+
check_admin,
|
26 |
+
connection_status,
|
27 |
+
is_user_admin,
|
28 |
+
)
|
29 |
+
|
30 |
+
DISABLE_CMDS = []
|
31 |
+
DISABLE_OTHER = []
|
32 |
+
ADMIN_CMDS = []
|
33 |
+
|
34 |
+
# <================================================ CLASS =======================================================>
|
35 |
+
class DisableAbleCommandHandler(CommandHandler):
|
36 |
+
def __init__(
|
37 |
+
self,
|
38 |
+
command,
|
39 |
+
callback,
|
40 |
+
block: bool,
|
41 |
+
filters: filters_module.BaseFilter = None,
|
42 |
+
admin_ok=False,
|
43 |
+
):
|
44 |
+
super().__init__(command, callback, block=block)
|
45 |
+
self.admin_ok = admin_ok
|
46 |
+
|
47 |
+
if isinstance(command, string_types):
|
48 |
+
commands = frozenset({command.lower()})
|
49 |
+
DISABLE_CMDS.append(command)
|
50 |
+
if admin_ok:
|
51 |
+
ADMIN_CMDS.append(command)
|
52 |
+
else:
|
53 |
+
commands = frozenset(x.lower() for x in command)
|
54 |
+
DISABLE_CMDS.extend(command)
|
55 |
+
if admin_ok:
|
56 |
+
ADMIN_CMDS.extend(command)
|
57 |
+
for comm in commands:
|
58 |
+
if not re.match(r"^[\da-z_]{1,32}$", comm):
|
59 |
+
raise ValueError(f"Command `{comm}` is not a valid bot command")
|
60 |
+
|
61 |
+
self.commands = commands
|
62 |
+
self.filters = (
|
63 |
+
filters if filters is not None else filters_module.UpdateType.MESSAGES
|
64 |
+
)
|
65 |
+
|
66 |
+
def check_update(
|
67 |
+
self, update
|
68 |
+
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
|
69 |
+
if isinstance(update, Update) and update.effective_message:
|
70 |
+
message = update.effective_message
|
71 |
+
|
72 |
+
if message.text and len(message.text) > 1:
|
73 |
+
fst_word = message.text.split(None, 1)[0]
|
74 |
+
if len(fst_word) > 1 and any(
|
75 |
+
fst_word.startswith(start) for start in CMD_STARTERS
|
76 |
+
):
|
77 |
+
args = message.text.split()[1:]
|
78 |
+
command_parts = fst_word[1:].split("@")
|
79 |
+
command_parts.append(message.get_bot().username)
|
80 |
+
|
81 |
+
if not (
|
82 |
+
command_parts[0].lower() in self.commands
|
83 |
+
and command_parts[1].lower()
|
84 |
+
== message.get_bot().username.lower()
|
85 |
+
):
|
86 |
+
return None
|
87 |
+
|
88 |
+
chat = update.effective_chat
|
89 |
+
user = update.effective_user
|
90 |
+
|
91 |
+
filter_result = self.filters.check_update(update)
|
92 |
+
if filter_result:
|
93 |
+
# disabled, admincmd, user admin
|
94 |
+
if sql.is_command_disabled(
|
95 |
+
chat.id, command_parts[0].lower()
|
96 |
+
):
|
97 |
+
# check if command was disabled
|
98 |
+
is_disabled = command_parts[
|
99 |
+
0
|
100 |
+
] in ADMIN_CMDS and is_user_admin(chat, user.id)
|
101 |
+
if not is_disabled:
|
102 |
+
return None
|
103 |
+
else:
|
104 |
+
return args, filter_result
|
105 |
+
|
106 |
+
return args, filter_result
|
107 |
+
return False
|
108 |
+
return None
|
109 |
+
|
110 |
+
class DisableAbleMessageHandler(MessageHandler):
|
111 |
+
def __init__(self, filters, callback, block: bool, friendly, **kwargs):
|
112 |
+
super().__init__(filters, callback, block=block, **kwargs)
|
113 |
+
DISABLE_OTHER.append(friendly)
|
114 |
+
self.friendly = friendly
|
115 |
+
if filters:
|
116 |
+
self.filters = filters_module.UpdateType.MESSAGES & filters
|
117 |
+
else:
|
118 |
+
self.filters = filters_module.UpdateType.MESSAGES
|
119 |
+
|
120 |
+
def check_update(self, update):
|
121 |
+
chat = update.effective_chat
|
122 |
+
message = update.effective_message
|
123 |
+
filter_result = self.filters.check_update(update)
|
124 |
+
|
125 |
+
try:
|
126 |
+
args = message.text.split()[1:]
|
127 |
+
except:
|
128 |
+
args = []
|
129 |
+
|
130 |
+
if super().check_update(update):
|
131 |
+
if sql.is_command_disabled(chat.id, self.friendly):
|
132 |
+
return False
|
133 |
+
else:
|
134 |
+
return args, filter_result
|
135 |
+
|
136 |
+
# <=======================================================================================================>
|
137 |
+
|
138 |
+
# <================================================ FUNCTION =======================================================>
|
139 |
+
@connection_status
|
140 |
+
@check_admin(is_user=True)
|
141 |
+
async def disable(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
142 |
+
args = context.args
|
143 |
+
chat = update.effective_chat
|
144 |
+
if len(args) >= 1:
|
145 |
+
disable_cmd = args[0]
|
146 |
+
if disable_cmd.startswith(CMD_STARTERS):
|
147 |
+
disable_cmd = disable_cmd[1:]
|
148 |
+
|
149 |
+
if disable_cmd in set(DISABLE_CMDS + DISABLE_OTHER):
|
150 |
+
sql.disable_command(chat.id, str(disable_cmd).lower())
|
151 |
+
await update.effective_message.reply_text(
|
152 |
+
f"Disabled the use of `{disable_cmd}`",
|
153 |
+
parse_mode=ParseMode.MARKDOWN,
|
154 |
+
)
|
155 |
+
else:
|
156 |
+
await update.effective_message.reply_text(
|
157 |
+
"That command can't be disabled"
|
158 |
+
)
|
159 |
+
|
160 |
+
else:
|
161 |
+
await update.effective_message.reply_text("What should I disable?")
|
162 |
+
|
163 |
+
@connection_status
|
164 |
+
@check_admin(is_user=True)
|
165 |
+
async def disable_module(
|
166 |
+
update: Update, context: ContextTypes.DEFAULT_TYPE
|
167 |
+
) -> None:
|
168 |
+
args = context.args
|
169 |
+
chat = update.effective_chat
|
170 |
+
if len(args) >= 1:
|
171 |
+
disable_module = "Mikobot.plugins." + args[0].rsplit(".", 1)[0]
|
172 |
+
|
173 |
+
try:
|
174 |
+
module = importlib.import_module(disable_module)
|
175 |
+
except:
|
176 |
+
await update.effective_message.reply_text(
|
177 |
+
"Does that module even exsist?"
|
178 |
+
)
|
179 |
+
return
|
180 |
+
|
181 |
+
try:
|
182 |
+
command_list = module.__command_list__
|
183 |
+
except:
|
184 |
+
await update.effective_message.reply_text(
|
185 |
+
"Module does not contain command list!",
|
186 |
+
)
|
187 |
+
return
|
188 |
+
|
189 |
+
disabled_cmds = []
|
190 |
+
failed_disabled_cmds = []
|
191 |
+
|
192 |
+
for disable_cmd in command_list:
|
193 |
+
if disable_cmd.startswith(CMD_STARTERS):
|
194 |
+
disable_cmd = disable_cmd[1:]
|
195 |
+
|
196 |
+
if disable_cmd in set(DISABLE_CMDS + DISABLE_OTHER):
|
197 |
+
sql.disable_command(chat.id, str(disable_cmd).lower())
|
198 |
+
disabled_cmds.append(disable_cmd)
|
199 |
+
else:
|
200 |
+
failed_disabled_cmds.append(disable_cmd)
|
201 |
+
|
202 |
+
if disabled_cmds:
|
203 |
+
disabled_cmds_string = ", ".join(disabled_cmds)
|
204 |
+
await update.effective_message.reply_text(
|
205 |
+
f"Disabled the use of`{disabled_cmds_string}`",
|
206 |
+
parse_mode=ParseMode.MARKDOWN,
|
207 |
+
)
|
208 |
+
|
209 |
+
if failed_disabled_cmds:
|
210 |
+
failed_disabled_cmds_string = ", ".join(failed_disabled_cmds)
|
211 |
+
await update.effective_message.reply_text(
|
212 |
+
f"Commands `{failed_disabled_cmds_string}` can't be disabled",
|
213 |
+
parse_mode=ParseMode.MARKDOWN,
|
214 |
+
)
|
215 |
+
|
216 |
+
else:
|
217 |
+
await update.effective_message.reply_text("What should I disable?")
|
218 |
+
|
219 |
+
@connection_status
|
220 |
+
@check_admin(is_user=True)
|
221 |
+
async def enable(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
222 |
+
args = context.args
|
223 |
+
chat = update.effective_chat
|
224 |
+
if len(args) >= 1:
|
225 |
+
enable_cmd = args[0]
|
226 |
+
if enable_cmd.startswith(CMD_STARTERS):
|
227 |
+
enable_cmd = enable_cmd[1:]
|
228 |
+
|
229 |
+
if sql.enable_command(chat.id, enable_cmd):
|
230 |
+
await update.effective_message.reply_text(
|
231 |
+
f"Enabled the use of`{enable_cmd}`",
|
232 |
+
parse_mode=ParseMode.MARKDOWN,
|
233 |
+
)
|
234 |
+
else:
|
235 |
+
await update.effective_message.reply_text("Is that even disabled?")
|
236 |
+
|
237 |
+
else:
|
238 |
+
await update.effective_message.reply_text("What sould I enable?")
|
239 |
+
|
240 |
+
@connection_status
|
241 |
+
@check_admin(is_user=True)
|
242 |
+
async def enable_module(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
243 |
+
args = context.args
|
244 |
+
chat = update.effective_chat
|
245 |
+
|
246 |
+
if len(args) >= 1:
|
247 |
+
enable_module = "Mikobot.plugins." + args[0].rsplit(".", 1)[0]
|
248 |
+
|
249 |
+
try:
|
250 |
+
module = importlib.import_module(enable_module)
|
251 |
+
except:
|
252 |
+
await update.effective_message.reply_text(
|
253 |
+
"Does that module even exsist?"
|
254 |
+
)
|
255 |
+
return
|
256 |
+
|
257 |
+
try:
|
258 |
+
command_list = module.__command_list__
|
259 |
+
except:
|
260 |
+
await update.effective_message.reply_text(
|
261 |
+
"Module does not contain command list!",
|
262 |
+
)
|
263 |
+
return
|
264 |
+
|
265 |
+
enabled_cmds = []
|
266 |
+
failed_enabled_cmds = []
|
267 |
+
|
268 |
+
for enable_cmd in command_list:
|
269 |
+
if enable_cmd.startswith(CMD_STARTERS):
|
270 |
+
enable_cmd = enable_cmd[1:]
|
271 |
+
|
272 |
+
if sql.enable_command(chat.id, enable_cmd):
|
273 |
+
enabled_cmds.append(enable_cmd)
|
274 |
+
else:
|
275 |
+
failed_enabled_cmds.append(enable_cmd)
|
276 |
+
|
277 |
+
if enabled_cmds:
|
278 |
+
enabled_cmds_string = ", ".join(enabled_cmds)
|
279 |
+
await update.effective_message.reply_text(
|
280 |
+
f"Enabled the use of`{enabled_cmds_string}`",
|
281 |
+
parse_mode=ParseMode.MARKDOWN,
|
282 |
+
)
|
283 |
+
|
284 |
+
if failed_enabled_cmds:
|
285 |
+
failed_enabled_cmds_string = ", ".join(failed_enabled_cmds)
|
286 |
+
await update.effective_message.reply_text(
|
287 |
+
f"Are the commands `{failed_enabled_cmds_string}` even disabled?",
|
288 |
+
parse_mode=ParseMode.MARKDOWN,
|
289 |
+
)
|
290 |
+
|
291 |
+
else:
|
292 |
+
await update.effective_message.reply_text("ᴡʜᴀᴛ sʜᴏᴜʟᴅ I ᴇɴᴀʙʟᴇ?")
|
293 |
+
|
294 |
+
@connection_status
|
295 |
+
@check_admin(is_user=True)
|
296 |
+
async def list_cmds(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
297 |
+
if DISABLE_CMDS + DISABLE_OTHER:
|
298 |
+
result = ""
|
299 |
+
for cmd in set(DISABLE_CMDS + DISABLE_OTHER):
|
300 |
+
result += f" - `{escape_markdown(cmd)}`\n"
|
301 |
+
await update.effective_message.reply_text(
|
302 |
+
f"The following commands are toggleable:\n{result}",
|
303 |
+
parse_mode=ParseMode.MARKDOWN,
|
304 |
+
)
|
305 |
+
else:
|
306 |
+
await update.effective_message.reply_text("No commands can be disabled.")
|
307 |
+
|
308 |
+
# do not async
|
309 |
+
def build_curr_disabled(chat_id: Union[str, int]) -> str:
|
310 |
+
disabled = sql.get_all_disabled(chat_id)
|
311 |
+
if not disabled:
|
312 |
+
return "No commands are disabled!"
|
313 |
+
|
314 |
+
result = ""
|
315 |
+
for cmd in disabled:
|
316 |
+
result += " - `{}`\n".format(escape_markdown(cmd))
|
317 |
+
return "The following commands are currently restricted:\n{}".format(result)
|
318 |
+
|
319 |
+
@connection_status
|
320 |
+
async def commands(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
321 |
+
chat = update.effective_chat
|
322 |
+
await update.effective_message.reply_text(
|
323 |
+
build_curr_disabled(chat.id),
|
324 |
+
parse_mode=ParseMode.MARKDOWN,
|
325 |
+
)
|
326 |
+
|
327 |
+
def __stats__():
|
328 |
+
return f"• {sql.num_disabled()} disabled items, across {sql.num_chats()} chats."
|
329 |
+
|
330 |
+
def __migrate__(old_chat_id, new_chat_id):
|
331 |
+
sql.migrate_chat(old_chat_id, new_chat_id)
|
332 |
+
|
333 |
+
def __chat_settings__(chat_id, user_id):
|
334 |
+
return build_curr_disabled(chat_id)
|
335 |
+
|
336 |
+
# <=================================================== HANDLER ====================================================>
|
337 |
+
|
338 |
+
DISABLE_HANDLER = CommandHandler("disable", disable, block=False)
|
339 |
+
DISABLE_MODULE_HANDLER = CommandHandler(
|
340 |
+
"disablemodule", disable_module, block=False
|
341 |
+
)
|
342 |
+
ENABLE_HANDLER = CommandHandler("enable", enable, block=False)
|
343 |
+
ENABLE_MODULE_HANDLER = CommandHandler("enablemodule", enable_module, block=False)
|
344 |
+
COMMANDS_HANDLER = CommandHandler(["cmds", "disabled"], commands, block=False)
|
345 |
+
TOGGLE_HANDLER = CommandHandler("listcmds", list_cmds, block=False)
|
346 |
+
|
347 |
+
function(DISABLE_HANDLER)
|
348 |
+
function(DISABLE_MODULE_HANDLER)
|
349 |
+
function(ENABLE_HANDLER)
|
350 |
+
function(ENABLE_MODULE_HANDLER)
|
351 |
+
function(COMMANDS_HANDLER)
|
352 |
+
function(TOGGLE_HANDLER)
|
353 |
+
|
354 |
+
# <=================================================== HELP ====================================================>
|
355 |
+
__help__ = """
|
356 |
+
» /cmds: Check the current status of disabled commands
|
357 |
+
|
358 |
+
➠ *Admins only*:
|
359 |
+
|
360 |
+
» /enable < cmd name >: Enable that command.
|
361 |
+
|
362 |
+
» /disable < cmd name >: Disable that command.
|
363 |
+
|
364 |
+
» /enablemodule < module name >: Enable all commands in that module.
|
365 |
+
|
366 |
+
» /disablemodule < module name >: Disable all commands in that module.
|
367 |
+
|
368 |
+
» /listcmds: List all possible toggleable commands.
|
369 |
+
"""
|
370 |
+
|
371 |
+
__mod_name__ = "DISABLE"
|
372 |
+
|
373 |
+
else:
|
374 |
+
DisableAbleCommandHandler = CommandHandler
|
375 |
+
DisableAbleMessageHandler = MessageHandler
|
376 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/extra.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
from time import gmtime, strftime, time
|
3 |
+
|
4 |
+
from pyrogram import filters
|
5 |
+
from pyrogram.types import Message
|
6 |
+
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
7 |
+
from telegram.ext import CallbackQueryHandler, CommandHandler, ContextTypes
|
8 |
+
|
9 |
+
from Mikobot import LOGGER, app, function
|
10 |
+
from Mikobot.plugins.helper_funcs.chat_status import check_admin
|
11 |
+
|
12 |
+
# <=======================================================================================================>
|
13 |
+
|
14 |
+
UPTIME = time() # Check bot uptime
|
15 |
+
|
16 |
+
|
17 |
+
# <================================================ FUNCTION =======================================================>
|
18 |
+
async def getid(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
19 |
+
chat = update.effective_chat
|
20 |
+
your_id = update.message.from_user.id
|
21 |
+
message_id = update.message.message_id
|
22 |
+
reply = update.message.reply_to_message
|
23 |
+
|
24 |
+
text = f"[Message ID:](https://t.me/{chat.username}/{message_id}) `{message_id}`\n"
|
25 |
+
text += f"[Your ID:](tg://user?id={your_id}) `{your_id}`\n"
|
26 |
+
|
27 |
+
if context.args:
|
28 |
+
try:
|
29 |
+
user_id = context.args[0]
|
30 |
+
text += f"[User ID:](tg://user?id={user_id}) `{user_id}`\n"
|
31 |
+
except Exception:
|
32 |
+
await update.message.reply_text(
|
33 |
+
"This user doesn't exist.", parse_mode="Markdown"
|
34 |
+
)
|
35 |
+
return
|
36 |
+
|
37 |
+
text += f"[Chat ID:](https://t.me/{chat.username}) `{chat.id}`\n\n"
|
38 |
+
|
39 |
+
if reply:
|
40 |
+
text += f"[Replied Message ID:](https://t.me/{chat.username}/{reply.message_id}) `{reply.message_id}`\n"
|
41 |
+
text += f"[Replied User ID:](tg://user?id={reply.from_user.id}) `{reply.from_user.id}`\n\n"
|
42 |
+
|
43 |
+
if reply and reply.forward_from_chat:
|
44 |
+
text += f"The forwarded channel, {reply.forward_from_chat.title}, has an id of `{reply.forward_from_chat.id}`\n\n"
|
45 |
+
|
46 |
+
if reply and reply.sender_chat:
|
47 |
+
text += f"ID of the replied chat/channel, is `{reply.sender_chat.id}`"
|
48 |
+
|
49 |
+
# Sticker ID to be sent
|
50 |
+
sticker_id = (
|
51 |
+
"CAACAgIAAx0CanzPTAABASPCZQdU9NbQIol5TW1GU2zV4KfjDMEAAnccAALIWZhJPyYLf3FzPHswBA"
|
52 |
+
)
|
53 |
+
|
54 |
+
# Send the sticker
|
55 |
+
await update.message.reply_sticker(sticker=sticker_id)
|
56 |
+
|
57 |
+
# Send the text message as a caption
|
58 |
+
await update.message.reply_text(
|
59 |
+
text, parse_mode="Markdown", disable_web_page_preview=True
|
60 |
+
)
|
61 |
+
|
62 |
+
|
63 |
+
# Function to handle the "logs" command
|
64 |
+
@check_admin(only_dev=True)
|
65 |
+
async def logs(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
66 |
+
user = update.effective_user
|
67 |
+
with open("Logs.txt", "rb") as f:
|
68 |
+
caption = "Here is your log"
|
69 |
+
reply_markup = InlineKeyboardMarkup(
|
70 |
+
[[InlineKeyboardButton("Close", callback_data="close")]]
|
71 |
+
)
|
72 |
+
message = await context.bot.send_document(
|
73 |
+
document=f,
|
74 |
+
filename=f.name,
|
75 |
+
caption=caption,
|
76 |
+
reply_markup=reply_markup,
|
77 |
+
chat_id=user.id,
|
78 |
+
)
|
79 |
+
|
80 |
+
# Store the message ID for later reference
|
81 |
+
context.user_data["log_message_id"] = message.message_id
|
82 |
+
|
83 |
+
|
84 |
+
# Asynchronous callback query handler for the "close" button
|
85 |
+
@check_admin(only_dev=True)
|
86 |
+
async def close_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
87 |
+
query = update.callback_query
|
88 |
+
message_id = context.user_data.get("log_message_id")
|
89 |
+
if message_id:
|
90 |
+
await context.bot.delete_message(
|
91 |
+
chat_id=query.message.chat_id, message_id=message_id
|
92 |
+
)
|
93 |
+
|
94 |
+
|
95 |
+
@app.on_message(filters.command("pyroping"))
|
96 |
+
async def ping(_, m: Message):
|
97 |
+
LOGGER.info(f"{m.from_user.id} used ping cmd in {m.chat.id}")
|
98 |
+
start = time()
|
99 |
+
replymsg = await m.reply_text(text="Pinging...", quote=True)
|
100 |
+
delta_ping = time() - start
|
101 |
+
|
102 |
+
up = strftime("%Hh %Mm %Ss", gmtime(time() - UPTIME))
|
103 |
+
image_url = "https://telegra.ph/file/f215a1c4adf25a5bad81b.jpg"
|
104 |
+
|
105 |
+
# Send the image as a reply
|
106 |
+
await replymsg.reply_photo(
|
107 |
+
photo=image_url,
|
108 |
+
caption=f"<b>Pyro-Pong!</b>\n{delta_ping * 1000:.3f} ms\n\nUptime: <code>{up}</code>",
|
109 |
+
)
|
110 |
+
await replymsg.delete()
|
111 |
+
|
112 |
+
|
113 |
+
# <=======================================================================================================>
|
114 |
+
|
115 |
+
|
116 |
+
# <================================================ HANDLER =======================================================>
|
117 |
+
function(CommandHandler("logs", logs, block=False))
|
118 |
+
function(CommandHandler("id", getid, block=False))
|
119 |
+
function(CallbackQueryHandler(close_callback, pattern="^close$", block=False))
|
120 |
+
|
121 |
+
# <================================================= HELP ======================================================>
|
122 |
+
__help__ = """
|
123 |
+
➠ *Commands*:
|
124 |
+
|
125 |
+
» /ping: see ping.
|
126 |
+
|
127 |
+
» /id: reply to get user id.
|
128 |
+
"""
|
129 |
+
|
130 |
+
__mod_name__ = "EXTRA"
|
131 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/flood.py
ADDED
@@ -0,0 +1,457 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import html
|
3 |
+
import re
|
4 |
+
|
5 |
+
from telegram import ChatPermissions, Update
|
6 |
+
from telegram.error import BadRequest
|
7 |
+
from telegram.ext import (
|
8 |
+
CallbackQueryHandler,
|
9 |
+
CommandHandler,
|
10 |
+
ContextTypes,
|
11 |
+
MessageHandler,
|
12 |
+
filters,
|
13 |
+
)
|
14 |
+
from telegram.helpers import mention_html
|
15 |
+
|
16 |
+
from Database.sql import antiflood_sql as sql
|
17 |
+
from Database.sql.approve_sql import is_approved
|
18 |
+
from Mikobot import dispatcher, function
|
19 |
+
from Mikobot.plugins.connection import connected
|
20 |
+
from Mikobot.plugins.helper_funcs.alternate import send_message
|
21 |
+
from Mikobot.plugins.helper_funcs.chat_status import check_admin, is_user_admin
|
22 |
+
from Mikobot.plugins.helper_funcs.string_handling import extract_time
|
23 |
+
from Mikobot.plugins.log_channel import loggable
|
24 |
+
|
25 |
+
# <=======================================================================================================>
|
26 |
+
|
27 |
+
FLOOD_GROUP = 3
|
28 |
+
|
29 |
+
|
30 |
+
# <================================================ FUNCTION =======================================================>
|
31 |
+
@loggable
|
32 |
+
async def check_flood(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
33 |
+
user = update.effective_user
|
34 |
+
chat = update.effective_chat
|
35 |
+
msg = update.effective_message
|
36 |
+
if not user:
|
37 |
+
return ""
|
38 |
+
|
39 |
+
if await is_user_admin(chat, user.id):
|
40 |
+
sql.update_flood(chat.id, None)
|
41 |
+
return ""
|
42 |
+
|
43 |
+
if is_approved(chat.id, user.id):
|
44 |
+
sql.update_flood(chat.id, None)
|
45 |
+
return
|
46 |
+
|
47 |
+
should_ban = sql.update_flood(chat.id, user.id)
|
48 |
+
if not should_ban:
|
49 |
+
return ""
|
50 |
+
|
51 |
+
try:
|
52 |
+
getmode, getvalue = sql.get_flood_setting(chat.id)
|
53 |
+
if getmode == 1:
|
54 |
+
await chat.ban_member(user.id)
|
55 |
+
execstrings = "BANNED"
|
56 |
+
tag = "BANNED"
|
57 |
+
elif getmode == 2:
|
58 |
+
await chat.ban_member(user.id)
|
59 |
+
await chat.unban_member(user.id)
|
60 |
+
execstrings = "KICKED"
|
61 |
+
tag = "KICKED"
|
62 |
+
elif getmode == 3:
|
63 |
+
await context.bot.restrict_chat_member(
|
64 |
+
chat.id,
|
65 |
+
user.id,
|
66 |
+
permissions=ChatPermissions(can_send_messages=False),
|
67 |
+
)
|
68 |
+
execstrings = "MUTED"
|
69 |
+
tag = "MUTED"
|
70 |
+
elif getmode == 4:
|
71 |
+
bantime = await extract_time(msg, getvalue)
|
72 |
+
await chat.ban_member(user.id, until_date=bantime)
|
73 |
+
execstrings = "BANNED for {}".format(getvalue)
|
74 |
+
tag = "TBAN"
|
75 |
+
elif getmode == 5:
|
76 |
+
mutetime = await extract_time(msg, getvalue)
|
77 |
+
await context.bot.restrict_chat_member(
|
78 |
+
chat.id,
|
79 |
+
user.id,
|
80 |
+
until_date=mutetime,
|
81 |
+
permissions=ChatPermissions(can_send_messages=False),
|
82 |
+
)
|
83 |
+
execstrings = "MUTED for {}".format(getvalue)
|
84 |
+
tag = "TMUTE"
|
85 |
+
await send_message(
|
86 |
+
update.effective_message,
|
87 |
+
"Beep boop! Boop beep!\n{}!".format(execstrings),
|
88 |
+
)
|
89 |
+
|
90 |
+
return (
|
91 |
+
"<b>{}:</b>"
|
92 |
+
"\n#{}"
|
93 |
+
"\n<b>user:</b> {}"
|
94 |
+
"\nFlooded the group.".format(
|
95 |
+
tag,
|
96 |
+
html.escape(chat.title),
|
97 |
+
mention_html(user.id, html.escape(user.first_name)),
|
98 |
+
)
|
99 |
+
)
|
100 |
+
|
101 |
+
except BadRequest:
|
102 |
+
await msg.reply_text(
|
103 |
+
"I can't restrict people here, give me permissions first! Until then, I'll disable anti-flood.",
|
104 |
+
)
|
105 |
+
sql.set_flood(chat.id, 0)
|
106 |
+
return (
|
107 |
+
"<b>{}:</b>"
|
108 |
+
"\n#INFO"
|
109 |
+
"\nDon't have enough permission to restrict users so automatically disabled anti-flood.".format(
|
110 |
+
chat.title,
|
111 |
+
)
|
112 |
+
)
|
113 |
+
|
114 |
+
|
115 |
+
@check_admin(permission="can_restrict_members", is_both=True, no_reply=True)
|
116 |
+
async def flood_button(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
117 |
+
bot = context.bot
|
118 |
+
query = update.callback_query
|
119 |
+
user = update.effective_user
|
120 |
+
match = re.match(r"unmute_flooder\((.+?)\)", query.data)
|
121 |
+
if match:
|
122 |
+
user_id = match.group(1)
|
123 |
+
chat = update.effective_chat.id
|
124 |
+
try:
|
125 |
+
await bot.restrict_chat_member(
|
126 |
+
chat,
|
127 |
+
int(user_id),
|
128 |
+
permissions=ChatPermissions(
|
129 |
+
can_send_messages=True,
|
130 |
+
can_send_media_messages=True,
|
131 |
+
can_send_other_messages=True,
|
132 |
+
can_add_web_page_previews=True,
|
133 |
+
),
|
134 |
+
)
|
135 |
+
await update.effective_message.edit_text(
|
136 |
+
f"Unmuted by {mention_html(user.id, html.escape(user.first_name))}.",
|
137 |
+
parse_mode="HTML",
|
138 |
+
)
|
139 |
+
except:
|
140 |
+
pass
|
141 |
+
|
142 |
+
|
143 |
+
@loggable
|
144 |
+
@check_admin(is_user=True)
|
145 |
+
async def set_flood(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
146 |
+
chat = update.effective_chat
|
147 |
+
user = update.effective_user
|
148 |
+
message = update.effective_message
|
149 |
+
args = context.args
|
150 |
+
|
151 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=True)
|
152 |
+
if conn:
|
153 |
+
chat_id = conn
|
154 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
155 |
+
chat_name = chat_obj.title
|
156 |
+
else:
|
157 |
+
if update.effective_message.chat.type == "private":
|
158 |
+
await send_message(
|
159 |
+
update.effective_message,
|
160 |
+
"This command is meant to use in a group, not in PM.",
|
161 |
+
)
|
162 |
+
return ""
|
163 |
+
chat_id = update.effective_chat.id
|
164 |
+
chat_name = update.effective_message.chat.title
|
165 |
+
|
166 |
+
if len(args) >= 1:
|
167 |
+
val = args[0].lower()
|
168 |
+
if val in ["off", "no", "0"]:
|
169 |
+
sql.set_flood(chat_id, 0)
|
170 |
+
if conn:
|
171 |
+
text = await message.reply_text(
|
172 |
+
"Antiflood has been disabled in {}.".format(chat_name),
|
173 |
+
)
|
174 |
+
else:
|
175 |
+
text = await message.reply_text("Antiflood has been disabled.")
|
176 |
+
|
177 |
+
elif val.isdigit():
|
178 |
+
amount = int(val)
|
179 |
+
if amount <= 0:
|
180 |
+
sql.set_flood(chat_id, 0)
|
181 |
+
if conn:
|
182 |
+
text = await message.reply_text(
|
183 |
+
"Antiflood has been disabled in {}.".format(chat_name),
|
184 |
+
)
|
185 |
+
else:
|
186 |
+
text = await message.reply_text("Antiflood has been disabled.")
|
187 |
+
return (
|
188 |
+
"<b>{}:</b>"
|
189 |
+
"\n#SETFLOOD"
|
190 |
+
"\n<b>Admin:</b> {}"
|
191 |
+
"\nDisable Antiflood.".format(
|
192 |
+
html.escape(chat_name),
|
193 |
+
mention_html(user.id, html.escape(user.first_name)),
|
194 |
+
)
|
195 |
+
)
|
196 |
+
|
197 |
+
elif amount <= 3:
|
198 |
+
await send_message(
|
199 |
+
update.effective_message,
|
200 |
+
"Antiflood must be either 0 (disabled) or a number greater than 3!",
|
201 |
+
)
|
202 |
+
return ""
|
203 |
+
|
204 |
+
else:
|
205 |
+
sql.set_flood(chat_id, amount)
|
206 |
+
if conn:
|
207 |
+
text = await message.reply_text(
|
208 |
+
"Antiflood limit has been set to {} in chat: {}".format(
|
209 |
+
amount,
|
210 |
+
chat_name,
|
211 |
+
),
|
212 |
+
)
|
213 |
+
else:
|
214 |
+
text = await message.reply_text(
|
215 |
+
"Successfully updated antiflood limit to {}!".format(amount),
|
216 |
+
)
|
217 |
+
return (
|
218 |
+
"<b>{}:</b>"
|
219 |
+
"\n#SETFLOOD"
|
220 |
+
"\n<b>Admin:</b> {}"
|
221 |
+
"\nSet Antiflood to <code>{}</code>.".format(
|
222 |
+
html.escape(chat_name),
|
223 |
+
mention_html(user.id, html.escape(user.first_name)),
|
224 |
+
amount,
|
225 |
+
)
|
226 |
+
)
|
227 |
+
|
228 |
+
else:
|
229 |
+
await message.reply_text(
|
230 |
+
"Invalid argument, please use a number, 'off', or 'no'."
|
231 |
+
)
|
232 |
+
else:
|
233 |
+
await message.reply_text(
|
234 |
+
(
|
235 |
+
"Use `/setflood number` to enable antiflood.\n"
|
236 |
+
"Or use `/setflood off` to disable antiflood."
|
237 |
+
),
|
238 |
+
parse_mode="markdown",
|
239 |
+
)
|
240 |
+
return ""
|
241 |
+
|
242 |
+
|
243 |
+
async def flood(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
244 |
+
chat = update.effective_chat
|
245 |
+
user = update.effective_user
|
246 |
+
msg = update.effective_message
|
247 |
+
|
248 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=False)
|
249 |
+
if conn:
|
250 |
+
chat_id = conn
|
251 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
252 |
+
chat_name = chat_obj.title
|
253 |
+
else:
|
254 |
+
if update.effective_message.chat.type == "private":
|
255 |
+
await send_message(
|
256 |
+
update.effective_message,
|
257 |
+
"This command is meant to use in a group, not in PM.",
|
258 |
+
)
|
259 |
+
return
|
260 |
+
chat_id = update.effective_chat.id
|
261 |
+
chat_name = update.effective_message.chat.title
|
262 |
+
|
263 |
+
limit = sql.get_flood_limit(chat_id)
|
264 |
+
if limit == 0:
|
265 |
+
if conn:
|
266 |
+
text = await msg.reply_text(
|
267 |
+
"I'm not enforcing any flood control in {}!".format(chat_name),
|
268 |
+
)
|
269 |
+
else:
|
270 |
+
text = await msg.reply_text("I'm not enforcing any flood control here!")
|
271 |
+
else:
|
272 |
+
if conn:
|
273 |
+
text = await msg.reply_text(
|
274 |
+
"I'm currently restricting members after {} consecutive messages in {}.".format(
|
275 |
+
limit,
|
276 |
+
chat_name,
|
277 |
+
),
|
278 |
+
)
|
279 |
+
else:
|
280 |
+
text = await msg.reply_text(
|
281 |
+
"I'm currently restricting members after {} consecutive messages.".format(
|
282 |
+
limit,
|
283 |
+
),
|
284 |
+
)
|
285 |
+
|
286 |
+
|
287 |
+
@check_admin(is_user=True)
|
288 |
+
async def set_flood_mode(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
289 |
+
chat = update.effective_chat
|
290 |
+
user = update.effective_user
|
291 |
+
msg = update.effective_message
|
292 |
+
args = context.args
|
293 |
+
|
294 |
+
conn = await connected(context.bot, update, chat, user.id, need_admin=True)
|
295 |
+
if conn:
|
296 |
+
chat = await dispatcher.bot.getChat(conn)
|
297 |
+
chat_id = conn
|
298 |
+
chat_obj = await dispatcher.bot.getChat(conn)
|
299 |
+
chat_name = chat_obj.title
|
300 |
+
else:
|
301 |
+
if update.effective_message.chat.type == "private":
|
302 |
+
await send_message(
|
303 |
+
update.effective_message,
|
304 |
+
"This command is meant to use in a group, not in PM.",
|
305 |
+
)
|
306 |
+
return ""
|
307 |
+
chat = update.effective_chat
|
308 |
+
chat_id = update.effective_chat.id
|
309 |
+
chat_name = update.effective_message.chat.title
|
310 |
+
|
311 |
+
if args:
|
312 |
+
if args[0].lower() == "ban":
|
313 |
+
settypeflood = "ban"
|
314 |
+
sql.set_flood_strength(chat_id, 1, "0")
|
315 |
+
elif args[0].lower() == "kick":
|
316 |
+
settypeflood = "kick"
|
317 |
+
sql.set_flood_strength(chat_id, 2, "0")
|
318 |
+
elif args[0].lower() == "mute":
|
319 |
+
settypeflood = "mute"
|
320 |
+
sql.set_flood_strength(chat_id, 3, "0")
|
321 |
+
elif args[0].lower() == "tban":
|
322 |
+
if len(args) == 1:
|
323 |
+
teks = """It looks like you tried to set time value for antiflood but you didn't specified time; Try, `/setfloodmode tban <timevalue>`.
|
324 |
+
Examples of time value: 4m = 4 minutes, 3h = 3 hours, 6d = 6 days, 5w = 5 weeks."""
|
325 |
+
await send_message(
|
326 |
+
update.effective_message, teks, parse_mode="markdown"
|
327 |
+
)
|
328 |
+
return
|
329 |
+
settypeflood = "tban for {}".format(args[1])
|
330 |
+
sql.set_flood_strength(chat_id, 4, str(args[1]))
|
331 |
+
elif args[0].lower() == "tmute":
|
332 |
+
if len(args) == 1:
|
333 |
+
teks = """It looks like you tried to set time value for antiflood but you didn't specified time; Try, `/setfloodmode tmute <timevalue>`.
|
334 |
+
Examples of time value: 4m = 4 minutes, 3h = 3 hours, 6d = 6 days, 5w = 5 weeks."""
|
335 |
+
await send_message(
|
336 |
+
update.effective_message, teks, parse_mode="markdown"
|
337 |
+
)
|
338 |
+
return
|
339 |
+
settypeflood = "tmute for {}".format(args[1])
|
340 |
+
sql.set_flood_strength(chat_id, 5, str(args[1]))
|
341 |
+
else:
|
342 |
+
await send_message(
|
343 |
+
update.effective_message,
|
344 |
+
"I only understand ban/kick/mute/tban/tmute!",
|
345 |
+
)
|
346 |
+
return
|
347 |
+
if conn:
|
348 |
+
text = await msg.reply_text(
|
349 |
+
"Exceeding consecutive flood limit will result in {} in {}!".format(
|
350 |
+
settypeflood,
|
351 |
+
chat_name,
|
352 |
+
),
|
353 |
+
)
|
354 |
+
else:
|
355 |
+
text = await msg.reply_text(
|
356 |
+
"Exceeding consecutive flood limit will result in {}!".format(
|
357 |
+
settypeflood,
|
358 |
+
),
|
359 |
+
)
|
360 |
+
return (
|
361 |
+
"<b>{}:</b>\n"
|
362 |
+
"<b>Admin:</b> {}\n"
|
363 |
+
"Has changed antiflood mode. User will {}.".format(
|
364 |
+
settypeflood,
|
365 |
+
html.escape(chat.title),
|
366 |
+
mention_html(user.id, html.escape(user.first_name)),
|
367 |
+
)
|
368 |
+
)
|
369 |
+
else:
|
370 |
+
getmode, getvalue = sql.get_flood_setting(chat.id)
|
371 |
+
if getmode == 1:
|
372 |
+
settypeflood = "ban"
|
373 |
+
elif getmode == 2:
|
374 |
+
settypeflood = "kick"
|
375 |
+
elif getmode == 3:
|
376 |
+
settypeflood = "mute"
|
377 |
+
elif getmode == 4:
|
378 |
+
settypeflood = "tban for {}".format(getvalue)
|
379 |
+
elif getmode == 5:
|
380 |
+
settypeflood = "tmute for {}".format(getvalue)
|
381 |
+
if conn:
|
382 |
+
text = await msg.reply_text(
|
383 |
+
"Sending more messages than flood limit will result in {} in {}.".format(
|
384 |
+
settypeflood,
|
385 |
+
chat_name,
|
386 |
+
),
|
387 |
+
)
|
388 |
+
else:
|
389 |
+
text = await msg.reply_text(
|
390 |
+
"Sending more messages than flood limit will result in {}.".format(
|
391 |
+
settypeflood,
|
392 |
+
),
|
393 |
+
)
|
394 |
+
return ""
|
395 |
+
|
396 |
+
|
397 |
+
def __migrate__(old_chat_id, new_chat_id):
|
398 |
+
sql.migrate_chat(old_chat_id, new_chat_id)
|
399 |
+
|
400 |
+
|
401 |
+
def __chat_settings__(chat_id, user_id):
|
402 |
+
limit = sql.get_flood_limit(chat_id)
|
403 |
+
if limit == 0:
|
404 |
+
return "Not enforcing flood control."
|
405 |
+
else:
|
406 |
+
return "Antiflood has been set to `{}`.".format(limit)
|
407 |
+
|
408 |
+
|
409 |
+
# <=================================================== HELP ====================================================>
|
410 |
+
|
411 |
+
|
412 |
+
__help__ = """
|
413 |
+
➠ *Antiflood allows you to take action on users that send more than x messages in a row. Exceeding the set flood will result in restricting that user.*
|
414 |
+
|
415 |
+
➠ *Admin Only*
|
416 |
+
|
417 |
+
» /flood: Get the current antiflood settings.
|
418 |
+
|
419 |
+
» /setflood <number/off/no>: Set the number of messages after which to take action on a user. Set to '0', 'off', or 'no' to disable.
|
420 |
+
|
421 |
+
» /setfloodmode <action type>: Choose which action to take on a user who has been flooding. Options: ban/kick/mute/tban/tmute.
|
422 |
+
"""
|
423 |
+
|
424 |
+
__mod_name__ = "ANTI-FLOOD"
|
425 |
+
|
426 |
+
# <================================================ HANDLER =======================================================>
|
427 |
+
FLOOD_BAN_HANDLER = MessageHandler(
|
428 |
+
filters.ALL & ~filters.StatusUpdate.ALL & filters.ChatType.GROUPS,
|
429 |
+
check_flood,
|
430 |
+
block=False,
|
431 |
+
)
|
432 |
+
SET_FLOOD_HANDLER = CommandHandler(
|
433 |
+
"setflood", set_flood, filters=filters.ChatType.GROUPS, block=False
|
434 |
+
)
|
435 |
+
SET_FLOOD_MODE_HANDLER = CommandHandler(
|
436 |
+
"setfloodmode", set_flood_mode, block=False
|
437 |
+
) # , filters=filters.ChatType.GROUPS)
|
438 |
+
FLOOD_QUERY_HANDLER = CallbackQueryHandler(
|
439 |
+
flood_button, pattern=r"unmute_flooder", block=False
|
440 |
+
)
|
441 |
+
FLOOD_HANDLER = CommandHandler(
|
442 |
+
"flood", flood, filters=filters.ChatType.GROUPS, block=False
|
443 |
+
)
|
444 |
+
|
445 |
+
function(FLOOD_BAN_HANDLER, FLOOD_GROUP)
|
446 |
+
function(FLOOD_QUERY_HANDLER)
|
447 |
+
function(SET_FLOOD_HANDLER)
|
448 |
+
function(SET_FLOOD_MODE_HANDLER)
|
449 |
+
function(FLOOD_HANDLER)
|
450 |
+
|
451 |
+
__handlers__ = [
|
452 |
+
(FLOOD_BAN_HANDLER, FLOOD_GROUP),
|
453 |
+
SET_FLOOD_HANDLER,
|
454 |
+
FLOOD_HANDLER,
|
455 |
+
SET_FLOOD_MODE_HANDLER,
|
456 |
+
]
|
457 |
+
# <================================================ END =======================================================>
|
Mikobot/plugins/gban.py
ADDED
@@ -0,0 +1,543 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# <============================================== IMPORTS =========================================================>
|
2 |
+
import html
|
3 |
+
import time
|
4 |
+
from datetime import datetime
|
5 |
+
from io import BytesIO
|
6 |
+
|
7 |
+
from telegram import ChatMemberAdministrator, Update
|
8 |
+
from telegram.constants import ParseMode
|
9 |
+
from telegram.error import BadRequest, Forbidden, TelegramError
|
10 |
+
from telegram.ext import CommandHandler, ContextTypes, MessageHandler, filters
|
11 |
+
from telegram.helpers import mention_html
|
12 |
+
|
13 |
+
import Database.sql.global_bans_sql as sql
|
14 |
+
from Database.sql.users_sql import get_user_com_chats
|
15 |
+
from Mikobot import (
|
16 |
+
DEV_USERS,
|
17 |
+
DRAGONS,
|
18 |
+
EVENT_LOGS,
|
19 |
+
OWNER_ID,
|
20 |
+
STRICT_GBAN,
|
21 |
+
SUPPORT_CHAT,
|
22 |
+
dispatcher,
|
23 |
+
function,
|
24 |
+
)
|
25 |
+
from Mikobot.plugins.helper_funcs.chat_status import (
|
26 |
+
check_admin,
|
27 |
+
is_user_admin,
|
28 |
+
support_plus,
|
29 |
+
)
|
30 |
+
from Mikobot.plugins.helper_funcs.extraction import extract_user, extract_user_and_text
|
31 |
+
from Mikobot.plugins.helper_funcs.misc import send_to_list
|
32 |
+
|
33 |
+
# <=======================================================================================================>
|
34 |
+
|
35 |
+
GBAN_ENFORCE_GROUP = 6
|
36 |
+
|
37 |
+
GBAN_ERRORS = {
|
38 |
+
"User is an administrator of the chat",
|
39 |
+
"Chat not found",
|
40 |
+
"Not enough rights to restrict/unrestrict chat member",
|
41 |
+
"User_not_participant",
|
42 |
+
"Peer_id_invalid",
|
43 |
+
"Group chat was deactivated",
|
44 |
+
"Need to be inviter of a user to kick it from a basic group",
|
45 |
+
"Chat_admin_required",
|
46 |
+
"Only the creator of a basic group can kick group administrators",
|
47 |
+
"Channel_private",
|
48 |
+
"Not in the chat",
|
49 |
+
"Can't remove chat owner",
|
50 |
+
}
|
51 |
+
|
52 |
+
UNGBAN_ERRORS = {
|
53 |
+
"User is an administrator of the chat",
|
54 |
+
"Chat not found",
|
55 |
+
"Not enough rights to restrict/unrestrict chat member",
|
56 |
+
"User_not_participant",
|
57 |
+
"Method is available for supergroup and channel chats only",
|
58 |
+
"Not in the chat",
|
59 |
+
"Channel_private",
|
60 |
+
"Chat_admin_required",
|
61 |
+
"Peer_id_invalid",
|
62 |
+
"User not found",
|
63 |
+
}
|
64 |
+
|
65 |
+
|
66 |
+
# <================================================ FUNCTION =======================================================>
|
67 |
+
@support_plus
|
68 |
+
async def gban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
69 |
+
bot, args = context.bot, context.args
|
70 |
+
message = update.effective_message
|
71 |
+
user = update.effective_user
|
72 |
+
chat = update.effective_chat
|
73 |
+
log_message = ""
|
74 |
+
|
75 |
+
user_id, reason = await extract_user_and_text(message, context, args)
|
76 |
+
|
77 |
+
if not user_id:
|
78 |
+
await message.reply_text(
|
79 |
+
"You don't seem to be referring to a user or the ID specified is incorrect..",
|
80 |
+
)
|
81 |
+
return
|
82 |
+
|
83 |
+
if int(user_id) in DEV_USERS:
|
84 |
+
await message.reply_text(
|
85 |
+
"That user is part of the Association\nI can't act against our own.",
|
86 |
+
)
|
87 |
+
return
|
88 |
+
|
89 |
+
if int(user_id) in DRAGONS:
|
90 |
+
await message.reply_text(
|
91 |
+
"I spy, with my little eye... a disaster! Why are you guys turning on each other?",
|
92 |
+
)
|
93 |
+
return
|
94 |
+
|
95 |
+
if user_id == bot.id:
|
96 |
+
await message.reply_text("You uhh...want me to kick myself?")
|
97 |
+
return
|
98 |
+
|
99 |
+
if user_id in [777000, 1087968824]:
|
100 |
+
await message.reply_text("Fool! You can't attack Telegram's native tech!")
|
101 |
+
return
|
102 |
+
|
103 |
+
try:
|
104 |
+
user_chat = await bot.get_chat(user_id)
|
105 |
+
except BadRequest as excp:
|
106 |
+
if excp.message == "User not found":
|
107 |
+
await message.reply_text("I can't seem to find this user.")
|
108 |
+
return ""
|
109 |
+
else:
|
110 |
+
return
|
111 |
+
|
112 |
+
if user_chat.type != "private":
|
113 |
+
await message.reply_text("That's not a user!")
|
114 |
+
return
|
115 |
+
|
116 |
+
if sql.is_user_gbanned(user_id):
|
117 |
+
if not reason:
|
118 |
+
await message.reply_text(
|
119 |
+
"This user is already gbanned; I'd change the reason, but you haven't given me one...",
|
120 |
+
)
|
121 |
+
return
|
122 |
+
|
123 |
+
old_reason = sql.update_gban_reason(
|
124 |
+
user_id,
|
125 |
+
user_chat.username or user_chat.first_name,
|
126 |
+
reason,
|
127 |
+
)
|
128 |
+
if old_reason:
|
129 |
+
await message.reply_text(
|
130 |
+
"This user is already gbanned, for the following reason:\n"
|
131 |
+
"<code>{}</code>\n"
|
132 |
+
"I've gone and updated it with your new reason!".format(
|
133 |
+
html.escape(old_reason),
|
134 |
+
),
|
135 |
+
parse_mode=ParseMode.HTML,
|
136 |
+
)
|
137 |
+
|
138 |
+
else:
|
139 |
+
await message.reply_text(
|
140 |
+
"This user is already gbanned, but had no reason set; I've gone and updated it!",
|
141 |
+
)
|
142 |
+
|
143 |
+
return
|
144 |
+
|
145 |
+
await message.reply_text("On it!")
|
146 |
+
|
147 |
+
start_time = time.time()
|
148 |
+
datetime_fmt = "%Y-%m-%dT%H:%M"
|
149 |
+
current_time = datetime.utcnow().strftime(datetime_fmt)
|
150 |
+
|
151 |
+
if chat.type != "private":
|
152 |
+
chat_origin = "<b>{} ({})</b>\n".format(html.escape(chat.title), chat.id)
|
153 |
+
else:
|
154 |
+
chat_origin = "<b>{}</b>\n".format(chat.id)
|
155 |
+
|
156 |
+
log_message = (
|
157 |
+
f"#GBANNED\n"
|
158 |
+
f"<b>Originated from:</b> <code>{chat_origin}</code>\n"
|
159 |
+
f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
|
160 |
+
f"<b>Banned User:</b> {mention_html(user_chat.id, user_chat.first_name)}\n"
|
161 |
+
f"<b>Banned User ID:</b> <code>{user_chat.id}</code>\n"
|
162 |
+
f"<b>Event Stamp:</b> <code>{current_time}</code>"
|
163 |
+
)
|
164 |
+
|
165 |
+
if reason:
|
166 |
+
if chat.type == chat.SUPERGROUP and chat.username:
|
167 |
+
log_message += f'\n<b>Reason:</b> <a href="https://telegram.me/{chat.username}/{message.message_id}">{reason}</a>'
|
168 |
+
else:
|
169 |
+
log_message += f"\n<b>Reason:</b> <code>{reason}</code>"
|
170 |
+
|
171 |
+
if EVENT_LOGS:
|
172 |
+
try:
|
173 |
+
log = await bot.send_message(
|
174 |
+
EVENT_LOGS, log_message, parse_mode=ParseMode.HTML
|
175 |
+
)
|
176 |
+
except BadRequest as excp:
|
177 |
+
log = await bot.send_message(
|
178 |
+
EVENT_LOGS,
|
179 |
+
log_message
|
180 |
+
+ "\n\nFormatting has been disabled due to an unexpected error.",
|
181 |
+
)
|
182 |
+
|
183 |
+
else:
|
184 |
+
send_to_list(bot, DRAGONS, log_message, html=True)
|
185 |
+
|
186 |
+
sql.gban_user(user_id, user_chat.username or user_chat.first_name, reason)
|
187 |
+
|
188 |
+
chats = get_user_com_chats(user_id)
|
189 |
+
gbanned_chats = 0
|
190 |
+
|
191 |
+
for chat in chats:
|
192 |
+
chat_id = int(chat)
|
193 |
+
|
194 |
+
# Check if this group has disabled gbans
|
195 |
+
if not sql.does_chat_gban(chat_id):
|
196 |
+
continue
|
197 |
+
|
198 |
+
try:
|
199 |
+
await bot.ban_chat_member(chat_id, user_id)
|
200 |
+
gbanned_chats += 1
|
201 |
+
|
202 |
+
except BadRequest as excp:
|
203 |
+
if excp.message in GBAN_ERRORS:
|
204 |
+
pass
|
205 |
+
else:
|
206 |
+
await message.reply_text(f"Could not gban due to: {excp.message}")
|
207 |
+
if EVENT_LOGS:
|
208 |
+
await bot.send_message(
|
209 |
+
EVENT_LOGS,
|
210 |
+
f"Could not gban due to {excp.message}",
|
211 |
+
parse_mode=ParseMode.HTML,
|
212 |
+
)
|
213 |
+
else:
|
214 |
+
send_to_list(
|
215 |
+
bot,
|
216 |
+
DRAGONS,
|
217 |
+
f"Could not gban due to: {excp.message}",
|
218 |
+
)
|
219 |
+
sql.ungban_user(user_id)
|
220 |
+
return
|
221 |
+
except TelegramError:
|
222 |
+
pass
|
223 |
+
|
224 |
+
if EVENT_LOGS:
|
225 |
+
await log.edit_text(
|
226 |
+
log_message + f"\n<b>Chats affected:</b> <code>{gbanned_chats}</code>",
|
227 |
+
parse_mode=ParseMode.HTML,
|
228 |
+
)
|
229 |
+
else:
|
230 |
+
send_to_list(
|
231 |
+
bot,
|
232 |
+
DRAGONS,
|
233 |
+
f"Gban complete! (User banned in <code>{gbanned_chats}</code> chats)",
|
234 |
+
html=True,
|
235 |
+
)
|
236 |
+
|
237 |
+
end_time = time.time()
|
238 |
+
gban_time = round((end_time - start_time), 2)
|
239 |
+
|
240 |
+
if gban_time > 60:
|
241 |
+
gban_time = round((gban_time / 60), 2)
|
242 |
+
await message.reply_text("Done! Gbanned.", parse_mode=ParseMode.HTML)
|
243 |
+
else:
|
244 |
+
await message.reply_text("Done! Gbanned.", parse_mode=ParseMode.HTML)
|
245 |
+
|
246 |
+
try:
|
247 |
+
await bot.send_message(
|
248 |
+
user_id,
|
249 |
+
"#EVENT"
|
250 |
+
"You have been marked as Malicious and as such have been banned from any future groups we manage."
|
251 |
+
f"\n<b>Reason:</b> <code>{html.escape(user.reason)}</code>"
|
252 |
+
f"</b>Appeal Chat:</b> @{SUPPORT_CHAT}",
|
253 |
+
parse_mode=ParseMode.HTML,
|
254 |
+
)
|
255 |
+
except:
|
256 |
+
pass # bot probably blocked by user
|
257 |
+
|
258 |
+
|
259 |
+
@support_plus
|
260 |
+
async def ungban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
261 |
+
bot, args = context.bot, context.args
|
262 |
+
message = update.effective_message
|
263 |
+
user = update.effective_user
|
264 |
+
chat = update.effective_chat
|
265 |
+
log_message = ""
|
266 |
+
|
267 |
+
user_id = await extract_user(message, context, args)
|
268 |
+
|
269 |
+
if not user_id:
|
270 |
+
await message.reply_text(
|
271 |
+
"You don't seem to be referring to a user or the ID specified is incorrect..",
|
272 |
+
)
|
273 |
+
return
|
274 |
+
|
275 |
+
user_chat = await bot.get_chat(user_id)
|
276 |
+
if user_chat.type != "private":
|
277 |
+
await message.reply_text("That's not a user!")
|
278 |
+
return
|
279 |
+
|
280 |
+
if not sql.is_user_gbanned(user_id):
|
281 |
+
await message.reply_text("This user is not gbanned!")
|
282 |
+
return
|
283 |
+
|
284 |
+
await message.reply_text(
|
285 |
+
f"I'll give {user_chat.first_name} a second chance, globally."
|
286 |
+
)
|
287 |
+
|
288 |
+
start_time = time.time()
|
289 |
+
datetime_fmt = "%Y-%m-%dT%H:%M"
|
290 |
+
current_time = datetime.utcnow().strftime(datetime_fmt)
|
291 |
+
|
292 |
+
if chat.type != "private":
|
293 |
+
chat_origin = f"<b>{html.escape(chat.title)} ({chat.id})</b>\n"
|
294 |
+
else:
|
295 |
+
chat_origin = f"<b>{chat.id}</b>\n"
|
296 |
+
|
297 |
+
log_message = (
|
298 |
+
f"#UNGBANNED\n"
|
299 |
+
f"<b>Originated from:</b> <code>{chat_origin}</code>\n"
|
300 |
+
f"<b>Admin:</b> {mention_html(user.id, user.first_name)}\n"
|
301 |
+
f"<b>Unbanned User:</b> {mention_html(user_chat.id, user_chat.first_name)}\n"
|
302 |
+
f"<b>Unbanned User ID:</b> <code>{user_chat.id}</code>\n"
|
303 |
+
f"<b>Event Stamp:</b> <code>{current_time}</code>"
|
304 |
+
)
|
305 |
+
|
306 |
+
if EVENT_LOGS:
|
307 |
+
try:
|
308 |
+
log = await bot.send_message(
|
309 |
+
EVENT_LOGS, log_message, parse_mode=ParseMode.HTML
|
310 |
+
)
|
311 |
+
except BadRequest as excp:
|
312 |
+
log = await bot.send_message(
|
313 |
+
EVENT_LOGS,
|
314 |
+
log_message
|
315 |
+
+ "\n\nFormatting has been disabled due to an unexpected error.",
|
316 |
+
)
|
317 |
+
else:
|
318 |
+
send_to_list(bot, DRAGONS, log_message, html=True)
|
319 |
+
|
320 |
+
chats = get_user_com_chats(user_id)
|
321 |
+
ungbanned_chats = 0
|
322 |
+
|
323 |
+
for chat in chats:
|
324 |
+
chat_id = int(chat)
|
325 |
+
|
326 |
+
# Check if this group has disabled gbans
|
327 |
+
if not sql.does_chat_gban(chat_id):
|
328 |
+
continue
|
329 |
+
|
330 |
+
try:
|
331 |
+
member = await bot.get_chat_member(chat_id, user_id)
|
332 |
+
if member.status == "kicked":
|
333 |
+
await bot.unban_chat_member(chat_id, user_id)
|
334 |
+
ungbanned_chats += 1
|
335 |
+
|
336 |
+
except BadRequest as excp:
|
337 |
+
if excp.message in UNGBAN_ERRORS:
|
338 |
+
pass
|
339 |
+
else:
|
340 |
+
await message.reply_text(f"Could not un-gban due to: {excp.message}")
|
341 |
+
if EVENT_LOGS:
|
342 |
+
await bot.send_message(
|
343 |
+
EVENT_LOGS,
|
344 |
+
f"Could not un-gban due to: {excp.message}",
|
345 |
+
parse_mode=ParseMode.HTML,
|
346 |
+
)
|
347 |
+
else:
|
348 |
+
await bot.send_message(
|
349 |
+
OWNER_ID,
|
350 |
+
f"Could not un-gban due to: {excp.message}",
|
351 |
+
)
|
352 |
+
return
|
353 |
+
except TelegramError:
|
354 |
+
pass
|
355 |
+
|
356 |
+
sql.ungban_user(user_id)
|
357 |
+
|
358 |
+
if EVENT_LOGS:
|
359 |
+
await log.edit_text(
|
360 |
+
log_message + f"\n<b>Chats affected:</b> {ungbanned_chats}",
|
361 |
+
parse_mode=ParseMode.HTML,
|
362 |
+
)
|
363 |
+
else:
|
364 |
+
send_to_list(bot, DRAGONS, "un-gban complete!")
|
365 |
+
|
366 |
+
end_time = time.time()
|
367 |
+
ungban_time = round((end_time - start_time), 2)
|
368 |
+
|
369 |
+
if ungban_time > 60:
|
370 |
+
ungban_time = round((ungban_time / 60), 2)
|
371 |
+
await message.reply_text(f"Person has been un-gbanned. Took {ungban_time} min")
|
372 |
+
else:
|
373 |
+
await message.reply_text(f"Person has been un-gbanned. Took {ungban_time} sec")
|
374 |
+
|
375 |
+
|
376 |
+
@support_plus
|
377 |
+
async def gbanlist(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
378 |
+
banned_users = sql.get_gban_list()
|
379 |
+
|
380 |
+
if not banned_users:
|
381 |
+
await update.effective_message.reply_text(
|
382 |
+
"There aren't any gbanned users! You're kinder than I expected...",
|
383 |
+
)
|
384 |
+
return
|
385 |
+
|
386 |
+
banfile = "Screw these guys.\n"
|
387 |
+
for user in banned_users:
|
388 |
+
banfile += f"[x] {user['name']} - {user['user_id']}\n"
|
389 |
+
if user["reason"]:
|
390 |
+
banfile += f"Reason: {user['reason']}\n"
|
391 |
+
|
392 |
+
with BytesIO(str.encode(banfile)) as output:
|
393 |
+
output.name = "gbanlist.txt"
|
394 |
+
await update.effective_message.reply_document(
|
395 |
+
document=output,
|
396 |
+
filename="gbanlist.txt",
|
397 |
+
caption="Here is the list of currently gbanned users.",
|
398 |
+
)
|
399 |
+
|
400 |
+
|
401 |
+
async def check_and_ban(update, user_id, should_message=True):
|
402 |
+
if sql.is_user_gbanned(user_id):
|
403 |
+
await update.effective_chat.ban_member(user_id)
|
404 |
+
if should_message:
|
405 |
+
text = (
|
406 |
+
f"<b>Alert</b>: this user is globally banned.\n"
|
407 |
+
f"<code>*bans them from here*</code>.\n"
|
408 |
+
f"<b>Appeal chat</b>: @{SUPPORT_CHAT}\n"
|
409 |
+
f"<b>User ID</b>: <code>{user_id}</code>"
|
410 |
+
)
|
411 |
+
user = sql.get_gbanned_user(user_id)
|
412 |
+
if user.reason:
|
413 |
+
text += f"\n<b>Ban Reason:</b> <code>{html.escape(user.reason)}</code>"
|
414 |
+
await update.effective_message.reply_text(text, parse_mode=ParseMode.HTML)
|
415 |
+
|
416 |
+
|
417 |
+
async def enforce_gban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
418 |
+
# Not using @restrict handler to avoid spamming - just ignore if cant gban.
|
419 |
+
bot = context.bot
|
420 |
+
try:
|
421 |
+
get_member = await update.effective_chat.get_member(
|
422 |
+
bot.id,
|
423 |
+
)
|
424 |
+
if isinstance(get_member, ChatMemberAdministrator):
|
425 |
+
restrict_permission = get_member.can_restrict_members
|
426 |
+
else:
|
427 |
+
return
|
428 |
+
except Forbidden:
|
429 |
+
return
|
430 |
+
if sql.does_chat_gban(update.effective_chat.id) and restrict_permission:
|
431 |
+
user = update.effective_user
|
432 |
+
chat = update.effective_chat
|
433 |
+
msg = update.effective_message
|
434 |
+
|
435 |
+
if user and not await is_user_admin(chat, user.id):
|
436 |
+
await check_and_ban(update, user.id)
|
437 |
+
return
|
438 |
+
|
439 |
+
if msg.new_chat_members:
|
440 |
+
new_members = update.effective_message.new_chat_members
|
441 |
+
for mem in new_members:
|
442 |
+
await check_and_ban(update, mem.id)
|
443 |
+
|
444 |
+
if msg.reply_to_message:
|
445 |
+
user = msg.reply_to_message.from_user
|
446 |
+
if user and not await is_user_admin(chat, user.id):
|
447 |
+
await check_and_ban(update, user.id, should_message=False)
|
448 |
+
|
449 |
+
|
450 |
+
@check_admin(is_user=True)
|
451 |
+
async def gbanstat(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
452 |
+
args = context.args
|
453 |
+
if len(args) > 0:
|
454 |
+
if args[0].lower() in ["on", "yes"]:
|
455 |
+
sql.enable_gbans(update.effective_chat.id)
|
456 |
+
await update.effective_message.reply_text(
|
457 |
+
"Antispam is now enabled ✅ "
|
458 |
+
"I am now protecting your group from potential remote threats!",
|
459 |
+
)
|
460 |
+
elif args[0].lower() in ["off", "no"]:
|
461 |
+
sql.disable_gbans(update.effective_chat.id)
|
462 |
+
await update.effective_message.reply_text(
|
463 |
+
"I am not now protecting your group from potential remote threats!",
|
464 |
+
)
|
465 |
+
else:
|
466 |
+
await update.effective_message.reply_text(
|
467 |
+
"Give me some arguments to choose a setting! on/off, yes/no!\n\n"
|
468 |
+
"Your current setting is: {}\n"
|
469 |
+
"When True, any gbans that happen will also happen in your group. "
|
470 |
+
"When False, they won't, leaving you at the possible mercy of "
|
471 |
+
"spammers.".format(sql.does_chat_gban(update.effective_chat.id)),
|
472 |
+
)
|
473 |
+
|
474 |
+
|
475 |
+
def __stats__():
|
476 |
+
return f"• {sql.num_gbanned_users()} gbanned users."
|
477 |
+
|
478 |
+
|
479 |
+
def __user_info__(user_id):
|
480 |
+
is_gbanned = sql.is_user_gbanned(user_id)
|
481 |
+
text = "Malicious: <b>{}</b>"
|
482 |
+
if user_id in [777000, 1087968824]:
|
483 |
+
return ""
|
484 |
+
if user_id == dispatcher.bot.id:
|
485 |
+
return ""
|
486 |
+
if int(user_id) in DRAGONS:
|
487 |
+
return ""
|
488 |
+
if is_gbanned:
|
489 |
+
text = text.format("Yes")
|
490 |
+
user = sql.get_gbanned_user(user_id)
|
491 |
+
if user.reason:
|
492 |
+
text += f"\n<b>Reason:</b> <code>{html.escape(user.reason)}</code>"
|
493 |
+
text += f"\n<b>Appeal Chat:</b> @{SUPPORT_CHAT}"
|
494 |
+
else:
|
495 |
+
text = text.format("???")
|
496 |
+
return text
|
497 |
+
|
498 |
+
|
499 |
+
def __migrate__(old_chat_id, new_chat_id):
|
500 |
+
sql.migrate_chat(old_chat_id, new_chat_id)
|
501 |
+
|
502 |
+
|
503 |
+
def __chat_settings__(chat_id, user_id):
|
504 |
+
return f"This chat is enforcing *gbans*: `{sql.does_chat_gban(chat_id)}`."
|
505 |
+
|
506 |
+
|
507 |
+
# <=================================================== HELP ====================================================>
|
508 |
+
|
509 |
+
|
510 |
+
__help__ = f"""
|
511 |
+
➠ *Admins only:*
|
512 |
+
» `/antispam <on/off/yes/no>`*:* Will toggle our antispam tech or return your current settings.
|
513 |
+
|
514 |
+
➠ Anti-Spam, used by bot devs to ban spammers across all groups. This helps protect \
|
515 |
+
you and your groups by removing spam flooders as quickly as possible.
|
516 |
+
➠ *Note:* Users can appeal gbans or report spammers at @hydraX2support
|
517 |
+
"""
|
518 |
+
|
519 |
+
# <================================================ HANDLER =======================================================>
|
520 |
+
GBAN_HANDLER = CommandHandler("gban", gban, block=False)
|
521 |
+
UNGBAN_HANDLER = CommandHandler("ungban", ungban, block=False)
|
522 |
+
GBAN_LIST = CommandHandler("gbanlist", gbanlist, block=False)
|
523 |
+
|
524 |
+
GBAN_STATUS = CommandHandler(
|
525 |
+
"antispam", gbanstat, filters=filters.ChatType.GROUPS, block=False
|
526 |
+
)
|
527 |
+
|
528 |
+
GBAN_ENFORCER = MessageHandler(
|
529 |
+
filters.ALL & filters.ChatType.GROUPS, enforce_gban, block=False
|
530 |
+
)
|
531 |
+
|
532 |
+
function(GBAN_HANDLER)
|
533 |
+
function(UNGBAN_HANDLER)
|
534 |
+
function(GBAN_LIST)
|
535 |
+
function(GBAN_STATUS)
|
536 |
+
|
537 |
+
__mod_name__ = "ANTI-SPAM"
|
538 |
+
__handlers__ = [GBAN_HANDLER, UNGBAN_HANDLER, GBAN_LIST, GBAN_STATUS]
|
539 |
+
|
540 |
+
if STRICT_GBAN: # enforce GBANS if this is set
|
541 |
+
function(GBAN_ENFORCER, GBAN_ENFORCE_GROUP)
|
542 |
+
__handlers__.append((GBAN_ENFORCER, GBAN_ENFORCE_GROUP))
|
543 |
+
# <================================================ END =======================================================>
|