Skip to content

Commit dadfd61

Browse files
committed
Implement persistent mutes on rejoin
1 parent ffef9bb commit dadfd61

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

mutes/info.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"author" : ["Cog Creators"],
3+
"name" : "mutes",
4+
"description" : "Copy of Redbot's mutes cog with custom changes",
5+
"requirements": ["aiosqlite"]
6+
}

mutes/mutes.py

+67-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import contextlib
33
import discord
44
import logging
5+
import aiosqlite
56

67
from abc import ABC
78
from typing import cast, Optional, Dict, List, Tuple, Literal, Union
@@ -11,7 +12,7 @@
1112
from .voicemutes import VoiceMutes
1213

1314
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
1516
from redbot.core.utils import AsyncIter, bounded_gather
1617
from redbot.core.utils.chat_formatting import (
1718
bold,
@@ -108,6 +109,8 @@ def __init__(self, bot: Red):
108109
# to wait for a guild to finish channel unmutes before
109110
# checking for manual overwrites
110111

112+
self.db_path = data_manager.cog_data_path(self) / "mutes.db"
113+
111114
self._init_task = asyncio.create_task(self._initialize())
112115

113116
async def red_delete_data_for_user(
@@ -149,6 +152,12 @@ async def _initialize(self):
149152
self._channel_mutes[c_id][int(user_id)] = mute
150153
self._unmute_task = asyncio.create_task(self._handle_automatic_unmute())
151154
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()
152161

153162
async def _maybe_update_config(self):
154163
schema_version = await self.config.schema_version()
@@ -641,6 +650,27 @@ async def on_member_update(self, before: discord.Member, after: discord.Member):
641650
)
642651
if should_save:
643652
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()
644674

645675
@commands.Cog.listener()
646676
async def on_guild_channel_update(
@@ -743,6 +773,25 @@ async def on_member_join(self, member: discord.Member):
743773
await self.mute_user(
744774
guild, guild.me, member, until, _("Previously muted in this server.")
745775
)
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))
746795

747796
@commands.group()
748797
@commands.guild_only()
@@ -1545,11 +1594,14 @@ async def mute_user(
15451594
self._server_mutes[guild.id][user.id] = {
15461595
"author": author.id,
15471596
"member": user.id,
1548-
"until": until.timestamp() if until else None,
1597+
"until": until.timestamp() if until else 0,
15491598
}
15501599
try:
15511600
await user.add_roles(role, reason=reason)
15521601
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()
15531605
except discord.errors.Forbidden:
15541606
if guild.id in self._server_mutes and user.id in self._server_mutes[guild.id]:
15551607
del self._server_mutes[guild.id][user.id]
@@ -1609,6 +1661,9 @@ async def unmute_user(
16091661
if guild.id in self._server_mutes:
16101662
if user.id in self._server_mutes[guild.id]:
16111663
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()
16121667
if not guild.me.guild_permissions.manage_roles or role >= guild.me.top_role:
16131668
ret["reason"] = _(MUTE_UNMUTE_ISSUES["permissions_issue_role"])
16141669
return ret
@@ -1630,6 +1685,9 @@ async def unmute_user(
16301685
else:
16311686
ret["success"] = True
16321687
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()
16331691
return ret
16341692

16351693
async def channel_mute_user(
@@ -1689,12 +1747,15 @@ async def channel_mute_user(
16891747
"author": author.id,
16901748
"guild": guild.id,
16911749
"member": user.id,
1692-
"until": until.timestamp() if until else None,
1750+
"until": until.timestamp() if until else 0,
16931751
}
16941752
try:
16951753
await channel.set_permissions(user, overwrite=overwrites, reason=reason)
16961754
async with self.config.channel(channel).muted_users() as muted_users:
16971755
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()
16981759
except discord.NotFound as e:
16991760
if channel.id in self._channel_mutes and user.id in self._channel_mutes[channel.id]:
17001761
del self._channel_mutes[channel.id][user.id]
@@ -1772,6 +1833,9 @@ async def channel_unmute_user(
17721833
overwrites.update(**old_values)
17731834
if channel.id in self._channel_mutes and user.id in self._channel_mutes[channel.id]:
17741835
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()
17751839
else:
17761840
return {
17771841
"success": False,

0 commit comments

Comments
 (0)