2
2
import contextlib
3
3
import discord
4
4
import logging
5
+ import aiosqlite
5
6
6
7
from abc import ABC
7
8
from typing import cast , Optional , Dict , List , Tuple , Literal , Union
11
12
from .voicemutes import VoiceMutes
12
13
13
14
from redbot .core .bot import Red
14
- from redbot .core import commands , checks , i18n , modlog , Config
15
+ from redbot .core import commands , checks , i18n , modlog , Config , data_manager
15
16
from redbot .core .utils import AsyncIter , bounded_gather
16
17
from redbot .core .utils .chat_formatting import (
17
18
bold ,
@@ -108,6 +109,8 @@ def __init__(self, bot: Red):
108
109
# to wait for a guild to finish channel unmutes before
109
110
# checking for manual overwrites
110
111
112
+ self .db_path = data_manager .cog_data_path (self ) / "mutes.db"
113
+
111
114
self ._init_task = asyncio .create_task (self ._initialize ())
112
115
113
116
async def red_delete_data_for_user (
@@ -149,6 +152,12 @@ async def _initialize(self):
149
152
self ._channel_mutes [c_id ][int (user_id )] = mute
150
153
self ._unmute_task = asyncio .create_task (self ._handle_automatic_unmute ())
151
154
self ._ready .set ()
155
+
156
+ async with aiosqlite .connect (self .db_path ) as db :
157
+ await db .execute ("CREATE TABLE IF NOT EXISTS global_mutes (user_id INTEGER NOT NULL PRIMARY KEY, author_id INTEGER, guild_id INTEGER, until INTEGER, reason TEXT)" )
158
+ await db .execute ("CREATE TABLE IF NOT EXISTS channel_mutes (user_id INTEGER NOT NULL, author_id INTEGER, channel_id INTEGER NOT NULL, guild_id INTEGER, until INTEGER, reason TEXT)" )
159
+ await db .execute ("CREATE INDEX IF NOT EXISTS idx_cmuid ON channel_mutes (user_id)" )
160
+ await db .commit ()
152
161
153
162
async def _maybe_update_config (self ):
154
163
schema_version = await self .config .schema_version ()
@@ -641,6 +650,27 @@ async def on_member_update(self, before: discord.Member, after: discord.Member):
641
650
)
642
651
if should_save :
643
652
await self .config .guild (guild ).muted_users .set (self ._server_mutes [guild .id ])
653
+ asyncio .create_task (self .check_channel_mutes (after ))
654
+
655
+ async def check_channel_mutes (self , member : discord .Member ):
656
+ async with aiosqlite .connect (self .db_path ) as db :
657
+ async with db .execute ("SELECT * FROM channel_mutes WHERE user_id = ?" , (member .id ,)) as cursor :
658
+ rows = await cursor .fetchall ()
659
+ for row in rows :
660
+ data = {
661
+ "author_id" : row [1 ],
662
+ "channel_id" : row [2 ],
663
+ "guild_id" : row [3 ],
664
+ "until" : row [4 ],
665
+ "reason" : row [5 ],
666
+ }
667
+ time_to_unmute = (data ["until" ] - datetime .now (timezone .utc ).timestamp ())
668
+ if time_to_unmute > 0 :
669
+ guild = self .bot .get_guild (data ["guild_id" ])
670
+ await self .channel_mute_user (guild , self .bot .get_channel (data ["channel_id" ]), guild .get_member (data ["author_id" ]), guild .get_member (member .id ), datetime .fromtimestamp (data ["until" ]), data ["reason" ])
671
+ else :
672
+ await db .execute ("DELETE FROM channel_mutes WHERE user_id = ? AND channel_id = ?" , (member .id , data ["channel_id" ]))
673
+ await db .commit ()
644
674
645
675
@commands .Cog .listener ()
646
676
async def on_guild_channel_update (
@@ -743,6 +773,25 @@ async def on_member_join(self, member: discord.Member):
743
773
await self .mute_user (
744
774
guild , guild .me , member , until , _ ("Previously muted in this server." )
745
775
)
776
+ async with aiosqlite .connect (self .db_path ) as db :
777
+ async with db .execute ("SELECT * FROM global_mutes WHERE user_id = ?" , (member .id ,)) as cursor :
778
+ row = await cursor .fetchone ()
779
+ if row :
780
+ data = {
781
+ "user_id" : row [0 ],
782
+ "author_id" : row [1 ],
783
+ "guild_id" : row [2 ],
784
+ "until" : row [3 ],
785
+ "reason" : row [4 ],
786
+ }
787
+ time_to_unmute = (data ["until" ] - datetime .now (timezone .utc ).timestamp ())
788
+ if time_to_unmute > 0 :
789
+ this_guild = self .bot .get_guild (data ["guild_id" ])
790
+ await self .mute_user (this_guild , this_guild .get_member (data ["author_id" ]), this_guild .get_member (member .id ), datetime .fromtimestamp (data ["until" ]), data ["reason" ])
791
+ else :
792
+ await db .execute ("DELETE FROM global_mutes WHERE user_id = ?" , (member .id ))
793
+ await db .commit ()
794
+ asyncio .create_task (self .check_channel_mutes (member ))
746
795
747
796
@commands .group ()
748
797
@commands .guild_only ()
@@ -1545,11 +1594,14 @@ async def mute_user(
1545
1594
self ._server_mutes [guild .id ][user .id ] = {
1546
1595
"author" : author .id ,
1547
1596
"member" : user .id ,
1548
- "until" : until .timestamp () if until else None ,
1597
+ "until" : until .timestamp () if until else 0 ,
1549
1598
}
1550
1599
try :
1551
1600
await user .add_roles (role , reason = reason )
1552
1601
await self .config .guild (guild ).muted_users .set (self ._server_mutes [guild .id ])
1602
+ async with aiosqlite .connect (self .db_path ) as db :
1603
+ await db .execute ("INSERT INTO global_mutes (user_id, author_id, guild_id, until, reason) VALUES (?, ?, ?, ?, ?) ON CONFLICT(user_id) DO UPDATE SET author_id = ?, until = ?, reason = ?" , (user .id , author .id , guild .id , until .timestamp () if until else 0 , reason , author .id , until .timestamp () if until else 0 , reason if reason else "" ))
1604
+ await db .commit ()
1553
1605
except discord .errors .Forbidden :
1554
1606
if guild .id in self ._server_mutes and user .id in self ._server_mutes [guild .id ]:
1555
1607
del self ._server_mutes [guild .id ][user .id ]
@@ -1609,6 +1661,9 @@ async def unmute_user(
1609
1661
if guild .id in self ._server_mutes :
1610
1662
if user .id in self ._server_mutes [guild .id ]:
1611
1663
del self ._server_mutes [guild .id ][user .id ]
1664
+ async with aiosqlite .connect (self .db_path ) as db :
1665
+ await db .execute ("DELETE FROM global_mutes WHERE user_id = ?" , (user .id ))
1666
+ await db .commit ()
1612
1667
if not guild .me .guild_permissions .manage_roles or role >= guild .me .top_role :
1613
1668
ret ["reason" ] = _ (MUTE_UNMUTE_ISSUES ["permissions_issue_role" ])
1614
1669
return ret
@@ -1630,6 +1685,9 @@ async def unmute_user(
1630
1685
else :
1631
1686
ret ["success" ] = True
1632
1687
await self .config .member (user ).clear ()
1688
+ async with aiosqlite .connect (self .db_path ) as db :
1689
+ await db .execute ("DELETE FROM global_mutes WHERE user_id = ?" , (user .id ))
1690
+ await db .commit ()
1633
1691
return ret
1634
1692
1635
1693
async def channel_mute_user (
@@ -1689,12 +1747,15 @@ async def channel_mute_user(
1689
1747
"author" : author .id ,
1690
1748
"guild" : guild .id ,
1691
1749
"member" : user .id ,
1692
- "until" : until .timestamp () if until else None ,
1750
+ "until" : until .timestamp () if until else 0 ,
1693
1751
}
1694
1752
try :
1695
1753
await channel .set_permissions (user , overwrite = overwrites , reason = reason )
1696
1754
async with self .config .channel (channel ).muted_users () as muted_users :
1697
1755
muted_users [str (user .id )] = self ._channel_mutes [channel .id ][user .id ]
1756
+ async with aiosqlite .connect (self .db_path ) as db :
1757
+ await db .execute ("INSERT INTO channel_mutes (user_id, author_id, channel_id, guild_id, until, reason) VALUES (?, ?, ?, ?, ?, ?)" , (user .id , author .id , channel .id , guild .id , until .timestamp () if until else 0 , reason if reason else "" ))
1758
+ await db .commit ()
1698
1759
except discord .NotFound as e :
1699
1760
if channel .id in self ._channel_mutes and user .id in self ._channel_mutes [channel .id ]:
1700
1761
del self ._channel_mutes [channel .id ][user .id ]
@@ -1772,6 +1833,9 @@ async def channel_unmute_user(
1772
1833
overwrites .update (** old_values )
1773
1834
if channel .id in self ._channel_mutes and user .id in self ._channel_mutes [channel .id ]:
1774
1835
del self ._channel_mutes [channel .id ][user .id ]
1836
+ async with aiosqlite .connect (self .db_path ) as db :
1837
+ await db .execute ("DELETE FROM channel_mutes WHERE user_id = ? AND channel_id = ?" , (user .id , channel .id ))
1838
+ await db .commit ()
1775
1839
else :
1776
1840
return {
1777
1841
"success" : False ,
0 commit comments