Karma commited on
Commit
f45efbd
·
1 Parent(s): 7a6546b

Add files via upload

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Database/mongodb/afk_db.py +53 -0
  2. Database/mongodb/blacklistdb.py +51 -0
  3. Database/mongodb/db.py +6 -0
  4. Database/mongodb/fsub_db.py +18 -0
  5. Database/mongodb/karma_mongo.py +122 -0
  6. Database/mongodb/locale_db.py +22 -0
  7. Database/mongodb/mongodb.py +75 -0
  8. Database/mongodb/sangmata_db.py +42 -0
  9. Database/mongodb/toggle_mongo.py +50 -0
  10. Database/mongodb/users_chats_db.py +111 -0
  11. Database/mongodb/users_db.py +102 -0
  12. Database/mongodb/whispers.py +19 -0
  13. Database/sql/__init__.py +27 -0
  14. Database/sql/afk_sql.py +99 -0
  15. Database/sql/antichannel_sql.py +88 -0
  16. Database/sql/antiflood_sql.py +171 -0
  17. Database/sql/antilinkedchannel_sql.py +142 -0
  18. Database/sql/approve_sql.py +85 -0
  19. Database/sql/blacklist_sql.py +223 -0
  20. Database/sql/blacklistusers_sql.py +90 -0
  21. Database/sql/blsticker_sql.py +223 -0
  22. Database/sql/cleaner_sql.py +225 -0
  23. Database/sql/connection_sql.py +230 -0
  24. Database/sql/cust_filters_sql.py +404 -0
  25. Database/sql/disable_sql.py +129 -0
  26. Database/sql/feds_sql.py +931 -0
  27. Database/sql/fontsql.py +2361 -0
  28. Database/sql/forceSubscribe_sql.py +46 -0
  29. Database/sql/global_bans_sql.py +167 -0
  30. Database/sql/kuki_sql.py +42 -0
  31. Database/sql/locks_sql.py +292 -0
  32. Database/sql/log_channel_sql.py +180 -0
  33. Database/sql/nightmode_sql.py +42 -0
  34. Database/sql/notes_sql.py +210 -0
  35. Database/sql/raid_sql.py +73 -0
  36. Database/sql/remind_sql.py +140 -0
  37. Database/sql/reporting_sql.py +115 -0
  38. Database/sql/rules_sql.py +58 -0
  39. Database/sql/userinfo_sql.py +100 -0
  40. Database/sql/users_sql.py +258 -0
  41. Database/sql/warns_sql.py +341 -0
  42. Database/sql/welcome_sql.py +507 -0
  43. Dockerfile +12 -0
  44. Extra/Calistoga-Regular.ttf +0 -0
  45. Extra/MutantAcademyStyle.ttf +0 -0
  46. Extra/a.jpg +0 -0
  47. Extra/bgg.jpg +0 -0
  48. Extra/default.ttf +0 -0
  49. Extra/profilepic.png +0 -0
  50. Infamous/karma.py +90 -0
Database/mongodb/afk_db.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from Database.mongodb.db import dbname
2
+
3
+ usersdb = dbname.users
4
+ cleandb = dbname.cleanmode
5
+ cleanmode = {}
6
+
7
+
8
+ async def is_cleanmode_on(chat_id: int) -> bool:
9
+ mode = cleanmode.get(chat_id)
10
+ if not mode:
11
+ user = await cleandb.find_one({"chat_id": chat_id})
12
+ if not user:
13
+ cleanmode[chat_id] = True
14
+ return True
15
+ cleanmode[chat_id] = False
16
+ return False
17
+ return mode
18
+
19
+
20
+ async def cleanmode_on(chat_id: int):
21
+ cleanmode[chat_id] = True
22
+ user = await cleandb.find_one({"chat_id": chat_id})
23
+ if user:
24
+ return await cleandb.delete_one({"chat_id": chat_id})
25
+
26
+
27
+ async def cleanmode_off(chat_id: int):
28
+ cleanmode[chat_id] = False
29
+ user = await cleandb.find_one({"chat_id": chat_id})
30
+ if not user:
31
+ return await cleandb.insert_one({"chat_id": chat_id})
32
+
33
+
34
+ async def is_afk(user_id: int) -> bool:
35
+ user = await usersdb.find_one({"user_id": user_id})
36
+ return (True, user["reason"]) if user else (False, {})
37
+
38
+
39
+ async def add_afk(user_id: int, mode):
40
+ await usersdb.update_one(
41
+ {"user_id": user_id}, {"$set": {"reason": mode}}, upsert=True
42
+ )
43
+
44
+
45
+ async def remove_afk(user_id: int):
46
+ user = await usersdb.find_one({"user_id": user_id})
47
+ if user:
48
+ return await usersdb.delete_one({"user_id": user_id})
49
+
50
+
51
+ async def get_afk_users() -> list:
52
+ users = usersdb.find({"user_id": {"$gt": 0}})
53
+ return list(await users.to_list(length=1000000000)) if users else []
Database/mongodb/blacklistdb.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import codecs
2
+ import pickle
3
+ from typing import List
4
+
5
+ from Database.mongodb.db import dbname
6
+
7
+ blacklist_filtersdb = dbname.blacklistFilters
8
+
9
+
10
+ def obj_to_str(obj):
11
+ if not obj:
12
+ return False
13
+ string = codecs.encode(pickle.dumps(obj), "base64").decode()
14
+ return string
15
+
16
+
17
+ def str_to_obj(string: str):
18
+ obj = pickle.loads(codecs.decode(string.encode(), "base64"))
19
+ return obj
20
+
21
+
22
+ async def get_blacklisted_words(chat_id: int) -> List[str]:
23
+ _filters = await blacklist_filtersdb.find_one({"chat_id": chat_id})
24
+ if not _filters:
25
+ return []
26
+ return _filters["filters"]
27
+
28
+
29
+ async def save_blacklist_filter(chat_id: int, word: str):
30
+ word = word.lower().strip()
31
+ _filters = await get_blacklisted_words(chat_id)
32
+ _filters.append(word)
33
+ await blacklist_filtersdb.update_one(
34
+ {"chat_id": chat_id},
35
+ {"$set": {"filters": _filters}},
36
+ upsert=True,
37
+ )
38
+
39
+
40
+ async def delete_blacklist_filter(chat_id: int, word: str) -> bool:
41
+ filtersd = await get_blacklisted_words(chat_id)
42
+ word = word.lower().strip()
43
+ if word in filtersd:
44
+ filtersd.remove(word)
45
+ await blacklist_filtersdb.update_one(
46
+ {"chat_id": chat_id},
47
+ {"$set": {"filters": filtersd}},
48
+ upsert=True,
49
+ )
50
+ return True
51
+ return False
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/fsub_db.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from Infamous.temp import dbname
2
+
3
+ fsub = dbname.force_sub
4
+
5
+
6
+ def fs_settings(chat_id: int):
7
+ _x = fsub.find_one({"chat_id": chat_id})
8
+ if _x:
9
+ return _x
10
+ return None
11
+
12
+
13
+ def add_channel(chat_id: int, channel):
14
+ fsub.update_one({"chat_id": chat_id}, {"$set": {"channel": channel}}, upsert=True)
15
+
16
+
17
+ def disapprove(chat_id: int):
18
+ fsub.delete_one({"chat_id": chat_id})
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/locale_db.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Iterable
2
+
3
+ from pyrogram.enums import ChatType
4
+
5
+ from Database.mongodb.db import dbname
6
+
7
+ localesdb = dbname.locale # DB for localization
8
+
9
+ group_types: Iterable[ChatType] = (ChatType.GROUP, ChatType.SUPERGROUP)
10
+
11
+
12
+ async def set_db_lang(chat_id: int, chat_type: str, lang_code: str):
13
+ await localesdb.update_one(
14
+ {"chat_id": chat_id},
15
+ {"$set": {"lang": lang_code, "chat_type": chat_type.value}},
16
+ upsert=True,
17
+ )
18
+
19
+
20
+ async def get_db_lang(chat_id: int) -> str:
21
+ ul = await localesdb.find_one({"chat_id": chat_id})
22
+ return ul["lang"] if ul else {}
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/sangmata_db.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from Database.mongodb.db import dbname
2
+
3
+ matadb = dbname["sangmata"]
4
+
5
+
6
+ # Get Data User
7
+ async def cek_userdata(user_id: int) -> bool:
8
+ user = await matadb.find_one({"user_id": user_id})
9
+ return bool(user)
10
+
11
+
12
+ async def get_userdata(user_id: int) -> bool:
13
+ user = await matadb.find_one({"user_id": user_id})
14
+ return user["username"], user["first_name"], user["last_name"]
15
+
16
+
17
+ async def add_userdata(user_id: int, username, first_name, last_name):
18
+ await matadb.update_one(
19
+ {"user_id": user_id},
20
+ {
21
+ "$set": {
22
+ "username": username,
23
+ "first_name": first_name,
24
+ "last_name": last_name,
25
+ }
26
+ },
27
+ upsert=True,
28
+ )
29
+
30
+
31
+ # Enable Mata MissKaty in Selected Chat
32
+ async def is_sangmata_on(chat_id: int) -> bool:
33
+ chat = await matadb.find_one({"chat_id_toggle": chat_id})
34
+ return bool(chat)
35
+
36
+
37
+ async def sangmata_on(chat_id: int) -> bool:
38
+ await matadb.insert_one({"chat_id_toggle": chat_id})
39
+
40
+
41
+ async def sangmata_off(chat_id: int):
42
+ await matadb.delete_one({"chat_id_toggle": chat_id})
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_chats_db.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from async_pymongo import AsyncClient
2
+
3
+ from Mikobot import DB_NAME, MONGO_DB_URI
4
+
5
+
6
+ class UsersData:
7
+ def __init__(self, uri, database_name):
8
+ self._client = AsyncClient(uri)
9
+ self.db = self._client[database_name]
10
+ self.col = self.db["userlist"]
11
+ self.grp = self.db["groups"]
12
+
13
+ @staticmethod
14
+ def new_user(id, name):
15
+ return dict(
16
+ id=id,
17
+ name=name,
18
+ ban_status=dict(
19
+ is_banned=False,
20
+ ban_reason="",
21
+ ),
22
+ )
23
+
24
+ @staticmethod
25
+ def new_group(id, title):
26
+ return dict(
27
+ id=id,
28
+ title=title,
29
+ chat_status=dict(
30
+ is_disabled=False,
31
+ reason="",
32
+ ),
33
+ )
34
+
35
+ async def add_user(self, id, name):
36
+ user = self.new_user(id, name)
37
+ await self.col.insert_one(user)
38
+
39
+ async def is_user_exist(self, id):
40
+ user = await self.col.find_one({"id": int(id)})
41
+ return bool(user)
42
+
43
+ async def total_users_count(self):
44
+ return await self.col.count_documents({})
45
+
46
+ async def remove_ban(self, id):
47
+ return await self.col.delete_one({"_id": id})
48
+
49
+ async def ban_user(self, user_id, ban_reason="No Reason"):
50
+ return await self.col.insert_one({"_id": user_id, "reason": ban_reason})
51
+
52
+ async def get_ban_status(self, id):
53
+ user = await self.col.find_one({"_id": int(id)})
54
+ if user:
55
+ return True, user
56
+ return False, None
57
+
58
+ async def get_all_users(self):
59
+ return self.col.find({})
60
+
61
+ async def delete_user(self, user_id):
62
+ await self.col.delete_many({"id": int(user_id)})
63
+
64
+ async def is_chat_exist(self, id):
65
+ user = await self.grp.find_one({"id": int(id)})
66
+ return bool(user)
67
+
68
+ async def get_banned(self):
69
+ users = self.col.find({"ban_status.is_banned": True})
70
+ chats = self.grp.find({"chat_status.is_disabled": True})
71
+ b_chats = [chat["id"] async for chat in chats]
72
+ b_users = [user["id"] async for user in users]
73
+ return b_users, b_chats
74
+
75
+ async def add_chat(self, chat, title):
76
+ chat = self.new_group(chat, title)
77
+ await self.grp.insert_one(chat)
78
+
79
+ async def get_chat(self, chat):
80
+ chat = await self.grp.find_one({"id": int(chat)})
81
+ return chat.get("chat_status") if chat else False
82
+
83
+ async def re_enable_chat(self, id):
84
+ chat_status = dict(
85
+ is_disabled=False,
86
+ reason="",
87
+ )
88
+ await self.grp.update_one(
89
+ {"id": int(id)}, {"$set": {"chat_status": chat_status}}
90
+ )
91
+
92
+ async def disable_chat(self, chat, reason="No Reason"):
93
+ chat_status = dict(
94
+ is_disabled=True,
95
+ reason=reason,
96
+ )
97
+ await self.grp.update_one(
98
+ {"id": int(chat)}, {"$set": {"chat_status": chat_status}}
99
+ )
100
+
101
+ async def total_chat_count(self):
102
+ return await self.grp.count_documents({})
103
+
104
+ async def get_all_chats(self):
105
+ return self.grp.find({})
106
+
107
+ async def get_db_size(self):
108
+ return (await self.db.command("dbstats"))["dataSize"]
109
+
110
+
111
+ db = UsersData(MONGO_DB_URI, DB_NAME)
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/afk_sql.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import threading
2
+ from datetime import datetime
3
+
4
+ from sqlalchemy import BigInteger, Boolean, Column, DateTime, UnicodeText
5
+
6
+ from Database.sql import BASE, SESSION
7
+
8
+
9
+ class AFK(BASE):
10
+ __tablename__ = "afk_user"
11
+
12
+ user_id = Column(BigInteger, primary_key=True)
13
+ is_afk = Column(Boolean)
14
+ reason = Column(UnicodeText)
15
+ time = Column(DateTime)
16
+
17
+ def __init__(self, user_id: int, reason: str = "", is_afk: bool = True):
18
+ self.user_id = user_id
19
+ self.reason = reason
20
+ self.is_afk = is_afk
21
+ self.time = datetime.now()
22
+
23
+ def __repr__(self):
24
+ return "afk_status for {}".format(self.user_id)
25
+
26
+
27
+ AFK.__table__.create(checkfirst=True)
28
+ INSERTION_LOCK = threading.RLock()
29
+
30
+ AFK_USERS = {}
31
+
32
+
33
+ def is_afk(user_id):
34
+ return user_id in AFK_USERS
35
+
36
+
37
+ def check_afk_status(user_id):
38
+ try:
39
+ return SESSION.query(AFK).get(user_id)
40
+ finally:
41
+ SESSION.close()
42
+
43
+
44
+ def set_afk(user_id, reason=""):
45
+ with INSERTION_LOCK:
46
+ curr = SESSION.query(AFK).get(user_id)
47
+ if not curr:
48
+ curr = AFK(user_id, reason, True)
49
+ else:
50
+ curr.is_afk = True
51
+
52
+ AFK_USERS[user_id] = {"reason": reason, "time": curr.time}
53
+
54
+ SESSION.add(curr)
55
+ SESSION.commit()
56
+
57
+
58
+ def rm_afk(user_id):
59
+ with INSERTION_LOCK:
60
+ curr = SESSION.query(AFK).get(user_id)
61
+ if curr:
62
+ if user_id in AFK_USERS: # sanity check
63
+ del AFK_USERS[user_id]
64
+
65
+ SESSION.delete(curr)
66
+ SESSION.commit()
67
+ return True
68
+
69
+ SESSION.close()
70
+ return False
71
+
72
+
73
+ def toggle_afk(user_id, reason=""):
74
+ with INSERTION_LOCK:
75
+ curr = SESSION.query(AFK).get(user_id)
76
+ if not curr:
77
+ curr = AFK(user_id, reason, True)
78
+ elif curr.is_afk:
79
+ curr.is_afk = False
80
+ elif not curr.is_afk:
81
+ curr.is_afk = True
82
+ SESSION.add(curr)
83
+ SESSION.commit()
84
+
85
+
86
+ def __load_afk_users():
87
+ global AFK_USERS
88
+ try:
89
+ all_afk = SESSION.query(AFK).all()
90
+ AFK_USERS = {
91
+ user.user_id: {"reason": user.reason, "time": user.time}
92
+ for user in all_afk
93
+ if user.is_afk
94
+ }
95
+ finally:
96
+ SESSION.close()
97
+
98
+
99
+ __load_afk_users()
Database/sql/antichannel_sql.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Boolean, Column
28
+ from sqlalchemy.sql.sqltypes import String
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class AntiChannelSettings(BASE):
34
+ __tablename__ = "anti_channel_settings"
35
+
36
+ chat_id = Column(String(14), primary_key=True)
37
+ setting = Column(Boolean, default=False, nullable=False)
38
+
39
+ def __init__(self, chat_id: int, disabled: bool):
40
+ self.chat_id = str(chat_id)
41
+ self.setting = disabled
42
+
43
+ def __repr__(self):
44
+ return "<ᴀɴᴛɪғʟᴏᴏᴅ sᴇᴛᴛɪɴɢ {} ({})>".format(self.chat_id, self.setting)
45
+
46
+
47
+ AntiChannelSettings.__table__.create(checkfirst=True)
48
+ ANTICHANNEL_SETTING_LOCK = threading.RLock()
49
+
50
+
51
+ def enable_antichannel(chat_id: int):
52
+ with ANTICHANNEL_SETTING_LOCK:
53
+ chat = SESSION.query(AntiChannelSettings).get(str(chat_id))
54
+ if not chat:
55
+ chat = AntiChannelSettings(str(chat_id), True)
56
+
57
+ chat.setting = True
58
+ SESSION.add(chat)
59
+ SESSION.commit()
60
+
61
+
62
+ def disable_antichannel(chat_id: int):
63
+ with ANTICHANNEL_SETTING_LOCK:
64
+ chat = SESSION.query(AntiChannelSettings).get(str(chat_id))
65
+ if not chat:
66
+ chat = AntiChannelSettings(str(chat_id), False)
67
+
68
+ chat.setting = False
69
+ SESSION.add(chat)
70
+ SESSION.commit()
71
+
72
+
73
+ def antichannel_status(chat_id: int) -> bool:
74
+ with ANTICHANNEL_SETTING_LOCK:
75
+ d = SESSION.query(AntiChannelSettings).get(str(chat_id))
76
+ if not d:
77
+ return False
78
+ return d.setting
79
+
80
+
81
+ def migrate_chat(old_chat_id, new_chat_id):
82
+ with ANTICHANNEL_SETTING_LOCK:
83
+ chat = SESSION.query(AntiChannelSettings).get(str(old_chat_id))
84
+ if chat:
85
+ chat.chat_id = new_chat_id
86
+ SESSION.add(chat)
87
+
88
+ SESSION.commit()
Database/sql/antiflood_sql.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Column, String, UnicodeText
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+ DEF_COUNT = 1
32
+ DEF_LIMIT = 0
33
+ DEF_OBJ = (None, DEF_COUNT, DEF_LIMIT)
34
+
35
+
36
+ class FloodControl(BASE):
37
+ __tablename__ = "antiflood"
38
+ chat_id = Column(String(14), primary_key=True)
39
+ user_id = Column(BigInteger)
40
+ count = Column(BigInteger, default=DEF_COUNT)
41
+ limit = Column(BigInteger, default=DEF_LIMIT)
42
+
43
+ def __init__(self, chat_id):
44
+ self.chat_id = str(chat_id) # ensure string
45
+
46
+ def __repr__(self):
47
+ return "<ғʟᴏᴏᴅ ᴄᴏɴᴛʀᴏʟ ғᴏʀ %s>" % self.chat_id
48
+
49
+
50
+ class FloodSettings(BASE):
51
+ __tablename__ = "antiflood_settings"
52
+ chat_id = Column(String(14), primary_key=True)
53
+ flood_type = Column(BigInteger, default=1)
54
+ value = Column(UnicodeText, default="0")
55
+
56
+ def __init__(self, chat_id, flood_type=1, value="0"):
57
+ self.chat_id = str(chat_id)
58
+ self.flood_type = flood_type
59
+ self.value = value
60
+
61
+ def __repr__(self):
62
+ return "<{} ᴡɪʟʟ ᴇxᴇᴄᴜᴛɪɴɢ {} ғᴏʀ ғʟᴏᴏᴅ.>".format(self.chat_id, self.flood_type)
63
+
64
+
65
+ FloodControl.__table__.create(checkfirst=True)
66
+ FloodSettings.__table__.create(checkfirst=True)
67
+
68
+ INSERTION_FLOOD_LOCK = threading.RLock()
69
+ INSERTION_FLOOD_SETTINGS_LOCK = threading.RLock()
70
+
71
+ CHAT_FLOOD = {}
72
+
73
+
74
+ def set_flood(chat_id, amount):
75
+ with INSERTION_FLOOD_LOCK:
76
+ flood = SESSION.query(FloodControl).get(str(chat_id))
77
+ if not flood:
78
+ flood = FloodControl(str(chat_id))
79
+
80
+ flood.user_id = None
81
+ flood.limit = amount
82
+
83
+ CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, amount)
84
+
85
+ SESSION.add(flood)
86
+ SESSION.commit()
87
+
88
+
89
+ def update_flood(chat_id: str, user_id) -> bool:
90
+ if str(chat_id) not in CHAT_FLOOD:
91
+ return
92
+
93
+ curr_user_id, count, limit = CHAT_FLOOD.get(str(chat_id), DEF_OBJ)
94
+
95
+ if limit == 0: # no antiflood
96
+ return False
97
+
98
+ if user_id != curr_user_id or user_id is None: # other user
99
+ CHAT_FLOOD[str(chat_id)] = (user_id, DEF_COUNT, limit)
100
+ return False
101
+
102
+ count += 1
103
+ if count > limit: # too many msgs, kick
104
+ CHAT_FLOOD[str(chat_id)] = (None, DEF_COUNT, limit)
105
+ return True
106
+
107
+ # default -> update
108
+ CHAT_FLOOD[str(chat_id)] = (user_id, count, limit)
109
+ return False
110
+
111
+
112
+ def get_flood_limit(chat_id):
113
+ return CHAT_FLOOD.get(str(chat_id), DEF_OBJ)[2]
114
+
115
+
116
+ def set_flood_strength(chat_id, flood_type, value):
117
+ # ғᴏʀ ғʟᴏᴏᴅ_ᴛʏᴘᴇ
118
+ # 1 = ban
119
+ # 2 = kick
120
+ # 3 = mute
121
+ # 4 = tban
122
+ # 5 = tmute
123
+ # 6 = ᴅᴍᴜᴛᴇ sᴏᴏɴ
124
+ with INSERTION_FLOOD_SETTINGS_LOCK:
125
+ curr_setting = SESSION.query(FloodSettings).get(str(chat_id))
126
+ if not curr_setting:
127
+ curr_setting = FloodSettings(
128
+ chat_id,
129
+ flood_type=int(flood_type),
130
+ value=value,
131
+ )
132
+
133
+ curr_setting.flood_type = int(flood_type)
134
+ curr_setting.value = str(value)
135
+
136
+ SESSION.add(curr_setting)
137
+ SESSION.commit()
138
+
139
+
140
+ def get_flood_setting(chat_id):
141
+ try:
142
+ setting = SESSION.query(FloodSettings).get(str(chat_id))
143
+ if setting:
144
+ return setting.flood_type, setting.value
145
+ return 1, "0"
146
+
147
+ finally:
148
+ SESSION.close()
149
+
150
+
151
+ def migrate_chat(old_chat_id, new_chat_id):
152
+ with INSERTION_FLOOD_LOCK:
153
+ flood = SESSION.query(FloodControl).get(str(old_chat_id))
154
+ if flood:
155
+ CHAT_FLOOD[str(new_chat_id)] = CHAT_FLOOD.get(str(old_chat_id), DEF_OBJ)
156
+ flood.chat_id = str(new_chat_id)
157
+ SESSION.commit()
158
+
159
+ SESSION.close()
160
+
161
+
162
+ def __load_flood_settings():
163
+ global CHAT_FLOOD
164
+ try:
165
+ all_chats = SESSION.query(FloodControl).all()
166
+ CHAT_FLOOD = {chat.chat_id: (None, DEF_COUNT, chat.limit) for chat in all_chats}
167
+ finally:
168
+ SESSION.close()
169
+
170
+
171
+ __load_flood_settings()
Database/sql/antilinkedchannel_sql.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Boolean, Column
28
+ from sqlalchemy.sql.sqltypes import String
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class AntiLinkedChannelSettings(BASE):
34
+ __tablename__ = "anti_linked_channel_settings"
35
+
36
+ chat_id = Column(String(14), primary_key=True)
37
+ setting = Column(Boolean, default=False, nullable=False)
38
+
39
+ def __init__(self, chat_id: int, disabled: bool):
40
+ self.chat_id = str(chat_id)
41
+ self.setting = disabled
42
+
43
+ def __repr__(self):
44
+ return "<Antilinked setting {} ({})>".format(self.chat_id, self.setting)
45
+
46
+
47
+ class AntiPinChannelSettings(BASE):
48
+ __tablename__ = "anti_pin_channel_settings"
49
+
50
+ chat_id = Column(String(14), primary_key=True)
51
+ setting = Column(Boolean, default=False, nullable=False)
52
+
53
+ def __init__(self, chat_id: int, disabled: bool):
54
+ self.chat_id = str(chat_id)
55
+ self.setting = disabled
56
+
57
+ def __repr__(self):
58
+ return "<ᴀɴᴛɪᴘɪɴ sᴇᴛᴛɪɴɢ {} ({})>".format(self.chat_id, self.setting)
59
+
60
+
61
+ AntiLinkedChannelSettings.__table__.create(checkfirst=True)
62
+ ANTI_LINKED_CHANNEL_SETTING_LOCK = threading.RLock()
63
+
64
+ AntiPinChannelSettings.__table__.create(checkfirst=True)
65
+ ANTI_PIN_CHANNEL_SETTING_LOCK = threading.RLock()
66
+
67
+
68
+ def enable_linked(chat_id: int):
69
+ with ANTI_LINKED_CHANNEL_SETTING_LOCK:
70
+ chat = SESSION.query(AntiLinkedChannelSettings).get(str(chat_id))
71
+ if not chat:
72
+ chat = AntiLinkedChannelSettings(chat_id, True)
73
+
74
+ chat.setting = True
75
+ SESSION.add(chat)
76
+ SESSION.commit()
77
+
78
+
79
+ def enable_pin(chat_id: int):
80
+ with ANTI_PIN_CHANNEL_SETTING_LOCK:
81
+ chat = SESSION.query(AntiPinChannelSettings).get(str(chat_id))
82
+ if not chat:
83
+ chat = AntiPinChannelSettings(chat_id, True)
84
+
85
+ chat.setting = True
86
+ SESSION.add(chat)
87
+ SESSION.commit()
88
+
89
+
90
+ def disable_linked(chat_id: int):
91
+ with ANTI_LINKED_CHANNEL_SETTING_LOCK:
92
+ chat = SESSION.query(AntiLinkedChannelSettings).get(str(chat_id))
93
+ if not chat:
94
+ chat = AntiLinkedChannelSettings(chat_id, False)
95
+
96
+ chat.setting = False
97
+ SESSION.add(chat)
98
+ SESSION.commit()
99
+
100
+
101
+ def disable_pin(chat_id: int):
102
+ with ANTI_PIN_CHANNEL_SETTING_LOCK:
103
+ chat = SESSION.query(AntiPinChannelSettings).get(str(chat_id))
104
+ if not chat:
105
+ chat = AntiPinChannelSettings(chat_id, False)
106
+
107
+ chat.setting = False
108
+ SESSION.add(chat)
109
+ SESSION.commit()
110
+
111
+
112
+ def status_linked(chat_id: int) -> bool:
113
+ with ANTI_LINKED_CHANNEL_SETTING_LOCK:
114
+ d = SESSION.query(AntiLinkedChannelSettings).get(str(chat_id))
115
+ if not d:
116
+ return False
117
+ return d.setting
118
+
119
+
120
+ def status_pin(chat_id: int) -> bool:
121
+ with ANTI_PIN_CHANNEL_SETTING_LOCK:
122
+ d = SESSION.query(AntiPinChannelSettings).get(str(chat_id))
123
+ if not d:
124
+ return False
125
+ return d.setting
126
+
127
+
128
+ def migrate_chat(old_chat_id, new_chat_id):
129
+ with ANTI_LINKED_CHANNEL_SETTING_LOCK:
130
+ chat = SESSION.query(AntiLinkedChannelSettings).get(str(old_chat_id))
131
+ if chat:
132
+ chat.chat_id = new_chat_id
133
+ SESSION.add(chat)
134
+
135
+ SESSION.commit()
136
+ with ANTI_PIN_CHANNEL_SETTING_LOCK:
137
+ chat = SESSION.query(AntiPinChannelSettings).get(str(old_chat_id))
138
+ if chat:
139
+ chat.chat_id = new_chat_id
140
+ SESSION.add(chat)
141
+
142
+ SESSION.commit()
Database/sql/approve_sql.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Column, String
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class Approvals(BASE):
33
+ __tablename__ = "approval"
34
+ chat_id = Column(String(14), primary_key=True)
35
+ user_id = Column(BigInteger, primary_key=True)
36
+
37
+ def __init__(self, chat_id, user_id):
38
+ self.chat_id = str(chat_id) # ensure string
39
+ self.user_id = user_id
40
+
41
+ def __repr__(self):
42
+ return "<ᴀᴘᴘʀᴏᴠᴇ %s>" % self.user_id
43
+
44
+
45
+ Approvals.__table__.create(checkfirst=True)
46
+
47
+ APPROVE_INSERTION_LOCK = threading.RLock()
48
+
49
+
50
+ def approve(chat_id, user_id):
51
+ with APPROVE_INSERTION_LOCK:
52
+ approve_user = Approvals(str(chat_id), user_id)
53
+ SESSION.add(approve_user)
54
+ SESSION.commit()
55
+
56
+
57
+ def is_approved(chat_id, user_id):
58
+ try:
59
+ return SESSION.query(Approvals).get((str(chat_id), user_id))
60
+ finally:
61
+ SESSION.close()
62
+
63
+
64
+ def disapprove(chat_id, user_id):
65
+ with APPROVE_INSERTION_LOCK:
66
+ disapprove_user = SESSION.query(Approvals).get((str(chat_id), user_id))
67
+ if disapprove_user:
68
+ SESSION.delete(disapprove_user)
69
+ SESSION.commit()
70
+ return True
71
+ else:
72
+ SESSION.close()
73
+ return False
74
+
75
+
76
+ def list_approved(chat_id):
77
+ try:
78
+ return (
79
+ SESSION.query(Approvals)
80
+ .filter(Approvals.chat_id == str(chat_id))
81
+ .order_by(Approvals.user_id.asc())
82
+ .all()
83
+ )
84
+ finally:
85
+ SESSION.close()
Database/sql/blacklist_sql.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Column, String, UnicodeText, distinct, func
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class BlackListFilters(BASE):
33
+ __tablename__ = "blacklist"
34
+ chat_id = Column(String(14), primary_key=True)
35
+ trigger = Column(UnicodeText, primary_key=True, nullable=False)
36
+
37
+ def __init__(self, chat_id, trigger):
38
+ self.chat_id = str(chat_id) # ensure string
39
+ self.trigger = trigger
40
+
41
+ def __repr__(self):
42
+ return "<ʙʟᴀᴄᴋʟɪsᴛ ғɪʟᴛᴇʀ '%s' ғᴏʀ %s>" % (self.trigger, self.chat_id)
43
+
44
+ def __eq__(self, other):
45
+ return bool(
46
+ isinstance(other, BlackListFilters)
47
+ and self.chat_id == other.chat_id
48
+ and self.trigger == other.trigger,
49
+ )
50
+
51
+
52
+ class BlacklistSettings(BASE):
53
+ __tablename__ = "blacklist_settings"
54
+ chat_id = Column(String(14), primary_key=True)
55
+ blacklist_type = Column(BigInteger, default=1)
56
+ value = Column(UnicodeText, default="0")
57
+
58
+ def __init__(self, chat_id, blacklist_type=1, value="0"):
59
+ self.chat_id = str(chat_id)
60
+ self.blacklist_type = blacklist_type
61
+ self.value = value
62
+
63
+ def __repr__(self):
64
+ return "<{} ᴡɪʟʟ ᴇxᴇᴄᴜᴛɪɴɢ {} ғᴏʀ ʙʟᴀᴄᴋʟɪsᴛ ᴛʀɪɢɢᴇʀ.>".format(
65
+ self.chat_id,
66
+ self.blacklist_type,
67
+ )
68
+
69
+
70
+ BlackListFilters.__table__.create(checkfirst=True)
71
+ BlacklistSettings.__table__.create(checkfirst=True)
72
+
73
+ BLACKLIST_FILTER_INSERTION_LOCK = threading.RLock()
74
+ BLACKLIST_SETTINGS_INSERTION_LOCK = threading.RLock()
75
+
76
+ CHAT_BLACKLISTS = {}
77
+ CHAT_SETTINGS_BLACKLISTS = {}
78
+
79
+
80
+ def add_to_blacklist(chat_id, trigger):
81
+ with BLACKLIST_FILTER_INSERTION_LOCK:
82
+ blacklist_filt = BlackListFilters(str(chat_id), trigger)
83
+
84
+ SESSION.merge(blacklist_filt) # merge to avoid duplicate key issues
85
+ SESSION.commit()
86
+ global CHAT_BLACKLISTS
87
+ if CHAT_BLACKLISTS.get(str(chat_id), set()) == set():
88
+ CHAT_BLACKLISTS[str(chat_id)] = {trigger}
89
+ else:
90
+ CHAT_BLACKLISTS.get(str(chat_id), set()).add(trigger)
91
+
92
+
93
+ def rm_from_blacklist(chat_id, trigger):
94
+ with BLACKLIST_FILTER_INSERTION_LOCK:
95
+ blacklist_filt = SESSION.query(BlackListFilters).get((str(chat_id), trigger))
96
+ if blacklist_filt:
97
+ if trigger in CHAT_BLACKLISTS.get(str(chat_id), set()): # sanity check
98
+ CHAT_BLACKLISTS.get(str(chat_id), set()).remove(trigger)
99
+
100
+ SESSION.delete(blacklist_filt)
101
+ SESSION.commit()
102
+ return True
103
+
104
+ SESSION.close()
105
+ return False
106
+
107
+
108
+ def get_chat_blacklist(chat_id):
109
+ return CHAT_BLACKLISTS.get(str(chat_id), set())
110
+
111
+
112
+ def num_blacklist_filters():
113
+ try:
114
+ return SESSION.query(BlackListFilters).count()
115
+ finally:
116
+ SESSION.close()
117
+
118
+
119
+ def num_blacklist_chat_filters(chat_id):
120
+ try:
121
+ return (
122
+ SESSION.query(BlackListFilters.chat_id)
123
+ .filter(BlackListFilters.chat_id == str(chat_id))
124
+ .count()
125
+ )
126
+ finally:
127
+ SESSION.close()
128
+
129
+
130
+ def num_blacklist_filter_chats():
131
+ try:
132
+ return SESSION.query(func.count(distinct(BlackListFilters.chat_id))).scalar()
133
+ finally:
134
+ SESSION.close()
135
+
136
+
137
+ def set_blacklist_strength(chat_id, blacklist_type, value):
138
+ # for blacklist_type
139
+ # 0 = nothing
140
+ # 1 = delete
141
+ # 2 = warn
142
+ # 3 = mute
143
+ # 4 = kick
144
+ # 5 = ban
145
+ # 6 = tban
146
+ # 7 = tmute
147
+ with BLACKLIST_SETTINGS_INSERTION_LOCK:
148
+ global CHAT_SETTINGS_BLACKLISTS
149
+ curr_setting = SESSION.query(BlacklistSettings).get(str(chat_id))
150
+ if not curr_setting:
151
+ curr_setting = BlacklistSettings(
152
+ chat_id,
153
+ blacklist_type=int(blacklist_type),
154
+ value=value,
155
+ )
156
+
157
+ curr_setting.blacklist_type = int(blacklist_type)
158
+ curr_setting.value = str(value)
159
+ CHAT_SETTINGS_BLACKLISTS[str(chat_id)] = {
160
+ "blacklist_type": int(blacklist_type),
161
+ "value": value,
162
+ }
163
+
164
+ SESSION.add(curr_setting)
165
+ SESSION.commit()
166
+
167
+
168
+ def get_blacklist_setting(chat_id):
169
+ try:
170
+ setting = CHAT_SETTINGS_BLACKLISTS.get(str(chat_id))
171
+ if setting:
172
+ return setting["blacklist_type"], setting["value"]
173
+ return 1, "0"
174
+
175
+ finally:
176
+ SESSION.close()
177
+
178
+
179
+ def __load_chat_blacklists():
180
+ global CHAT_BLACKLISTS
181
+ try:
182
+ chats = SESSION.query(BlackListFilters.chat_id).distinct().all()
183
+ for (chat_id,) in chats: # remove tuple by ( ,)
184
+ CHAT_BLACKLISTS[chat_id] = []
185
+
186
+ all_filters = SESSION.query(BlackListFilters).all()
187
+ for x in all_filters:
188
+ CHAT_BLACKLISTS[x.chat_id] += [x.trigger]
189
+
190
+ CHAT_BLACKLISTS = {x: set(y) for x, y in CHAT_BLACKLISTS.items()}
191
+
192
+ finally:
193
+ SESSION.close()
194
+
195
+
196
+ def __load_chat_settings_blacklists():
197
+ global CHAT_SETTINGS_BLACKLISTS
198
+ try:
199
+ chats_settings = SESSION.query(BlacklistSettings).all()
200
+ for x in chats_settings: # remove tuple by ( ,)
201
+ CHAT_SETTINGS_BLACKLISTS[x.chat_id] = {
202
+ "blacklist_type": x.blacklist_type,
203
+ "value": x.value,
204
+ }
205
+
206
+ finally:
207
+ SESSION.close()
208
+
209
+
210
+ def migrate_chat(old_chat_id, new_chat_id):
211
+ with BLACKLIST_FILTER_INSERTION_LOCK:
212
+ chat_filters = (
213
+ SESSION.query(BlackListFilters)
214
+ .filter(BlackListFilters.chat_id == str(old_chat_id))
215
+ .all()
216
+ )
217
+ for filt in chat_filters:
218
+ filt.chat_id = str(new_chat_id)
219
+ SESSION.commit()
220
+
221
+
222
+ __load_chat_blacklists()
223
+ __load_chat_settings_blacklists()
Database/sql/blacklistusers_sql.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Column, String, UnicodeText
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class BlacklistUsers(BASE):
33
+ __tablename__ = "blacklistusers"
34
+ user_id = Column(String(14), primary_key=True)
35
+ reason = Column(UnicodeText)
36
+
37
+ def __init__(self, user_id, reason=None):
38
+ self.user_id = user_id
39
+ self.reason = reason
40
+
41
+
42
+ BlacklistUsers.__table__.create(checkfirst=True)
43
+
44
+ BLACKLIST_LOCK = threading.RLock()
45
+ BLACKLIST_USERS = set()
46
+
47
+
48
+ def blacklist_user(user_id, reason=None):
49
+ with BLACKLIST_LOCK:
50
+ user = SESSION.query(BlacklistUsers).get(str(user_id))
51
+ if not user:
52
+ user = BlacklistUsers(str(user_id), reason)
53
+ else:
54
+ user.reason = reason
55
+
56
+ SESSION.add(user)
57
+ SESSION.commit()
58
+ __load_blacklist_userid_list()
59
+
60
+
61
+ def unblacklist_user(user_id):
62
+ with BLACKLIST_LOCK:
63
+ user = SESSION.query(BlacklistUsers).get(str(user_id))
64
+ if user:
65
+ SESSION.delete(user)
66
+
67
+ SESSION.commit()
68
+ __load_blacklist_userid_list()
69
+
70
+
71
+ def get_reason(user_id):
72
+ user = SESSION.query(BlacklistUsers).get(str(user_id))
73
+ rep = user.reason if user else ""
74
+ SESSION.close()
75
+ return rep
76
+
77
+
78
+ def is_user_blacklisted(user_id):
79
+ return user_id in BLACKLIST_USERS
80
+
81
+
82
+ def __load_blacklist_userid_list():
83
+ global BLACKLIST_USERS
84
+ try:
85
+ BLACKLIST_USERS = {int(x.user_id) for x in SESSION.query(BlacklistUsers).all()}
86
+ finally:
87
+ SESSION.close()
88
+
89
+
90
+ __load_blacklist_userid_list()
Database/sql/blsticker_sql.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Column, String, UnicodeText, distinct, func
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class StickersFilters(BASE):
33
+ __tablename__ = "blacklist_stickers"
34
+ chat_id = Column(String(14), primary_key=True)
35
+ trigger = Column(UnicodeText, primary_key=True, nullable=False)
36
+
37
+ def __init__(self, chat_id, trigger):
38
+ self.chat_id = str(chat_id) # ensure string
39
+ self.trigger = trigger
40
+
41
+ def __repr__(self):
42
+ return "<sᴛɪᴄᴋᴇʀs ғɪʟᴛᴇʀ '%s' ғᴏʀ %s>" % (self.trigger, self.chat_id)
43
+
44
+ def __eq__(self, other):
45
+ return bool(
46
+ isinstance(other, StickersFilters)
47
+ and self.chat_id == other.chat_id
48
+ and self.trigger == other.trigger,
49
+ )
50
+
51
+
52
+ class StickerSettings(BASE):
53
+ __tablename__ = "blsticker_settings"
54
+ chat_id = Column(String(14), primary_key=True)
55
+ blacklist_type = Column(BigInteger, default=1)
56
+ value = Column(UnicodeText, default="0")
57
+
58
+ def __init__(self, chat_id, blacklist_type=1, value="0"):
59
+ self.chat_id = str(chat_id)
60
+ self.blacklist_type = blacklist_type
61
+ self.value = value
62
+
63
+ def __repr__(self):
64
+ return "<{} ᴡɪʟʟ ᴇxᴇᴄᴜᴛɪɴɢ {} ғᴏʀ ʙʟᴀᴄᴋʟɪsᴛ ᴛʀɪɢɢᴇʀ.>".format(
65
+ self.chat_id,
66
+ self.blacklist_type,
67
+ )
68
+
69
+
70
+ StickersFilters.__table__.create(checkfirst=True)
71
+ StickerSettings.__table__.create(checkfirst=True)
72
+
73
+ STICKERS_FILTER_INSERTION_LOCK = threading.RLock()
74
+ STICKSET_FILTER_INSERTION_LOCK = threading.RLock()
75
+
76
+ CHAT_STICKERS = {}
77
+ CHAT_BLSTICK_BLACKLISTS = {}
78
+
79
+
80
+ def add_to_stickers(chat_id, trigger):
81
+ with STICKERS_FILTER_INSERTION_LOCK:
82
+ stickers_filt = StickersFilters(str(chat_id), trigger)
83
+
84
+ SESSION.merge(stickers_filt) # merge to avoid duplicate key issues
85
+ SESSION.commit()
86
+ global CHAT_STICKERS
87
+ if CHAT_STICKERS.get(str(chat_id), set()) == set():
88
+ CHAT_STICKERS[str(chat_id)] = {trigger}
89
+ else:
90
+ CHAT_STICKERS.get(str(chat_id), set()).add(trigger)
91
+
92
+
93
+ def rm_from_stickers(chat_id, trigger):
94
+ with STICKERS_FILTER_INSERTION_LOCK:
95
+ stickers_filt = SESSION.query(StickersFilters).get((str(chat_id), trigger))
96
+ if stickers_filt:
97
+ if trigger in CHAT_STICKERS.get(str(chat_id), set()): # sanity check
98
+ CHAT_STICKERS.get(str(chat_id), set()).remove(trigger)
99
+
100
+ SESSION.delete(stickers_filt)
101
+ SESSION.commit()
102
+ return True
103
+
104
+ SESSION.close()
105
+ return False
106
+
107
+
108
+ def get_chat_stickers(chat_id):
109
+ return CHAT_STICKERS.get(str(chat_id), set())
110
+
111
+
112
+ def num_stickers_filters():
113
+ try:
114
+ return SESSION.query(StickersFilters).count()
115
+ finally:
116
+ SESSION.close()
117
+
118
+
119
+ def num_stickers_chat_filters(chat_id):
120
+ try:
121
+ return (
122
+ SESSION.query(StickersFilters.chat_id)
123
+ .filter(StickersFilters.chat_id == str(chat_id))
124
+ .count()
125
+ )
126
+ finally:
127
+ SESSION.close()
128
+
129
+
130
+ def num_stickers_filter_chats():
131
+ try:
132
+ return SESSION.query(func.count(distinct(StickersFilters.chat_id))).scalar()
133
+ finally:
134
+ SESSION.close()
135
+
136
+
137
+ def set_blacklist_strength(chat_id, blacklist_type, value):
138
+ # for blacklist_type
139
+ # 0 = nothing
140
+ # 1 = delete
141
+ # 2 = warn
142
+ # 3 = mute
143
+ # 4 = kick
144
+ # 5 = ban
145
+ # 6 = tban
146
+ # 7 = tmute
147
+ with STICKSET_FILTER_INSERTION_LOCK:
148
+ global CHAT_BLSTICK_BLACKLISTS
149
+ curr_setting = SESSION.query(StickerSettings).get(str(chat_id))
150
+ if not curr_setting:
151
+ curr_setting = StickerSettings(
152
+ chat_id,
153
+ blacklist_type=int(blacklist_type),
154
+ value=value,
155
+ )
156
+
157
+ curr_setting.blacklist_type = int(blacklist_type)
158
+ curr_setting.value = str(value)
159
+ CHAT_BLSTICK_BLACKLISTS[str(chat_id)] = {
160
+ "blacklist_type": int(blacklist_type),
161
+ "value": value,
162
+ }
163
+
164
+ SESSION.add(curr_setting)
165
+ SESSION.commit()
166
+
167
+
168
+ def get_blacklist_setting(chat_id):
169
+ try:
170
+ setting = CHAT_BLSTICK_BLACKLISTS.get(str(chat_id))
171
+ if setting:
172
+ return setting["blacklist_type"], setting["value"]
173
+ return 1, "0"
174
+
175
+ finally:
176
+ SESSION.close()
177
+
178
+
179
+ def __load_CHAT_STICKERS():
180
+ global CHAT_STICKERS
181
+ try:
182
+ chats = SESSION.query(StickersFilters.chat_id).distinct().all()
183
+ for (chat_id,) in chats: # remove tuple by ( ,)
184
+ CHAT_STICKERS[chat_id] = []
185
+
186
+ all_filters = SESSION.query(StickersFilters).all()
187
+ for x in all_filters:
188
+ CHAT_STICKERS[x.chat_id] += [x.trigger]
189
+
190
+ CHAT_STICKERS = {x: set(y) for x, y in CHAT_STICKERS.items()}
191
+
192
+ finally:
193
+ SESSION.close()
194
+
195
+
196
+ def __load_chat_stickerset_blacklists():
197
+ global CHAT_BLSTICK_BLACKLISTS
198
+ try:
199
+ chats_settings = SESSION.query(StickerSettings).all()
200
+ for x in chats_settings: # remove tuple by ( ,)
201
+ CHAT_BLSTICK_BLACKLISTS[x.chat_id] = {
202
+ "blacklist_type": x.blacklist_type,
203
+ "value": x.value,
204
+ }
205
+
206
+ finally:
207
+ SESSION.close()
208
+
209
+
210
+ def migrate_chat(old_chat_id, new_chat_id):
211
+ with STICKERS_FILTER_INSERTION_LOCK:
212
+ chat_filters = (
213
+ SESSION.query(StickersFilters)
214
+ .filter(StickersFilters.chat_id == str(old_chat_id))
215
+ .all()
216
+ )
217
+ for filt in chat_filters:
218
+ filt.chat_id = str(new_chat_id)
219
+ SESSION.commit()
220
+
221
+
222
+ __load_CHAT_STICKERS()
223
+ __load_chat_stickerset_blacklists()
Database/sql/cleaner_sql.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Boolean, Column, UnicodeText
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class CleanerBlueTextChatSettings(BASE):
33
+ __tablename__ = "cleaner_bluetext_chat_setting"
34
+ chat_id = Column(UnicodeText, primary_key=True)
35
+ is_enable = Column(Boolean, default=False)
36
+
37
+ def __init__(self, chat_id, is_enable):
38
+ self.chat_id = chat_id
39
+ self.is_enable = is_enable
40
+
41
+ def __repr__(self):
42
+ return "ᴄʟᴇᴀɴ ʙʟᴜᴇ ᴛᴇxᴛ ғᴏʀ {}".format(self.chat_id)
43
+
44
+
45
+ class CleanerBlueTextChat(BASE):
46
+ __tablename__ = "cleaner_bluetext_chat_ignore_commands"
47
+ chat_id = Column(UnicodeText, primary_key=True)
48
+ command = Column(UnicodeText, primary_key=True)
49
+
50
+ def __init__(self, chat_id, command):
51
+ self.chat_id = chat_id
52
+ self.command = command
53
+
54
+
55
+ class CleanerBlueTextGlobal(BASE):
56
+ __tablename__ = "cleaner_bluetext_global_ignore_commands"
57
+ command = Column(UnicodeText, primary_key=True)
58
+
59
+ def __init__(self, command):
60
+ self.command = command
61
+
62
+
63
+ CleanerBlueTextChatSettings.__table__.create(checkfirst=True)
64
+ CleanerBlueTextChat.__table__.create(checkfirst=True)
65
+ CleanerBlueTextGlobal.__table__.create(checkfirst=True)
66
+
67
+ CLEANER_CHAT_SETTINGS = threading.RLock()
68
+ CLEANER_CHAT_LOCK = threading.RLock()
69
+ CLEANER_GLOBAL_LOCK = threading.RLock()
70
+
71
+ CLEANER_CHATS = {}
72
+ GLOBAL_IGNORE_COMMANDS = set()
73
+
74
+
75
+ def set_cleanbt(chat_id, is_enable):
76
+ with CLEANER_CHAT_SETTINGS:
77
+ curr = SESSION.query(CleanerBlueTextChatSettings).get(str(chat_id))
78
+
79
+ if not curr:
80
+ curr = CleanerBlueTextChatSettings(str(chat_id), is_enable)
81
+ else:
82
+ curr.is_enabled = is_enable
83
+
84
+ if str(chat_id) not in CLEANER_CHATS:
85
+ CLEANER_CHATS.setdefault(
86
+ str(chat_id), {"setting": False, "commands": set()}
87
+ )
88
+
89
+ CLEANER_CHATS[str(chat_id)]["setting"] = is_enable
90
+
91
+ SESSION.add(curr)
92
+ SESSION.commit()
93
+
94
+
95
+ def chat_ignore_command(chat_id, ignore):
96
+ ignore = ignore.lower()
97
+ with CLEANER_CHAT_LOCK:
98
+ ignored = SESSION.query(CleanerBlueTextChat).get((str(chat_id), ignore))
99
+
100
+ if not ignored:
101
+ if str(chat_id) not in CLEANER_CHATS:
102
+ CLEANER_CHATS.setdefault(
103
+ str(chat_id), {"setting": False, "commands": set()}
104
+ )
105
+
106
+ CLEANER_CHATS[str(chat_id)]["commands"].add(ignore)
107
+
108
+ ignored = CleanerBlueTextChat(str(chat_id), ignore)
109
+ SESSION.add(ignored)
110
+ SESSION.commit()
111
+ return True
112
+ SESSION.close()
113
+ return False
114
+
115
+
116
+ def chat_unignore_command(chat_id, unignore):
117
+ unignore = unignore.lower()
118
+ with CLEANER_CHAT_LOCK:
119
+ unignored = SESSION.query(CleanerBlueTextChat).get((str(chat_id), unignore))
120
+
121
+ if unignored:
122
+ if str(chat_id) not in CLEANER_CHATS:
123
+ CLEANER_CHATS.setdefault(
124
+ str(chat_id), {"setting": False, "commands": set()}
125
+ )
126
+ if unignore in CLEANER_CHATS.get(str(chat_id)).get("commands"):
127
+ CLEANER_CHATS[str(chat_id)]["commands"].remove(unignore)
128
+
129
+ SESSION.delete(unignored)
130
+ SESSION.commit()
131
+ return True
132
+
133
+ SESSION.close()
134
+ return False
135
+
136
+
137
+ def global_ignore_command(command):
138
+ command = command.lower()
139
+ with CLEANER_GLOBAL_LOCK:
140
+ ignored = SESSION.query(CleanerBlueTextGlobal).get(str(command))
141
+
142
+ if not ignored:
143
+ GLOBAL_IGNORE_COMMANDS.add(command)
144
+
145
+ ignored = CleanerBlueTextGlobal(str(command))
146
+ SESSION.add(ignored)
147
+ SESSION.commit()
148
+ return True
149
+
150
+ SESSION.close()
151
+ return False
152
+
153
+
154
+ def global_unignore_command(command):
155
+ command = command.lower()
156
+ with CLEANER_GLOBAL_LOCK:
157
+ unignored = SESSION.query(CleanerBlueTextGlobal).get(str(command))
158
+
159
+ if unignored:
160
+ if command in GLOBAL_IGNORE_COMMANDS:
161
+ GLOBAL_IGNORE_COMMANDS.remove(command)
162
+
163
+ SESSION.delete(command)
164
+ SESSION.commit()
165
+ return True
166
+
167
+ SESSION.close()
168
+ return False
169
+
170
+
171
+ def is_command_ignored(chat_id, command):
172
+ if command.lower() in GLOBAL_IGNORE_COMMANDS:
173
+ return True
174
+
175
+ if str(chat_id) in CLEANER_CHATS and command.lower() in CLEANER_CHATS.get(
176
+ str(chat_id)
177
+ ).get("commands"):
178
+ return True
179
+
180
+ return False
181
+
182
+
183
+ def is_enabled(chat_id):
184
+ if str(chat_id) in CLEANER_CHATS:
185
+ return CLEANER_CHATS.get(str(chat_id)).get("setting")
186
+
187
+ return False
188
+
189
+
190
+ def get_all_ignored(chat_id):
191
+ if str(chat_id) in CLEANER_CHATS:
192
+ LOCAL_IGNORE_COMMANDS = CLEANER_CHATS.get(str(chat_id)).get("commands")
193
+ else:
194
+ LOCAL_IGNORE_COMMANDS = set()
195
+
196
+ return GLOBAL_IGNORE_COMMANDS, LOCAL_IGNORE_COMMANDS
197
+
198
+
199
+ def __load_cleaner_list():
200
+ global GLOBAL_IGNORE_COMMANDS
201
+ global CLEANER_CHATS
202
+
203
+ try:
204
+ GLOBAL_IGNORE_COMMANDS = {
205
+ x.command for x in SESSION.query(CleanerBlueTextGlobal).all()
206
+ }
207
+ finally:
208
+ SESSION.close()
209
+
210
+ try:
211
+ for x in SESSION.query(CleanerBlueTextChatSettings).all():
212
+ CLEANER_CHATS.setdefault(x.chat_id, {"setting": False, "commands": set()})
213
+ CLEANER_CHATS[x.chat_id]["setting"] = x.is_enable
214
+ finally:
215
+ SESSION.close()
216
+
217
+ try:
218
+ for x in SESSION.query(CleanerBlueTextChat).all():
219
+ CLEANER_CHATS.setdefault(x.chat_id, {"setting": False, "commands": set()})
220
+ CLEANER_CHATS[x.chat_id]["commands"].add(x.command)
221
+ finally:
222
+ SESSION.close()
223
+
224
+
225
+ __load_cleaner_list()
Database/sql/connection_sql.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+ import time
27
+ from typing import Union
28
+
29
+ from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText
30
+
31
+ from Database.sql import BASE, SESSION
32
+
33
+
34
+ class ChatAccessConnectionSettings(BASE):
35
+ __tablename__ = "access_connection"
36
+ chat_id = Column(String(14), primary_key=True)
37
+ allow_connect_to_chat = Column(Boolean, default=True)
38
+
39
+ def __init__(self, chat_id, allow_connect_to_chat):
40
+ self.chat_id = str(chat_id)
41
+ self.allow_connect_to_chat = str(allow_connect_to_chat)
42
+
43
+ def __repr__(self):
44
+ return "<ᴄʜᴀᴛ ᴀᴄᴄᴇss sᴇᴛᴛɪɴɢs ({}) is {}>".format(
45
+ self.chat_id,
46
+ self.allow_connect_to_chat,
47
+ )
48
+
49
+
50
+ class Connection(BASE):
51
+ __tablename__ = "connection"
52
+ user_id = Column(BigInteger, primary_key=True)
53
+ chat_id = Column(String(14))
54
+
55
+ def __init__(self, user_id, chat_id):
56
+ self.user_id = user_id
57
+ self.chat_id = str(chat_id) # Ensure String
58
+
59
+
60
+ class ConnectionHistory(BASE):
61
+ __tablename__ = "connection_history"
62
+ user_id = Column(BigInteger, primary_key=True)
63
+ chat_id = Column(String(14), primary_key=True)
64
+ chat_name = Column(UnicodeText)
65
+ conn_time = Column(BigInteger)
66
+
67
+ def __init__(self, user_id, chat_id, chat_name, conn_time):
68
+ self.user_id = user_id
69
+ self.chat_id = str(chat_id)
70
+ self.chat_name = str(chat_name)
71
+ self.conn_time = int(conn_time)
72
+
73
+ def __repr__(self):
74
+ return "<ᴄᴏɴɴᴇᴄᴛɪᴏɴ ᴜsᴇʀ {} ʜɪsᴛᴏʀʏ {}>".format(self.user_id, self.chat_id)
75
+
76
+
77
+ ChatAccessConnectionSettings.__table__.create(checkfirst=True)
78
+ Connection.__table__.create(checkfirst=True)
79
+ ConnectionHistory.__table__.create(checkfirst=True)
80
+
81
+ CHAT_ACCESS_LOCK = threading.RLock()
82
+ CONNECTION_INSERTION_LOCK = threading.RLock()
83
+ CONNECTION_HISTORY_LOCK = threading.RLock()
84
+
85
+ HISTORY_CONNECT = {}
86
+
87
+
88
+ def allow_connect_to_chat(chat_id: Union[str, int]) -> bool:
89
+ try:
90
+ chat_setting = SESSION.query(ChatAccessConnectionSettings).get(str(chat_id))
91
+ if chat_setting:
92
+ return chat_setting.allow_connect_to_chat
93
+ return False
94
+ finally:
95
+ SESSION.close()
96
+
97
+
98
+ def set_allow_connect_to_chat(chat_id: Union[int, str], setting: bool):
99
+ with CHAT_ACCESS_LOCK:
100
+ chat_setting = SESSION.query(ChatAccessConnectionSettings).get(str(chat_id))
101
+ if not chat_setting:
102
+ chat_setting = ChatAccessConnectionSettings(chat_id, setting)
103
+
104
+ chat_setting.allow_connect_to_chat = setting
105
+ SESSION.add(chat_setting)
106
+ SESSION.commit()
107
+
108
+
109
+ def connect(user_id, chat_id):
110
+ with CONNECTION_INSERTION_LOCK:
111
+ prev = SESSION.query(Connection).get((int(user_id)))
112
+ if prev:
113
+ SESSION.delete(prev)
114
+ connect_to_chat = Connection(int(user_id), chat_id)
115
+ SESSION.add(connect_to_chat)
116
+ SESSION.commit()
117
+ return True
118
+
119
+
120
+ def get_connected_chat(user_id):
121
+ try:
122
+ return SESSION.query(Connection).get((int(user_id)))
123
+ finally:
124
+ SESSION.close()
125
+
126
+
127
+ def curr_connection(chat_id):
128
+ try:
129
+ return SESSION.query(Connection).get((str(chat_id)))
130
+ finally:
131
+ SESSION.close()
132
+
133
+
134
+ def disconnect(user_id):
135
+ with CONNECTION_INSERTION_LOCK:
136
+ disconnect = SESSION.query(Connection).get((int(user_id)))
137
+ if disconnect:
138
+ SESSION.delete(disconnect)
139
+ SESSION.commit()
140
+ return True
141
+ SESSION.close()
142
+ return False
143
+
144
+
145
+ def add_history_conn(user_id, chat_id, chat_name):
146
+ global HISTORY_CONNECT
147
+ with CONNECTION_HISTORY_LOCK:
148
+ conn_time = int(time.time())
149
+ if HISTORY_CONNECT.get(int(user_id)):
150
+ counting = (
151
+ SESSION.query(ConnectionHistory.user_id)
152
+ .filter(ConnectionHistory.user_id == str(user_id))
153
+ .count()
154
+ )
155
+ getchat_id = {
156
+ HISTORY_CONNECT[int(user_id)][x]["chat_id"]: x
157
+ for x in HISTORY_CONNECT[int(user_id)]
158
+ }
159
+
160
+ if chat_id in getchat_id:
161
+ todeltime = getchat_id[str(chat_id)]
162
+ delold = SESSION.query(ConnectionHistory).get(
163
+ (int(user_id), str(chat_id)),
164
+ )
165
+ if delold:
166
+ SESSION.delete(delold)
167
+ HISTORY_CONNECT[int(user_id)].pop(todeltime)
168
+ elif counting >= 5:
169
+ todel = list(HISTORY_CONNECT[int(user_id)])
170
+ todel.reverse()
171
+ todel = todel[4:]
172
+ for x in todel:
173
+ chat_old = HISTORY_CONNECT[int(user_id)][x]["chat_id"]
174
+ delold = SESSION.query(ConnectionHistory).get(
175
+ (int(user_id), str(chat_old)),
176
+ )
177
+ if delold:
178
+ SESSION.delete(delold)
179
+ HISTORY_CONNECT[int(user_id)].pop(x)
180
+ else:
181
+ HISTORY_CONNECT[int(user_id)] = {}
182
+ delold = SESSION.query(ConnectionHistory).get((int(user_id), str(chat_id)))
183
+ if delold:
184
+ SESSION.delete(delold)
185
+ history = ConnectionHistory(int(user_id), str(chat_id), chat_name, conn_time)
186
+ SESSION.add(history)
187
+ SESSION.commit()
188
+ HISTORY_CONNECT[int(user_id)][conn_time] = {
189
+ "chat_name": chat_name,
190
+ "chat_id": str(chat_id),
191
+ }
192
+
193
+
194
+ def get_history_conn(user_id):
195
+ if not HISTORY_CONNECT.get(int(user_id)):
196
+ HISTORY_CONNECT[int(user_id)] = {}
197
+ return HISTORY_CONNECT[int(user_id)]
198
+
199
+
200
+ def clear_history_conn(user_id):
201
+ global HISTORY_CONNECT
202
+ todel = list(HISTORY_CONNECT[int(user_id)])
203
+ for x in todel:
204
+ chat_old = HISTORY_CONNECT[int(user_id)][x]["chat_id"]
205
+ delold = SESSION.query(ConnectionHistory).get((int(user_id), str(chat_old)))
206
+ if delold:
207
+ SESSION.delete(delold)
208
+ HISTORY_CONNECT[int(user_id)].pop(x)
209
+ SESSION.commit()
210
+ return True
211
+
212
+
213
+ def __load_user_history():
214
+ global HISTORY_CONNECT
215
+ try:
216
+ qall = SESSION.query(ConnectionHistory).all()
217
+ HISTORY_CONNECT = {}
218
+ for x in qall:
219
+ check = HISTORY_CONNECT.get(x.user_id)
220
+ if check is None:
221
+ HISTORY_CONNECT[x.user_id] = {}
222
+ HISTORY_CONNECT[x.user_id][x.conn_time] = {
223
+ "chat_name": x.chat_name,
224
+ "chat_id": x.chat_id,
225
+ }
226
+ finally:
227
+ SESSION.close()
228
+
229
+
230
+ __load_user_history()
Database/sql/cust_filters_sql.py ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ is_sticker = Column(Boolean, nullable=False, default=False)
15
+ is_document = Column(Boolean, nullable=False, default=False)
16
+ is_image = Column(Boolean, nullable=False, default=False)
17
+ is_audio = Column(Boolean, nullable=False, default=False)
18
+ is_voice = Column(Boolean, nullable=False, default=False)
19
+ is_video = Column(Boolean, nullable=False, default=False)
20
+
21
+ has_buttons = Column(Boolean, nullable=False, default=False)
22
+ # NOTE: Here for legacy purposes, to ensure older filters don't mess up.
23
+ has_markdown = Column(Boolean, nullable=False, default=False)
24
+
25
+ # NEW FILTER
26
+ # alter table cust_filters add column reply_text text;
27
+ # alter table cust_filters add column file_type integer default 1;
28
+ # alter table cust_filters add column file_id text;
29
+ reply_text = Column(UnicodeText)
30
+ file_type = Column(Integer, nullable=False, default=1)
31
+ file_id = Column(UnicodeText, default=None)
32
+
33
+ def __init__(
34
+ self,
35
+ chat_id,
36
+ keyword,
37
+ reply,
38
+ is_sticker=False,
39
+ is_document=False,
40
+ is_image=False,
41
+ is_audio=False,
42
+ is_voice=False,
43
+ is_video=False,
44
+ has_buttons=False,
45
+ reply_text=None,
46
+ file_type=1,
47
+ file_id=None,
48
+ ):
49
+ self.chat_id = str(chat_id) # ensure string
50
+ self.keyword = keyword
51
+ self.reply = reply
52
+ self.is_sticker = is_sticker
53
+ self.is_document = is_document
54
+ self.is_image = is_image
55
+ self.is_audio = is_audio
56
+ self.is_voice = is_voice
57
+ self.is_video = is_video
58
+ self.has_buttons = has_buttons
59
+ self.has_markdown = True
60
+
61
+ self.reply_text = reply_text
62
+ self.file_type = file_type
63
+ self.file_id = file_id
64
+
65
+ def __repr__(self):
66
+ return "<Permissions for %s>" % self.chat_id
67
+
68
+ def __eq__(self, other):
69
+ return bool(
70
+ isinstance(other, CustomFilters)
71
+ and self.chat_id == other.chat_id
72
+ and self.keyword == other.keyword
73
+ )
74
+
75
+
76
+ class NewCustomFilters(BASE):
77
+ __tablename__ = "cust_filters_new"
78
+ chat_id = Column(String(14), primary_key=True)
79
+ keyword = Column(UnicodeText, primary_key=True, nullable=False)
80
+ text = Column(UnicodeText)
81
+ file_type = Column(Integer, nullable=False, default=1)
82
+ file_id = Column(UnicodeText, default=None)
83
+
84
+ def __init__(self, chat_id, keyword, text, file_type, file_id):
85
+ self.chat_id = str(chat_id) # ensure string
86
+ self.keyword = keyword
87
+ self.text = text
88
+ self.file_type = file_type
89
+ self.file_id = file_id
90
+
91
+ def __repr__(self):
92
+ return "<Filter for %s>" % self.chat_id
93
+
94
+ def __eq__(self, other):
95
+ return bool(
96
+ isinstance(other, CustomFilters)
97
+ and self.chat_id == other.chat_id
98
+ and self.keyword == other.keyword
99
+ )
100
+
101
+
102
+ class Buttons(BASE):
103
+ __tablename__ = "cust_filter_urls"
104
+ id = Column(Integer, primary_key=True, autoincrement=True)
105
+ chat_id = Column(String(14), primary_key=True)
106
+ keyword = Column(UnicodeText, primary_key=True)
107
+ name = Column(UnicodeText, nullable=False)
108
+ url = Column(UnicodeText, nullable=False)
109
+ same_line = Column(Boolean, default=False)
110
+
111
+ def __init__(self, chat_id, keyword, name, url, same_line=False):
112
+ self.chat_id = str(chat_id)
113
+ self.keyword = keyword
114
+ self.name = name
115
+ self.url = url
116
+ self.same_line = same_line
117
+
118
+
119
+ CustomFilters.__table__.create(checkfirst=True)
120
+ Buttons.__table__.create(checkfirst=True)
121
+
122
+ CUST_FILT_LOCK = threading.RLock()
123
+ BUTTON_LOCK = threading.RLock()
124
+ CHAT_FILTERS = {}
125
+
126
+
127
+ def get_all_filters():
128
+ try:
129
+ return SESSION.query(CustomFilters).all()
130
+ finally:
131
+ SESSION.close()
132
+
133
+
134
+ def add_filter(
135
+ chat_id,
136
+ keyword,
137
+ reply,
138
+ is_sticker=False,
139
+ is_document=False,
140
+ is_image=False,
141
+ is_audio=False,
142
+ is_voice=False,
143
+ is_video=False,
144
+ buttons=None,
145
+ ):
146
+ global CHAT_FILTERS
147
+
148
+ if buttons is None:
149
+ buttons = []
150
+
151
+ with CUST_FILT_LOCK:
152
+ prev = SESSION.query(CustomFilters).get((str(chat_id), keyword))
153
+ if prev:
154
+ with BUTTON_LOCK:
155
+ prev_buttons = (
156
+ SESSION.query(Buttons)
157
+ .filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
158
+ .all()
159
+ )
160
+ for btn in prev_buttons:
161
+ SESSION.delete(btn)
162
+ SESSION.delete(prev)
163
+
164
+ filt = CustomFilters(
165
+ str(chat_id),
166
+ keyword,
167
+ reply,
168
+ is_sticker,
169
+ is_document,
170
+ is_image,
171
+ is_audio,
172
+ is_voice,
173
+ is_video,
174
+ bool(buttons),
175
+ )
176
+
177
+ if keyword not in CHAT_FILTERS.get(str(chat_id), []):
178
+ CHAT_FILTERS[str(chat_id)] = sorted(
179
+ CHAT_FILTERS.get(str(chat_id), []) + [keyword],
180
+ key=lambda x: (-len(x), x),
181
+ )
182
+
183
+ SESSION.add(filt)
184
+ SESSION.commit()
185
+
186
+ for b_name, url, same_line in buttons:
187
+ add_note_button_to_db(chat_id, keyword, b_name, url, same_line)
188
+
189
+
190
+ def new_add_filter(
191
+ chat_id, keyword, reply_text, file_type, file_id, buttons, media_spoiler
192
+ ):
193
+ global CHAT_FILTERS
194
+
195
+ if buttons is None:
196
+ buttons = []
197
+
198
+ with CUST_FILT_LOCK:
199
+ prev = SESSION.query(CustomFilters).get((str(chat_id), keyword))
200
+ if prev:
201
+ with BUTTON_LOCK:
202
+ prev_buttons = (
203
+ SESSION.query(Buttons)
204
+ .filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
205
+ .all()
206
+ )
207
+ for btn in prev_buttons:
208
+ SESSION.delete(btn)
209
+ SESSION.delete(prev)
210
+
211
+ filt = CustomFilters(
212
+ str(chat_id),
213
+ keyword,
214
+ reply="there is should be a new reply",
215
+ is_sticker=False,
216
+ is_document=False,
217
+ is_image=False,
218
+ is_audio=False,
219
+ is_voice=False,
220
+ is_video=False,
221
+ has_buttons=bool(buttons),
222
+ reply_text=reply_text,
223
+ file_type=file_type.value,
224
+ file_id=file_id,
225
+ )
226
+
227
+ if keyword not in CHAT_FILTERS.get(str(chat_id), []):
228
+ CHAT_FILTERS[str(chat_id)] = sorted(
229
+ CHAT_FILTERS.get(str(chat_id), []) + [keyword],
230
+ key=lambda x: (-len(x), x),
231
+ )
232
+
233
+ SESSION.add(filt)
234
+ SESSION.commit()
235
+
236
+ for b_name, url, same_line in buttons:
237
+ add_note_button_to_db(chat_id, keyword, b_name, url, same_line)
238
+
239
+
240
+ def remove_filter(chat_id, keyword):
241
+ global CHAT_FILTERS
242
+ with CUST_FILT_LOCK:
243
+ filt = SESSION.query(CustomFilters).get((str(chat_id), keyword))
244
+ if filt:
245
+ if keyword in CHAT_FILTERS.get(str(chat_id), []): # Sanity check
246
+ CHAT_FILTERS.get(str(chat_id), []).remove(keyword)
247
+
248
+ with BUTTON_LOCK:
249
+ prev_buttons = (
250
+ SESSION.query(Buttons)
251
+ .filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
252
+ .all()
253
+ )
254
+ for btn in prev_buttons:
255
+ SESSION.delete(btn)
256
+
257
+ SESSION.delete(filt)
258
+ SESSION.commit()
259
+ return True
260
+
261
+ SESSION.close()
262
+ return False
263
+
264
+
265
+ def get_chat_triggers(chat_id):
266
+ return CHAT_FILTERS.get(str(chat_id), set())
267
+
268
+
269
+ def get_chat_filters(chat_id):
270
+ try:
271
+ return (
272
+ SESSION.query(CustomFilters)
273
+ .filter(CustomFilters.chat_id == str(chat_id))
274
+ .order_by(func.length(CustomFilters.keyword).desc())
275
+ .order_by(CustomFilters.keyword.asc())
276
+ .all()
277
+ )
278
+ finally:
279
+ SESSION.close()
280
+
281
+
282
+ def get_filter(chat_id, keyword):
283
+ try:
284
+ return SESSION.query(CustomFilters).get((str(chat_id), keyword))
285
+ finally:
286
+ SESSION.close()
287
+
288
+
289
+ def add_note_button_to_db(chat_id, keyword, b_name, url, same_line):
290
+ with BUTTON_LOCK:
291
+ button = Buttons(chat_id, keyword, b_name, url, same_line)
292
+ SESSION.add(button)
293
+ SESSION.commit()
294
+
295
+
296
+ def get_buttons(chat_id, keyword):
297
+ try:
298
+ return (
299
+ SESSION.query(Buttons)
300
+ .filter(Buttons.chat_id == str(chat_id), Buttons.keyword == keyword)
301
+ .order_by(Buttons.id)
302
+ .all()
303
+ )
304
+ finally:
305
+ SESSION.close()
306
+
307
+
308
+ def num_filters():
309
+ try:
310
+ return SESSION.query(CustomFilters).count()
311
+ finally:
312
+ SESSION.close()
313
+
314
+
315
+ def num_chats():
316
+ try:
317
+ return SESSION.query(func.count(distinct(CustomFilters.chat_id))).scalar()
318
+ finally:
319
+ SESSION.close()
320
+
321
+
322
+ def __load_chat_filters():
323
+ global CHAT_FILTERS
324
+ try:
325
+ chats = SESSION.query(CustomFilters.chat_id).distinct().all()
326
+ for (chat_id,) in chats: # remove tuple by ( ,)
327
+ CHAT_FILTERS[chat_id] = []
328
+
329
+ all_filters = SESSION.query(CustomFilters).all()
330
+ for x in all_filters:
331
+ CHAT_FILTERS[x.chat_id] += [x.keyword]
332
+
333
+ CHAT_FILTERS = {
334
+ x: sorted(set(y), key=lambda i: (-len(i), i))
335
+ for x, y in CHAT_FILTERS.items()
336
+ }
337
+
338
+ finally:
339
+ SESSION.close()
340
+
341
+
342
+ # ONLY USE FOR MIGRATE OLD FILTERS TO NEW FILTERS
343
+ def __migrate_filters():
344
+ try:
345
+ all_filters = SESSION.query(CustomFilters).distinct().all()
346
+ for x in all_filters:
347
+ if x.is_document:
348
+ file_type = Types.DOCUMENT
349
+ elif x.is_image:
350
+ file_type = Types.PHOTO
351
+ elif x.is_video:
352
+ file_type = Types.VIDEO
353
+ elif x.is_sticker:
354
+ file_type = Types.STICKER
355
+ elif x.is_audio:
356
+ file_type = Types.AUDIO
357
+ elif x.is_voice:
358
+ file_type = Types.VOICE
359
+ else:
360
+ file_type = Types.TEXT
361
+
362
+ print(str(x.chat_id), x.keyword, x.reply, file_type.value)
363
+ if file_type == Types.TEXT:
364
+ filt = CustomFilters(
365
+ str(x.chat_id), x.keyword, x.reply, file_type.value, None
366
+ )
367
+ else:
368
+ filt = CustomFilters(
369
+ str(x.chat_id), x.keyword, None, file_type.value, x.reply
370
+ )
371
+
372
+ SESSION.add(filt)
373
+ SESSION.commit()
374
+
375
+ finally:
376
+ SESSION.close()
377
+
378
+
379
+ def migrate_chat(old_chat_id, new_chat_id):
380
+ with CUST_FILT_LOCK:
381
+ chat_filters = (
382
+ SESSION.query(CustomFilters)
383
+ .filter(CustomFilters.chat_id == str(old_chat_id))
384
+ .all()
385
+ )
386
+ for filt in chat_filters:
387
+ filt.chat_id = str(new_chat_id)
388
+ SESSION.commit()
389
+ try:
390
+ CHAT_FILTERS[str(new_chat_id)] = CHAT_FILTERS[str(old_chat_id)]
391
+ except KeyError:
392
+ pass
393
+ del CHAT_FILTERS[str(old_chat_id)]
394
+
395
+ with BUTTON_LOCK:
396
+ chat_buttons = (
397
+ SESSION.query(Buttons).filter(Buttons.chat_id == str(old_chat_id)).all()
398
+ )
399
+ for btn in chat_buttons:
400
+ btn.chat_id = str(new_chat_id)
401
+ SESSION.commit()
402
+
403
+
404
+ __load_chat_filters()
Database/sql/disable_sql.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Column, String, UnicodeText, distinct, func
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class Disable(BASE):
33
+ __tablename__ = "disabled_commands"
34
+ chat_id = Column(String(14), primary_key=True)
35
+ command = Column(UnicodeText, primary_key=True)
36
+
37
+ def __init__(self, chat_id, command):
38
+ self.chat_id = chat_id
39
+ self.command = command
40
+
41
+ def __repr__(self):
42
+ return "ᴅɪsᴀʙʟᴇᴅ ᴄᴍᴅ {} in {}".format(self.command, self.chat_id)
43
+
44
+
45
+ Disable.__table__.create(checkfirst=True)
46
+ DISABLE_INSERTION_LOCK = threading.RLock()
47
+
48
+ DISABLED = {}
49
+
50
+
51
+ def disable_command(chat_id, disable):
52
+ with DISABLE_INSERTION_LOCK:
53
+ disabled = SESSION.query(Disable).get((str(chat_id), disable))
54
+
55
+ if not disabled:
56
+ DISABLED.setdefault(str(chat_id), set()).add(disable)
57
+
58
+ disabled = Disable(str(chat_id), disable)
59
+ SESSION.add(disabled)
60
+ SESSION.commit()
61
+ return True
62
+
63
+ SESSION.close()
64
+ return False
65
+
66
+
67
+ def enable_command(chat_id, enable):
68
+ with DISABLE_INSERTION_LOCK:
69
+ disabled = SESSION.query(Disable).get((str(chat_id), enable))
70
+
71
+ if disabled:
72
+ if enable in DISABLED.get(str(chat_id)): # sanity check
73
+ DISABLED.setdefault(str(chat_id), set()).remove(enable)
74
+
75
+ SESSION.delete(disabled)
76
+ SESSION.commit()
77
+ return True
78
+
79
+ SESSION.close()
80
+ return False
81
+
82
+
83
+ def is_command_disabled(chat_id, cmd):
84
+ return str(cmd).lower() in DISABLED.get(str(chat_id), set())
85
+
86
+
87
+ def get_all_disabled(chat_id):
88
+ return DISABLED.get(str(chat_id), set())
89
+
90
+
91
+ def num_chats():
92
+ try:
93
+ return SESSION.query(func.count(distinct(Disable.chat_id))).scalar()
94
+ finally:
95
+ SESSION.close()
96
+
97
+
98
+ def num_disabled():
99
+ try:
100
+ return SESSION.query(Disable).count()
101
+ finally:
102
+ SESSION.close()
103
+
104
+
105
+ def migrate_chat(old_chat_id, new_chat_id):
106
+ with DISABLE_INSERTION_LOCK:
107
+ chats = SESSION.query(Disable).filter(Disable.chat_id == str(old_chat_id)).all()
108
+ for chat in chats:
109
+ chat.chat_id = str(new_chat_id)
110
+ SESSION.add(chat)
111
+
112
+ if str(old_chat_id) in DISABLED:
113
+ DISABLED[str(new_chat_id)] = DISABLED.get(str(old_chat_id), set())
114
+
115
+ SESSION.commit()
116
+
117
+
118
+ def __load_disabled_commands():
119
+ global DISABLED
120
+ try:
121
+ all_chats = SESSION.query(Disable).all()
122
+ for chat in all_chats:
123
+ DISABLED.setdefault(chat.chat_id, set()).add(chat.command)
124
+
125
+ finally:
126
+ SESSION.close()
127
+
128
+
129
+ __load_disabled_commands()
Database/sql/feds_sql.py ADDED
@@ -0,0 +1,931 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ast
2
+ import threading
3
+
4
+ from sqlalchemy import BigInteger, Boolean, Column, Integer, String, UnicodeText
5
+ from telegram.error import BadRequest, Forbidden
6
+
7
+ from Database.sql import BASE, SESSION
8
+ from Mikobot import dispatcher
9
+
10
+
11
+ class Federations(BASE):
12
+ __tablename__ = "feds"
13
+ owner_id = Column(String(14))
14
+ fed_name = Column(UnicodeText)
15
+ fed_id = Column(UnicodeText, primary_key=True)
16
+ fed_rules = Column(UnicodeText)
17
+ fed_log = Column(UnicodeText)
18
+ fed_users = Column(UnicodeText)
19
+
20
+ def __init__(self, owner_id, fed_name, fed_id, fed_rules, fed_log, fed_users):
21
+ self.owner_id = owner_id
22
+ self.fed_name = fed_name
23
+ self.fed_id = fed_id
24
+ self.fed_rules = fed_rules
25
+ self.fed_log = fed_log
26
+ self.fed_users = fed_users
27
+
28
+
29
+ class ChatF(BASE):
30
+ __tablename__ = "chat_feds"
31
+ chat_id = Column(String(14), primary_key=True)
32
+ chat_name = Column(UnicodeText)
33
+ fed_id = Column(UnicodeText)
34
+
35
+ def __init__(self, chat_id, chat_name, fed_id):
36
+ self.chat_id = chat_id
37
+ self.chat_name = chat_name
38
+ self.fed_id = fed_id
39
+
40
+
41
+ class BansF(BASE):
42
+ __tablename__ = "bans_feds"
43
+ fed_id = Column(UnicodeText, primary_key=True)
44
+ user_id = Column(String(14), primary_key=True)
45
+ first_name = Column(UnicodeText, nullable=False)
46
+ last_name = Column(UnicodeText)
47
+ user_name = Column(UnicodeText)
48
+ reason = Column(UnicodeText, default="")
49
+ time = Column(Integer, default=0)
50
+
51
+ def __init__(self, fed_id, user_id, first_name, last_name, user_name, reason, time):
52
+ self.fed_id = fed_id
53
+ self.user_id = user_id
54
+ self.first_name = first_name
55
+ self.last_name = last_name
56
+ self.user_name = user_name
57
+ self.reason = reason
58
+ self.time = time
59
+
60
+
61
+ class FedsUserSettings(BASE):
62
+ __tablename__ = "feds_settings"
63
+ user_id = Column(BigInteger, primary_key=True)
64
+ should_report = Column(Boolean, default=True)
65
+
66
+ def __init__(self, user_id):
67
+ self.user_id = user_id
68
+
69
+ def __repr__(self):
70
+ return "<Feds report settings ({})>".format(self.user_id)
71
+
72
+
73
+ class FedSubs(BASE):
74
+ __tablename__ = "feds_subs"
75
+ fed_id = Column(UnicodeText, primary_key=True)
76
+ fed_subs = Column(UnicodeText, primary_key=True, nullable=False)
77
+
78
+ def __init__(self, fed_id, fed_subs):
79
+ self.fed_id = fed_id
80
+ self.fed_subs = fed_subs
81
+
82
+ def __repr__(self):
83
+ return "<Fed {} subscribes for {}>".format(self.fed_id, self.fed_subs)
84
+
85
+
86
+ # Dropping db
87
+ # Federations.__table__.drop()
88
+ # ChatF.__table__.drop()
89
+ # BansF.__table__.drop()
90
+ # FedSubs.__table__.drop()
91
+
92
+ Federations.__table__.create(checkfirst=True)
93
+ ChatF.__table__.create(checkfirst=True)
94
+ BansF.__table__.create(checkfirst=True)
95
+ FedsUserSettings.__table__.create(checkfirst=True)
96
+ FedSubs.__table__.create(checkfirst=True)
97
+
98
+ FEDS_LOCK = threading.RLock()
99
+ CHAT_FEDS_LOCK = threading.RLock()
100
+ FEDS_SETTINGS_LOCK = threading.RLock()
101
+ FEDS_SUBSCRIBER_LOCK = threading.RLock()
102
+
103
+ FEDERATION_BYNAME = {}
104
+ FEDERATION_BYOWNER = {}
105
+ FEDERATION_BYFEDID = {}
106
+
107
+ FEDERATION_CHATS = {}
108
+ FEDERATION_CHATS_BYID = {}
109
+
110
+ FEDERATION_BANNED_FULL = {}
111
+ FEDERATION_BANNED_USERID = {}
112
+
113
+ FEDERATION_NOTIFICATION = {}
114
+ FEDS_SUBSCRIBER = {}
115
+ MYFEDS_SUBSCRIBER = {}
116
+
117
+
118
+ def get_fed_info(fed_id):
119
+ get = FEDERATION_BYFEDID.get(str(fed_id))
120
+ if get is None:
121
+ return False
122
+ return get
123
+
124
+
125
+ def get_fed_id(chat_id):
126
+ get = FEDERATION_CHATS.get(str(chat_id))
127
+ if get is None:
128
+ return False
129
+ else:
130
+ return get["fid"]
131
+
132
+
133
+ def get_fed_name(chat_id):
134
+ get = FEDERATION_CHATS.get(str(chat_id))
135
+ if get is None:
136
+ return False
137
+ else:
138
+ return get["chat_name"]
139
+
140
+
141
+ def get_user_fban(fed_id, user_id):
142
+ if not FEDERATION_BANNED_FULL.get(fed_id):
143
+ return False, False, False
144
+ user_info = FEDERATION_BANNED_FULL[fed_id].get(user_id)
145
+ if not user_info:
146
+ return None, None, None
147
+ return user_info["first_name"], user_info["reason"], user_info["time"]
148
+
149
+
150
+ def get_user_admin_fed_name(user_id):
151
+ user_feds = []
152
+ for f in FEDERATION_BYFEDID:
153
+ if int(user_id) in ast.literal_eval(
154
+ ast.literal_eval(FEDERATION_BYFEDID[f]["fusers"])["members"]
155
+ ):
156
+ user_feds.append(FEDERATION_BYFEDID[f]["fname"])
157
+ return user_feds
158
+
159
+
160
+ def get_user_owner_fed_name(user_id):
161
+ user_feds = []
162
+ for f in FEDERATION_BYFEDID:
163
+ if int(user_id) == int(
164
+ ast.literal_eval(FEDERATION_BYFEDID[f]["fusers"])["owner"]
165
+ ):
166
+ user_feds.append(FEDERATION_BYFEDID[f]["fname"])
167
+ return user_feds
168
+
169
+
170
+ def get_user_admin_fed_full(user_id):
171
+ user_feds = []
172
+ for f in FEDERATION_BYFEDID:
173
+ if int(user_id) in ast.literal_eval(
174
+ ast.literal_eval(FEDERATION_BYFEDID[f]["fusers"])["members"]
175
+ ):
176
+ user_feds.append({"fed_id": f, "fed": FEDERATION_BYFEDID[f]})
177
+ return user_feds
178
+
179
+
180
+ def get_user_owner_fed_full(user_id):
181
+ user_feds = []
182
+ for f in FEDERATION_BYFEDID:
183
+ if int(user_id) == int(
184
+ ast.literal_eval(FEDERATION_BYFEDID[f]["fusers"])["owner"]
185
+ ):
186
+ user_feds.append({"fed_id": f, "fed": FEDERATION_BYFEDID[f]})
187
+ return user_feds
188
+
189
+
190
+ def get_user_fbanlist(user_id):
191
+ banlist = FEDERATION_BANNED_FULL
192
+ user_name = ""
193
+ fedname = []
194
+ for x in banlist:
195
+ if banlist[x].get(user_id):
196
+ if user_name == "":
197
+ user_name = banlist[x][user_id].get("first_name")
198
+ fedname.append([x, banlist[x][user_id].get("reason")])
199
+ return user_name, fedname
200
+
201
+
202
+ def new_fed(owner_id, fed_name, fed_id):
203
+ with FEDS_LOCK:
204
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
205
+ fed = Federations(
206
+ str(owner_id),
207
+ fed_name,
208
+ str(fed_id),
209
+ "Rules is not set in this federation.",
210
+ None,
211
+ str({"owner": str(owner_id), "members": "[]"}),
212
+ )
213
+ SESSION.add(fed)
214
+ SESSION.commit()
215
+ FEDERATION_BYOWNER[str(owner_id)] = {
216
+ "fid": str(fed_id),
217
+ "fname": fed_name,
218
+ "frules": "Rules is not set in this federation.",
219
+ "flog": None,
220
+ "fusers": str({"owner": str(owner_id), "members": "[]"}),
221
+ }
222
+ FEDERATION_BYFEDID[str(fed_id)] = {
223
+ "owner": str(owner_id),
224
+ "fname": fed_name,
225
+ "frules": "Rules is not set in this federation.",
226
+ "flog": None,
227
+ "fusers": str({"owner": str(owner_id), "members": "[]"}),
228
+ }
229
+ FEDERATION_BYNAME[fed_name] = {
230
+ "fid": str(fed_id),
231
+ "owner": str(owner_id),
232
+ "frules": "Rules is not set in this federation.",
233
+ "flog": None,
234
+ "fusers": str({"owner": str(owner_id), "members": "[]"}),
235
+ }
236
+ return fed
237
+
238
+
239
+ def del_fed(fed_id):
240
+ with FEDS_LOCK:
241
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME, FEDERATION_CHATS, FEDERATION_CHATS_BYID, FEDERATION_BANNED_USERID, FEDERATION_BANNED_FULL
242
+ getcache = FEDERATION_BYFEDID.get(fed_id)
243
+ if getcache is None:
244
+ return False
245
+ # Variables
246
+ getfed = FEDERATION_BYFEDID.get(fed_id)
247
+ owner_id = getfed["owner"]
248
+ fed_name = getfed["fname"]
249
+ # Delete from cache
250
+ FEDERATION_BYOWNER.pop(owner_id)
251
+ FEDERATION_BYFEDID.pop(fed_id)
252
+ FEDERATION_BYNAME.pop(fed_name)
253
+ if FEDERATION_CHATS_BYID.get(fed_id):
254
+ for x in FEDERATION_CHATS_BYID[fed_id]:
255
+ delchats = SESSION.query(ChatF).get(str(x))
256
+ if delchats:
257
+ SESSION.delete(delchats)
258
+ SESSION.commit()
259
+ FEDERATION_CHATS.pop(x)
260
+ FEDERATION_CHATS_BYID.pop(fed_id)
261
+ # Delete fedban users
262
+ getall = FEDERATION_BANNED_USERID.get(fed_id)
263
+ if getall:
264
+ for x in getall:
265
+ banlist = SESSION.query(BansF).get((fed_id, str(x)))
266
+ if banlist:
267
+ SESSION.delete(banlist)
268
+ SESSION.commit()
269
+ if FEDERATION_BANNED_USERID.get(fed_id):
270
+ FEDERATION_BANNED_USERID.pop(fed_id)
271
+ if FEDERATION_BANNED_FULL.get(fed_id):
272
+ FEDERATION_BANNED_FULL.pop(fed_id)
273
+ # Delete fedsubs
274
+ getall = MYFEDS_SUBSCRIBER.get(fed_id)
275
+ if getall:
276
+ for x in getall:
277
+ getsubs = SESSION.query(FedSubs).get((fed_id, str(x)))
278
+ if getsubs:
279
+ SESSION.delete(getsubs)
280
+ SESSION.commit()
281
+ if FEDS_SUBSCRIBER.get(fed_id):
282
+ FEDS_SUBSCRIBER.pop(fed_id)
283
+ if MYFEDS_SUBSCRIBER.get(fed_id):
284
+ MYFEDS_SUBSCRIBER.pop(fed_id)
285
+ # Delete from database
286
+ curr = SESSION.query(Federations).get(fed_id)
287
+ if curr:
288
+ SESSION.delete(curr)
289
+ SESSION.commit()
290
+ return True
291
+
292
+
293
+ def rename_fed(fed_id, owner_id, newname):
294
+ with FEDS_LOCK:
295
+ global FEDERATION_BYFEDID, FEDERATION_BYOWNER, FEDERATION_BYNAME
296
+ fed = SESSION.query(Federations).get(fed_id)
297
+ if not fed:
298
+ return False
299
+ fed.fed_name = newname
300
+ SESSION.commit()
301
+
302
+ # Update the dicts
303
+ oldname = FEDERATION_BYFEDID[str(fed_id)]["fname"]
304
+ tempdata = FEDERATION_BYNAME[oldname]
305
+ FEDERATION_BYNAME.pop(oldname)
306
+
307
+ FEDERATION_BYOWNER[str(owner_id)]["fname"] = newname
308
+ FEDERATION_BYFEDID[str(fed_id)]["fname"] = newname
309
+ FEDERATION_BYNAME[newname] = tempdata
310
+ return True
311
+
312
+
313
+ def chat_join_fed(fed_id, chat_name, chat_id):
314
+ with FEDS_LOCK:
315
+ global FEDERATION_CHATS, FEDERATION_CHATS_BYID
316
+ r = ChatF(chat_id, chat_name, fed_id)
317
+ SESSION.add(r)
318
+ FEDERATION_CHATS[str(chat_id)] = {"chat_name": chat_name, "fid": fed_id}
319
+ checkid = FEDERATION_CHATS_BYID.get(fed_id)
320
+ if checkid is None:
321
+ FEDERATION_CHATS_BYID[fed_id] = []
322
+ FEDERATION_CHATS_BYID[fed_id].append(str(chat_id))
323
+ SESSION.commit()
324
+ return r
325
+
326
+
327
+ def search_fed_by_name(fed_name):
328
+ allfed = FEDERATION_BYNAME.get(fed_name)
329
+ if allfed is None:
330
+ return False
331
+ return allfed
332
+
333
+
334
+ def search_user_in_fed(fed_id, user_id):
335
+ getfed = FEDERATION_BYFEDID.get(fed_id)
336
+ if getfed is None:
337
+ return False
338
+ getfed = ast.literal_eval(getfed["fusers"])["members"]
339
+ if user_id in ast.literal_eval(getfed):
340
+ return True
341
+ else:
342
+ return False
343
+
344
+
345
+ def user_demote_fed(fed_id, user_id):
346
+ with FEDS_LOCK:
347
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
348
+ # Variables
349
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
350
+ owner_id = getfed["owner"]
351
+ fed_name = getfed["fname"]
352
+ fed_rules = getfed["frules"]
353
+ fed_log = getfed["flog"]
354
+ # Temp set
355
+ try:
356
+ members = ast.literal_eval(ast.literal_eval(getfed["fusers"])["members"])
357
+ except ValueError:
358
+ return False
359
+ members.remove(user_id)
360
+ # Set user
361
+ FEDERATION_BYOWNER[str(owner_id)]["fusers"] = str(
362
+ {"owner": str(owner_id), "members": str(members)},
363
+ )
364
+ FEDERATION_BYFEDID[str(fed_id)]["fusers"] = str(
365
+ {"owner": str(owner_id), "members": str(members)},
366
+ )
367
+ FEDERATION_BYNAME[fed_name]["fusers"] = str(
368
+ {"owner": str(owner_id), "members": str(members)},
369
+ )
370
+ # Set on database
371
+ fed = Federations(
372
+ str(owner_id),
373
+ fed_name,
374
+ str(fed_id),
375
+ fed_rules,
376
+ fed_log,
377
+ str({"owner": str(owner_id), "members": str(members)}),
378
+ )
379
+ SESSION.merge(fed)
380
+ SESSION.commit()
381
+ return True
382
+
383
+ curr = SESSION.query(UserF).all()
384
+ result = False
385
+ for r in curr:
386
+ if int(r.user_id) == int(user_id):
387
+ if r.fed_id == fed_id:
388
+ SESSION.delete(r)
389
+ SESSION.commit()
390
+ result = True
391
+
392
+ SESSION.close()
393
+ return result
394
+
395
+
396
+ def user_join_fed(fed_id, user_id):
397
+ with FEDS_LOCK:
398
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
399
+ # Variables
400
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
401
+ owner_id = getfed["owner"]
402
+ fed_name = getfed["fname"]
403
+ fed_rules = getfed["frules"]
404
+ fed_log = getfed["flog"]
405
+ # Temp set
406
+ members = ast.literal_eval(ast.literal_eval(getfed["fusers"])["members"])
407
+ members.append(user_id)
408
+ # Set user
409
+ FEDERATION_BYOWNER[str(owner_id)]["fusers"] = str(
410
+ {"owner": str(owner_id), "members": str(members)},
411
+ )
412
+ FEDERATION_BYFEDID[str(fed_id)]["fusers"] = str(
413
+ {"owner": str(owner_id), "members": str(members)},
414
+ )
415
+ FEDERATION_BYNAME[fed_name]["fusers"] = str(
416
+ {"owner": str(owner_id), "members": str(members)},
417
+ )
418
+ # Set on database
419
+ fed = Federations(
420
+ str(owner_id),
421
+ fed_name,
422
+ str(fed_id),
423
+ fed_rules,
424
+ fed_log,
425
+ str({"owner": str(owner_id), "members": str(members)}),
426
+ )
427
+ SESSION.merge(fed)
428
+ SESSION.commit()
429
+ __load_all_feds_chats()
430
+ return True
431
+
432
+
433
+ def chat_leave_fed(chat_id):
434
+ with FEDS_LOCK:
435
+ global FEDERATION_CHATS, FEDERATION_CHATS_BYID
436
+ # Set variables
437
+ fed_info = FEDERATION_CHATS.get(str(chat_id))
438
+ if fed_info is None:
439
+ return False
440
+ fed_id = fed_info["fid"]
441
+ # Delete from cache
442
+ FEDERATION_CHATS.pop(str(chat_id))
443
+ FEDERATION_CHATS_BYID[str(fed_id)].remove(str(chat_id))
444
+ # Delete from db
445
+ curr = SESSION.query(ChatF).all()
446
+ for U in curr:
447
+ if int(U.chat_id) == int(chat_id):
448
+ SESSION.delete(U)
449
+ SESSION.commit()
450
+ return True
451
+
452
+
453
+ def all_fed_chats(fed_id):
454
+ with FEDS_LOCK:
455
+ getfed = FEDERATION_CHATS_BYID.get(fed_id)
456
+ if getfed is None:
457
+ return []
458
+ else:
459
+ return getfed
460
+
461
+
462
+ def all_fed_users(fed_id):
463
+ with FEDS_LOCK:
464
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
465
+ if getfed is None:
466
+ return False
467
+ fed_owner = ast.literal_eval(ast.literal_eval(getfed["fusers"])["owner"])
468
+ fed_admins = ast.literal_eval(ast.literal_eval(getfed["fusers"])["members"])
469
+ fed_admins.append(fed_owner)
470
+ return fed_admins
471
+
472
+
473
+ def all_fed_members(fed_id):
474
+ with FEDS_LOCK:
475
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
476
+ fed_admins = ast.literal_eval(ast.literal_eval(getfed["fusers"])["members"])
477
+ return fed_admins
478
+
479
+
480
+ def set_frules(fed_id, rules):
481
+ with FEDS_LOCK:
482
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
483
+ # Variables
484
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
485
+ owner_id = getfed["owner"]
486
+ fed_name = getfed["fname"]
487
+ fed_members = getfed["fusers"]
488
+ fed_rules = str(rules)
489
+ fed_log = getfed["flog"]
490
+ # Set user
491
+ FEDERATION_BYOWNER[str(owner_id)]["frules"] = fed_rules
492
+ FEDERATION_BYFEDID[str(fed_id)]["frules"] = fed_rules
493
+ FEDERATION_BYNAME[fed_name]["frules"] = fed_rules
494
+ # Set on database
495
+ fed = Federations(
496
+ str(owner_id),
497
+ fed_name,
498
+ str(fed_id),
499
+ fed_rules,
500
+ fed_log,
501
+ str(fed_members),
502
+ )
503
+ SESSION.merge(fed)
504
+ SESSION.commit()
505
+ return True
506
+
507
+
508
+ def get_frules(fed_id):
509
+ with FEDS_LOCK:
510
+ rules = FEDERATION_BYFEDID[str(fed_id)]["frules"]
511
+ return rules
512
+
513
+
514
+ def fban_user(fed_id, user_id, first_name, last_name, user_name, reason, time):
515
+ with FEDS_LOCK:
516
+ r = SESSION.query(BansF).all()
517
+ for I in r:
518
+ if I.fed_id == fed_id:
519
+ if int(I.user_id) == int(user_id):
520
+ SESSION.delete(I)
521
+
522
+ r = BansF(
523
+ str(fed_id),
524
+ str(user_id),
525
+ first_name,
526
+ last_name,
527
+ user_name,
528
+ reason,
529
+ time,
530
+ )
531
+
532
+ SESSION.add(r)
533
+ try:
534
+ SESSION.commit()
535
+ except:
536
+ SESSION.rollback()
537
+ return False
538
+ finally:
539
+ SESSION.commit()
540
+ __load_all_feds_banned()
541
+ return r
542
+
543
+
544
+ def multi_fban_user(
545
+ multi_fed_id,
546
+ multi_user_id,
547
+ multi_first_name,
548
+ multi_last_name,
549
+ multi_user_name,
550
+ multi_reason,
551
+ ):
552
+ if True: # with FEDS_LOCK:
553
+ counter = 0
554
+ time = 0
555
+ for x in range(len(multi_fed_id)):
556
+ fed_id = multi_fed_id[x]
557
+ user_id = multi_user_id[x]
558
+ first_name = multi_first_name[x]
559
+ last_name = multi_last_name[x]
560
+ user_name = multi_user_name[x]
561
+ reason = multi_reason[x]
562
+ r = SESSION.query(BansF).all()
563
+ for I in r:
564
+ if I.fed_id == fed_id:
565
+ if int(I.user_id) == int(user_id):
566
+ SESSION.delete(I)
567
+
568
+ r = BansF(
569
+ str(fed_id),
570
+ str(user_id),
571
+ first_name,
572
+ last_name,
573
+ user_name,
574
+ reason,
575
+ time,
576
+ )
577
+
578
+ SESSION.add(r)
579
+ counter += 1
580
+ try:
581
+ SESSION.commit()
582
+ except:
583
+ SESSION.rollback()
584
+ return False
585
+ finally:
586
+ SESSION.commit()
587
+ __load_all_feds_banned()
588
+ return counter
589
+
590
+
591
+ def un_fban_user(fed_id, user_id):
592
+ with FEDS_LOCK:
593
+ r = SESSION.query(BansF).all()
594
+ for I in r:
595
+ if I.fed_id == fed_id:
596
+ if int(I.user_id) == int(user_id):
597
+ SESSION.delete(I)
598
+ try:
599
+ SESSION.commit()
600
+ except:
601
+ SESSION.rollback()
602
+ return False
603
+ finally:
604
+ SESSION.commit()
605
+ __load_all_feds_banned()
606
+ return I
607
+
608
+
609
+ def get_fban_user(fed_id, user_id):
610
+ list_fbanned = FEDERATION_BANNED_USERID.get(fed_id)
611
+ if list_fbanned is None:
612
+ FEDERATION_BANNED_USERID[fed_id] = []
613
+ if user_id in FEDERATION_BANNED_USERID[fed_id]:
614
+ r = SESSION.query(BansF).all()
615
+ reason = None
616
+ for I in r:
617
+ if I.fed_id == fed_id:
618
+ if int(I.user_id) == int(user_id):
619
+ reason = I.reason
620
+ time = I.time
621
+ return True, reason, time
622
+ else:
623
+ return False, None, None
624
+
625
+
626
+ def get_all_fban_users(fed_id):
627
+ list_fbanned = FEDERATION_BANNED_USERID.get(fed_id)
628
+ if list_fbanned is None:
629
+ FEDERATION_BANNED_USERID[fed_id] = []
630
+ return FEDERATION_BANNED_USERID[fed_id]
631
+
632
+
633
+ def get_all_fban_users_target(fed_id, user_id):
634
+ list_fbanned = FEDERATION_BANNED_FULL.get(fed_id)
635
+ if list_fbanned is None:
636
+ FEDERATION_BANNED_FULL[fed_id] = []
637
+ return False
638
+ getuser = list_fbanned[str(user_id)]
639
+ return getuser
640
+
641
+
642
+ def get_all_fban_users_global():
643
+ list_fbanned = FEDERATION_BANNED_USERID
644
+ total = []
645
+ for x in list(FEDERATION_BANNED_USERID):
646
+ for y in FEDERATION_BANNED_USERID[x]:
647
+ total.append(y)
648
+ return total
649
+
650
+
651
+ def get_all_feds_users_global():
652
+ list_fed = FEDERATION_BYFEDID
653
+ total = []
654
+ for x in list(FEDERATION_BYFEDID):
655
+ total.append(FEDERATION_BYFEDID[x])
656
+ return total
657
+
658
+
659
+ def search_fed_by_id(fed_id):
660
+ get = FEDERATION_BYFEDID.get(fed_id)
661
+ if get is None:
662
+ return False
663
+ else:
664
+ return get
665
+ result = False
666
+ for Q in curr:
667
+ if Q.fed_id == fed_id:
668
+ result = Q.fed_id
669
+
670
+ return result
671
+
672
+
673
+ def user_feds_report(user_id: int) -> bool:
674
+ user_setting = FEDERATION_NOTIFICATION.get(str(user_id))
675
+ if user_setting is None:
676
+ user_setting = True
677
+ return user_setting
678
+
679
+
680
+ def set_feds_setting(user_id: int, setting: bool):
681
+ with FEDS_SETTINGS_LOCK:
682
+ global FEDERATION_NOTIFICATION
683
+ user_setting = SESSION.query(FedsUserSettings).get(user_id)
684
+ if not user_setting:
685
+ user_setting = FedsUserSettings(user_id)
686
+
687
+ user_setting.should_report = setting
688
+ FEDERATION_NOTIFICATION[str(user_id)] = setting
689
+ SESSION.add(user_setting)
690
+ SESSION.commit()
691
+
692
+
693
+ async def get_fed_log(fed_id):
694
+ fed_setting = FEDERATION_BYFEDID.get(str(fed_id))
695
+ if fed_setting is None:
696
+ fed_setting = False
697
+ return fed_setting
698
+ if fed_setting.get("flog") is None:
699
+ return False
700
+ elif fed_setting.get("flog"):
701
+ try:
702
+ await dispatcher.bot.get_chat(fed_setting.get("flog"))
703
+ except BadRequest:
704
+ set_fed_log(fed_id, None)
705
+ return False
706
+ except Forbidden:
707
+ set_fed_log(fed_id, None)
708
+ return False
709
+ return fed_setting.get("flog")
710
+ else:
711
+ return False
712
+
713
+
714
+ def set_fed_log(fed_id, chat_id):
715
+ with FEDS_LOCK:
716
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
717
+ # Variables
718
+ getfed = FEDERATION_BYFEDID.get(str(fed_id))
719
+ owner_id = getfed["owner"]
720
+ fed_name = getfed["fname"]
721
+ fed_members = getfed["fusers"]
722
+ fed_rules = getfed["frules"]
723
+ fed_log = str(chat_id)
724
+ # Set user
725
+ FEDERATION_BYOWNER[str(owner_id)]["flog"] = fed_log
726
+ FEDERATION_BYFEDID[str(fed_id)]["flog"] = fed_log
727
+ FEDERATION_BYNAME[fed_name]["flog"] = fed_log
728
+ # Set on database
729
+ fed = Federations(
730
+ str(owner_id),
731
+ fed_name,
732
+ str(fed_id),
733
+ fed_rules,
734
+ fed_log,
735
+ str(fed_members),
736
+ )
737
+ SESSION.merge(fed)
738
+ SESSION.commit()
739
+ return True
740
+
741
+
742
+ def subs_fed(fed_id, my_fed):
743
+ check = get_spec_subs(fed_id, my_fed)
744
+ if check:
745
+ return False
746
+ with FEDS_SUBSCRIBER_LOCK:
747
+ subsfed = FedSubs(fed_id, my_fed)
748
+
749
+ SESSION.merge(subsfed) # merge to avoid duplicate key issues
750
+ SESSION.commit()
751
+ global FEDS_SUBSCRIBER, MYFEDS_SUBSCRIBER
752
+ # Temporary Data For Subbed Feds
753
+ if FEDS_SUBSCRIBER.get(fed_id, set()) == set():
754
+ FEDS_SUBSCRIBER[fed_id] = {my_fed}
755
+ else:
756
+ FEDS_SUBSCRIBER.get(fed_id, set()).add(my_fed)
757
+ # Temporary data for Fed Subs
758
+ if MYFEDS_SUBSCRIBER.get(my_fed, set()) == set():
759
+ MYFEDS_SUBSCRIBER[my_fed] = {fed_id}
760
+ else:
761
+ MYFEDS_SUBSCRIBER.get(my_fed, set()).add(fed_id)
762
+ return True
763
+
764
+
765
+ def unsubs_fed(fed_id, my_fed):
766
+ with FEDS_SUBSCRIBER_LOCK:
767
+ getsubs = SESSION.query(FedSubs).get((fed_id, my_fed))
768
+ if getsubs:
769
+ if my_fed in FEDS_SUBSCRIBER.get(fed_id, set()): # sanity check
770
+ FEDS_SUBSCRIBER.get(fed_id, set()).remove(my_fed)
771
+ if fed_id in MYFEDS_SUBSCRIBER.get(my_fed, set()): # sanity check
772
+ MYFEDS_SUBSCRIBER.get(my_fed, set()).remove(fed_id)
773
+
774
+ SESSION.delete(getsubs)
775
+ SESSION.commit()
776
+ return True
777
+
778
+ SESSION.close()
779
+ return False
780
+
781
+
782
+ def get_all_subs(fed_id):
783
+ return FEDS_SUBSCRIBER.get(fed_id, set())
784
+
785
+
786
+ def get_spec_subs(fed_id, fed_target):
787
+ if FEDS_SUBSCRIBER.get(fed_id, set()) == set():
788
+ return {}
789
+ else:
790
+ return FEDS_SUBSCRIBER.get(fed_id, fed_target)
791
+
792
+
793
+ def get_mysubs(my_fed):
794
+ return list(MYFEDS_SUBSCRIBER.get(my_fed))
795
+
796
+
797
+ def get_subscriber(fed_id):
798
+ return FEDS_SUBSCRIBER.get(fed_id, set())
799
+
800
+
801
+ def __load_all_feds():
802
+ global FEDERATION_BYOWNER, FEDERATION_BYFEDID, FEDERATION_BYNAME
803
+ try:
804
+ feds = SESSION.query(Federations).all()
805
+ for x in feds: # remove tuple by ( ,)
806
+ # Fed by Owner
807
+ check = FEDERATION_BYOWNER.get(x.owner_id)
808
+ if check is None:
809
+ FEDERATION_BYOWNER[x.owner_id] = []
810
+ FEDERATION_BYOWNER[str(x.owner_id)] = {
811
+ "fid": str(x.fed_id),
812
+ "fname": x.fed_name,
813
+ "frules": x.fed_rules,
814
+ "flog": x.fed_log,
815
+ "fusers": str(x.fed_users),
816
+ }
817
+ # Fed By FedId
818
+ check = FEDERATION_BYFEDID.get(x.fed_id)
819
+ if check is None:
820
+ FEDERATION_BYFEDID[x.fed_id] = []
821
+ FEDERATION_BYFEDID[str(x.fed_id)] = {
822
+ "owner": str(x.owner_id),
823
+ "fname": x.fed_name,
824
+ "frules": x.fed_rules,
825
+ "flog": x.fed_log,
826
+ "fusers": str(x.fed_users),
827
+ }
828
+ # Fed By Name
829
+ check = FEDERATION_BYNAME.get(x.fed_name)
830
+ if check is None:
831
+ FEDERATION_BYNAME[x.fed_name] = []
832
+ FEDERATION_BYNAME[x.fed_name] = {
833
+ "fid": str(x.fed_id),
834
+ "owner": str(x.owner_id),
835
+ "frules": x.fed_rules,
836
+ "flog": x.fed_log,
837
+ "fusers": str(x.fed_users),
838
+ }
839
+ finally:
840
+ SESSION.close()
841
+
842
+
843
+ def __load_all_feds_chats():
844
+ global FEDERATION_CHATS, FEDERATION_CHATS_BYID
845
+ try:
846
+ qall = SESSION.query(ChatF).all()
847
+ FEDERATION_CHATS = {}
848
+ FEDERATION_CHATS_BYID = {}
849
+ for x in qall:
850
+ # Federation Chats
851
+ check = FEDERATION_CHATS.get(x.chat_id)
852
+ if check is None:
853
+ FEDERATION_CHATS[x.chat_id] = {}
854
+ FEDERATION_CHATS[x.chat_id] = {"chat_name": x.chat_name, "fid": x.fed_id}
855
+ # Federation Chats By ID
856
+ check = FEDERATION_CHATS_BYID.get(x.fed_id)
857
+ if check is None:
858
+ FEDERATION_CHATS_BYID[x.fed_id] = []
859
+ FEDERATION_CHATS_BYID[x.fed_id].append(x.chat_id)
860
+ finally:
861
+ SESSION.close()
862
+
863
+
864
+ def __load_all_feds_banned():
865
+ global FEDERATION_BANNED_USERID, FEDERATION_BANNED_FULL
866
+ try:
867
+ FEDERATION_BANNED_USERID = {}
868
+ FEDERATION_BANNED_FULL = {}
869
+ qall = SESSION.query(BansF).all()
870
+ for x in qall:
871
+ check = FEDERATION_BANNED_USERID.get(x.fed_id)
872
+ if check is None:
873
+ FEDERATION_BANNED_USERID[x.fed_id] = []
874
+ if int(x.user_id) not in FEDERATION_BANNED_USERID[x.fed_id]:
875
+ FEDERATION_BANNED_USERID[x.fed_id].append(int(x.user_id))
876
+ check = FEDERATION_BANNED_FULL.get(x.fed_id)
877
+ if check is None:
878
+ FEDERATION_BANNED_FULL[x.fed_id] = {}
879
+ FEDERATION_BANNED_FULL[x.fed_id][x.user_id] = {
880
+ "first_name": x.first_name,
881
+ "last_name": x.last_name,
882
+ "user_name": x.user_name,
883
+ "reason": x.reason,
884
+ "time": x.time,
885
+ }
886
+ finally:
887
+ SESSION.close()
888
+
889
+
890
+ def __load_all_feds_settings():
891
+ global FEDERATION_NOTIFICATION
892
+ try:
893
+ getuser = SESSION.query(FedsUserSettings).all()
894
+ for x in getuser:
895
+ FEDERATION_NOTIFICATION[str(x.user_id)] = x.should_report
896
+ finally:
897
+ SESSION.close()
898
+
899
+
900
+ def __load_feds_subscriber():
901
+ global FEDS_SUBSCRIBER
902
+ global MYFEDS_SUBSCRIBER
903
+ try:
904
+ feds = SESSION.query(FedSubs.fed_id).distinct().all()
905
+ for (fed_id,) in feds: # remove tuple by ( ,)
906
+ FEDS_SUBSCRIBER[fed_id] = []
907
+ MYFEDS_SUBSCRIBER[fed_id] = []
908
+
909
+ all_fedsubs = SESSION.query(FedSubs).all()
910
+ for x in all_fedsubs:
911
+ FEDS_SUBSCRIBER[x.fed_id] += [x.fed_subs]
912
+ try:
913
+ MYFEDS_SUBSCRIBER[x.fed_subs] += [x.fed_id]
914
+ except KeyError:
915
+ getsubs = SESSION.query(FedSubs).get((x.fed_id, x.fed_subs))
916
+ if getsubs:
917
+ SESSION.delete(getsubs)
918
+ SESSION.commit()
919
+
920
+ FEDS_SUBSCRIBER = {x: set(y) for x, y in FEDS_SUBSCRIBER.items()}
921
+ MYFEDS_SUBSCRIBER = {x: set(y) for x, y in MYFEDS_SUBSCRIBER.items()}
922
+
923
+ finally:
924
+ SESSION.close()
925
+
926
+
927
+ __load_all_feds()
928
+ __load_all_feds_chats()
929
+ __load_all_feds_banned()
930
+ __load_all_feds_settings()
931
+ __load_feds_subscriber()
Database/sql/fontsql.py ADDED
@@ -0,0 +1,2361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class Fonts:
2
+ def typewriter(text):
3
+ style = {
4
+ "a": "𝚊",
5
+ "b": "𝚋",
6
+ "c": "𝚌",
7
+ "d": "𝚍",
8
+ "e": "𝚎",
9
+ "f": "𝚏",
10
+ "g": "𝚐",
11
+ "h": "𝚑",
12
+ "i": "𝚒",
13
+ "j": "𝚓",
14
+ "k": "𝚔",
15
+ "l": "𝚕",
16
+ "m": "𝚖",
17
+ "n": "𝚗",
18
+ "o": "𝚘",
19
+ "p": "𝚙",
20
+ "q": "𝚚",
21
+ "r": "𝚛",
22
+ "s": "𝚜",
23
+ "t": "𝚝",
24
+ "u": "𝚞",
25
+ "v": "𝚟",
26
+ "w": "𝚠",
27
+ "x": "𝚡",
28
+ "y": "𝚢",
29
+ "z": "𝚣",
30
+ "A": "𝙰",
31
+ "B": "𝙱",
32
+ "C": "𝙲",
33
+ "D": "𝙳",
34
+ "E": "𝙴",
35
+ "F": "𝙵",
36
+ "G": "𝙶",
37
+ "H": "𝙷",
38
+ "I": "𝙸",
39
+ "J": "𝙹",
40
+ "K": "𝙺",
41
+ "L": "𝙻",
42
+ "M": "𝙼",
43
+ "N": "𝙽",
44
+ "O": "𝙾",
45
+ "P": "𝙿",
46
+ "Q": "𝚀",
47
+ "R": "𝚁",
48
+ "S": "𝚂",
49
+ "T": "𝚃",
50
+ "U": "𝚄",
51
+ "V": "𝚅",
52
+ "W": "𝚆",
53
+ "X": "𝚇",
54
+ "Y": "𝚈",
55
+ "Z": "𝚉",
56
+ }
57
+ for i, j in style.items():
58
+ text = text.replace(i, j)
59
+ return text
60
+
61
+ def outline(text):
62
+ style = {
63
+ "a": "𝕒",
64
+ "b": "𝕓",
65
+ "c": "𝕔",
66
+ "d": "𝕕",
67
+ "e": "𝕖",
68
+ "f": "𝕗",
69
+ "g": "𝕘",
70
+ "h": "𝕙",
71
+ "i": "𝕚",
72
+ "j": "𝕛",
73
+ "k": "𝕜",
74
+ "l": "𝕝",
75
+ "m": "𝕞",
76
+ "n": "𝕟",
77
+ "o": "𝕠",
78
+ "p": "𝕡",
79
+ "q": "𝕢",
80
+ "r": "𝕣",
81
+ "s": "𝕤",
82
+ "t": "𝕥",
83
+ "u": "𝕦",
84
+ "v": "𝕧",
85
+ "w": "𝕨",
86
+ "x": "𝕩",
87
+ "y": "𝕪",
88
+ "z": "𝕫",
89
+ "A": "𝔸",
90
+ "B": "𝔹",
91
+ "C": "ℂ",
92
+ "D": "𝔻",
93
+ "E": "𝔼",
94
+ "F": "𝔽",
95
+ "G": "𝔾",
96
+ "H": "ℍ",
97
+ "I": "𝕀",
98
+ "J": "𝕁",
99
+ "K": "𝕂",
100
+ "L": "𝕃",
101
+ "M": "𝕄",
102
+ "N": "ℕ",
103
+ "O": "𝕆",
104
+ "P": "ℙ",
105
+ "Q": "ℚ",
106
+ "R": "ℝ",
107
+ "S": "𝕊",
108
+ "T": "𝕋",
109
+ "U": "𝕌",
110
+ "V": "𝕍",
111
+ "W": "𝕎",
112
+ "X": "𝕏",
113
+ "Y": "𝕐",
114
+ "Z": "ℤ",
115
+ "0": "𝟘",
116
+ "1": "𝟙",
117
+ "2": "𝟚",
118
+ "3": "𝟛",
119
+ "4": "𝟜",
120
+ "5": "𝟝",
121
+ "6": "𝟞",
122
+ "7": "𝟟",
123
+ "8": "𝟠",
124
+ "9": "𝟡",
125
+ }
126
+ for i, j in style.items():
127
+ text = text.replace(i, j)
128
+ return text
129
+
130
+ def serief(text):
131
+ style = {
132
+ "a": "𝐚",
133
+ "b": "𝐛",
134
+ "c": "𝐜",
135
+ "d": "𝐝",
136
+ "e": "𝐞",
137
+ "f": "𝐟",
138
+ "g": "𝐠",
139
+ "h": "𝐡",
140
+ "i": "𝐢",
141
+ "j": "𝐣",
142
+ "k": "𝐤",
143
+ "l": "𝐥",
144
+ "m": "𝐦",
145
+ "n": "𝐧",
146
+ "o": "𝐨",
147
+ "p": "𝐩",
148
+ "q": "𝐪",
149
+ "r": "𝐫",
150
+ "s": "𝐬",
151
+ "t": "𝐭",
152
+ "u": "𝐮",
153
+ "v": "𝐯",
154
+ "w": "𝐰",
155
+ "x": "𝐱",
156
+ "y": "𝐲",
157
+ "z": "𝐳",
158
+ "A": "𝐀",
159
+ "B": "𝐁",
160
+ "C": "𝐂",
161
+ "D": "𝐃",
162
+ "E": "𝐄",
163
+ "F": "𝐅",
164
+ "G": "𝐆",
165
+ "H": "𝐇",
166
+ "I": "𝐈",
167
+ "J": "𝐉",
168
+ "K": "𝐊",
169
+ "L": "𝐋",
170
+ "M": "𝐌",
171
+ "N": "𝐍",
172
+ "O": "𝐎",
173
+ "P": "𝐏",
174
+ "Q": "𝐐",
175
+ "R": "𝐑",
176
+ "S": "𝐒",
177
+ "T": "𝐓",
178
+ "U": "𝐔",
179
+ "V": "𝐕",
180
+ "W": "𝐖",
181
+ "X": "𝐗",
182
+ "Y": "𝐘",
183
+ "Z": "𝐙",
184
+ "0": "𝟎",
185
+ "1": "𝟏",
186
+ "2": "𝟐",
187
+ "3": "𝟑",
188
+ "4": "𝟒",
189
+ "5": "𝟓",
190
+ "6": "𝟔",
191
+ "7": "𝟕",
192
+ "8": "𝟖",
193
+ "9": "𝟗",
194
+ }
195
+ for i, j in style.items():
196
+ text = text.replace(i, j)
197
+ return text
198
+
199
+ def bold_cool(text):
200
+ style = {
201
+ "a": "𝒂",
202
+ "b": "𝒃",
203
+ "c": "𝒄",
204
+ "d": "𝒅",
205
+ "e": "𝒆",
206
+ "f": "𝒇",
207
+ "g": "𝒈",
208
+ "h": "𝒉",
209
+ "i": "𝒊",
210
+ "j": "𝒋",
211
+ "k": "𝒌",
212
+ "l": "𝒍",
213
+ "m": "𝒎",
214
+ "n": "𝒏",
215
+ "o": "𝒐",
216
+ "p": "𝒑",
217
+ "q": "𝒒",
218
+ "r": "𝒓",
219
+ "s": "𝒔",
220
+ "t": "𝒕",
221
+ "u": "𝒖",
222
+ "v": "𝒗",
223
+ "w": "𝒘",
224
+ "x": "𝒙",
225
+ "y": "𝒚",
226
+ "z": "𝒛",
227
+ "A": "𝑨",
228
+ "B": "𝑩",
229
+ "C": "𝑪",
230
+ "D": "𝑫",
231
+ "E": "𝑬",
232
+ "F": "𝑭",
233
+ "G": "𝑮",
234
+ "H": "𝑯",
235
+ "I": "𝑰",
236
+ "J": "𝑱",
237
+ "K": "𝑲",
238
+ "L": "𝑳",
239
+ "M": "𝑴",
240
+ "N": "𝑵",
241
+ "O": "𝑶",
242
+ "P": "𝑷",
243
+ "Q": "𝑸",
244
+ "R": "𝑹",
245
+ "S": "𝑺",
246
+ "T": "𝑻",
247
+ "U": "𝑼",
248
+ "V": "𝑽",
249
+ "W": "𝑾",
250
+ "X": "𝑿",
251
+ "Y": "𝒀",
252
+ "Z": "𝒁",
253
+ }
254
+ for i, j in style.items():
255
+ text = text.replace(i, j)
256
+ return text
257
+
258
+ def cool(text):
259
+ style = {
260
+ "a": "𝑎",
261
+ "b": "𝑏",
262
+ "c": "𝑐",
263
+ "d": "𝑑",
264
+ "e": "𝑒",
265
+ "f": "𝑓",
266
+ "g": "𝑔",
267
+ "h": "ℎ",
268
+ "i": "𝑖",
269
+ "j": "𝑗",
270
+ "k": "𝑘",
271
+ "l": "𝑙",
272
+ "m": "𝑚",
273
+ "n": "𝑛",
274
+ "o": "𝑜",
275
+ "p": "𝑝",
276
+ "q": "𝑞",
277
+ "r": "𝑟",
278
+ "s": "𝑠",
279
+ "t": "𝑡",
280
+ "u": "𝑢",
281
+ "v": "𝑣",
282
+ "w": "𝑤",
283
+ "x": "𝑥",
284
+ "y": "𝑦",
285
+ "z": "𝑧",
286
+ "A": "𝐴",
287
+ "B": "𝐵",
288
+ "C": "𝐶",
289
+ "D": "𝐷",
290
+ "E": "𝐸",
291
+ "F": "𝐹",
292
+ "G": "𝐺",
293
+ "H": "𝐻",
294
+ "I": "𝐼",
295
+ "J": "𝐽",
296
+ "K": "𝐾",
297
+ "L": "𝐿",
298
+ "M": "𝑀",
299
+ "N": "𝑁",
300
+ "O": "𝑂",
301
+ "P": "𝑃",
302
+ "Q": "𝑄",
303
+ "R": "𝑅",
304
+ "S": "𝑆",
305
+ "T": "𝑇",
306
+ "U": "𝑈",
307
+ "V": "𝑉",
308
+ "W": "𝑊",
309
+ "X": "𝑋",
310
+ "Y": "𝑌",
311
+ "Z": "𝑍",
312
+ }
313
+ for i, j in style.items():
314
+ text = text.replace(i, j)
315
+ return text
316
+
317
+ def smallcap(text):
318
+ style = {
319
+ "a": "ᴀ",
320
+ "b": "ʙ",
321
+ "c": "ᴄ",
322
+ "d": "ᴅ",
323
+ "e": "ᴇ",
324
+ "f": "ғ",
325
+ "g": "ɢ",
326
+ "h": "ʜ",
327
+ "i": "ɪ",
328
+ "j": "J",
329
+ "k": "ᴋ",
330
+ "l": "ʟ",
331
+ "m": "ᴍ",
332
+ "n": "ɴ",
333
+ "o": "ᴏ",
334
+ "p": "ᴘ",
335
+ "q": "ǫ",
336
+ "r": "ʀ",
337
+ "s": "s",
338
+ "t": "ᴛ",
339
+ "u": "ᴜ",
340
+ "v": "ᴠ",
341
+ "w": "ᴡ",
342
+ "x": "x",
343
+ "y": "ʏ",
344
+ "z": "ᴢ",
345
+ "A": "A",
346
+ "B": "B",
347
+ "C": "C",
348
+ "D": "D",
349
+ "E": "E",
350
+ "F": "F",
351
+ "G": "G",
352
+ "H": "H",
353
+ "I": "I",
354
+ "J": "J",
355
+ "K": "K",
356
+ "L": "L",
357
+ "M": "M",
358
+ "N": "N",
359
+ "O": "O",
360
+ "P": "P",
361
+ "Q": "Q",
362
+ "R": "R",
363
+ "S": "S",
364
+ "T": "T",
365
+ "U": "U",
366
+ "V": "V",
367
+ "W": "W",
368
+ "X": "X",
369
+ "Y": "Y",
370
+ "Z": "Z",
371
+ "0": "𝟶",
372
+ "1": "𝟷",
373
+ "2": "𝟸",
374
+ "3": "𝟹",
375
+ "4": "𝟺",
376
+ "5": "𝟻",
377
+ "6": "𝟼",
378
+ "7": "𝟽",
379
+ "8": "𝟾",
380
+ "9": "𝟿",
381
+ }
382
+ for i, j in style.items():
383
+ text = text.replace(i, j)
384
+ return text
385
+
386
+ def script(text):
387
+ style = {
388
+ "a": "𝒶",
389
+ "b": "𝒷",
390
+ "c": "𝒸",
391
+ "d": "𝒹",
392
+ "e": "ℯ",
393
+ "f": "𝒻",
394
+ "g": "ℊ",
395
+ "h": "𝒽",
396
+ "i": "𝒾",
397
+ "j": "𝒿",
398
+ "k": "𝓀",
399
+ "l": "𝓁",
400
+ "m": "𝓂",
401
+ "n": "𝓃",
402
+ "o": "ℴ",
403
+ "p": "𝓅",
404
+ "q": "𝓆",
405
+ "r": "𝓇",
406
+ "s": "��",
407
+ "t": "𝓉",
408
+ "u": "𝓊",
409
+ "v": "𝓋",
410
+ "w": "𝓌",
411
+ "x": "𝓍",
412
+ "y": "𝓎",
413
+ "z": "𝓏",
414
+ "A": "𝒜",
415
+ "B": "ℬ",
416
+ "C": "𝒞",
417
+ "D": "𝒟",
418
+ "E": "ℰ",
419
+ "F": "ℱ",
420
+ "G": "𝒢",
421
+ "H": "ℋ",
422
+ "I": "ℐ",
423
+ "J": "𝒥",
424
+ "K": "𝒦",
425
+ "L": "ℒ",
426
+ "M": "ℳ",
427
+ "N": "𝒩",
428
+ "O": "𝒪",
429
+ "P": "𝒫",
430
+ "Q": "𝒬",
431
+ "R": "ℛ",
432
+ "S": "𝒮",
433
+ "T": "𝒯",
434
+ "U": "𝒰",
435
+ "V": "𝒱",
436
+ "W": "𝒲",
437
+ "X": "𝒳",
438
+ "Y": "𝒴",
439
+ "Z": "𝒵",
440
+ }
441
+ for i, j in style.items():
442
+ text = text.replace(i, j)
443
+ return text
444
+
445
+ def bold_script(text):
446
+ style = {
447
+ "a": "𝓪",
448
+ "b": "𝓫",
449
+ "c": "𝓬",
450
+ "d": "𝓭",
451
+ "e": "𝓮",
452
+ "f": "𝓯",
453
+ "g": "𝓰",
454
+ "h": "𝓱",
455
+ "i": "𝓲",
456
+ "j": "𝓳",
457
+ "k": "𝓴",
458
+ "l": "𝓵",
459
+ "m": "𝓶",
460
+ "n": "𝓷",
461
+ "o": "𝓸",
462
+ "p": "𝓹",
463
+ "q": "𝓺",
464
+ "r": "𝓻",
465
+ "s": "𝓼",
466
+ "t": "𝓽",
467
+ "u": "𝓾",
468
+ "v": "𝓿",
469
+ "w": "𝔀",
470
+ "x": "𝔁",
471
+ "y": "𝔂",
472
+ "z": "𝔃",
473
+ "A": "𝓐",
474
+ "B": "𝓑",
475
+ "C": "𝓒",
476
+ "D": "𝓓",
477
+ "E": "𝓔",
478
+ "F": "𝓕",
479
+ "G": "𝓖",
480
+ "H": "𝓗",
481
+ "I": "𝓘",
482
+ "J": "𝓙",
483
+ "K": "𝓚",
484
+ "L": "𝓛",
485
+ "M": "𝓜",
486
+ "N": "𝓝",
487
+ "O": "𝓞",
488
+ "P": "𝓟",
489
+ "Q": "𝓠",
490
+ "R": "𝓡",
491
+ "S": "𝓢",
492
+ "T": "𝓣",
493
+ "U": "𝓤",
494
+ "V": "𝓥",
495
+ "W": "𝓦",
496
+ "X": "𝓧",
497
+ "Y": "𝓨",
498
+ "Z": "𝓩",
499
+ }
500
+ for i, j in style.items():
501
+ text = text.replace(i, j)
502
+ return text
503
+
504
+ def tiny(text):
505
+ style = {
506
+ "a": "ᵃ",
507
+ "b": "ᵇ",
508
+ "c": "ᶜ",
509
+ "d": "ᵈ",
510
+ "e": "ᵉ",
511
+ "f": "ᶠ",
512
+ "g": "ᵍ",
513
+ "h": "ʰ",
514
+ "i": "ⁱ",
515
+ "j": "ʲ",
516
+ "k": "ᵏ",
517
+ "l": "ˡ",
518
+ "m": "ᵐ",
519
+ "n": "ⁿ",
520
+ "o": "ᵒ",
521
+ "p": "ᵖ",
522
+ "q": "ᵠ",
523
+ "r": "ʳ",
524
+ "s": "ˢ",
525
+ "t": "ᵗ",
526
+ "u": "ᵘ",
527
+ "v": "ᵛ",
528
+ "w": "ʷ",
529
+ "x": "ˣ",
530
+ "y": "ʸ",
531
+ "z": "ᶻ",
532
+ "A": "ᵃ",
533
+ "B": "ᵇ",
534
+ "C": "ᶜ",
535
+ "D": "ᵈ",
536
+ "E": "ᵉ",
537
+ "F": "ᶠ",
538
+ "G": "ᵍ",
539
+ "H": "ʰ",
540
+ "I": "ⁱ",
541
+ "J": "ʲ",
542
+ "K": "ᵏ",
543
+ "L": "ˡ",
544
+ "M": "ᵐ",
545
+ "N": "ⁿ",
546
+ "O": "ᵒ",
547
+ "P": "ᵖ",
548
+ "Q": "ᵠ",
549
+ "R": "ʳ",
550
+ "S": "ˢ",
551
+ "T": "ᵗ",
552
+ "U": "ᵘ",
553
+ "V": "ᵛ",
554
+ "W": "ʷ",
555
+ "X": "ˣ",
556
+ "Y": "ʸ",
557
+ "Z": "ᶻ",
558
+ }
559
+ for i, j in style.items():
560
+ text = text.replace(i, j)
561
+ return text
562
+
563
+ def comic(text):
564
+ style = {
565
+ "a": "ᗩ",
566
+ "b": "ᗷ",
567
+ "c": "ᑕ",
568
+ "d": "ᗪ",
569
+ "e": "ᗴ",
570
+ "f": "ᖴ",
571
+ "g": "ᘜ",
572
+ "h": "ᕼ",
573
+ "i": "I",
574
+ "j": "ᒍ",
575
+ "k": "K",
576
+ "l": "ᒪ",
577
+ "m": "ᗰ",
578
+ "n": "ᑎ",
579
+ "o": "O",
580
+ "p": "ᑭ",
581
+ "q": "ᑫ",
582
+ "r": "ᖇ",
583
+ "s": "Տ",
584
+ "t": "T",
585
+ "u": "ᑌ",
586
+ "v": "ᐯ",
587
+ "w": "ᗯ",
588
+ "x": "᙭",
589
+ "y": "Y",
590
+ "z": "ᘔ",
591
+ "A": "ᗩ",
592
+ "B": "ᗷ",
593
+ "C": "ᑕ",
594
+ "D": "ᗪ",
595
+ "E": "ᗴ",
596
+ "F": "ᖴ",
597
+ "G": "ᘜ",
598
+ "H": "ᕼ",
599
+ "I": "I",
600
+ "J": "ᒍ",
601
+ "K": "K",
602
+ "L": "ᒪ",
603
+ "M": "ᗰ",
604
+ "N": "ᑎ",
605
+ "O": "O",
606
+ "P": "ᑭ",
607
+ "Q": "ᑫ",
608
+ "R": "ᖇ",
609
+ "S": "Տ",
610
+ "T": "T",
611
+ "U": "ᑌ",
612
+ "V": "���",
613
+ "W": "ᗯ",
614
+ "X": "᙭",
615
+ "Y": "Y",
616
+ "Z": "ᘔ",
617
+ }
618
+ for i, j in style.items():
619
+ text = text.replace(i, j)
620
+ return text
621
+
622
+ def san(text):
623
+ style = {
624
+ "a": "𝗮",
625
+ "b": "𝗯",
626
+ "c": "𝗰",
627
+ "d": "𝗱",
628
+ "e": "𝗲",
629
+ "f": "𝗳",
630
+ "g": "𝗴",
631
+ "h": "𝗵",
632
+ "i": "𝗶",
633
+ "j": "𝗷",
634
+ "k": "𝗸",
635
+ "l": "𝗹",
636
+ "m": "𝗺",
637
+ "n": "𝗻",
638
+ "o": "𝗼",
639
+ "p": "𝗽",
640
+ "q": "𝗾",
641
+ "r": "𝗿",
642
+ "s": "𝘀",
643
+ "t": "𝘁",
644
+ "u": "𝘂",
645
+ "v": "𝘃",
646
+ "w": "𝘄",
647
+ "x": "𝘅",
648
+ "y": "𝘆",
649
+ "z": "𝘇",
650
+ "A": "𝗔",
651
+ "B": "𝗕",
652
+ "C": "𝗖",
653
+ "D": "𝗗",
654
+ "E": "𝗘",
655
+ "F": "𝗙",
656
+ "G": "𝗚",
657
+ "H": "𝗛",
658
+ "I": "𝗜",
659
+ "J": "𝗝",
660
+ "K": "𝗞",
661
+ "L": "𝗟",
662
+ "M": "𝗠",
663
+ "N": "𝗡",
664
+ "O": "𝗢",
665
+ "P": "𝗣",
666
+ "Q": "𝗤",
667
+ "R": "𝗥",
668
+ "S": "𝗦",
669
+ "T": "𝗧",
670
+ "U": "𝗨",
671
+ "V": "𝗩",
672
+ "W": "𝗪",
673
+ "X": "𝗫",
674
+ "Y": "𝗬",
675
+ "Z": "𝗭",
676
+ "0": "𝟬",
677
+ "1": "𝟭",
678
+ "2": "𝟮",
679
+ "3": "𝟯",
680
+ "4": "𝟰",
681
+ "5": "𝟱",
682
+ "6": "𝟲",
683
+ "7": "𝟳",
684
+ "8": "𝟴",
685
+ "9": "𝟵",
686
+ }
687
+ for i, j in style.items():
688
+ text = text.replace(i, j)
689
+ return text
690
+
691
+ def slant_san(text):
692
+ style = {
693
+ "a": "𝙖",
694
+ "b": "𝙗",
695
+ "c": "𝙘",
696
+ "d": "𝙙",
697
+ "e": "𝙚",
698
+ "f": "𝙛",
699
+ "g": "𝙜",
700
+ "h": "𝙝",
701
+ "i": "𝙞",
702
+ "j": "𝙟",
703
+ "k": "𝙠",
704
+ "l": "𝙡",
705
+ "m": "𝙢",
706
+ "n": "𝙣",
707
+ "o": "𝙤",
708
+ "p": "𝙥",
709
+ "q": "𝙦",
710
+ "r": "𝙧",
711
+ "s": "𝙨",
712
+ "t": "𝙩",
713
+ "u": "𝙪",
714
+ "v": "𝙫",
715
+ "w": "𝙬",
716
+ "x": "𝙭",
717
+ "y": "𝙮",
718
+ "z": "𝙯",
719
+ "A": "𝘼",
720
+ "B": "𝘽",
721
+ "C": "𝘾",
722
+ "D": "𝘿",
723
+ "E": "𝙀",
724
+ "F": "𝙁",
725
+ "G": "𝙂",
726
+ "H": "𝙃",
727
+ "I": "𝙄",
728
+ "J": "𝙅",
729
+ "K": "𝙆",
730
+ "L": "𝙇",
731
+ "M": "𝙈",
732
+ "N": "𝙉",
733
+ "O": "𝙊",
734
+ "P": "𝙋",
735
+ "Q": "𝙌",
736
+ "R": "𝙍",
737
+ "S": "𝙎",
738
+ "T": "𝙏",
739
+ "U": "𝙐",
740
+ "V": "𝙑",
741
+ "W": "𝙒",
742
+ "X": "𝙓",
743
+ "Y": "𝙔",
744
+ "Z": "𝙕",
745
+ }
746
+ for i, j in style.items():
747
+ text = text.replace(i, j)
748
+ return text
749
+
750
+ def slant(text):
751
+ style = {
752
+ "a": "𝘢",
753
+ "b": "𝘣",
754
+ "c": "𝘤",
755
+ "d": "𝘥",
756
+ "e": "𝘦",
757
+ "f": "𝘧",
758
+ "g": "𝘨",
759
+ "h": "𝘩",
760
+ "i": "𝘪",
761
+ "j": "𝘫",
762
+ "k": "𝘬",
763
+ "l": "𝘭",
764
+ "m": "𝘮",
765
+ "n": "𝘯",
766
+ "o": "𝘰",
767
+ "p": "𝘱",
768
+ "q": "𝘲",
769
+ "r": "𝘳",
770
+ "s": "𝘴",
771
+ "t": "𝘵",
772
+ "u": "𝘶",
773
+ "v": "𝘷",
774
+ "w": "𝘸",
775
+ "x": "𝘹",
776
+ "y": "𝘺",
777
+ "z": "𝘻",
778
+ "A": "𝘈",
779
+ "B": "𝘉",
780
+ "C": "𝘊",
781
+ "D": "𝘋",
782
+ "E": "𝘌",
783
+ "F": "𝘍",
784
+ "G": "𝘎",
785
+ "H": "𝘏",
786
+ "I": "𝘐",
787
+ "J": "𝘑",
788
+ "K": "𝘒",
789
+ "L": "𝘓",
790
+ "M": "𝘔",
791
+ "N": "𝘕",
792
+ "O": "𝘖",
793
+ "P": "𝘗",
794
+ "Q": "𝘘",
795
+ "R": "𝘙",
796
+ "S": "𝘚",
797
+ "T": "𝘛",
798
+ "U": "𝘜",
799
+ "V": "𝘝",
800
+ "W": "𝘞",
801
+ "X": "𝘟",
802
+ "Y": "𝘠",
803
+ "Z": "𝘡",
804
+ }
805
+ for i, j in style.items():
806
+ text = text.replace(i, j)
807
+ return text
808
+
809
+ def sim(text):
810
+ style = {
811
+ "a": "𝖺",
812
+ "b": "𝖻",
813
+ "c": "𝖼",
814
+ "d": "𝖽",
815
+ "e": "𝖾",
816
+ "f": "𝖿",
817
+ "g": "𝗀",
818
+ "h": "𝗁",
819
+ "i": "𝗂",
820
+ "j": "𝗃",
821
+ "k": "𝗄",
822
+ "l": "𝗅",
823
+ "m": "𝗆",
824
+ "n": "𝗇",
825
+ "o": "𝗈",
826
+ "p": "𝗉",
827
+ "q": "𝗊",
828
+ "r": "𝗋",
829
+ "s": "𝗌",
830
+ "t": "𝗍",
831
+ "u": "𝗎",
832
+ "v": "𝗏",
833
+ "w": "𝗐",
834
+ "x": "𝗑",
835
+ "y": "𝗒",
836
+ "z": "𝗓",
837
+ "A": "𝖠",
838
+ "B": "𝖡",
839
+ "C": "𝖢",
840
+ "D": "𝖣",
841
+ "E": "𝖤",
842
+ "F": "𝖥",
843
+ "G": "𝖦",
844
+ "H": "𝖧",
845
+ "I": "𝖨",
846
+ "J": "𝖩",
847
+ "K": "𝖪",
848
+ "L": "𝖫",
849
+ "M": "𝖬",
850
+ "N": "𝖭",
851
+ "O": "𝖮",
852
+ "P": "𝖯",
853
+ "Q": "𝖰",
854
+ "R": "𝖱",
855
+ "S": "𝖲",
856
+ "T": "𝖳",
857
+ "U": "𝖴",
858
+ "V": "𝖵",
859
+ "W": "𝖶",
860
+ "X": "𝖷",
861
+ "Y": "𝖸",
862
+ "Z": "𝖹",
863
+ }
864
+ for i, j in style.items():
865
+ text = text.replace(i, j)
866
+ return text
867
+
868
+ def circles(text):
869
+ style = {
870
+ "a": "Ⓐ︎",
871
+ "b": "Ⓑ︎",
872
+ "c": "Ⓒ︎",
873
+ "d": "Ⓓ︎",
874
+ "e": "Ⓔ︎",
875
+ "f": "Ⓕ︎",
876
+ "g": "Ⓖ︎",
877
+ "h": "Ⓗ︎",
878
+ "i": "Ⓘ︎",
879
+ "j": "Ⓙ︎",
880
+ "k": "Ⓚ︎",
881
+ "l": "Ⓛ︎",
882
+ "m": "Ⓜ︎",
883
+ "n": "Ⓝ︎",
884
+ "o": "Ⓞ︎",
885
+ "p": "Ⓟ︎",
886
+ "q": "Ⓠ︎",
887
+ "r": "Ⓡ︎",
888
+ "s": "Ⓢ︎",
889
+ "t": "Ⓣ︎",
890
+ "u": "Ⓤ︎",
891
+ "v": "Ⓥ︎",
892
+ "w": "Ⓦ︎",
893
+ "x": "Ⓧ︎",
894
+ "y": "Ⓨ︎",
895
+ "z": "Ⓩ︎",
896
+ "A": "Ⓐ︎",
897
+ "B": "Ⓑ︎",
898
+ "C": "Ⓒ︎",
899
+ "D": "Ⓓ︎",
900
+ "E": "Ⓔ︎",
901
+ "F": "Ⓕ︎",
902
+ "G": "Ⓖ︎",
903
+ "H": "Ⓗ︎",
904
+ "I": "Ⓘ︎",
905
+ "J": "Ⓙ︎",
906
+ "K": "Ⓚ︎",
907
+ "L": "Ⓛ︎",
908
+ "M": "Ⓜ︎",
909
+ "N": "Ⓝ︎",
910
+ "O": "Ⓞ︎",
911
+ "P": "Ⓟ︎",
912
+ "Q": "Ⓠ︎",
913
+ "R": "Ⓡ︎",
914
+ "S": "Ⓢ︎",
915
+ "T": "Ⓣ︎",
916
+ "U": "Ⓤ︎",
917
+ "V": "Ⓥ︎",
918
+ "W": "Ⓦ︎",
919
+ "X": "Ⓧ︎",
920
+ "Y": "Ⓨ︎",
921
+ "Z": "Ⓩ︎",
922
+ "0": "⓪",
923
+ "1": "①",
924
+ "2": "②",
925
+ "3": "③",
926
+ "4": "④",
927
+ "5": "⑤",
928
+ "6": "⑥",
929
+ "7": "⑦",
930
+ "8": "⑧",
931
+ "9": "⑨",
932
+ }
933
+ for i, j in style.items():
934
+ text = text.replace(i, j)
935
+ return text
936
+
937
+ def dark_circle(text):
938
+ style = {
939
+ "a": "🅐︎",
940
+ "b": "🅑︎",
941
+ "c": "🅒︎",
942
+ "d": "🅓︎",
943
+ "e": "🅔︎",
944
+ "f": "🅕︎",
945
+ "g": "🅖︎",
946
+ "h": "🅗︎",
947
+ "i": "🅘︎",
948
+ "j": "🅙︎",
949
+ "k": "🅚︎",
950
+ "l": "🅛︎",
951
+ "m": "🅜︎",
952
+ "n": "🅝︎",
953
+ "o": "🅞︎",
954
+ "p": "🅟︎",
955
+ "q": "🅠︎",
956
+ "r": "🅡︎",
957
+ "s": "🅢︎",
958
+ "t": "🅣︎",
959
+ "u": "🅤︎",
960
+ "v": "🅥︎",
961
+ "w": "🅦︎",
962
+ "x": "🅧︎",
963
+ "y": "🅨︎",
964
+ "z": "🅩︎",
965
+ "A": "🅐︎",
966
+ "B": "🅑︎",
967
+ "C": "🅒︎",
968
+ "D": "🅓︎",
969
+ "E": "🅔︎",
970
+ "F": "🅕︎",
971
+ "G": "🅖︎",
972
+ "H": "🅗︎",
973
+ "I": "🅘︎",
974
+ "J": "🅙︎",
975
+ "K": "🅚︎",
976
+ "L": "🅛︎",
977
+ "M": "🅜︎",
978
+ "N": "🅝︎",
979
+ "O": "🅞︎",
980
+ "P": "🅟︎",
981
+ "Q": "🅠︎",
982
+ "R": "🅡︎",
983
+ "S": "🅢︎",
984
+ "T": "🅣︎",
985
+ "U": "🅤︎",
986
+ "V": "🅥︎",
987
+ "W": "🅦︎",
988
+ "X": "🅧︎",
989
+ "Y": "🅨︎",
990
+ "Z": "🅩",
991
+ "0": "⓿",
992
+ "1": "➊",
993
+ "2": "➋",
994
+ "3": "➌",
995
+ "4": "➍",
996
+ "5": "➎",
997
+ "6": "➏",
998
+ "7": "➐",
999
+ "8": "➑",
1000
+ "9": "➒",
1001
+ }
1002
+ for i, j in style.items():
1003
+ text = text.replace(i, j)
1004
+ return text
1005
+
1006
+ def gothic(text):
1007
+ style = {
1008
+ "a": "𝔞",
1009
+ "b": "𝔟",
1010
+ "c": "𝔠",
1011
+ "d": "𝔡",
1012
+ "e": "𝔢",
1013
+ "f": "𝔣",
1014
+ "g": "𝔤",
1015
+ "h": "𝔥",
1016
+ "i": "𝔦",
1017
+ "j": "𝔧",
1018
+ "k": "𝔨",
1019
+ "l": "𝔩",
1020
+ "m": "𝔪",
1021
+ "n": "𝔫",
1022
+ "o": "𝔬",
1023
+ "p": "𝔭",
1024
+ "q": "𝔮",
1025
+ "r": "𝔯",
1026
+ "s": "𝔰",
1027
+ "t": "𝔱",
1028
+ "u": "𝔲",
1029
+ "v": "𝔳",
1030
+ "w": "𝔴",
1031
+ "x": "𝔵",
1032
+ "y": "𝔶",
1033
+ "z": "𝔷",
1034
+ "A": "𝔄",
1035
+ "B": "𝔅",
1036
+ "C": "ℭ",
1037
+ "D": "𝔇",
1038
+ "E": "𝔈",
1039
+ "F": "𝔉",
1040
+ "G": "𝔊",
1041
+ "H": "ℌ",
1042
+ "I": "ℑ",
1043
+ "J": "𝔍",
1044
+ "K": "𝔎",
1045
+ "L": "𝔏",
1046
+ "M": "𝔐",
1047
+ "N": "𝔑",
1048
+ "O": "𝔒",
1049
+ "P": "𝔓",
1050
+ "Q": "𝔔",
1051
+ "R": "ℜ",
1052
+ "S": "𝔖",
1053
+ "T": "𝔗",
1054
+ "U": "𝔘",
1055
+ "V": "𝔙",
1056
+ "W": "𝔚",
1057
+ "X": "𝔛",
1058
+ "Y": "𝔜",
1059
+ "Z": "ℨ",
1060
+ }
1061
+ for i, j in style.items():
1062
+ text = text.replace(i, j)
1063
+ return text
1064
+
1065
+ def bold_gothic(text):
1066
+ style = {
1067
+ "a": "𝖆",
1068
+ "b": "𝖇",
1069
+ "c": "𝖈",
1070
+ "d": "𝖉",
1071
+ "e": "𝖊",
1072
+ "f": "𝖋",
1073
+ "g": "𝖌",
1074
+ "h": "𝖍",
1075
+ "i": "𝖎",
1076
+ "j": "𝖏",
1077
+ "k": "𝖐",
1078
+ "l": "𝖑",
1079
+ "m": "𝖒",
1080
+ "n": "𝖓",
1081
+ "o": "𝖔",
1082
+ "p": "𝖕",
1083
+ "q": "𝖖",
1084
+ "r": "𝖗",
1085
+ "s": "𝖘",
1086
+ "t": "𝖙",
1087
+ "u": "𝖚",
1088
+ "v": "𝖛",
1089
+ "w": "𝖜",
1090
+ "x": "𝖝",
1091
+ "y": "𝖞",
1092
+ "z": "𝖟",
1093
+ "A": "𝕬",
1094
+ "B": "𝕭",
1095
+ "C": "𝕮",
1096
+ "D": "𝕺",
1097
+ "E": "𝕰",
1098
+ "F": "𝕱",
1099
+ "G": "𝕲",
1100
+ "H": "𝕳",
1101
+ "I": "𝕴",
1102
+ "J": "𝕵",
1103
+ "K": "𝕶",
1104
+ "L": "𝕷",
1105
+ "M": "𝕸",
1106
+ "N": "𝕹",
1107
+ "O": "𝕺",
1108
+ "P": "𝕻",
1109
+ "Q": "𝕼",
1110
+ "R": "𝕽",
1111
+ "S": "𝕾",
1112
+ "T": "𝕿",
1113
+ "U": "𝖀",
1114
+ "V": "𝖁",
1115
+ "W": "𝖂",
1116
+ "X": "𝖃",
1117
+ "Y": "𝖄",
1118
+ "Z": "𝖅",
1119
+ }
1120
+ for i, j in style.items():
1121
+ text = text.replace(i, j)
1122
+ return text
1123
+
1124
+ def cloud(text):
1125
+ style = {
1126
+ "a": "a͜͡",
1127
+ "b": "b͜͡",
1128
+ "c": "c͜͡",
1129
+ "d": "d͜͡",
1130
+ "e": "e͜͡",
1131
+ "f": "f͜͡",
1132
+ "g": "g͜͡",
1133
+ "h": "h͜͡",
1134
+ "i": "i͜͡",
1135
+ "j": "j͜͡",
1136
+ "k": "k͜͡",
1137
+ "l": "l͜͡",
1138
+ "m": "m͜͡",
1139
+ "n": "n͜͡",
1140
+ "o": "o͜͡",
1141
+ "p": "p͜͡",
1142
+ "q": "q͜͡",
1143
+ "r": "r͜͡",
1144
+ "s": "s͜͡",
1145
+ "t": "t͜͡",
1146
+ "u": "u͜͡",
1147
+ "v": "v͜͡",
1148
+ "w": "w͜͡",
1149
+ "x": "x͜͡",
1150
+ "y": "y͜͡",
1151
+ "z": "z͜͡",
1152
+ "A": "A͜͡",
1153
+ "B": "B͜͡",
1154
+ "C": "C͜͡",
1155
+ "D": "D͜͡",
1156
+ "E": "E͜͡",
1157
+ "F": "F͜͡",
1158
+ "G": "G͜͡",
1159
+ "H": "H͜͡",
1160
+ "I": "I͜͡",
1161
+ "J": "J͜͡",
1162
+ "K": "K͜͡",
1163
+ "L": "L͜͡",
1164
+ "M": "M͜͡",
1165
+ "N": "N͜͡",
1166
+ "O": "O͜͡",
1167
+ "P": "P͜͡",
1168
+ "Q": "Q͜͡",
1169
+ "R": "R͜͡",
1170
+ "S": "S͜͡",
1171
+ "T": "T͜͡",
1172
+ "U": "U͜͡",
1173
+ "V": "V͜͡",
1174
+ "W": "W͜͡",
1175
+ "X": "X͜͡",
1176
+ "Y": "Y͜͡",
1177
+ "Z": "Z͜͡",
1178
+ }
1179
+ for i, j in style.items():
1180
+ text = text.replace(i, j)
1181
+ return text
1182
+
1183
+ def happy(text):
1184
+ style = {
1185
+ "a": "ă̈",
1186
+ "b": "b̆̈",
1187
+ "c": "c̆̈",
1188
+ "d": "d̆̈",
1189
+ "e": "ĕ̈",
1190
+ "f": "f̆̈",
1191
+ "g": "ğ̈",
1192
+ "h": "h̆̈",
1193
+ "i": "ĭ̈",
1194
+ "j": "j̆̈",
1195
+ "k": "k̆̈",
1196
+ "l": "l̆̈",
1197
+ "m": "m̆̈",
1198
+ "n": "n̆̈",
1199
+ "o": "ŏ̈",
1200
+ "p": "p̆̈",
1201
+ "q": "q̆̈",
1202
+ "r": "r̆̈",
1203
+ "s": "s̆̈",
1204
+ "t": "t̆̈",
1205
+ "u": "ŭ̈",
1206
+ "v": "v̆̈",
1207
+ "w": "w̆̈",
1208
+ "x": "x̆̈",
1209
+ "y": "y̆̈",
1210
+ "z": "z̆̈",
1211
+ "A": "Ă̈",
1212
+ "B": "B̆̈",
1213
+ "C": "C̆̈",
1214
+ "D": "D̆̈",
1215
+ "E": "Ĕ̈",
1216
+ "F": "F̆̈",
1217
+ "G": "Ğ̈",
1218
+ "H": "H̆̈",
1219
+ "I": "Ĭ̈",
1220
+ "J": "J̆̈",
1221
+ "K": "K̆̈",
1222
+ "L": "L̆̈",
1223
+ "M": "M̆̈",
1224
+ "N": "N̆̈",
1225
+ "O": "Ŏ̈",
1226
+ "P": "P̆̈",
1227
+ "Q": "Q̆̈",
1228
+ "R": "R̆̈",
1229
+ "S": "S̆̈",
1230
+ "T": "T̆̈",
1231
+ "U": "Ŭ̈",
1232
+ "V": "V̆̈",
1233
+ "W": "W̆̈",
1234
+ "X": "X̆̈",
1235
+ "Y": "Y̆̈",
1236
+ "Z": "Z̆̈",
1237
+ }
1238
+ for i, j in style.items():
1239
+ text = text.replace(i, j)
1240
+ return text
1241
+
1242
+ def sad(text):
1243
+ style = {
1244
+ "a": "ȃ̈",
1245
+ "b": "b̑̈",
1246
+ "c": "c̑̈",
1247
+ "d": "d̑̈",
1248
+ "e": "ȇ̈",
1249
+ "f": "f̑̈",
1250
+ "g": "g̑̈",
1251
+ "h": "h̑̈",
1252
+ "i": "ȋ̈",
1253
+ "j": "j̑̈",
1254
+ "k": "k̑̈",
1255
+ "l": "l̑̈",
1256
+ "m": "m̑̈",
1257
+ "n": "n̑̈",
1258
+ "o": "ȏ̈",
1259
+ "p": "p̑̈",
1260
+ "q": "q̑̈",
1261
+ "r": "ȓ̈",
1262
+ "s": "s̑̈",
1263
+ "t": "t̑̈",
1264
+ "u": "ȗ̈",
1265
+ "v": "v̑̈",
1266
+ "w": "w̑̈",
1267
+ "x": "x̑̈",
1268
+ "y": "y̑̈",
1269
+ "z": "z̑̈",
1270
+ "A": "Ȃ̈",
1271
+ "B": "B̑̈",
1272
+ "C": "C̑̈",
1273
+ "D": "D̑̈",
1274
+ "E": "Ȇ̈",
1275
+ "F": "F̑̈",
1276
+ "G": "G̑̈",
1277
+ "H": "H̑̈",
1278
+ "I": "Ȋ̈",
1279
+ "J": "J̑̈",
1280
+ "K": "K̑̈",
1281
+ "L": "L̑̈",
1282
+ "M": "M̑̈",
1283
+ "N": "N̑̈",
1284
+ "O": "Ȏ̈",
1285
+ "P": "P̑̈",
1286
+ "Q": "Q̑̈",
1287
+ "R": "Ȓ̈",
1288
+ "S": "S̑̈",
1289
+ "T": "T̑̈",
1290
+ "U": "Ȗ̈",
1291
+ "V": "V̑̈",
1292
+ "W": "W̑̈",
1293
+ "X": "X̑̈",
1294
+ "Y": "Y̑̈",
1295
+ "Z": "Z̑̈",
1296
+ }
1297
+ for i, j in style.items():
1298
+ text = text.replace(i, j)
1299
+ return text
1300
+
1301
+ def special(text):
1302
+ style = {
1303
+ "a": "🇦 ",
1304
+ "b": "🇧 ",
1305
+ "c": "🇨 ",
1306
+ "d": "🇩 ",
1307
+ "e": "🇪 ",
1308
+ "f": "🇫 ",
1309
+ "g": "🇬 ",
1310
+ "h": "🇭 ",
1311
+ "i": "🇮 ",
1312
+ "j": "🇯 ",
1313
+ "k": "🇰 ",
1314
+ "l": "🇱 ",
1315
+ "m": "🇲 ",
1316
+ "n": "🇳 ",
1317
+ "o": "🇴 ",
1318
+ "p": "🇵 ",
1319
+ "q": "🇶 ",
1320
+ "r": "🇷 ",
1321
+ "s": "🇸 ",
1322
+ "t": "🇹 ",
1323
+ "u": "🇺 ",
1324
+ "v": "🇻 ",
1325
+ "w": "🇼 ",
1326
+ "x": "🇽 ",
1327
+ "y": "🇾 ",
1328
+ "z": "🇿 ",
1329
+ "A": "🇦 ",
1330
+ "B": "🇧 ",
1331
+ "C": "🇨 ",
1332
+ "D": "🇩 ",
1333
+ "E": "🇪 ",
1334
+ "F": "🇫 ",
1335
+ "G": "🇬 ",
1336
+ "H": "🇭 ",
1337
+ "I": "🇮 ",
1338
+ "J": "🇯 ",
1339
+ "K": "🇰 ",
1340
+ "L": "🇱 ",
1341
+ "M": "🇲 ",
1342
+ "N": "🇳 ",
1343
+ "O": "🇴 ",
1344
+ "P": "🇵 ",
1345
+ "Q": "🇶 ",
1346
+ "R": "🇷 ",
1347
+ "S": "🇸 ",
1348
+ "T": "🇹 ",
1349
+ "U": "🇺 ",
1350
+ "V": "🇻 ",
1351
+ "W": "🇼 ",
1352
+ "X": "🇽 ",
1353
+ "Y": "🇾 ",
1354
+ "Z": "🇿 ",
1355
+ }
1356
+ for i, j in style.items():
1357
+ text = text.replace(i, j)
1358
+ return text
1359
+
1360
+ def square(text):
1361
+ style = {
1362
+ "a": "🄰",
1363
+ "b": "🄱",
1364
+ "c": "🄲",
1365
+ "d": "🄳",
1366
+ "e": "🄴",
1367
+ "f": "🄵",
1368
+ "g": "🄶",
1369
+ "h": "🄷",
1370
+ "i": "🄸",
1371
+ "j": "🄹",
1372
+ "k": "🄺",
1373
+ "l": "🄻",
1374
+ "m": "🄼",
1375
+ "n": "🄽",
1376
+ "o": "🄾",
1377
+ "p": "🄿",
1378
+ "q": "🅀",
1379
+ "r": "🅁",
1380
+ "s": "🅂",
1381
+ "t": "🅃",
1382
+ "u": "🅄",
1383
+ "v": "🅅",
1384
+ "w": "🅆",
1385
+ "x": "🅇",
1386
+ "y": "🅈",
1387
+ "z": "🅉",
1388
+ "A": "🄰",
1389
+ "B": "🄱",
1390
+ "C": "🄲",
1391
+ "D": "🄳",
1392
+ "E": "🄴",
1393
+ "F": "🄵",
1394
+ "G": "🄶",
1395
+ "H": "🄷",
1396
+ "I": "🄸",
1397
+ "J": "🄹",
1398
+ "K": "🄺",
1399
+ "L": "🄻",
1400
+ "M": "🄼",
1401
+ "N": "🄽",
1402
+ "O": "🄾",
1403
+ "P": "🄿",
1404
+ "Q": "🅀",
1405
+ "R": "🅁",
1406
+ "S": "🅂",
1407
+ "T": "🅃",
1408
+ "U": "🅄",
1409
+ "V": "🅅",
1410
+ "W": "🅆",
1411
+ "X": "🅇",
1412
+ "Y": "🅈",
1413
+ "Z": "🅉",
1414
+ }
1415
+ for i, j in style.items():
1416
+ text = text.replace(i, j)
1417
+ return text
1418
+
1419
+ def dark_square(text):
1420
+ style = {
1421
+ "a": "🅰︎",
1422
+ "b": "🅱︎",
1423
+ "c": "🅲︎",
1424
+ "d": "🅳︎",
1425
+ "e": "🅴︎",
1426
+ "f": "🅵︎",
1427
+ "g": "🅶︎",
1428
+ "h": "🅷︎",
1429
+ "i": "🅸︎",
1430
+ "j": "🅹︎",
1431
+ "k": "🅺︎",
1432
+ "l": "🅻︎",
1433
+ "m": "🅼︎",
1434
+ "n": "🅽︎",
1435
+ "o": "🅾︎",
1436
+ "p": "🅿︎",
1437
+ "q": "🆀︎",
1438
+ "r": "🆁︎",
1439
+ "s": "🆂︎",
1440
+ "t": "🆃︎",
1441
+ "u": "🆄︎",
1442
+ "v": "🆅︎",
1443
+ "w": "🆆︎",
1444
+ "x": "🆇︎",
1445
+ "y": "🆈︎",
1446
+ "z": "🆉︎",
1447
+ "A": "🅰︎",
1448
+ "B": "🅱︎",
1449
+ "C": "🅲︎",
1450
+ "D": "🅳︎",
1451
+ "E": "🅴︎",
1452
+ "F": "🅵︎",
1453
+ "G": "🅶︎",
1454
+ "H": "🅷︎",
1455
+ "I": "🅸︎",
1456
+ "J": "🅹︎",
1457
+ "K": "🅺︎",
1458
+ "L": "🅻︎",
1459
+ "M": "🅼︎",
1460
+ "N": "🅽︎",
1461
+ "O": "🅾︎",
1462
+ "P": "🅿︎",
1463
+ "Q": "🆀︎",
1464
+ "R": "🆁︎",
1465
+ "S": "🆂︎",
1466
+ "T": "🆃︎",
1467
+ "U": "🆄︎",
1468
+ "V": "🆅︎",
1469
+ "W": "🆆︎",
1470
+ "X": "🆇︎",
1471
+ "Y": "🆈︎",
1472
+ "Z": "🆉︎",
1473
+ }
1474
+ for i, j in style.items():
1475
+ text = text.replace(i, j)
1476
+ return text
1477
+
1478
+ def andalucia(text):
1479
+ style = {
1480
+ "a": "ꪖ",
1481
+ "b": "᥇",
1482
+ "c": "ᥴ",
1483
+ "d": "ᦔ",
1484
+ "e": "ꫀ",
1485
+ "f": "ᠻ",
1486
+ "g": "ᧁ",
1487
+ "h": "ꫝ",
1488
+ "i": "𝓲",
1489
+ "j": "𝓳",
1490
+ "k": "𝘬",
1491
+ "l": "ꪶ",
1492
+ "m": "ꪑ",
1493
+ "n": "ꪀ",
1494
+ "o": "ꪮ",
1495
+ "p": "ρ",
1496
+ "q": "𝘲",
1497
+ "r": "𝘳",
1498
+ "s": "𝘴",
1499
+ "t": "𝓽",
1500
+ "u": "ꪊ",
1501
+ "v": "ꪜ",
1502
+ "w": "᭙",
1503
+ "x": "᥊",
1504
+ "y": "ꪗ",
1505
+ "z": "ɀ",
1506
+ "A": "ꪖ",
1507
+ "B": "᥇",
1508
+ "C": "ᥴ",
1509
+ "D": "ᦔ",
1510
+ "E": "ꫀ",
1511
+ "F": "ᠻ",
1512
+ "G": "ᧁ",
1513
+ "H": "ꫝ",
1514
+ "I": "𝓲",
1515
+ "J": "𝓳",
1516
+ "K": "𝘬",
1517
+ "L": "ꪶ",
1518
+ "M": "ꪑ",
1519
+ "N": "ꪀ",
1520
+ "O": "ꪮ",
1521
+ "P": "ρ",
1522
+ "Q": "𝘲",
1523
+ "R": "𝘳",
1524
+ "S": "𝘴",
1525
+ "T": "𝓽",
1526
+ "U": "ꪊ",
1527
+ "V": "ꪜ",
1528
+ "W": "᭙",
1529
+ "X": "᥊",
1530
+ "Y": "ꪗ",
1531
+ "Z": "ɀ",
1532
+ }
1533
+ for i, j in style.items():
1534
+ text = text.replace(i, j)
1535
+ return text
1536
+
1537
+ def manga(text):
1538
+ style = {
1539
+ "a": "卂",
1540
+ "b": "乃",
1541
+ "c": "匚",
1542
+ "d": "ᗪ",
1543
+ "e": "乇",
1544
+ "f": "千",
1545
+ "g": "ᘜ",
1546
+ "h": "卄",
1547
+ "i": "|",
1548
+ "j": "フ",
1549
+ "k": "Ҝ",
1550
+ "l": "ㄥ",
1551
+ "m": "爪",
1552
+ "n": "几",
1553
+ "o": "ㄖ",
1554
+ "p": "卩",
1555
+ "q": "Ҩ",
1556
+ "r": "尺",
1557
+ "s": "丂",
1558
+ "t": "ㄒ",
1559
+ "u": "ㄩ",
1560
+ "v": "ᐯ",
1561
+ "w": "山",
1562
+ "x": "乂",
1563
+ "y": "ㄚ",
1564
+ "z": "乙",
1565
+ "A": "卂",
1566
+ "B": "乃",
1567
+ "C": "匚",
1568
+ "D": "ᗪ",
1569
+ "E": "乇",
1570
+ "F": "千",
1571
+ "G": "ᘜ",
1572
+ "H": "卄",
1573
+ "I": "|",
1574
+ "J": "フ",
1575
+ "K": "Ҝ",
1576
+ "L": "ㄥ",
1577
+ "M": "爪",
1578
+ "N": "几",
1579
+ "O": "ㄖ",
1580
+ "P": "卩",
1581
+ "Q": "Ҩ",
1582
+ "R": "尺",
1583
+ "S": "丂",
1584
+ "T": "ㄒ",
1585
+ "U": "ㄩ",
1586
+ "V": "ᐯ",
1587
+ "W": "山",
1588
+ "X": "乂",
1589
+ "Y": "ㄚ",
1590
+ "Z": "乙",
1591
+ }
1592
+ for i, j in style.items():
1593
+ text = text.replace(i, j)
1594
+ return text
1595
+
1596
+ def stinky(text):
1597
+ style = {
1598
+ "a": "a̾",
1599
+ "b": "b̾",
1600
+ "c": "c̾",
1601
+ "d": "d̾",
1602
+ "e": "e̾",
1603
+ "f": "f̾",
1604
+ "g": "g̾",
1605
+ "h": "h̾",
1606
+ "i": "i̾",
1607
+ "j": "j̾",
1608
+ "k": "k̾",
1609
+ "l": "l̾",
1610
+ "m": "m̾",
1611
+ "n": "n̾",
1612
+ "o": "o̾",
1613
+ "p": "p̾",
1614
+ "q": "q̾",
1615
+ "r": "r̾",
1616
+ "s": "s̾",
1617
+ "t": "t̾",
1618
+ "u": "u̾",
1619
+ "v": "v̾",
1620
+ "w": "w̾",
1621
+ "x": "x̾",
1622
+ "y": "y̾",
1623
+ "z": "z̾",
1624
+ "A": "A̾",
1625
+ "B": "B̾",
1626
+ "C": "C̾",
1627
+ "D": "D̾",
1628
+ "E": "E̾",
1629
+ "F": "F̾",
1630
+ "G": "G̾",
1631
+ "H": "H̾",
1632
+ "I": "I̾",
1633
+ "J": "J̾",
1634
+ "K": "K̾",
1635
+ "L": "L̾",
1636
+ "M": "M̾",
1637
+ "N": "N̾",
1638
+ "O": "O̾",
1639
+ "P": "P̾",
1640
+ "Q": "Q̾",
1641
+ "R": "R̾",
1642
+ "S": "S̾",
1643
+ "T": "T̾",
1644
+ "U": "U̾",
1645
+ "V": "V̾",
1646
+ "W": "W̾",
1647
+ "X": "X̾",
1648
+ "Y": "Y̾",
1649
+ "Z": "Z̾",
1650
+ }
1651
+ for i, j in style.items():
1652
+ text = text.replace(i, j)
1653
+ return text
1654
+
1655
+ def bubbles(text):
1656
+ style = {
1657
+ "a": "ḁͦ",
1658
+ "b": "b̥ͦ",
1659
+ "c": "c̥ͦ",
1660
+ "d": "d̥ͦ",
1661
+ "e": "e̥ͦ",
1662
+ "f": "f̥ͦ",
1663
+ "g": "g̥ͦ",
1664
+ "h": "h̥ͦ",
1665
+ "i": "i̥ͦ",
1666
+ "j": "j̥ͦ",
1667
+ "k": "k̥ͦ",
1668
+ "l": "l̥ͦ",
1669
+ "m": "m̥ͦ",
1670
+ "n": "n̥ͦ",
1671
+ "o": "o̥ͦ",
1672
+ "p": "p̥ͦ",
1673
+ "q": "q̥ͦ",
1674
+ "r": "r̥ͦ",
1675
+ "s": "s̥ͦ",
1676
+ "t": "t̥ͦ",
1677
+ "u": "u̥ͦ",
1678
+ "v": "v̥ͦ",
1679
+ "w": "w̥ͦ",
1680
+ "x": "x̥ͦ",
1681
+ "y": "y̥ͦ",
1682
+ "z": "z̥ͦ",
1683
+ "A": "Ḁͦ",
1684
+ "B": "B̥ͦ",
1685
+ "C": "C̥ͦ",
1686
+ "D": "D̥ͦ",
1687
+ "E": "E̥ͦ",
1688
+ "F": "F̥ͦ",
1689
+ "G": "G̥ͦ",
1690
+ "H": "H̥ͦ",
1691
+ "I": "I̥ͦ",
1692
+ "J": "J̥ͦ",
1693
+ "K": "K̥ͦ",
1694
+ "L": "L̥ͦ",
1695
+ "M": "M̥ͦ",
1696
+ "N": "N̥ͦ",
1697
+ "O": "O̥ͦ",
1698
+ "P": "P̥ͦ",
1699
+ "Q": "Q̥ͦ",
1700
+ "R": "R̥ͦ",
1701
+ "S": "S̥ͦ",
1702
+ "T": "T̥ͦ",
1703
+ "U": "U̥ͦ",
1704
+ "V": "V̥ͦ",
1705
+ "W": "W̥ͦ",
1706
+ "X": "X̥ͦ",
1707
+ "Y": "Y̥ͦ",
1708
+ "Z": "Z̥ͦ",
1709
+ }
1710
+ for i, j in style.items():
1711
+ text = text.replace(i, j)
1712
+ return text
1713
+
1714
+ def underline(text):
1715
+ style = {
1716
+ "a": "a͟",
1717
+ "b": "b͟",
1718
+ "c": "c͟",
1719
+ "d": "d͟",
1720
+ "e": "e͟",
1721
+ "f": "f͟",
1722
+ "g": "g͟",
1723
+ "h": "h͟",
1724
+ "i": "i͟",
1725
+ "j": "j͟",
1726
+ "k": "k͟",
1727
+ "l": "l͟",
1728
+ "m": "m͟",
1729
+ "n": "n͟",
1730
+ "o": "o͟",
1731
+ "p": "p͟",
1732
+ "q": "q͟",
1733
+ "r": "r͟",
1734
+ "s": "s͟",
1735
+ "t": "t͟",
1736
+ "u": "u͟",
1737
+ "v": "v͟",
1738
+ "w": "w͟",
1739
+ "x": "x͟",
1740
+ "y": "y͟",
1741
+ "z": "z͟",
1742
+ "A": "A͟",
1743
+ "B": "B͟",
1744
+ "C": "C͟",
1745
+ "D": "D͟",
1746
+ "E": "E͟",
1747
+ "F": "F͟",
1748
+ "G": "G͟",
1749
+ "H": "H͟",
1750
+ "I": "I͟",
1751
+ "J": "J͟",
1752
+ "K": "K͟",
1753
+ "L": "L͟",
1754
+ "M": "M͟",
1755
+ "N": "N͟",
1756
+ "O": "O͟",
1757
+ "P": "P͟",
1758
+ "Q": "Q͟",
1759
+ "R": "R͟",
1760
+ "S": "S͟",
1761
+ "T": "T͟",
1762
+ "U": "U͟",
1763
+ "V": "V͟",
1764
+ "W": "W͟",
1765
+ "X": "X͟",
1766
+ "Y": "Y͟",
1767
+ "Z": "Z͟",
1768
+ }
1769
+ for i, j in style.items():
1770
+ text = text.replace(i, j)
1771
+ return text
1772
+
1773
+ def ladybug(text):
1774
+ style = {
1775
+ "a": "ꍏ",
1776
+ "b": "ꌃ",
1777
+ "c": "ꏳ",
1778
+ "d": "ꀷ",
1779
+ "e": "ꏂ",
1780
+ "f": "ꎇ",
1781
+ "g": "ꁅ",
1782
+ "h": "ꀍ",
1783
+ "i": "ꀤ",
1784
+ "j": "꒻",
1785
+ "k": "ꀘ",
1786
+ "l": "꒒",
1787
+ "m": "ꎭ",
1788
+ "n": "ꈤ",
1789
+ "o": "ꂦ",
1790
+ "p": "ᖘ",
1791
+ "q": "ꆰ",
1792
+ "r": "ꋪ",
1793
+ "s": "ꌚ",
1794
+ "t": "꓄",
1795
+ "u": "ꀎ",
1796
+ "v": "꒦",
1797
+ "w": "ꅐ",
1798
+ "x": "ꉧ",
1799
+ "y": "ꌩ",
1800
+ "z": "ꁴ",
1801
+ "A": "ꍏ",
1802
+ "B": "ꌃ",
1803
+ "C": "ꏳ",
1804
+ "D": "ꀷ",
1805
+ "E": "ꏂ",
1806
+ "F": "ꎇ",
1807
+ "G": "ꁅ",
1808
+ "H": "ꀍ",
1809
+ "I": "ꀤ",
1810
+ "J": "꒻",
1811
+ "K": "ꀘ",
1812
+ "L": "꒒",
1813
+ "M": "ꎭ",
1814
+ "N": "ꈤ",
1815
+ "O": "ꂦ",
1816
+ "P": "ᖘ",
1817
+ "Q": "ꆰ",
1818
+ "R": "ꋪ",
1819
+ "S": "ꌚ",
1820
+ "T": "꓄",
1821
+ "U": "ꀎ",
1822
+ "V": "꒦",
1823
+ "W": "ꅐ",
1824
+ "X": "ꉧ",
1825
+ "Y": "ꌩ",
1826
+ "Z": "ꁴ",
1827
+ }
1828
+ for i, j in style.items():
1829
+ text = text.replace(i, j)
1830
+ return text
1831
+
1832
+ def rays(text):
1833
+ style = {
1834
+ "a": "a҉",
1835
+ "b": "b҉",
1836
+ "c": "c҉",
1837
+ "d": "d҉",
1838
+ "e": "e҉",
1839
+ "f": "f҉",
1840
+ "g": "g҉",
1841
+ "h": "h҉",
1842
+ "i": "i҉",
1843
+ "j": "j҉",
1844
+ "k": "k҉",
1845
+ "l": "l҉",
1846
+ "m": "m҉",
1847
+ "n": "n҉",
1848
+ "o": "o҉",
1849
+ "p": "p҉",
1850
+ "q": "q҉",
1851
+ "r": "r҉",
1852
+ "s": "s҉",
1853
+ "t": "t҉",
1854
+ "u": "u҉",
1855
+ "v": "v҉",
1856
+ "w": "w҉",
1857
+ "x": "x҉",
1858
+ "y": "y҉",
1859
+ "z": "z҉",
1860
+ "A": "A҉",
1861
+ "B": "B҉",
1862
+ "C": "C҉",
1863
+ "D": "D҉",
1864
+ "E": "E҉",
1865
+ "F": "F҉",
1866
+ "G": "G҉",
1867
+ "H": "H҉",
1868
+ "I": "I҉",
1869
+ "J": "J҉",
1870
+ "K": "K҉",
1871
+ "L": "L҉",
1872
+ "M": "M҉",
1873
+ "N": "N҉",
1874
+ "O": "O҉",
1875
+ "P": "P҉",
1876
+ "Q": "Q҉",
1877
+ "R": "R҉",
1878
+ "S": "S҉",
1879
+ "T": "T҉",
1880
+ "U": "U҉",
1881
+ "V": "V҉",
1882
+ "W": "W҉",
1883
+ "X": "X҉",
1884
+ "Y": "Y҉",
1885
+ "Z": "Z҉",
1886
+ }
1887
+ for i, j in style.items():
1888
+ text = text.replace(i, j)
1889
+ return text
1890
+
1891
+ def birds(text):
1892
+ style = {
1893
+ "a": "a҈",
1894
+ "b": "b҈",
1895
+ "c": "c҈",
1896
+ "d": "d҈",
1897
+ "e": "e҈",
1898
+ "f": "f҈",
1899
+ "g": "g҈",
1900
+ "h": "h҈",
1901
+ "i": "i҈",
1902
+ "j": "j҈",
1903
+ "k": "k҈",
1904
+ "l": "l҈",
1905
+ "m": "m҈",
1906
+ "n": "n҈",
1907
+ "o": "o҈",
1908
+ "p": "p҈",
1909
+ "q": "q҈",
1910
+ "r": "r҈",
1911
+ "s": "s҈",
1912
+ "t": "t҈",
1913
+ "u": "u҈",
1914
+ "v": "v҈",
1915
+ "w": "w҈",
1916
+ "x": "x҈",
1917
+ "y": "y҈",
1918
+ "z": "z҈",
1919
+ "A": "A҈",
1920
+ "B": "B҈",
1921
+ "C": "C҈",
1922
+ "D": "D҈",
1923
+ "E": "E҈",
1924
+ "F": "F҈",
1925
+ "G": "G҈",
1926
+ "H": "H҈",
1927
+ "I": "I҈",
1928
+ "J": "J҈",
1929
+ "K": "K҈",
1930
+ "L": "L҈",
1931
+ "M": "M҈",
1932
+ "N": "N҈",
1933
+ "O": "O҈",
1934
+ "P": "P҈",
1935
+ "Q": "Q҈",
1936
+ "R": "R҈",
1937
+ "S": "S҈",
1938
+ "T": "T҈",
1939
+ "U": "U҈",
1940
+ "V": "V҈",
1941
+ "W": "W҈",
1942
+ "X": "X҈",
1943
+ "Y": "Y҈",
1944
+ "Z": "Z҈",
1945
+ }
1946
+ for i, j in style.items():
1947
+ text = text.replace(i, j)
1948
+ return text
1949
+
1950
+ def slash(text):
1951
+ style = {
1952
+ "a": "a̸",
1953
+ "b": "b̸",
1954
+ "c": "c̸",
1955
+ "d": "d̸",
1956
+ "e": "e̸",
1957
+ "f": "f̸",
1958
+ "g": "g̸",
1959
+ "h": "h̸",
1960
+ "i": "i̸",
1961
+ "j": "j̸",
1962
+ "k": "k̸",
1963
+ "l": "l̸",
1964
+ "m": "m̸",
1965
+ "n": "n̸",
1966
+ "o": "o̸",
1967
+ "p": "p̸",
1968
+ "q": "q̸",
1969
+ "r": "r̸",
1970
+ "s": "s̸",
1971
+ "t": "t̸",
1972
+ "u": "u̸",
1973
+ "v": "v̸",
1974
+ "w": "w̸",
1975
+ "x": "x̸",
1976
+ "y": "y̸",
1977
+ "z": "z̸",
1978
+ "A": "A̸",
1979
+ "B": "B̸",
1980
+ "C": "C̸",
1981
+ "D": "D̸",
1982
+ "E": "E̸",
1983
+ "F": "F̸",
1984
+ "G": "G̸",
1985
+ "H": "H̸",
1986
+ "I": "I̸",
1987
+ "J": "J̸",
1988
+ "K": "K̸",
1989
+ "L": "L̸",
1990
+ "M": "M̸",
1991
+ "N": "N̸",
1992
+ "O": "O̸",
1993
+ "P": "P̸",
1994
+ "Q": "Q̸",
1995
+ "R": "R̸",
1996
+ "S": "S̸",
1997
+ "T": "T̸",
1998
+ "U": "U̸",
1999
+ "V": "V̸",
2000
+ "W": "W̸",
2001
+ "X": "X̸",
2002
+ "Y": "Y̸",
2003
+ "Z": "Z̸",
2004
+ }
2005
+ for i, j in style.items():
2006
+ text = text.replace(i, j)
2007
+ return text
2008
+
2009
+ def stop(text):
2010
+ style = {
2011
+ "a": "a⃠",
2012
+ "b": "b⃠",
2013
+ "c": "c⃠",
2014
+ "d": "d⃠",
2015
+ "e": "e⃠",
2016
+ "f": "f⃠",
2017
+ "g": "g⃠",
2018
+ "h": "h⃠",
2019
+ "i": "i⃠",
2020
+ "j": "j⃠",
2021
+ "k": "k⃠",
2022
+ "l": "l⃠",
2023
+ "m": "m⃠",
2024
+ "n": "n⃠",
2025
+ "o": "o⃠",
2026
+ "p": "p⃠",
2027
+ "q": "q⃠",
2028
+ "r": "r⃠",
2029
+ "s": "s⃠",
2030
+ "t": "t⃠",
2031
+ "u": "u⃠",
2032
+ "v": "v⃠",
2033
+ "w": "w⃠",
2034
+ "x": "x⃠",
2035
+ "y": "y⃠",
2036
+ "z": "z⃠",
2037
+ "A": "A⃠",
2038
+ "B": "B⃠",
2039
+ "C": "C⃠",
2040
+ "D": "D⃠",
2041
+ "E": "E⃠",
2042
+ "F": "F⃠",
2043
+ "G": "G⃠",
2044
+ "H": "H⃠",
2045
+ "I": "I⃠",
2046
+ "J": "J⃠",
2047
+ "K": "K⃠",
2048
+ "L": "L⃠",
2049
+ "M": "M⃠",
2050
+ "N": "N⃠",
2051
+ "O": "O⃠",
2052
+ "P": "P⃠",
2053
+ "Q": "Q⃠",
2054
+ "R": "R⃠",
2055
+ "S": "S⃠",
2056
+ "T": "T⃠",
2057
+ "U": "U⃠",
2058
+ "V": "V⃠",
2059
+ "W": "W⃠",
2060
+ "X": "X⃠",
2061
+ "Y": "Y⃠",
2062
+ "Z": "Z⃠",
2063
+ }
2064
+ for i, j in style.items():
2065
+ text = text.replace(i, j)
2066
+ return text
2067
+
2068
+ def skyline(text):
2069
+ style = {
2070
+ "a": "a̺͆",
2071
+ "b": "b̺͆",
2072
+ "c": "c̺͆",
2073
+ "d": "d̺͆",
2074
+ "e": "e̺͆",
2075
+ "f": "f̺͆",
2076
+ "g": "g̺͆",
2077
+ "h": "h̺͆",
2078
+ "i": "i̺͆",
2079
+ "j": "j̺͆",
2080
+ "k": "k̺͆",
2081
+ "l": "l̺͆",
2082
+ "m": "m̺͆",
2083
+ "n": "n̺͆",
2084
+ "o": "o̺͆",
2085
+ "p": "p̺͆",
2086
+ "q": "q̺͆",
2087
+ "r": "r̺͆",
2088
+ "s": "s̺͆",
2089
+ "t": "t̺͆",
2090
+ "u": "u̺͆",
2091
+ "v": "v̺͆",
2092
+ "w": "w̺͆",
2093
+ "x": "x̺͆",
2094
+ "y": "y̺͆",
2095
+ "z": "z̺͆",
2096
+ "A": "A̺͆",
2097
+ "B": "B̺͆",
2098
+ "C": "C̺͆",
2099
+ "D": "D̺͆",
2100
+ "E": "E̺͆",
2101
+ "F": "F̺͆",
2102
+ "G": "G̺͆",
2103
+ "H": "H̺͆",
2104
+ "I": "I̺͆",
2105
+ "J": "J̺͆",
2106
+ "K": "K̺͆",
2107
+ "L": "L̺͆",
2108
+ "M": "M̺͆",
2109
+ "N": "N̺͆",
2110
+ "O": "O̺͆",
2111
+ "P": "P̺͆",
2112
+ "Q": "Q̺͆",
2113
+ "R": "R̺͆",
2114
+ "S": "S̺͆",
2115
+ "T": "T̺͆",
2116
+ "U": "U̺͆",
2117
+ "V": "V̺͆",
2118
+ "W": "W̺͆",
2119
+ "X": "X̺͆",
2120
+ "Y": "Y̺͆",
2121
+ "Z": "Z̺͆",
2122
+ }
2123
+ for i, j in style.items():
2124
+ text = text.replace(i, j)
2125
+ return text
2126
+
2127
+ def arrows(text):
2128
+ style = {
2129
+ "a": "a͎",
2130
+ "b": "b͎",
2131
+ "c": "c͎",
2132
+ "d": "d͎",
2133
+ "e": "e͎",
2134
+ "f": "f͎",
2135
+ "g": "g͎",
2136
+ "h": "h͎",
2137
+ "i": "i͎",
2138
+ "j": "j͎",
2139
+ "k": "k͎",
2140
+ "l": "l͎",
2141
+ "m": "m͎",
2142
+ "n": "n͎",
2143
+ "o": "o͎",
2144
+ "p": "p͎",
2145
+ "q": "q͎",
2146
+ "r": "r͎",
2147
+ "s": "s͎",
2148
+ "t": "t͎",
2149
+ "u": "u͎",
2150
+ "v": "v͎",
2151
+ "w": "w͎",
2152
+ "x": "x͎",
2153
+ "y": "y͎",
2154
+ "z": "z͎",
2155
+ "A": "A͎",
2156
+ "B": "B͎",
2157
+ "C": "C͎",
2158
+ "D": "D͎",
2159
+ "E": "E͎",
2160
+ "F": "F͎",
2161
+ "G": "G͎",
2162
+ "H": "H͎",
2163
+ "I": "I͎",
2164
+ "J": "J͎",
2165
+ "K": "K͎",
2166
+ "L": "L͎",
2167
+ "M": "M͎",
2168
+ "N": "N͎",
2169
+ "O": "O͎",
2170
+ "P": "P͎",
2171
+ "Q": "Q͎",
2172
+ "R": "R͎",
2173
+ "S": "S͎",
2174
+ "T": "T͎",
2175
+ "U": "U͎",
2176
+ "V": "V͎",
2177
+ "W": "W͎",
2178
+ "X": "X͎",
2179
+ "Y": "Y͎",
2180
+ "Z": "Z͎",
2181
+ }
2182
+ for i, j in style.items():
2183
+ text = text.replace(i, j)
2184
+ return text
2185
+
2186
+ def rvnes(text):
2187
+ style = {
2188
+ "a": "ል",
2189
+ "b": "ጌ",
2190
+ "c": "ር",
2191
+ "d": "ዕ",
2192
+ "e": "ቿ",
2193
+ "f": "ቻ",
2194
+ "g": "ኗ",
2195
+ "h": "ዘ",
2196
+ "i": "ጎ",
2197
+ "j": "ጋ",
2198
+ "k": "ጕ",
2199
+ "l": "ረ",
2200
+ "m": "ጠ",
2201
+ "n": "ክ",
2202
+ "o": "ዐ",
2203
+ "p": "የ",
2204
+ "q": "ዒ",
2205
+ "r": "ዪ",
2206
+ "s": "ነ",
2207
+ "t": "ፕ",
2208
+ "u": "ሁ",
2209
+ "v": "ሀ",
2210
+ "w": "ሠ",
2211
+ "x": "ሸ",
2212
+ "y": "ሃ",
2213
+ "z": "ጊ",
2214
+ "A": "ል",
2215
+ "B": "ጌ",
2216
+ "C": "ር",
2217
+ "D": "ዕ",
2218
+ "E": "ቿ",
2219
+ "F": "ቻ",
2220
+ "G": "ኗ",
2221
+ "H": "ዘ",
2222
+ "I": "ጎ",
2223
+ "J": "ጋ",
2224
+ "K": "ጕ",
2225
+ "L": "ረ",
2226
+ "M": "ጠ",
2227
+ "N": "ክ",
2228
+ "O": "ዐ",
2229
+ "P": "የ",
2230
+ "Q": "ዒ",
2231
+ "R": "ዪ",
2232
+ "S": "ነ",
2233
+ "T": "ፕ",
2234
+ "U": "ሁ",
2235
+ "V": "ሀ",
2236
+ "W": "ሠ",
2237
+ "X": "ሸ",
2238
+ "Y": "ሃ",
2239
+ "Z": "ጊ",
2240
+ }
2241
+ for i, j in style.items():
2242
+ text = text.replace(i, j)
2243
+ return text
2244
+
2245
+ def strike(text):
2246
+ style = {
2247
+ "a": "a̶",
2248
+ "b": "b̶",
2249
+ "c": "c̶",
2250
+ "d": "d̶",
2251
+ "e": "e̶",
2252
+ "f": "f̶",
2253
+ "g": "g̶",
2254
+ "h": "h̶",
2255
+ "i": "i̶",
2256
+ "j": "j̶",
2257
+ "k": "k̶",
2258
+ "l": "l̶",
2259
+ "m": "m̶",
2260
+ "n": "n̶",
2261
+ "o": "o̶",
2262
+ "p": "p̶",
2263
+ "q": "q̶",
2264
+ "r": "r̶",
2265
+ "s": "s̶",
2266
+ "t": "t̶",
2267
+ "u": "u̶",
2268
+ "v": "v̶",
2269
+ "w": "w̶",
2270
+ "x": "x̶",
2271
+ "y": "y̶",
2272
+ "z": "z̶",
2273
+ "A": "A̶",
2274
+ "B": "B̶",
2275
+ "C": "C̶",
2276
+ "D": "D̶",
2277
+ "E": "E̶",
2278
+ "F": "F̶",
2279
+ "G": "G̶",
2280
+ "H": "H̶",
2281
+ "I": "I̶",
2282
+ "J": "J̶",
2283
+ "K": "K̶",
2284
+ "L": "L̶",
2285
+ "M": "M̶",
2286
+ "N": "N̶",
2287
+ "O": "O̶",
2288
+ "P": "P̶",
2289
+ "Q": "Q̶",
2290
+ "R": "R̶",
2291
+ "S": "S̶",
2292
+ "T": "T̶",
2293
+ "U": "U̶",
2294
+ "V": "V̶",
2295
+ "W": "W̶",
2296
+ "X": "X̶",
2297
+ "Y": "Y̶",
2298
+ "Z": "Z̶",
2299
+ }
2300
+ for i, j in style.items():
2301
+ text = text.replace(i, j)
2302
+ return text
2303
+
2304
+ def frozen(text):
2305
+ style = {
2306
+ "a": "a༙",
2307
+ "b": "b༙",
2308
+ "c": "c༙",
2309
+ "d": "d༙",
2310
+ "e": "e༙",
2311
+ "f": "f༙",
2312
+ "g": "g༙",
2313
+ "h": "h༙",
2314
+ "i": "i༙",
2315
+ "j": "j༙",
2316
+ "k": "k༙",
2317
+ "l": "l༙",
2318
+ "m": "m༙",
2319
+ "n": "n༙",
2320
+ "o": "o༙",
2321
+ "p": "p༙",
2322
+ "q": "q༙",
2323
+ "r": "r༙",
2324
+ "s": "s༙",
2325
+ "t": "t༙",
2326
+ "u": "u༙",
2327
+ "v": "v༙",
2328
+ "w": "w༙",
2329
+ "x": "x༙",
2330
+ "y": "y༙",
2331
+ "z": "z༙",
2332
+ "A": "A༙",
2333
+ "B": "B༙",
2334
+ "C": "C༙",
2335
+ "D": "D༙",
2336
+ "E": "E༙",
2337
+ "F": "F༙",
2338
+ "G": "G༙",
2339
+ "H": "H༙",
2340
+ "I": "I༙",
2341
+ "J": "J༙",
2342
+ "K": "K༙",
2343
+ "L": "L༙",
2344
+ "M": "M༙",
2345
+ "N": "N༙",
2346
+ "O": "O༙",
2347
+ "P": "P༙",
2348
+ "Q": "Q༙",
2349
+ "R": "R༙",
2350
+ "S": "S༙",
2351
+ "T": "T༙",
2352
+ "U": "U༙",
2353
+ "V": "V༙",
2354
+ "W": "W༙",
2355
+ "X": "X༙",
2356
+ "Y": "Y༙",
2357
+ "Z": "Z༙",
2358
+ }
2359
+ for i, j in style.items():
2360
+ text = text.replace(i, j)
2361
+ return text
Database/sql/forceSubscribe_sql.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import Column, Numeric, String
2
+
3
+ from Database.sql import BASE, SESSION
4
+
5
+
6
+ class forceSubscribe(BASE):
7
+ __tablename__ = "forceSubscribe"
8
+ chat_id = Column(Numeric, primary_key=True)
9
+ channel = Column(String)
10
+
11
+ def __init__(self, chat_id, channel):
12
+ self.chat_id = chat_id
13
+ self.channel = channel
14
+
15
+
16
+ forceSubscribe.__table__.create(checkfirst=True)
17
+
18
+
19
+ def fs_settings(chat_id):
20
+ try:
21
+ return (
22
+ SESSION.query(forceSubscribe)
23
+ .filter(forceSubscribe.chat_id == chat_id)
24
+ .one()
25
+ )
26
+ except:
27
+ return None
28
+ finally:
29
+ SESSION.close()
30
+
31
+
32
+ def add_channel(chat_id, channel):
33
+ adder = SESSION.query(forceSubscribe).get(chat_id)
34
+ if adder:
35
+ adder.channel = channel
36
+ else:
37
+ adder = forceSubscribe(chat_id, channel)
38
+ SESSION.add(adder)
39
+ SESSION.commit()
40
+
41
+
42
+ def disapprove(chat_id):
43
+ rem = SESSION.query(forceSubscribe).get(chat_id)
44
+ if rem:
45
+ SESSION.delete(rem)
46
+ SESSION.commit()
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/locks_sql.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ # New chat added -> setup permissions
26
+ import threading
27
+
28
+ from sqlalchemy import Boolean, Column, String
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class Permissions(BASE):
34
+ __tablename__ = "permissions"
35
+ chat_id = Column(String(14), primary_key=True)
36
+ # Booleans are for "is this locked", _NOT_ "is this allowed"
37
+ audio = Column(Boolean, default=False)
38
+ voice = Column(Boolean, default=False)
39
+ contact = Column(Boolean, default=False)
40
+ video = Column(Boolean, default=False)
41
+ document = Column(Boolean, default=False)
42
+ photo = Column(Boolean, default=False)
43
+ sticker = Column(Boolean, default=False)
44
+ gif = Column(Boolean, default=False)
45
+ url = Column(Boolean, default=False)
46
+ bots = Column(Boolean, default=False)
47
+ forward = Column(Boolean, default=False)
48
+ game = Column(Boolean, default=False)
49
+ location = Column(Boolean, default=False)
50
+ rtl = Column(Boolean, default=False)
51
+ button = Column(Boolean, default=False)
52
+ egame = Column(Boolean, default=False)
53
+ inline = Column(Boolean, default=False)
54
+
55
+ def __init__(self, chat_id):
56
+ self.chat_id = str(chat_id) # ensure string
57
+ self.audio = False
58
+ self.voice = False
59
+ self.contact = False
60
+ self.video = False
61
+ self.document = False
62
+ self.photo = False
63
+ self.sticker = False
64
+ self.gif = False
65
+ self.url = False
66
+ self.bots = False
67
+ self.forward = False
68
+ self.game = False
69
+ self.location = False
70
+ self.rtl = False
71
+ self.button = False
72
+ self.egame = False
73
+ self.inline = False
74
+
75
+ def __repr__(self):
76
+ return "<ᴘᴇʀᴍɪssɪᴏɴs ғᴏʀ %s>" % self.chat_id
77
+
78
+
79
+ class Restrictions(BASE):
80
+ __tablename__ = "restrictions"
81
+ chat_id = Column(String(14), primary_key=True)
82
+ # Booleans are for "is this restricted", _NOT_ "is this allowed"
83
+ messages = Column(Boolean, default=False)
84
+ media = Column(Boolean, default=False)
85
+ other = Column(Boolean, default=False)
86
+ preview = Column(Boolean, default=False)
87
+
88
+ def __init__(self, chat_id):
89
+ self.chat_id = str(chat_id) # ensure string
90
+ self.messages = False
91
+ self.media = False
92
+ self.other = False
93
+ self.preview = False
94
+
95
+ def __repr__(self):
96
+ return "<ʀᴇsᴛʀɪᴄᴛɪᴏɴs ғᴏʀ %s>" % self.chat_id
97
+
98
+
99
+ # For those who faced database error, Just uncomment the
100
+ # line below and run bot for 1 time & remove that line!
101
+
102
+ Permissions.__table__.create(checkfirst=True)
103
+ # Permissions.__table__.drop()
104
+ Restrictions.__table__.create(checkfirst=True)
105
+
106
+ PERM_LOCK = threading.RLock()
107
+ RESTR_LOCK = threading.RLock()
108
+
109
+
110
+ def init_permissions(chat_id, reset=False):
111
+ curr_perm = SESSION.query(Permissions).get(str(chat_id))
112
+ if reset:
113
+ SESSION.delete(curr_perm)
114
+ SESSION.flush()
115
+ perm = Permissions(str(chat_id))
116
+ SESSION.add(perm)
117
+ SESSION.commit()
118
+ return perm
119
+
120
+
121
+ def init_restrictions(chat_id, reset=False):
122
+ curr_restr = SESSION.query(Restrictions).get(str(chat_id))
123
+ if reset:
124
+ SESSION.delete(curr_restr)
125
+ SESSION.flush()
126
+ restr = Restrictions(str(chat_id))
127
+ SESSION.add(restr)
128
+ SESSION.commit()
129
+ return restr
130
+
131
+
132
+ def update_lock(chat_id, lock_type, locked):
133
+ with PERM_LOCK:
134
+ curr_perm = SESSION.query(Permissions).get(str(chat_id))
135
+ if not curr_perm:
136
+ curr_perm = init_permissions(chat_id)
137
+
138
+ if lock_type == "audio":
139
+ curr_perm.audio = locked
140
+ elif lock_type == "voice":
141
+ curr_perm.voice = locked
142
+ elif lock_type == "contact":
143
+ curr_perm.contact = locked
144
+ elif lock_type == "video":
145
+ curr_perm.video = locked
146
+ elif lock_type == "document":
147
+ curr_perm.document = locked
148
+ elif lock_type == "photo":
149
+ curr_perm.photo = locked
150
+ elif lock_type == "sticker":
151
+ curr_perm.sticker = locked
152
+ elif lock_type == "gif":
153
+ curr_perm.gif = locked
154
+ elif lock_type == "url":
155
+ curr_perm.url = locked
156
+ elif lock_type == "bots":
157
+ curr_perm.bots = locked
158
+ elif lock_type == "forward":
159
+ curr_perm.forward = locked
160
+ elif lock_type == "game":
161
+ curr_perm.game = locked
162
+ elif lock_type == "location":
163
+ curr_perm.location = locked
164
+ elif lock_type == "rtl":
165
+ curr_perm.rtl = locked
166
+ elif lock_type == "button":
167
+ curr_perm.button = locked
168
+ elif lock_type == "egame":
169
+ curr_perm.egame = locked
170
+ elif lock_type == "inline":
171
+ curr_perm.inline = locked
172
+
173
+ SESSION.add(curr_perm)
174
+ SESSION.commit()
175
+
176
+
177
+ def update_restriction(chat_id, restr_type, locked):
178
+ with RESTR_LOCK:
179
+ curr_restr = SESSION.query(Restrictions).get(str(chat_id))
180
+ if not curr_restr:
181
+ curr_restr = init_restrictions(chat_id)
182
+
183
+ if restr_type == "messages":
184
+ curr_restr.messages = locked
185
+ elif restr_type == "media":
186
+ curr_restr.media = locked
187
+ elif restr_type == "other":
188
+ curr_restr.other = locked
189
+ elif restr_type == "previews":
190
+ curr_restr.preview = locked
191
+ elif restr_type == "all":
192
+ curr_restr.messages = locked
193
+ curr_restr.media = locked
194
+ curr_restr.other = locked
195
+ curr_restr.preview = locked
196
+ SESSION.add(curr_restr)
197
+ SESSION.commit()
198
+
199
+
200
+ def is_locked(chat_id, lock_type):
201
+ curr_perm = SESSION.query(Permissions).get(str(chat_id))
202
+ SESSION.close()
203
+
204
+ if not curr_perm:
205
+ return False
206
+
207
+ if lock_type == "sticker":
208
+ return curr_perm.sticker
209
+ if lock_type == "photo":
210
+ return curr_perm.photo
211
+ if lock_type == "audio":
212
+ return curr_perm.audio
213
+ if lock_type == "voice":
214
+ return curr_perm.voice
215
+ if lock_type == "contact":
216
+ return curr_perm.contact
217
+ if lock_type == "video":
218
+ return curr_perm.video
219
+ if lock_type == "document":
220
+ return curr_perm.document
221
+ if lock_type == "gif":
222
+ return curr_perm.gif
223
+ if lock_type == "url":
224
+ return curr_perm.url
225
+ if lock_type == "bots":
226
+ return curr_perm.bots
227
+ if lock_type == "forward":
228
+ return curr_perm.forward
229
+ if lock_type == "game":
230
+ return curr_perm.game
231
+ if lock_type == "location":
232
+ return curr_perm.location
233
+ if lock_type == "rtl":
234
+ return curr_perm.rtl
235
+ if lock_type == "button":
236
+ return curr_perm.button
237
+ if lock_type == "egame":
238
+ return curr_perm.egame
239
+ if lock_type == "inline":
240
+ return curr_perm.inline
241
+
242
+
243
+ def is_restr_locked(chat_id, lock_type):
244
+ curr_restr = SESSION.query(Restrictions).get(str(chat_id))
245
+ SESSION.close()
246
+
247
+ if not curr_restr:
248
+ return False
249
+
250
+ if lock_type == "messages":
251
+ return curr_restr.messages
252
+ if lock_type == "media":
253
+ return curr_restr.media
254
+ if lock_type == "other":
255
+ return curr_restr.other
256
+ if lock_type == "previews":
257
+ return curr_restr.preview
258
+ if lock_type == "all":
259
+ return (
260
+ curr_restr.messages
261
+ and curr_restr.media
262
+ and curr_restr.other
263
+ and curr_restr.preview
264
+ )
265
+
266
+
267
+ def get_locks(chat_id):
268
+ try:
269
+ return SESSION.query(Permissions).get(str(chat_id))
270
+ finally:
271
+ SESSION.close()
272
+
273
+
274
+ def get_restr(chat_id):
275
+ try:
276
+ return SESSION.query(Restrictions).get(str(chat_id))
277
+ finally:
278
+ SESSION.close()
279
+
280
+
281
+ def migrate_chat(old_chat_id, new_chat_id):
282
+ with PERM_LOCK:
283
+ perms = SESSION.query(Permissions).get(str(old_chat_id))
284
+ if perms:
285
+ perms.chat_id = str(new_chat_id)
286
+ SESSION.commit()
287
+
288
+ with RESTR_LOCK:
289
+ rest = SESSION.query(Restrictions).get(str(old_chat_id))
290
+ if rest:
291
+ rest.chat_id = str(new_chat_id)
292
+ SESSION.commit()
Database/sql/log_channel_sql.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+ import typing
27
+
28
+ from sqlalchemy import BigInteger, Boolean, Column, String, distinct, func
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class GroupLogs(BASE):
34
+ __tablename__ = "log_channels"
35
+ chat_id = Column(String(14), primary_key=True)
36
+ log_channel = Column(String(14), nullable=False)
37
+
38
+ def __init__(self, chat_id, log_channel):
39
+ self.chat_id = str(chat_id)
40
+ self.log_channel = str(log_channel)
41
+
42
+
43
+ class LogChannelSettings(BASE):
44
+ __tablename__ = "log_channel_setting"
45
+ chat_id = Column(BigInteger, primary_key=True)
46
+ log_joins = Column(Boolean, default=True)
47
+ log_leave = Column(Boolean, default=True)
48
+ log_warn = Column(Boolean, default=True)
49
+ log_action = Column(Boolean, default=True)
50
+ # log_media = Column(Boolean)
51
+ log_report = Column(Boolean, default=True)
52
+
53
+ def __init__(
54
+ self,
55
+ chat_id: int,
56
+ log_join: bool,
57
+ log_leave: bool,
58
+ log_warn: bool,
59
+ log_action: bool,
60
+ log_report: bool,
61
+ ):
62
+ self.chat_id = chat_id
63
+ self.log_warn = log_warn
64
+ self.log_joins = log_join
65
+ self.log_leave = log_leave
66
+ self.log_report = log_report
67
+ self.log_action = log_action
68
+
69
+ def toggle_warn(self) -> bool:
70
+ self.log_warn = not self.log_warn
71
+ SESSION.commit()
72
+ return self.log_warn
73
+
74
+ def toggle_joins(self) -> bool:
75
+ self.log_joins = not self.log_joins
76
+ SESSION.commit()
77
+ return self.log_joins
78
+
79
+ def toggle_leave(self) -> bool:
80
+ self.log_leave = not self.log_leave
81
+ SESSION.commit()
82
+ return self.log_leave
83
+
84
+ def toggle_report(self) -> bool:
85
+ self.log_report = not self.log_report
86
+ SESSION.commit()
87
+ return self.log_report
88
+
89
+ def toggle_action(self) -> bool:
90
+ self.log_action = not self.log_action
91
+ SESSION.commit()
92
+ return self.log_action
93
+
94
+
95
+ GroupLogs.__table__.create(checkfirst=True)
96
+ LogChannelSettings.__table__.create(checkfirst=True)
97
+
98
+ LOGS_INSERTION_LOCK = threading.RLock()
99
+ LOG_SETTING_LOCK = threading.RLock()
100
+ CHANNELS = {}
101
+
102
+
103
+ def get_chat_setting(chat_id: int) -> typing.Optional[LogChannelSettings]:
104
+ with LOG_SETTING_LOCK:
105
+ return SESSION.query(LogChannelSettings).get(chat_id)
106
+
107
+
108
+ def set_chat_setting(setting: LogChannelSettings):
109
+ with LOGS_INSERTION_LOCK:
110
+ res: LogChannelSettings = SESSION.query(LogChannelSettings).get(setting.chat_id)
111
+ if res:
112
+ res.log_warn = setting.log_warn
113
+ res.log_action = setting.log_action
114
+ res.log_report = setting.log_report
115
+ res.log_joins = setting.log_joins
116
+ res.log_leave = setting.log_leave
117
+ else:
118
+ SESSION.add(setting)
119
+ SESSION.commit()
120
+
121
+
122
+ def set_chat_log_channel(chat_id, log_channel):
123
+ with LOGS_INSERTION_LOCK:
124
+ res = SESSION.query(GroupLogs).get(str(chat_id))
125
+ if res:
126
+ res.log_channel = log_channel
127
+ else:
128
+ res = GroupLogs(chat_id, log_channel)
129
+ SESSION.add(res)
130
+
131
+ CHANNELS[str(chat_id)] = log_channel
132
+ SESSION.commit()
133
+
134
+
135
+ def get_chat_log_channel(chat_id):
136
+ return CHANNELS.get(str(chat_id))
137
+
138
+
139
+ def stop_chat_logging(chat_id):
140
+ with LOGS_INSERTION_LOCK:
141
+ res = SESSION.query(GroupLogs).get(str(chat_id))
142
+ if res:
143
+ if str(chat_id) in CHANNELS:
144
+ del CHANNELS[str(chat_id)]
145
+
146
+ log_channel = res.log_channel
147
+ SESSION.delete(res)
148
+ SESSION.commit()
149
+ return log_channel
150
+
151
+
152
+ def num_logchannels():
153
+ try:
154
+ return SESSION.query(func.count(distinct(GroupLogs.chat_id))).scalar()
155
+ finally:
156
+ SESSION.close()
157
+
158
+
159
+ def migrate_chat(old_chat_id, new_chat_id):
160
+ with LOGS_INSERTION_LOCK:
161
+ chat = SESSION.query(GroupLogs).get(str(old_chat_id))
162
+ if chat:
163
+ chat.chat_id = str(new_chat_id)
164
+ SESSION.add(chat)
165
+ if str(old_chat_id) in CHANNELS:
166
+ CHANNELS[str(new_chat_id)] = CHANNELS.get(str(old_chat_id))
167
+
168
+ SESSION.commit()
169
+
170
+
171
+ def __load_log_channels():
172
+ global CHANNELS
173
+ try:
174
+ all_chats = SESSION.query(GroupLogs).all()
175
+ CHANNELS = {chat.chat_id: chat.log_channel for chat in all_chats}
176
+ finally:
177
+ SESSION.close()
178
+
179
+
180
+ __load_log_channels()
Database/sql/nightmode_sql.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import Column, String
2
+
3
+ from Database.sql import BASE, SESSION
4
+
5
+
6
+ class Nightmode(BASE):
7
+ __tablename__ = "nightmode"
8
+ chat_id = Column(String(14), primary_key=True)
9
+
10
+ def __init__(self, chat_id):
11
+ self.chat_id = chat_id
12
+
13
+
14
+ Nightmode.__table__.create(checkfirst=True)
15
+
16
+
17
+ def add_nightmode(chat_id: str):
18
+ nightmoddy = Nightmode(str(chat_id))
19
+ SESSION.add(nightmoddy)
20
+ SESSION.commit()
21
+
22
+
23
+ def rmnightmode(chat_id: str):
24
+ rmnightmoddy = SESSION.query(Nightmode).get(str(chat_id))
25
+ if rmnightmoddy:
26
+ SESSION.delete(rmnightmoddy)
27
+ SESSION.commit()
28
+
29
+
30
+ def get_all_chat_id():
31
+ stark = SESSION.query(Nightmode).all()
32
+ SESSION.close()
33
+ return stark
34
+
35
+
36
+ def is_nightmode_indb(chat_id: str):
37
+ try:
38
+ s__ = SESSION.query(Nightmode).get(str(chat_id))
39
+ if s__:
40
+ return str(s__.chat_id)
41
+ finally:
42
+ SESSION.close()
Database/sql/notes_sql.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ # Note: chat_id's are stored as strings because the int is too large to be stored in a PSQL database.
26
+ import threading
27
+
28
+ from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText, distinct, func
29
+
30
+ from Database.sql import BASE, SESSION
31
+ from Mikobot.plugins.helper_funcs.msg_types import Types
32
+
33
+
34
+ class Notes(BASE):
35
+ __tablename__ = "notes"
36
+ chat_id = Column(String(14), primary_key=True)
37
+ name = Column(UnicodeText, primary_key=True)
38
+ value = Column(UnicodeText, nullable=False)
39
+ file = Column(UnicodeText)
40
+ is_reply = Column(Boolean, default=False)
41
+ has_buttons = Column(Boolean, default=False)
42
+ msgtype = Column(BigInteger, default=Types.BUTTON_TEXT.value)
43
+
44
+ def __init__(self, chat_id, name, value, msgtype, file=None):
45
+ self.chat_id = str(chat_id) # ensure string
46
+ self.name = name
47
+ self.value = value
48
+ self.msgtype = msgtype
49
+ self.file = file
50
+
51
+ def __repr__(self):
52
+ return "<ɴᴏᴛᴇ %s>" % self.name
53
+
54
+
55
+ class Buttons(BASE):
56
+ __tablename__ = "note_urls"
57
+ id = Column(BigInteger, primary_key=True, autoincrement=True)
58
+ chat_id = Column(String(14), primary_key=True)
59
+ note_name = Column(UnicodeText, 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, note_name, name, url, same_line=False):
65
+ self.chat_id = str(chat_id)
66
+ self.note_name = note_name
67
+ self.name = name
68
+ self.url = url
69
+ self.same_line = same_line
70
+
71
+
72
+ Notes.__table__.create(checkfirst=True)
73
+ Buttons.__table__.create(checkfirst=True)
74
+
75
+ NOTES_INSERTION_LOCK = threading.RLock()
76
+ BUTTONS_INSERTION_LOCK = threading.RLock()
77
+
78
+
79
+ def add_note_to_db(chat_id, note_name, note_data, msgtype, buttons=None, file=None):
80
+ if not buttons:
81
+ buttons = []
82
+
83
+ with NOTES_INSERTION_LOCK:
84
+ prev = SESSION.query(Notes).get((str(chat_id), note_name))
85
+ if prev:
86
+ with BUTTONS_INSERTION_LOCK:
87
+ prev_buttons = (
88
+ SESSION.query(Buttons)
89
+ .filter(
90
+ Buttons.chat_id == str(chat_id),
91
+ Buttons.note_name == note_name,
92
+ )
93
+ .all()
94
+ )
95
+ for btn in prev_buttons:
96
+ SESSION.delete(btn)
97
+ SESSION.delete(prev)
98
+ note = Notes(
99
+ str(chat_id),
100
+ note_name,
101
+ note_data or "",
102
+ msgtype=msgtype.value,
103
+ file=file,
104
+ )
105
+ SESSION.add(note)
106
+ SESSION.commit()
107
+
108
+ for b_name, url, same_line in buttons:
109
+ add_note_button_to_db(chat_id, note_name, b_name, url, same_line)
110
+
111
+
112
+ def get_note(chat_id, note_name):
113
+ try:
114
+ return (
115
+ SESSION.query(Notes)
116
+ .filter(func.lower(Notes.name) == note_name, Notes.chat_id == str(chat_id))
117
+ .first()
118
+ )
119
+ finally:
120
+ SESSION.close()
121
+
122
+
123
+ def rm_note(chat_id, note_name):
124
+ with NOTES_INSERTION_LOCK:
125
+ note = (
126
+ SESSION.query(Notes)
127
+ .filter(func.lower(Notes.name) == note_name, Notes.chat_id == str(chat_id))
128
+ .first()
129
+ )
130
+ if note:
131
+ with BUTTONS_INSERTION_LOCK:
132
+ buttons = (
133
+ SESSION.query(Buttons)
134
+ .filter(
135
+ Buttons.chat_id == str(chat_id),
136
+ Buttons.note_name == note_name,
137
+ )
138
+ .all()
139
+ )
140
+ for btn in buttons:
141
+ SESSION.delete(btn)
142
+
143
+ SESSION.delete(note)
144
+ SESSION.commit()
145
+ return True
146
+ SESSION.close()
147
+ return False
148
+
149
+
150
+ def get_all_chat_notes(chat_id):
151
+ try:
152
+ return (
153
+ SESSION.query(Notes)
154
+ .filter(Notes.chat_id == str(chat_id))
155
+ .order_by(Notes.name.asc())
156
+ .all()
157
+ )
158
+ finally:
159
+ SESSION.close()
160
+
161
+
162
+ def add_note_button_to_db(chat_id, note_name, b_name, url, same_line):
163
+ with BUTTONS_INSERTION_LOCK:
164
+ button = Buttons(chat_id, note_name, b_name, url, same_line)
165
+ SESSION.add(button)
166
+ SESSION.commit()
167
+
168
+
169
+ def get_buttons(chat_id, note_name):
170
+ try:
171
+ return (
172
+ SESSION.query(Buttons)
173
+ .filter(Buttons.chat_id == str(chat_id), Buttons.note_name == note_name)
174
+ .order_by(Buttons.id)
175
+ .all()
176
+ )
177
+ finally:
178
+ SESSION.close()
179
+
180
+
181
+ def num_notes():
182
+ try:
183
+ return SESSION.query(Notes).count()
184
+ finally:
185
+ SESSION.close()
186
+
187
+
188
+ def num_chats():
189
+ try:
190
+ return SESSION.query(func.count(distinct(Notes.chat_id))).scalar()
191
+ finally:
192
+ SESSION.close()
193
+
194
+
195
+ def migrate_chat(old_chat_id, new_chat_id):
196
+ with NOTES_INSERTION_LOCK:
197
+ chat_notes = (
198
+ SESSION.query(Notes).filter(Notes.chat_id == str(old_chat_id)).all()
199
+ )
200
+ for note in chat_notes:
201
+ note.chat_id = str(new_chat_id)
202
+
203
+ with BUTTONS_INSERTION_LOCK:
204
+ chat_buttons = (
205
+ SESSION.query(Buttons).filter(Buttons.chat_id == str(old_chat_id)).all()
206
+ )
207
+ for btn in chat_buttons:
208
+ btn.chat_id = str(new_chat_id)
209
+
210
+ SESSION.commit()
Database/sql/raid_sql.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import Column, String
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class RaidChats(BASE):
33
+ __tablename__ = "raid_chats"
34
+ chat_id = Column(String(14), primary_key=True)
35
+
36
+ def __init__(self, chat_id):
37
+ self.chat_id = chat_id
38
+
39
+
40
+ RaidChats.__table__.create(checkfirst=True)
41
+ INSERTION_LOCK = threading.RLock()
42
+
43
+
44
+ def is_raid(chat_id):
45
+ try:
46
+ chat = SESSION.query(RaidChats).get(str(chat_id))
47
+ return bool(chat)
48
+ finally:
49
+ SESSION.close()
50
+
51
+
52
+ def set_raid(chat_id):
53
+ with INSERTION_LOCK:
54
+ raidchat = SESSION.query(RaidChats).get(str(chat_id))
55
+ if not raidchat:
56
+ raidchat = RaidChats(str(chat_id))
57
+ SESSION.add(raidchat)
58
+ SESSION.commit()
59
+
60
+
61
+ def rem_raid(chat_id):
62
+ with INSERTION_LOCK:
63
+ raidchat = SESSION.query(RaidChats).get(str(chat_id))
64
+ if raidchat:
65
+ SESSION.delete(raidchat)
66
+ SESSION.commit()
67
+
68
+
69
+ def get_all_raid_chats():
70
+ try:
71
+ return SESSION.query(RaidChats.chat_id).all()
72
+ finally:
73
+ SESSION.close()
Database/sql/remind_sql.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+ import time
27
+
28
+ from sqlalchemy import Column, Integer, String, UnicodeText
29
+ from sqlalchemy.sql.sqltypes import BigInteger
30
+
31
+ from Database.sql import BASE, SESSION
32
+
33
+
34
+ class Reminds(BASE):
35
+ __tablename__ = "reminds"
36
+ chat_id = Column(String(14), primary_key=True)
37
+ time_seconds = Column(Integer, primary_key=True)
38
+ remind_message = Column(UnicodeText, default="")
39
+ user_id = Column(BigInteger, default=0)
40
+
41
+ def __init__(self, chat_id, time_seconds):
42
+ self.chat_id = str(chat_id)
43
+ self.time_seconds = int(time_seconds)
44
+
45
+ def __repr__(self):
46
+ return "<ʀᴇᴍɪɴᴅ ɪɴ {} ғᴏʀ ᴛɪᴍᴇ {}>".format(
47
+ self.chat_id,
48
+ self.time_seconds,
49
+ )
50
+
51
+
52
+ # Reminds.__table__.drop()
53
+ Reminds.__table__.create(checkfirst=True)
54
+
55
+ INSERTION_LOCK = threading.RLock()
56
+
57
+ REMINDERS = {}
58
+
59
+
60
+ def set_remind(chat_id, time_sec, remind_message, user_id):
61
+ with INSERTION_LOCK:
62
+ reminds = SESSION.query(Reminds).get((str(chat_id), time_sec))
63
+ if not reminds:
64
+ reminds = Reminds(chat_id, time_sec)
65
+ reminds.remind_message = remind_message
66
+ reminds.user_id = user_id
67
+ SESSION.add(reminds)
68
+ SESSION.commit()
69
+ if not time_sec in REMINDERS:
70
+ REMINDERS[time_sec] = []
71
+ REMINDERS[time_sec].append(
72
+ {"chat_id": str(chat_id), "message": remind_message, "user_id": user_id}
73
+ )
74
+
75
+
76
+ def rem_remind(chat_id, time_sec, remind_message, user_id):
77
+ with INSERTION_LOCK:
78
+ reminds = SESSION.query(Reminds).get((str(chat_id), time_sec))
79
+ if reminds:
80
+ SESSION.delete(reminds)
81
+ SESSION.commit()
82
+ REMINDERS[time_sec].remove(
83
+ {"chat_id": str(chat_id), "message": remind_message, "user_id": user_id}
84
+ )
85
+ return True
86
+ SESSION.close()
87
+ return False
88
+
89
+
90
+ def get_remind_in_chat(chat_id, timestamp):
91
+ return (
92
+ SESSION.query(Reminds)
93
+ .filter(Reminds.chat_id == str(chat_id), Reminds.time_seconds == timestamp)
94
+ .first()
95
+ )
96
+
97
+
98
+ def num_reminds_in_chat(chat_id):
99
+ return SESSION.query(Reminds).filter(Reminds.chat_id == str(chat_id)).count()
100
+
101
+
102
+ def get_reminds_in_chat(chat_id):
103
+ try:
104
+ return (
105
+ SESSION.query(Reminds)
106
+ .filter(Reminds.chat_id == str(chat_id))
107
+ .order_by(Reminds.time_seconds.asc())
108
+ .all()
109
+ )
110
+ finally:
111
+ SESSION.close()
112
+
113
+
114
+ def __get_all_reminds():
115
+ try:
116
+ chats = SESSION.query(Reminds).all()
117
+ for chat in chats:
118
+ if (chat.time_seconds <= round(time.time())) or chat.user_id == 0:
119
+ try:
120
+ rem_remind(
121
+ chat.chat_id,
122
+ chat.time_seconds,
123
+ chat.remind_message,
124
+ chat.user_id,
125
+ )
126
+ except:
127
+ pass
128
+ continue
129
+ REMINDERS[chat.time_seconds] = [
130
+ {
131
+ "chat_id": chat.chat_id,
132
+ "message": chat.remind_message,
133
+ "user_id": chat.user_id,
134
+ }
135
+ ]
136
+ finally:
137
+ SESSION.close()
138
+
139
+
140
+ __get_all_reminds()
Database/sql/reporting_sql.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Arsh
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+ from typing import Union
27
+
28
+ from sqlalchemy import BigInteger, Boolean, Column, String
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class ReportingUserSettings(BASE):
34
+ __tablename__ = "user_report_settings"
35
+ user_id = Column(BigInteger, primary_key=True)
36
+ should_report = Column(Boolean, default=True)
37
+
38
+ def __init__(self, user_id):
39
+ self.user_id = user_id
40
+
41
+ def __repr__(self):
42
+ return "<ᴜsᴇʀ ʀᴇᴘᴏʀᴛ sᴇᴛᴛɪɴɢs ({})>".format(self.user_id)
43
+
44
+
45
+ class ReportingChatSettings(BASE):
46
+ __tablename__ = "chat_report_settings"
47
+ chat_id = Column(String(14), primary_key=True)
48
+ should_report = Column(Boolean, default=True)
49
+
50
+ def __init__(self, chat_id):
51
+ self.chat_id = str(chat_id)
52
+
53
+ def __repr__(self):
54
+ return "<ᴄʜᴀᴛ ʀᴇᴘᴏʀᴛ sᴇᴛᴛɪɴɢs ({})>".format(self.chat_id)
55
+
56
+
57
+ ReportingUserSettings.__table__.create(checkfirst=True)
58
+ ReportingChatSettings.__table__.create(checkfirst=True)
59
+
60
+ CHAT_LOCK = threading.RLock()
61
+ USER_LOCK = threading.RLock()
62
+
63
+
64
+ def chat_should_report(chat_id: Union[str, int]) -> bool:
65
+ try:
66
+ chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id))
67
+ if chat_setting:
68
+ return chat_setting.should_report
69
+ return False
70
+ finally:
71
+ SESSION.close()
72
+
73
+
74
+ def user_should_report(user_id: int) -> bool:
75
+ try:
76
+ user_setting = SESSION.query(ReportingUserSettings).get(user_id)
77
+ if user_setting:
78
+ return user_setting.should_report
79
+ return True
80
+ finally:
81
+ SESSION.close()
82
+
83
+
84
+ def set_chat_setting(chat_id: Union[int, str], setting: bool):
85
+ with CHAT_LOCK:
86
+ chat_setting = SESSION.query(ReportingChatSettings).get(str(chat_id))
87
+ if not chat_setting:
88
+ chat_setting = ReportingChatSettings(chat_id)
89
+
90
+ chat_setting.should_report = setting
91
+ SESSION.add(chat_setting)
92
+ SESSION.commit()
93
+
94
+
95
+ def set_user_setting(user_id: int, setting: bool):
96
+ with USER_LOCK:
97
+ user_setting = SESSION.query(ReportingUserSettings).get(user_id)
98
+ if not user_setting:
99
+ user_setting = ReportingUserSettings(user_id)
100
+
101
+ user_setting.should_report = setting
102
+ SESSION.add(user_setting)
103
+ SESSION.commit()
104
+
105
+
106
+ def migrate_chat(old_chat_id, new_chat_id):
107
+ with CHAT_LOCK:
108
+ chat_notes = (
109
+ SESSION.query(ReportingChatSettings)
110
+ .filter(ReportingChatSettings.chat_id == str(old_chat_id))
111
+ .all()
112
+ )
113
+ for note in chat_notes:
114
+ note.chat_id = str(new_chat_id)
115
+ SESSION.commit()
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,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏᴏ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Column, UnicodeText
28
+
29
+ from Database.sql import BASE, SESSION
30
+
31
+
32
+ class UserInfo(BASE):
33
+ __tablename__ = "userinfo"
34
+ user_id = Column(BigInteger, primary_key=True)
35
+ info = Column(UnicodeText)
36
+
37
+ def __init__(self, user_id, info):
38
+ self.user_id = user_id
39
+ self.info = info
40
+
41
+ def __repr__(self):
42
+ return "<ᴜsᴇʀ ɪɴғᴏ %d>" % self.user_id
43
+
44
+
45
+ class UserBio(BASE):
46
+ __tablename__ = "userbio"
47
+ user_id = Column(BigInteger, primary_key=True)
48
+ bio = Column(UnicodeText)
49
+
50
+ def __init__(self, user_id, bio):
51
+ self.user_id = user_id
52
+ self.bio = bio
53
+
54
+ def __repr__(self):
55
+ return "<ᴜsᴇʀ ɪɴғᴏ %d>" % self.user_id
56
+
57
+
58
+ UserInfo.__table__.create(checkfirst=True)
59
+ UserBio.__table__.create(checkfirst=True)
60
+
61
+ INSERTION_LOCK = threading.RLock()
62
+
63
+
64
+ def get_user_me_info(user_id):
65
+ userinfo = SESSION.query(UserInfo).get(user_id)
66
+ SESSION.close()
67
+ if userinfo:
68
+ return userinfo.info
69
+ return None
70
+
71
+
72
+ def set_user_me_info(user_id, info):
73
+ with INSERTION_LOCK:
74
+ userinfo = SESSION.query(UserInfo).get(user_id)
75
+ if userinfo:
76
+ userinfo.info = info
77
+ else:
78
+ userinfo = UserInfo(user_id, info)
79
+ SESSION.add(userinfo)
80
+ SESSION.commit()
81
+
82
+
83
+ def get_user_bio(user_id):
84
+ userbio = SESSION.query(UserBio).get(user_id)
85
+ SESSION.close()
86
+ if userbio:
87
+ return userbio.bio
88
+ return None
89
+
90
+
91
+ def set_user_bio(user_id, bio):
92
+ with INSERTION_LOCK:
93
+ userbio = SESSION.query(UserBio).get(user_id)
94
+ if userbio:
95
+ userbio.bio = bio
96
+ else:
97
+ userbio = UserBio(user_id, bio)
98
+
99
+ SESSION.add(userbio)
100
+ SESSION.commit()
Database/sql/users_sql.py ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import (
28
+ BigInteger,
29
+ Column,
30
+ ForeignKey,
31
+ String,
32
+ UnicodeText,
33
+ UniqueConstraint,
34
+ func,
35
+ )
36
+
37
+ from Database.sql import BASE, SESSION
38
+ from Mikobot import dispatcher
39
+
40
+
41
+ class Users(BASE):
42
+ __tablename__ = "users"
43
+ user_id = Column(BigInteger, primary_key=True)
44
+ username = Column(UnicodeText)
45
+
46
+ def __init__(self, user_id, username=None):
47
+ self.user_id = user_id
48
+ self.username = username
49
+
50
+ def __repr__(self):
51
+ return "<ᴜsᴇʀ {} ({})>".format(self.username, self.user_id)
52
+
53
+
54
+ class Chats(BASE):
55
+ __tablename__ = "chats"
56
+ chat_id = Column(String(14), primary_key=True)
57
+ chat_name = Column(UnicodeText, nullable=False)
58
+
59
+ def __init__(self, chat_id, chat_name):
60
+ self.chat_id = str(chat_id)
61
+ self.chat_name = chat_name
62
+
63
+ def __repr__(self):
64
+ return "<ᴄʜᴀᴛ {} ({})>".format(self.chat_name, self.chat_id)
65
+
66
+
67
+ class ChatMembers(BASE):
68
+ __tablename__ = "chat_members"
69
+ priv_chat_id = Column(BigInteger, primary_key=True)
70
+ # NOTE: Use dual primary key instead of private primary key?
71
+ chat = Column(
72
+ String(14),
73
+ ForeignKey("chats.chat_id", onupdate="CASCADE", ondelete="CASCADE"),
74
+ nullable=False,
75
+ )
76
+ user = Column(
77
+ BigInteger,
78
+ ForeignKey("users.user_id", onupdate="CASCADE", ondelete="CASCADE"),
79
+ nullable=False,
80
+ )
81
+ __table_args__ = (UniqueConstraint("chat", "user", name="_chat_members_uc"),)
82
+
83
+ def __init__(self, chat, user):
84
+ self.chat = chat
85
+ self.user = user
86
+
87
+ def __repr__(self):
88
+ return "<ᴄʜᴀᴛ ᴜsᴇʀ {} ({}) ɪɴ ᴄʜᴀᴛ {} ({})>".format(
89
+ self.user.username,
90
+ self.user.user_id,
91
+ self.chat.chat_name,
92
+ self.chat.chat_id,
93
+ )
94
+
95
+
96
+ Users.__table__.create(checkfirst=True)
97
+ Chats.__table__.create(checkfirst=True)
98
+ ChatMembers.__table__.create(checkfirst=True)
99
+
100
+ INSERTION_LOCK = threading.RLock()
101
+
102
+
103
+ def ensure_bot_in_db():
104
+ with INSERTION_LOCK:
105
+ bot = Users(dispatcher.bot.id, dispatcher.bot.username)
106
+ SESSION.merge(bot)
107
+ SESSION.commit()
108
+
109
+
110
+ def update_user(user_id, username, chat_id=None, chat_name=None):
111
+ with INSERTION_LOCK:
112
+ user = SESSION.query(Users).get(user_id)
113
+ if not user:
114
+ user = Users(user_id, username)
115
+ SESSION.add(user)
116
+ SESSION.flush()
117
+ else:
118
+ user.username = username
119
+
120
+ if not chat_id or not chat_name:
121
+ SESSION.commit()
122
+ return
123
+
124
+ chat = SESSION.query(Chats).get(str(chat_id))
125
+ if not chat:
126
+ chat = Chats(str(chat_id), chat_name)
127
+ SESSION.add(chat)
128
+ SESSION.flush()
129
+
130
+ else:
131
+ chat.chat_name = chat_name
132
+
133
+ member = (
134
+ SESSION.query(ChatMembers)
135
+ .filter(ChatMembers.chat == chat.chat_id, ChatMembers.user == user.user_id)
136
+ .first()
137
+ )
138
+ if not member:
139
+ chat_member = ChatMembers(chat.chat_id, user.user_id)
140
+ SESSION.add(chat_member)
141
+
142
+ SESSION.commit()
143
+
144
+
145
+ def get_userid_by_name(username):
146
+ try:
147
+ return (
148
+ SESSION.query(Users)
149
+ .filter(func.lower(Users.username) == username.lower())
150
+ .all()
151
+ )
152
+ finally:
153
+ SESSION.close()
154
+
155
+
156
+ def get_name_by_userid(user_id):
157
+ try:
158
+ return SESSION.query(Users).get(Users.user_id == int(user_id)).first()
159
+ finally:
160
+ SESSION.close()
161
+
162
+
163
+ def get_chat_members(chat_id):
164
+ try:
165
+ return SESSION.query(ChatMembers).filter(ChatMembers.chat == str(chat_id)).all()
166
+ finally:
167
+ SESSION.close()
168
+
169
+
170
+ def get_all_chats():
171
+ try:
172
+ return SESSION.query(Chats).all()
173
+ finally:
174
+ SESSION.close()
175
+
176
+
177
+ def get_all_users():
178
+ try:
179
+ return SESSION.query(Users).all()
180
+ finally:
181
+ SESSION.close()
182
+
183
+
184
+ def get_user_num_chats(user_id):
185
+ try:
186
+ return (
187
+ SESSION.query(ChatMembers).filter(ChatMembers.user == int(user_id)).count()
188
+ )
189
+ finally:
190
+ SESSION.close()
191
+
192
+
193
+ def get_user_com_chats(user_id):
194
+ try:
195
+ chat_members = (
196
+ SESSION.query(ChatMembers).filter(ChatMembers.user == int(user_id)).all()
197
+ )
198
+ return [i.chat for i in chat_members]
199
+ finally:
200
+ SESSION.close()
201
+
202
+
203
+ def num_chats():
204
+ try:
205
+ return SESSION.query(Chats).count()
206
+ finally:
207
+ SESSION.close()
208
+
209
+
210
+ def num_users():
211
+ try:
212
+ return SESSION.query(Users).count()
213
+ finally:
214
+ SESSION.close()
215
+
216
+
217
+ def migrate_chat(old_chat_id, new_chat_id):
218
+ with INSERTION_LOCK:
219
+ chat = SESSION.query(Chats).get(str(old_chat_id))
220
+ if chat:
221
+ chat.chat_id = str(new_chat_id)
222
+ SESSION.commit()
223
+
224
+ chat_members = (
225
+ SESSION.query(ChatMembers)
226
+ .filter(ChatMembers.chat == str(old_chat_id))
227
+ .all()
228
+ )
229
+ for member in chat_members:
230
+ member.chat = str(new_chat_id)
231
+ SESSION.commit()
232
+
233
+
234
+ ensure_bot_in_db()
235
+
236
+
237
+ def del_user(user_id):
238
+ with INSERTION_LOCK:
239
+ curr = SESSION.query(Users).get(user_id)
240
+ if curr:
241
+ SESSION.delete(curr)
242
+ SESSION.commit()
243
+ return True
244
+
245
+ ChatMembers.query.filter(ChatMembers.user == user_id).delete()
246
+ SESSION.commit()
247
+ SESSION.close()
248
+ return False
249
+
250
+
251
+ def rem_chat(chat_id):
252
+ with INSERTION_LOCK:
253
+ chat = SESSION.query(Chats).get(str(chat_id))
254
+ if chat:
255
+ SESSION.delete(chat)
256
+ SESSION.commit()
257
+ else:
258
+ SESSION.close()
Database/sql/warns_sql.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import threading
26
+
27
+ from sqlalchemy import BigInteger, Boolean, Column, String, UnicodeText, distinct, func
28
+ from sqlalchemy.dialects import postgresql
29
+
30
+ from Database.sql import BASE, SESSION
31
+
32
+
33
+ class Warns(BASE):
34
+ __tablename__ = "warns"
35
+
36
+ user_id = Column(BigInteger, primary_key=True)
37
+ chat_id = Column(String(14), primary_key=True)
38
+ num_warns = Column(BigInteger, default=0)
39
+ reasons = Column(postgresql.ARRAY(UnicodeText))
40
+
41
+ def __init__(self, user_id, chat_id):
42
+ self.user_id = user_id
43
+ self.chat_id = str(chat_id)
44
+ self.num_warns = 0
45
+ self.reasons = []
46
+
47
+ def __repr__(self):
48
+ return "<{} ᴡᴀʀɴs ғᴏʀ {} ɪɴ {} ғᴏʀ ʀᴇᴀsᴏɴs {}>".format(
49
+ self.num_warns,
50
+ self.user_id,
51
+ self.chat_id,
52
+ self.reasons,
53
+ )
54
+
55
+
56
+ class WarnFilters(BASE):
57
+ __tablename__ = "warn_filters"
58
+ chat_id = Column(String(14), primary_key=True)
59
+ keyword = Column(UnicodeText, primary_key=True, nullable=False)
60
+ reply = Column(UnicodeText, nullable=False)
61
+
62
+ def __init__(self, chat_id, keyword, reply):
63
+ self.chat_id = str(chat_id) # ensure string
64
+ self.keyword = keyword
65
+ self.reply = reply
66
+
67
+ def __repr__(self):
68
+ return "<ᴘᴇʀᴍɪssɪᴏɴs ғᴏʀ %s>" % self.chat_id
69
+
70
+ def __eq__(self, other):
71
+ return bool(
72
+ isinstance(other, WarnFilters)
73
+ and self.chat_id == other.chat_id
74
+ and self.keyword == other.keyword,
75
+ )
76
+
77
+
78
+ class WarnSettings(BASE):
79
+ __tablename__ = "warn_settings"
80
+ chat_id = Column(String(14), primary_key=True)
81
+ warn_limit = Column(BigInteger, default=3)
82
+ soft_warn = Column(Boolean, default=False)
83
+
84
+ def __init__(self, chat_id, warn_limit=3, soft_warn=False):
85
+ self.chat_id = str(chat_id)
86
+ self.warn_limit = warn_limit
87
+ self.soft_warn = soft_warn
88
+
89
+ def __repr__(self):
90
+ return "<{} ʜᴀs {} ᴘᴏssɪʙʟᴇ ᴡᴀʀɴs.>".format(self.chat_id, self.warn_limit)
91
+
92
+
93
+ Warns.__table__.create(checkfirst=True)
94
+ WarnFilters.__table__.create(checkfirst=True)
95
+ WarnSettings.__table__.create(checkfirst=True)
96
+
97
+ WARN_INSERTION_LOCK = threading.RLock()
98
+ WARN_FILTER_INSERTION_LOCK = threading.RLock()
99
+ WARN_SETTINGS_LOCK = threading.RLock()
100
+
101
+ WARN_FILTERS = {}
102
+
103
+
104
+ def warn_user(user_id, chat_id, reason=None):
105
+ with WARN_INSERTION_LOCK:
106
+ warned_user = SESSION.query(Warns).get((user_id, str(chat_id)))
107
+ if not warned_user:
108
+ warned_user = Warns(user_id, str(chat_id))
109
+
110
+ warned_user.num_warns += 1
111
+ if reason:
112
+ warned_user.reasons = warned_user.reasons + [
113
+ reason,
114
+ ] # TODO:: double check this wizardry
115
+
116
+ reasons = warned_user.reasons
117
+ num = warned_user.num_warns
118
+
119
+ SESSION.add(warned_user)
120
+ SESSION.commit()
121
+
122
+ return num, reasons
123
+
124
+
125
+ def remove_warn(user_id, chat_id):
126
+ with WARN_INSERTION_LOCK:
127
+ removed = False
128
+ warned_user = SESSION.query(Warns).get((user_id, str(chat_id)))
129
+
130
+ if warned_user and warned_user.num_warns > 0:
131
+ warned_user.num_warns -= 1
132
+ warned_user.reasons = warned_user.reasons[:-1]
133
+ SESSION.add(warned_user)
134
+ SESSION.commit()
135
+ removed = True
136
+
137
+ SESSION.close()
138
+ return removed
139
+
140
+
141
+ def reset_warns(user_id, chat_id):
142
+ with WARN_INSERTION_LOCK:
143
+ warned_user = SESSION.query(Warns).get((user_id, str(chat_id)))
144
+ if warned_user:
145
+ warned_user.num_warns = 0
146
+ warned_user.reasons = []
147
+
148
+ SESSION.add(warned_user)
149
+ SESSION.commit()
150
+ SESSION.close()
151
+
152
+
153
+ def get_warns(user_id, chat_id):
154
+ try:
155
+ user = SESSION.query(Warns).get((user_id, str(chat_id)))
156
+ if not user:
157
+ return None
158
+ reasons = user.reasons
159
+ num = user.num_warns
160
+ return num, reasons
161
+ finally:
162
+ SESSION.close()
163
+
164
+
165
+ def add_warn_filter(chat_id, keyword, reply):
166
+ with WARN_FILTER_INSERTION_LOCK:
167
+ warn_filt = WarnFilters(str(chat_id), keyword, reply)
168
+
169
+ if keyword not in WARN_FILTERS.get(str(chat_id), []):
170
+ WARN_FILTERS[str(chat_id)] = sorted(
171
+ WARN_FILTERS.get(str(chat_id), []) + [keyword],
172
+ key=lambda x: (-len(x), x),
173
+ )
174
+
175
+ SESSION.merge(warn_filt) # merge to avoid duplicate key issues
176
+ SESSION.commit()
177
+
178
+
179
+ def remove_warn_filter(chat_id, keyword):
180
+ with WARN_FILTER_INSERTION_LOCK:
181
+ warn_filt = SESSION.query(WarnFilters).get((str(chat_id), keyword))
182
+ if warn_filt:
183
+ if keyword in WARN_FILTERS.get(str(chat_id), []): # sanity check
184
+ WARN_FILTERS.get(str(chat_id), []).remove(keyword)
185
+
186
+ SESSION.delete(warn_filt)
187
+ SESSION.commit()
188
+ return True
189
+ SESSION.close()
190
+ return False
191
+
192
+
193
+ def get_chat_warn_triggers(chat_id):
194
+ return WARN_FILTERS.get(str(chat_id), set())
195
+
196
+
197
+ def get_chat_warn_filters(chat_id):
198
+ try:
199
+ return (
200
+ SESSION.query(WarnFilters).filter(WarnFilters.chat_id == str(chat_id)).all()
201
+ )
202
+ finally:
203
+ SESSION.close()
204
+
205
+
206
+ def get_warn_filter(chat_id, keyword):
207
+ try:
208
+ return SESSION.query(WarnFilters).get((str(chat_id), keyword))
209
+ finally:
210
+ SESSION.close()
211
+
212
+
213
+ def set_warn_limit(chat_id, warn_limit):
214
+ with WARN_SETTINGS_LOCK:
215
+ curr_setting = SESSION.query(WarnSettings).get(str(chat_id))
216
+ if not curr_setting:
217
+ curr_setting = WarnSettings(chat_id, warn_limit=warn_limit)
218
+
219
+ curr_setting.warn_limit = warn_limit
220
+
221
+ SESSION.add(curr_setting)
222
+ SESSION.commit()
223
+
224
+
225
+ def set_warn_strength(chat_id, soft_warn):
226
+ with WARN_SETTINGS_LOCK:
227
+ curr_setting = SESSION.query(WarnSettings).get(str(chat_id))
228
+ if not curr_setting:
229
+ curr_setting = WarnSettings(chat_id, soft_warn=soft_warn)
230
+
231
+ curr_setting.soft_warn = soft_warn
232
+
233
+ SESSION.add(curr_setting)
234
+ SESSION.commit()
235
+
236
+
237
+ def get_warn_setting(chat_id):
238
+ try:
239
+ setting = SESSION.query(WarnSettings).get(str(chat_id))
240
+ if setting:
241
+ return setting.warn_limit, setting.soft_warn
242
+ return 3, False
243
+
244
+ finally:
245
+ SESSION.close()
246
+
247
+
248
+ def num_warns():
249
+ try:
250
+ return SESSION.query(func.sum(Warns.num_warns)).scalar() or 0
251
+ finally:
252
+ SESSION.close()
253
+
254
+
255
+ def num_warn_chats():
256
+ try:
257
+ return SESSION.query(func.count(distinct(Warns.chat_id))).scalar()
258
+ finally:
259
+ SESSION.close()
260
+
261
+
262
+ def num_warn_filters():
263
+ try:
264
+ return SESSION.query(WarnFilters).count()
265
+ finally:
266
+ SESSION.close()
267
+
268
+
269
+ def num_warn_chat_filters(chat_id):
270
+ try:
271
+ return (
272
+ SESSION.query(WarnFilters.chat_id)
273
+ .filter(WarnFilters.chat_id == str(chat_id))
274
+ .count()
275
+ )
276
+ finally:
277
+ SESSION.close()
278
+
279
+
280
+ def num_warn_filter_chats():
281
+ try:
282
+ return SESSION.query(func.count(distinct(WarnFilters.chat_id))).scalar()
283
+ finally:
284
+ SESSION.close()
285
+
286
+
287
+ def __load_chat_warn_filters():
288
+ global WARN_FILTERS
289
+ try:
290
+ chats = SESSION.query(WarnFilters.chat_id).distinct().all()
291
+ for (chat_id,) in chats: # remove tuple by ( ,)
292
+ WARN_FILTERS[chat_id] = []
293
+
294
+ all_filters = SESSION.query(WarnFilters).all()
295
+ for x in all_filters:
296
+ WARN_FILTERS[x.chat_id] += [x.keyword]
297
+
298
+ WARN_FILTERS = {
299
+ x: sorted(set(y), key=lambda i: (-len(i), i))
300
+ for x, y in WARN_FILTERS.items()
301
+ }
302
+
303
+ finally:
304
+ SESSION.close()
305
+
306
+
307
+ def migrate_chat(old_chat_id, new_chat_id):
308
+ with WARN_INSERTION_LOCK:
309
+ chat_notes = (
310
+ SESSION.query(Warns).filter(Warns.chat_id == str(old_chat_id)).all()
311
+ )
312
+ for note in chat_notes:
313
+ note.chat_id = str(new_chat_id)
314
+ SESSION.commit()
315
+
316
+ with WARN_FILTER_INSERTION_LOCK:
317
+ chat_filters = (
318
+ SESSION.query(WarnFilters)
319
+ .filter(WarnFilters.chat_id == str(old_chat_id))
320
+ .all()
321
+ )
322
+ for filt in chat_filters:
323
+ filt.chat_id = str(new_chat_id)
324
+ SESSION.commit()
325
+ old_warn_filt = WARN_FILTERS.get(str(old_chat_id))
326
+ if old_warn_filt is not None:
327
+ WARN_FILTERS[str(new_chat_id)] = old_warn_filt
328
+ del WARN_FILTERS[str(old_chat_id)]
329
+
330
+ with WARN_SETTINGS_LOCK:
331
+ chat_settings = (
332
+ SESSION.query(WarnSettings)
333
+ .filter(WarnSettings.chat_id == str(old_chat_id))
334
+ .all()
335
+ )
336
+ for setting in chat_settings:
337
+ setting.chat_id = str(new_chat_id)
338
+ SESSION.commit()
339
+
340
+
341
+ __load_chat_warn_filters()
Database/sql/welcome_sql.py ADDED
@@ -0,0 +1,507 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Aʙɪsʜɴᴏɪ
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ import random
26
+ import threading
27
+ from typing import Union
28
+
29
+ from sqlalchemy import BigInteger, Boolean, Column, Integer, String, UnicodeText
30
+
31
+ from Database.sql import BASE, SESSION
32
+ from Mikobot.plugins.helper_funcs.msg_types import Types
33
+
34
+ DEFAULT_WELCOME = "ʜᴇʏ {first}, ʜᴏᴡ ᴀʀᴇ ʏᴏᴜ?"
35
+ DEFAULT_GOODBYE = "ɴɪᴄᴇ ᴋɴᴏᴡɪɴɢ ʏᴀ!"
36
+
37
+ DEFAULT_WELCOME_MESSAGES = [
38
+ "{first} ɪs ʜᴇʀᴇ!", # Discord welcome messages copied
39
+ "ʀᴇᴀᴅʏ ᴘʟᴀʏᴇʀ {first}",
40
+ "ᴡᴇʟᴄᴏᴍᴇ ʙʀᴏ {first}",
41
+ ]
42
+
43
+ DEFAULT_GOODBYE_MESSAGES = [
44
+ "{first} ᴡɪʟʟ ʙᴇ ᴍɪssᴇᴅ.",
45
+ "{first} ᴡʜᴇɴ ʙᴀᴄᴋ ?.",
46
+ ]
47
+
48
+
49
+ class Welcome(BASE):
50
+ __tablename__ = "welcome_pref"
51
+ chat_id = Column(String(14), primary_key=True)
52
+ should_welcome = Column(Boolean, default=True)
53
+ should_goodbye = Column(Boolean, default=True)
54
+ custom_content = Column(UnicodeText, default=None)
55
+
56
+ custom_welcome = Column(
57
+ UnicodeText, default=random.choice(DEFAULT_WELCOME_MESSAGES)
58
+ )
59
+ welcome_type = Column(Integer, default=Types.TEXT.value)
60
+
61
+ custom_leave = Column(UnicodeText, default=random.choice(DEFAULT_GOODBYE_MESSAGES))
62
+ leave_type = Column(Integer, default=Types.TEXT.value)
63
+
64
+ clean_welcome = Column(BigInteger)
65
+
66
+ def __init__(self, chat_id, should_welcome=True, should_goodbye=True):
67
+ self.chat_id = chat_id
68
+ self.should_welcome = should_welcome
69
+ self.should_goodbye = should_goodbye
70
+
71
+ def __repr__(self):
72
+ return "<ᴄʜᴀᴛ {} sʜᴏᴜʟᴅ sʜᴏᴜʟᴅ ɴᴇᴡ ᴜsᴇʀs: {}>".format(
73
+ self.chat_id, self.should_welcome
74
+ )
75
+
76
+
77
+ class WelcomeButtons(BASE):
78
+ __tablename__ = "welcome_urls"
79
+ id = Column(Integer, primary_key=True, autoincrement=True)
80
+ chat_id = Column(String(14), primary_key=True)
81
+ name = Column(UnicodeText, nullable=False)
82
+ url = Column(UnicodeText, nullable=False)
83
+ same_line = Column(Boolean, default=False)
84
+
85
+ def __init__(self, chat_id, name, url, same_line=False):
86
+ self.chat_id = str(chat_id)
87
+ self.name = name
88
+ self.url = url
89
+ self.same_line = same_line
90
+
91
+
92
+ class GoodbyeButtons(BASE):
93
+ __tablename__ = "leave_urls"
94
+ id = Column(Integer, primary_key=True, autoincrement=True)
95
+ chat_id = Column(String(14), primary_key=True)
96
+ name = Column(UnicodeText, nullable=False)
97
+ url = Column(UnicodeText, nullable=False)
98
+ same_line = Column(Boolean, default=False)
99
+
100
+ def __init__(self, chat_id, name, url, same_line=False):
101
+ self.chat_id = str(chat_id)
102
+ self.name = name
103
+ self.url = url
104
+ self.same_line = same_line
105
+
106
+
107
+ class WelcomeMute(BASE):
108
+ __tablename__ = "welcome_mutes"
109
+ chat_id = Column(String(14), primary_key=True)
110
+ welcomemutes = Column(UnicodeText, default=False)
111
+
112
+ def __init__(self, chat_id, welcomemutes):
113
+ self.chat_id = str(chat_id) # ensure string
114
+ self.welcomemutes = welcomemutes
115
+
116
+
117
+ class WelcomeMuteUsers(BASE):
118
+ __tablename__ = "human_checks"
119
+ user_id = Column(BigInteger, primary_key=True)
120
+ chat_id = Column(String(14), primary_key=True)
121
+ human_check = Column(Boolean)
122
+
123
+ def __init__(self, user_id, chat_id, human_check):
124
+ self.user_id = user_id # ensure string
125
+ self.chat_id = str(chat_id)
126
+ self.human_check = human_check
127
+
128
+
129
+ class CleanServiceSetting(BASE):
130
+ __tablename__ = "clean_service"
131
+ chat_id = Column(String(14), primary_key=True)
132
+ clean_service = Column(Boolean, default=True)
133
+
134
+ def __init__(self, chat_id):
135
+ self.chat_id = str(chat_id)
136
+
137
+ def __repr__(self):
138
+ return "<ᴄʜᴀᴛ ᴜsᴇᴅ ᴄʟᴇᴀɴ sᴇʀᴠɪᴄᴇ ({})>".format(self.chat_id)
139
+
140
+
141
+ class RaidMode(BASE):
142
+ __tablename__ = "raid_mode"
143
+ chat_id = Column(String(14), primary_key=True)
144
+ status = Column(Boolean, default=False)
145
+ time = Column(Integer, default=21600)
146
+ acttime = Column(Integer, default=3600)
147
+ # permanent = Column(Boolean, default=False)
148
+
149
+ def __init__(self, chat_id, status, time, acttime):
150
+ self.chat_id = str(chat_id)
151
+ self.status = status
152
+ self.time = time
153
+ self.acttime = acttime
154
+ # self.permanent = permanent
155
+
156
+
157
+ Welcome.__table__.create(checkfirst=True)
158
+ WelcomeButtons.__table__.create(checkfirst=True)
159
+ GoodbyeButtons.__table__.create(checkfirst=True)
160
+ WelcomeMute.__table__.create(checkfirst=True)
161
+ WelcomeMuteUsers.__table__.create(checkfirst=True)
162
+ CleanServiceSetting.__table__.create(checkfirst=True)
163
+ RaidMode.__table__.create(checkfirst=True)
164
+
165
+ INSERTION_LOCK = threading.RLock()
166
+ WELC_BTN_LOCK = threading.RLock()
167
+ LEAVE_BTN_LOCK = threading.RLock()
168
+ WM_LOCK = threading.RLock()
169
+ CS_LOCK = threading.RLock()
170
+ RAID_LOCK = threading.RLock()
171
+
172
+
173
+ def welcome_mutes(chat_id):
174
+ try:
175
+ welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id))
176
+ if welcomemutes:
177
+ return welcomemutes.welcomemutes
178
+ return False
179
+ finally:
180
+ SESSION.close()
181
+
182
+
183
+ def set_welcome_mutes(chat_id, welcomemutes):
184
+ with WM_LOCK:
185
+ prev = SESSION.query(WelcomeMute).get((str(chat_id)))
186
+ if prev:
187
+ SESSION.delete(prev)
188
+ welcome_m = WelcomeMute(str(chat_id), welcomemutes)
189
+ SESSION.add(welcome_m)
190
+ SESSION.commit()
191
+
192
+
193
+ def set_human_checks(user_id, chat_id):
194
+ with INSERTION_LOCK:
195
+ human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id)))
196
+ if not human_check:
197
+ human_check = WelcomeMuteUsers(user_id, str(chat_id), True)
198
+
199
+ else:
200
+ human_check.human_check = True
201
+
202
+ SESSION.add(human_check)
203
+ SESSION.commit()
204
+
205
+ return human_check
206
+
207
+
208
+ def get_human_checks(user_id, chat_id):
209
+ try:
210
+ human_check = SESSION.query(WelcomeMuteUsers).get((user_id, str(chat_id)))
211
+ if not human_check:
212
+ return None
213
+ human_check = human_check.human_check
214
+ return human_check
215
+ finally:
216
+ SESSION.close()
217
+
218
+
219
+ def get_welc_mutes_pref(chat_id):
220
+ welcomemutes = SESSION.query(WelcomeMute).get(str(chat_id))
221
+ SESSION.close()
222
+
223
+ if welcomemutes:
224
+ return welcomemutes.welcomemutes
225
+
226
+ return False
227
+
228
+
229
+ def get_welc_pref(chat_id):
230
+ welc = SESSION.query(Welcome).get(str(chat_id))
231
+ SESSION.close()
232
+ if welc:
233
+ return (
234
+ welc.should_welcome,
235
+ welc.custom_welcome,
236
+ welc.custom_content,
237
+ welc.welcome_type,
238
+ )
239
+
240
+ else:
241
+ # Welcome by default.
242
+ return True, DEFAULT_WELCOME, None, Types.TEXT
243
+
244
+
245
+ def get_gdbye_pref(chat_id):
246
+ welc = SESSION.query(Welcome).get(str(chat_id))
247
+ SESSION.close()
248
+ if welc:
249
+ return welc.should_goodbye, welc.custom_leave, welc.leave_type
250
+ else:
251
+ # Welcome by default.
252
+ return True, DEFAULT_GOODBYE, Types.TEXT
253
+
254
+
255
+ def set_clean_welcome(chat_id, clean_welcome):
256
+ with INSERTION_LOCK:
257
+ curr = SESSION.query(Welcome).get(str(chat_id))
258
+ if not curr:
259
+ curr = Welcome(str(chat_id))
260
+
261
+ curr.clean_welcome = int(clean_welcome)
262
+
263
+ SESSION.add(curr)
264
+ SESSION.commit()
265
+
266
+
267
+ def get_clean_pref(chat_id):
268
+ welc = SESSION.query(Welcome).get(str(chat_id))
269
+ SESSION.close()
270
+
271
+ if welc:
272
+ return welc.clean_welcome
273
+
274
+ return False
275
+
276
+
277
+ def set_welc_preference(chat_id, should_welcome):
278
+ with INSERTION_LOCK:
279
+ curr = SESSION.query(Welcome).get(str(chat_id))
280
+ if not curr:
281
+ curr = Welcome(str(chat_id), should_welcome=should_welcome)
282
+ else:
283
+ curr.should_welcome = should_welcome
284
+
285
+ SESSION.add(curr)
286
+ SESSION.commit()
287
+
288
+
289
+ def set_gdbye_preference(chat_id, should_goodbye):
290
+ with INSERTION_LOCK:
291
+ curr = SESSION.query(Welcome).get(str(chat_id))
292
+ if not curr:
293
+ curr = Welcome(str(chat_id), should_goodbye=should_goodbye)
294
+ else:
295
+ curr.should_goodbye = should_goodbye
296
+
297
+ SESSION.add(curr)
298
+ SESSION.commit()
299
+
300
+
301
+ def set_custom_welcome(
302
+ chat_id, custom_content, custom_welcome, welcome_type, buttons=None
303
+ ):
304
+ if buttons is None:
305
+ buttons = []
306
+
307
+ with INSERTION_LOCK:
308
+ welcome_settings = SESSION.query(Welcome).get(str(chat_id))
309
+ if not welcome_settings:
310
+ welcome_settings = Welcome(str(chat_id), True)
311
+
312
+ if custom_welcome or custom_content:
313
+ welcome_settings.custom_content = custom_content
314
+ welcome_settings.custom_welcome = custom_welcome
315
+ welcome_settings.welcome_type = welcome_type.value
316
+
317
+ else:
318
+ welcome_settings.custom_welcome = DEFAULT_WELCOME
319
+ welcome_settings.welcome_type = Types.TEXT.value
320
+
321
+ SESSION.add(welcome_settings)
322
+
323
+ with WELC_BTN_LOCK:
324
+ prev_buttons = (
325
+ SESSION.query(WelcomeButtons)
326
+ .filter(WelcomeButtons.chat_id == str(chat_id))
327
+ .all()
328
+ )
329
+ for btn in prev_buttons:
330
+ SESSION.delete(btn)
331
+
332
+ for b_name, url, same_line in buttons:
333
+ button = WelcomeButtons(chat_id, b_name, url, same_line)
334
+ SESSION.add(button)
335
+
336
+ SESSION.commit()
337
+
338
+
339
+ def get_custom_welcome(chat_id):
340
+ welcome_settings = SESSION.query(Welcome).get(str(chat_id))
341
+ ret = DEFAULT_WELCOME
342
+ if welcome_settings and welcome_settings.custom_welcome:
343
+ ret = welcome_settings.custom_welcome
344
+
345
+ SESSION.close()
346
+ return ret
347
+
348
+
349
+ def set_custom_gdbye(chat_id, custom_goodbye, goodbye_type, buttons=None):
350
+ if buttons is None:
351
+ buttons = []
352
+
353
+ with INSERTION_LOCK:
354
+ welcome_settings = SESSION.query(Welcome).get(str(chat_id))
355
+ if not welcome_settings:
356
+ welcome_settings = Welcome(str(chat_id), True)
357
+
358
+ if custom_goodbye:
359
+ welcome_settings.custom_leave = custom_goodbye
360
+ welcome_settings.leave_type = goodbye_type.value
361
+
362
+ else:
363
+ welcome_settings.custom_leave = DEFAULT_GOODBYE
364
+ welcome_settings.leave_type = Types.TEXT.value
365
+
366
+ SESSION.add(welcome_settings)
367
+
368
+ with LEAVE_BTN_LOCK:
369
+ prev_buttons = (
370
+ SESSION.query(GoodbyeButtons)
371
+ .filter(GoodbyeButtons.chat_id == str(chat_id))
372
+ .all()
373
+ )
374
+ for btn in prev_buttons:
375
+ SESSION.delete(btn)
376
+
377
+ for b_name, url, same_line in buttons:
378
+ button = GoodbyeButtons(chat_id, b_name, url, same_line)
379
+ SESSION.add(button)
380
+
381
+ SESSION.commit()
382
+
383
+
384
+ def get_custom_gdbye(chat_id):
385
+ welcome_settings = SESSION.query(Welcome).get(str(chat_id))
386
+ ret = DEFAULT_GOODBYE
387
+ if welcome_settings and welcome_settings.custom_leave:
388
+ ret = welcome_settings.custom_leave
389
+
390
+ SESSION.close()
391
+ return ret
392
+
393
+
394
+ def get_welc_buttons(chat_id):
395
+ try:
396
+ return (
397
+ SESSION.query(WelcomeButtons)
398
+ .filter(WelcomeButtons.chat_id == str(chat_id))
399
+ .order_by(WelcomeButtons.id)
400
+ .all()
401
+ )
402
+ finally:
403
+ SESSION.close()
404
+
405
+
406
+ def get_gdbye_buttons(chat_id):
407
+ try:
408
+ return (
409
+ SESSION.query(GoodbyeButtons)
410
+ .filter(GoodbyeButtons.chat_id == str(chat_id))
411
+ .order_by(GoodbyeButtons.id)
412
+ .all()
413
+ )
414
+ finally:
415
+ SESSION.close()
416
+
417
+
418
+ def clean_service(chat_id: Union[str, int]) -> bool:
419
+ try:
420
+ chat_setting = SESSION.query(CleanServiceSetting).get(str(chat_id))
421
+ if chat_setting:
422
+ return chat_setting.clean_service
423
+ return False
424
+ finally:
425
+ SESSION.close()
426
+
427
+
428
+ def set_clean_service(chat_id: Union[int, str], setting: bool):
429
+ with CS_LOCK:
430
+ chat_setting = SESSION.query(CleanServiceSetting).get(str(chat_id))
431
+ if not chat_setting:
432
+ chat_setting = CleanServiceSetting(chat_id)
433
+
434
+ chat_setting.clean_service = setting
435
+ SESSION.add(chat_setting)
436
+ SESSION.commit()
437
+
438
+
439
+ def migrate_chat(old_chat_id, new_chat_id):
440
+ with INSERTION_LOCK:
441
+ chat = SESSION.query(Welcome).get(str(old_chat_id))
442
+ if chat:
443
+ chat.chat_id = str(new_chat_id)
444
+
445
+ with WELC_BTN_LOCK:
446
+ chat_buttons = (
447
+ SESSION.query(WelcomeButtons)
448
+ .filter(WelcomeButtons.chat_id == str(old_chat_id))
449
+ .all()
450
+ )
451
+ for btn in chat_buttons:
452
+ btn.chat_id = str(new_chat_id)
453
+
454
+ with LEAVE_BTN_LOCK:
455
+ chat_buttons = (
456
+ SESSION.query(GoodbyeButtons)
457
+ .filter(GoodbyeButtons.chat_id == str(old_chat_id))
458
+ .all()
459
+ )
460
+ for btn in chat_buttons:
461
+ btn.chat_id = str(new_chat_id)
462
+
463
+ SESSION.commit()
464
+
465
+
466
+ def getRaidStatus(chat_id):
467
+ try:
468
+ if stat := SESSION.query(RaidMode).get(str(chat_id)):
469
+ return stat.status, stat.time, stat.acttime
470
+ return False, 21600, 3600 # default
471
+ finally:
472
+ SESSION.close()
473
+
474
+
475
+ def setRaidStatus(chat_id, status, time=21600, acttime=3600):
476
+ with RAID_LOCK:
477
+ if prevObj := SESSION.query(RaidMode).get(str(chat_id)):
478
+ SESSION.delete(prevObj)
479
+ newObj = RaidMode(str(chat_id), status, time, acttime)
480
+ SESSION.add(newObj)
481
+ SESSION.commit()
482
+
483
+
484
+ def toggleRaidStatus(chat_id):
485
+ newObj = True
486
+ with RAID_LOCK:
487
+ prevObj = SESSION.query(RaidMode).get(str(chat_id))
488
+ if prevObj:
489
+ newObj = not prevObj.status
490
+ stat = RaidMode(
491
+ str(chat_id), newObj, prevObj.time or 21600, prevObj.acttime or 3600
492
+ )
493
+ SESSION.add(stat)
494
+ SESSION.commit()
495
+ return newObj
496
+
497
+
498
+ def _ResetRaidOnRestart():
499
+ with RAID_LOCK:
500
+ raid = SESSION.query(RaidMode).all()
501
+ for r in raid:
502
+ r.status = False
503
+ SESSION.commit()
504
+
505
+
506
+ # it uses a cron job to turn off so if the bot restarts and there is a pending raid disable job then raid will stay on
507
+ _ResetRaidOnRestart()
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11.9
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,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ FIRST_PART_TEXT = "✨ *ʜᴇʟʟᴏ* `{}` . . ."
36
+
37
+ PM_START_TEXT = "✨ *ɪ ᴀᴍ ᴍɪᴋᴏ, ᴀ ɢᴇɴꜱʜɪɴ ɪᴍᴘᴀᴄᴛ ᴛʜᴇᴍᴇᴅ ʀᴏʙᴏᴛ ᴡʜɪᴄʜ ᴄᴀɴ ʜᴇʟᴘ ʏᴏᴜ ᴛᴏ ᴍᴀɴᴀɢᴇ ᴀɴᴅ ꜱᴇᴄᴜʀᴇ ʏᴏᴜʀ ɢʀᴏᴜᴘ ᴡɪᴛʜ ʜᴜɢᴇ ɢʀᴏᴜᴘ ᴍᴀɴᴀɢᴇᴍᴇɴᴛ*"
38
+
39
+ START_BTN = [
40
+ [
41
+ InlineKeyboardButton(
42
+ text="⇦ ADD ME ⇨",
43
+ url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
44
+ ),
45
+ ],
46
+ [
47
+ InlineKeyboardButton(text="HELP", callback_data="extra_command_handler"),
48
+ ],
49
+ [
50
+ InlineKeyboardButton(text="DETAILS", callback_data="Miko_"),
51
+ InlineKeyboardButton(text="SOURCE", callback_data="git_source"),
52
+ ],
53
+ [
54
+ InlineKeyboardButton(text="CREATOR", url=f"tg://user?id={OWNER_ID}"),
55
+ ],
56
+ ]
57
+
58
+ GROUP_START_BTN = [
59
+ [
60
+ InlineKeyboardButton(
61
+ text="⇦ ADD ME ⇨",
62
+ url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
63
+ ),
64
+ ],
65
+ [
66
+ InlineKeyboardButton(text="SUPPORT", url=f"https://t.me/{SUPPORT_CHAT}"),
67
+ InlineKeyboardButton(text="CREATOR", url=f"tg://user?id={OWNER_ID}"),
68
+ ],
69
+ ]
70
+
71
+ ALIVE_BTN = [
72
+ [
73
+ ib(text="UPDATES", url="https://t.me/Hydra_Updates"),
74
+ ib(text="SUPPORT", url="https://t.me/hydraXsupport"),
75
+ ],
76
+ [
77
+ ib(
78
+ text="⇦ ADD ME ⇨",
79
+ url=f"https://t.me/{BOT_USERNAME}?startgroup=true",
80
+ ),
81
+ ],
82
+ ]
83
+
84
+ HELP_STRINGS = """
85
+ 🫧 *Yae-Miko* 🫧 [ㅤ](https://telegra.ph/file/b05535884267a19ee5c93.jpg)
86
+
87
+ ☉ *Here, you will find a list of all the available commands.*
88
+
89
+ ᴀʟʟ ᴄᴏᴍᴍᴀɴᴅs ᴄᴀɴ ʙᴇ ᴜsᴇᴅ ᴡɪᴛʜ : /
90
+ """