From e9f7b86be9c1e13993077e1f897478e5fc8d44ed Mon Sep 17 00:00:00 2001 From: brandons209 Date: Thu, 29 Oct 2020 04:36:43 -0400 Subject: [PATCH] big 3.4 update part 1, still need to add data removal handling --- Leveler/info.json | 5 +- Leveler/leveler.py | 9 ++- activitylog/activitylog.py | 132 +++++++++++++++------------------ activitylog/info.json | 8 +- activitylog/time_utils.py | 59 --------------- activitylog/utils.py | 112 ++++++++++++++++++++++++++++ birthday/birthday.py | 4 +- birthday/info.json | 5 +- confession/info.json | 5 +- costmanager/info.json | 5 +- costmanager/manager.py | 6 +- disable/disable.py | 2 + disable/info.json | 5 +- economytrickle/core.py | 2 + economytrickle/info.json | 3 +- emoji/info.json | 4 +- isolate/info.json | 5 +- isolate/isolate.py | 10 +++ isolate/utils.py | 6 +- markov/info.json | 5 +- markov/markov.py | 4 +- moreadmin/info.json | 5 +- moreadmin/moreadmin.py | 16 +++- nitroemoji/info.json | 5 +- nitroemoji/nitroemoji.py | 6 ++ personalroles/info.json | 4 +- personalroles/personalroles.py | 6 ++ pony/info.json | 5 +- punish/info.json | 5 +- punish/punish.py | 12 ++- punish/utils.py | 6 +- reactpoll/info.json | 4 +- reactpoll/reactpoll.py | 4 + rolemanagement/events.py | 9 +++ rolemanagement/info.json | 3 +- rolemanagement/massmanager.py | 7 +- roleplay/info.json | 19 +++++ roletracker/info.json | 12 +-- roletracker/roletracker.py | 2 + rules/info.json | 5 +- scheduler/info.json | 2 +- scheduler/scheduler.py | 2 +- sfx/info.json | 5 +- smartreact/info.json | 4 +- smartreact/smartreact.py | 2 + trickortreat/info.json | 5 +- welcome/info.json | 7 +- welcome/welcome.py | 14 +++- 48 files changed, 370 insertions(+), 202 deletions(-) delete mode 100644 activitylog/time_utils.py create mode 100644 activitylog/utils.py create mode 100644 roleplay/info.json diff --git a/Leveler/info.json b/Leveler/info.json index bb23044..30b0596 100644 --- a/Leveler/info.json +++ b/Leveler/info.json @@ -1,11 +1,12 @@ { "author": ["Malarne (Malarne#1418)"], - "min_bot_version": "3.0.2", + "min_bot_version": "3.4.0", "description": "A leveler cog for Red V3\nInspired by Stevy's v2 leveler cog\nPlease consult the docs at ayrobot.netlify.com for setup informations.\nThanks for using my cog !\nNB:Channel whitelist is enabled by default, you can manage that under `[p]levelerset channel whitelist` command !", "hidden": false, "install_msg": "Thank you for installing this leveler !\nPlease consult the docs at https://discord-cogs.readthedocs.io/en/latest/leveler.html for setup informations.\nPlease note that this cog come with bundled data, mostly the font for profile image.", "required_cogs": {}, "requirements": ["pillow"], "short": "Leveler tool, better than MEE6", - "tags": ["leveler", "pillow", "fun"] + "tags": ["leveler", "pillow", "fun"], + "end_user_data_statement": "Stores some level info like experience, profile description/picture, and message ID of user's last message in guild." } diff --git a/Leveler/leveler.py b/Leveler/leveler.py index 1d2402c..48f5698 100644 --- a/Leveler/leveler.py +++ b/Leveler/leveler.py @@ -287,6 +287,8 @@ class Leveler(commands.Cog): await ctx.send(file=discord.File(img)) async def listener(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return if type(message.author) != discord.Member: # throws an error when webhooks talk, this fixes it return @@ -330,7 +332,10 @@ class Leveler(commands.Cog): await self.profiles._set_user_lastmessage(message.author, timenow) lvl = await self.profiles._get_level(message.author) if lvl == oldlvl + 1 and await self.profiles.data.guild(message.guild).lvlup_announce(): - await message.channel.send(_("{} is now level {} !".format(message.author.mention, lvl))) + await message.channel.send( + _("{} is now level {} !".format(message.author.mention, lvl)), + allowed_mentions=discord.AllowedMentions.all(), + ) await self.profiles._check_exp(message.author) await self.profiles._check_role_member(message.author) @@ -644,5 +649,7 @@ class Leveler(commands.Cog): # Listeners @commands.Cog.listener() async def on_member_remove(self, member): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return # reset level stats on leave. await self.profiles.data.member(member).clear() diff --git a/activitylog/activitylog.py b/activitylog/activitylog.py index 4da6021..ba37f1a 100644 --- a/activitylog/activitylog.py +++ b/activitylog/activitylog.py @@ -5,13 +5,14 @@ from redbot.core.data_manager import cog_data_path from redbot.core.utils.mod import is_mod_or_superior import discord -from .time_utils import * +from .utils import * from datetime import datetime from dateutil.relativedelta import relativedelta import time import os import asyncio import glob +import io # plotting from bisect import bisect_left @@ -46,66 +47,6 @@ DELETE_AUDIT_TEMPLATE = "@{0.name}#{0.discriminator}(id:{0.id}) deleted message MAX_LINES = 50000 -def get_all_names(guild_files, user): - names = [str(user)] - for log in guild_files: - if not os.path.exists(log): - continue - with open(log, "r") as f: - for line in f: - if str(user.id) in line: - # user change their name - if "Member username:" in line: - username = line.strip().split('"') - discrim = username[1].split("#")[-1] - username = username[-2] + "#" + discrim - names.append(username) - # user changed their 4 digit discriminator - elif "Member discriminator:" in line: - username = line.strip().split('"')[-2] - names.append(username) - # starting name - elif "Member join:" in line: - username = line.strip().split("@")[-1].split("#") - username = username[0] + "#" + username[1].split(" ")[0] - if username is not str(user): - names.append(username) - return set(names) - - -def format_list(*items, join="and", delim=", "): - if len(items) > 1: - return (" %s " % join).join((delim.join(items[:-1]), items[-1])) - elif items: - return items[0] - else: - return "" - - -class LogHandle: - """basic wrapper for logfile handles, used to keep track of stale handles""" - - def __init__(self, path, time=None, mode="a", buf=1): - self.handle = open(path, mode, buf, errors="backslashreplace") - self.lock = asyncio.Lock() - - if time: - self.time = time - else: - self.time = datetime.fromtimestamp(os.path.getmtime(path)) - - async def write(self, value): - async with self.lock: - self._write(value) - - def close(self): - self.handle.close() - - def _write(self, value): - self.time = datetime.utcnow() - self.handle.write(value) - - class ActivityLogger(commands.Cog): """Log activity seen by bot""" @@ -259,7 +200,7 @@ class ActivityLogger(commands.Cog): if is_mod: try: - await ctx.send(embed=data) + await ctx.send(embed=data, allowed_mentions=discord.AllowedMentions.all()) except discord.HTTPException: await ctx.send("I need the `Embed links` permission to send this") else: @@ -317,19 +258,10 @@ class ActivityLogger(commands.Cog): ) msg += f"Bans: `{bans}`, Kicks: `{kicks}`, Mutes: `{mutes}`, Warnings: `{warns}`" if len(names) > 1: - return msg, format_list(*names) + return msg, humanize_list(names) return msg, None - @commands.command(name="fixavglen") - @checks.is_owner() - async def fixavglen(self, ctx): - for guild in self.bot.guilds: - for member in guild.members: - async with self.config.member(member).stats() as stats: - stats["avg_len"] = stats["total_msg"] - stats["bot_cmd"] - await ctx.tick() - @commands.command(name="graphstats") @checks.mod() @commands.guild_only() @@ -1141,14 +1073,14 @@ class ActivityLogger(commands.Cog): await self.config.guild(ctx.guild).prefixes.set([ctx.clean_prefix]) self.cache[ctx.guild.id]["prefixes"] = [ctx.clean_prefix] return - await ctx.send("Current Prefixes: " + format_list(*curr, delim=", ")) + await ctx.send("Current Prefixes: " + humanize_list(curr)) return prefixes = [p for p in prefixes.split(" ")] await self.config.guild(ctx.guild).prefixes.set(prefixes) self.cache[ctx.guild.id]["prefixes"] = prefixes prefixes = [f"`{p}`" for p in prefixes] - await ctx.send("Prefixes set to: " + format_list(*prefixes, delim=", ")) + await ctx.send("Prefixes set to: " + humanize_list(prefixes)) @logset.command(name="rotation") async def set_rotation(self, ctx, freq: str = None): @@ -1434,16 +1366,22 @@ class ActivityLogger(commands.Cog): # Listeners @commands.Cog.listener() async def on_message(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return await self.message_handler(message) @commands.Cog.listener() async def on_message_edit(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return timestamp = before.created_at.strftime(TIMESTAMP_FORMAT) entry = EDIT_TEMPLATE.format(before, after, timestamp) await self.log(after.channel, entry, after.edited_at) @commands.Cog.listener() async def on_message_delete(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return entry_s = None timestamp = message.created_at.strftime(TIMESTAMP_FORMAT) try: @@ -1468,16 +1406,22 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_join(self, guild): + if await self.bot.cog_disabled_in_guild(self, guild): + return entry = "this bot joined the guild" await self.log(guild, entry) @commands.Cog.listener() async def on_guild_remove(self, guild): + if await self.bot.cog_disabled_in_guild(self, guild): + return entry = "this bot left the guild" await self.log(guild, entry) @commands.Cog.listener() async def on_guild_update(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after): + return entries = [] user = None try: @@ -1535,6 +1479,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_role_create(self, role): + if await self.bot.cog_disabled_in_guild(self, role.guild): + return user = None try: async for entry in role.guild.audit_logs(limit=2): @@ -1553,6 +1499,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_role_delete(self, role): + if await self.bot.cog_disabled_in_guild(self, role.guild): + return user = None try: async for entry in role.guild.audit_logs(limit=2): @@ -1571,6 +1519,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_role_update(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return entries = [] user = None try: @@ -1655,6 +1605,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_member_join(self, member): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return entry = "Member join: @{0} (id {0.id})".format(member) async with self.config.user(member).past_names() as past_names: @@ -1665,6 +1617,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_member_remove(self, member): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return user = None try: async for entry in member.guild.audit_logs(limit=2): @@ -1688,6 +1642,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_member_ban(self, guild, member): + if await self.bot.cog_disabled_in_guild(self, guild): + return user = None try: async for entry in guild.audit_logs(limit=2): @@ -1706,6 +1662,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_member_unban(self, guild, member): + if await self.bot.cog_disabled_in_guild(self, guild): + return user = None try: async for entry in guild.audit_logs(limit=2): @@ -1724,6 +1682,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_member_update(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return entries = [] user = None try: @@ -1799,6 +1759,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_channel_create(self, channel): + if await self.bot.cog_disabled_in_guild(self, channel.guild): + return user = None try: async for entry in channel.guild.audit_logs(limit=2): @@ -1819,6 +1781,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_channel_delete(self, channel): + if await self.bot.cog_disabled_in_guild(self, channel.guild): + return user = None try: async for entry in channel.guild.audit_logs(limit=2): @@ -1839,6 +1803,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_guild_channel_update(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return user = None try: async for entry in after.guild.audit_logs(limit=2): @@ -1900,6 +1866,8 @@ class ActivityLogger(commands.Cog): @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return if not self.should_log(before.channel): return @@ -1958,3 +1926,19 @@ class ActivityLogger(commands.Cog): if before.self_video != after.self_video: verb = "start-video" if after.self_video else "stop-video" await self.log(before.channel, "guild self-{0}: {1} (id {1.id})".format(verb, member)) + + # async def red_get_data_for_user(self, user_id: int): + # default_user = {"past_names": []} + # default_member = { + # "stats": {"total_msg": 0, "bot_cmd": 0, "avg_len": 0.0, "vc_time_sec": 0.0, "last_vc_time": None} + # } + # past_names = await self.config.user_from_id(user_id).past_names() + # data = {"past_names": past_names} + + # for guild in self.bot.guilds: + # member = guild.get_member(user_id) + # if member: + # data[guild.name] = await self.config.member(member).stats() + + async def red_delete_data_for_user(self, requester: str, user_id: int): + pass diff --git a/activitylog/info.json b/activitylog/info.json index 0497b8a..4486ab3 100644 --- a/activitylog/info.json +++ b/activitylog/info.json @@ -3,11 +3,6 @@ "Brandons209", "calebj" ], - "bot_version": [ - 3, - 0, - 0 - ], "description": "Log messages, dms, attachments, guild updates (roles, channels, bans, kicks etc) and be able to retrieve these logs for review. Saves these right to disk and customize then to rotate log files. Tracks user's stats; how many messages they send, how many are bot commands, time spent in VC, and moderator actions against them. Also provides an upgraded userinfo command that gives these stats alongside the information Red's userinfo command gives. This is rewritten from @calebj's V2 cog.", "hidden": false, "install_msg": "Thank you for using this cog! Make sure to set bot prefixes using [p]logset prefixes for proper stat logging.", @@ -19,5 +14,6 @@ "log", "activity" ], - "min_bot_version": "3.3.0" + "min_bot_version": "3.4.0", + "end_user_data_statement": "Depending on setup, can log user messages, voice channel activity, audit actions in guilds, activity statistics per guild, user name changes, and any moderation actions per guild." } diff --git a/activitylog/time_utils.py b/activitylog/time_utils.py deleted file mode 100644 index 5e891df..0000000 --- a/activitylog/time_utils.py +++ /dev/null @@ -1,59 +0,0 @@ -# thanks to @Sinbad for time parsing! -from __future__ import annotations - -import re -from datetime import datetime as dt -from typing import Optional - -import pytz -from dateutil import parser -from dateutil.tz import gettz -from dateutil.relativedelta import relativedelta - -TIME_RE_STRING = r"\s?".join( - [ - r"((?P\d+?)\s?(years?|y))?", - r"((?P\d+?)\s?(months?|mt))?", - r"((?P\d+?)\s?(weeks?|w))?", - r"((?P\d+?)\s?(days?|d))?", - r"((?P\d+?)\s?(hours?|hrs|hr?))?", - r"((?P\d+?)\s?(minutes?|mins?|m(?!o)))?", # prevent matching "months" - r"((?P\d+?)\s?(seconds?|secs?|s))?", - ] -) - -TIME_RE = re.compile(TIME_RE_STRING, re.I) - - -def gen_tzinfos(): - for zone in pytz.common_timezones: - try: - tzdate = pytz.timezone(zone).localize(dt.utcnow(), is_dst=None) - except pytz.NonExistentTimeError: - pass - else: - tzinfo = gettz(zone) - - if tzinfo: - yield tzdate.tzname(), tzinfo - - -def parse_time(datetimestring: str): - tzinfo = dict(gen_tzinfos()) - ret = parser.parse(datetimestring, tzinfos=tzinfo) - if ret.tzinfo is not None: - ret = ret.astimezone(pytz.utc) - return ret - - -def parse_time_naive(datetimestring: str): - return parser.parse(datetimestring) - - -def parse_timedelta(argument: str) -> Optional[relativedelta]: - matches = TIME_RE.match(argument) - if matches: - params = {k: int(v) for k, v in matches.groupdict().items() if v} - if params: - return relativedelta(**params) - return None diff --git a/activitylog/utils.py b/activitylog/utils.py new file mode 100644 index 0000000..7caa16c --- /dev/null +++ b/activitylog/utils.py @@ -0,0 +1,112 @@ +# thanks to @Sinbad for time parsing! +from __future__ import annotations + +import re +from datetime import datetime as dt +from typing import Optional +import os +import asyncio + +import pytz +from dateutil import parser +from dateutil.tz import gettz +from dateutil.relativedelta import relativedelta + +TIME_RE_STRING = r"\s?".join( + [ + r"((?P\d+?)\s?(years?|y))?", + r"((?P\d+?)\s?(months?|mt))?", + r"((?P\d+?)\s?(weeks?|w))?", + r"((?P\d+?)\s?(days?|d))?", + r"((?P\d+?)\s?(hours?|hrs|hr?))?", + r"((?P\d+?)\s?(minutes?|mins?|m(?!o)))?", # prevent matching "months" + r"((?P\d+?)\s?(seconds?|secs?|s))?", + ] +) + +TIME_RE = re.compile(TIME_RE_STRING, re.I) + + +def gen_tzinfos(): + for zone in pytz.common_timezones: + try: + tzdate = pytz.timezone(zone).localize(dt.utcnow(), is_dst=None) + except pytz.NonExistentTimeError: + pass + else: + tzinfo = gettz(zone) + + if tzinfo: + yield tzdate.tzname(), tzinfo + + +def parse_time(datetimestring: str): + tzinfo = dict(gen_tzinfos()) + ret = parser.parse(datetimestring, tzinfos=tzinfo) + if ret.tzinfo is not None: + ret = ret.astimezone(pytz.utc) + return ret + + +def parse_time_naive(datetimestring: str): + return parser.parse(datetimestring) + + +def parse_timedelta(argument: str) -> Optional[relativedelta]: + matches = TIME_RE.match(argument) + if matches: + params = {k: int(v) for k, v in matches.groupdict().items() if v} + if params: + return relativedelta(**params) + return None + + +def get_all_names(guild_files, user): + names = [str(user)] + for log in guild_files: + if not os.path.exists(log): + continue + with open(log, "r") as f: + for line in f: + if str(user.id) in line: + # user change their name + if "Member username:" in line: + username = line.strip().split('"') + discrim = username[1].split("#")[-1] + username = username[-2] + "#" + discrim + names.append(username) + # user changed their 4 digit discriminator + elif "Member discriminator:" in line: + username = line.strip().split('"')[-2] + names.append(username) + # starting name + elif "Member join:" in line: + username = line.strip().split("@")[-1].split("#") + username = username[0] + "#" + username[1].split(" ")[0] + if username is not str(user): + names.append(username) + return set(names) + + +class LogHandle: + """basic wrapper for logfile handles, used to keep track of stale handles""" + + def __init__(self, path, time=None, mode="a", buf=1): + self.handle = open(path, mode, buf, errors="backslashreplace") + self.lock = asyncio.Lock() + + if time: + self.time = time + else: + self.time = dt.fromtimestamp(os.path.getmtime(path)) + + async def write(self, value): + async with self.lock: + self._write(value) + + def close(self): + self.handle.close() + + def _write(self, value): + self.time = dt.utcnow() + self.handle.write(value) diff --git a/birthday/birthday.py b/birthday/birthday.py index a2a81a7..996bd92 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -63,6 +63,8 @@ class Birthday(commands.Cog): async def check_bdays(self): for guild in self.bot.guilds: + if await self.bot.cog_disabled_in_guild(self, guild): + continue for member in guild.members: await self.check_member_bday(member) @@ -97,7 +99,7 @@ class Birthday(commands.Cog): else: embed.description = f"Happy Birthday to {member.mention}!" try: - await channel.send(embed=embed) + await channel.send(embed=embed, allow_mentions=True) except: pass diff --git a/birthday/info.json b/birthday/info.json index fe0abce..3777f79 100644 --- a/birthday/info.json +++ b/birthday/info.json @@ -6,7 +6,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", @@ -17,5 +17,6 @@ "tags": [ "brandons209", "pancakesparkle" - ] + ], + "end_user_data_statement": "This cog will store a user's birthday." } diff --git a/confession/info.json b/confession/info.json index 730c044..6f4a980 100644 --- a/confession/info.json +++ b/confession/info.json @@ -1,9 +1,10 @@ { "author" : ["Brandons209", "Jinatku"], - "bot_version": [3,0,0], + "bot_version": [3,4,0], "install_msg" : "Let your users confess their terrible terrible crimes in secrecy!", "short" : "Confess secretly.", "description" : "Confess in a confession room to repent your crimes.", "tags" : ["confession", "crime", "secret"], - "hidden" : false + "hidden" : false, + "end_user_data_statement": "This cog won't store anything for a user." } diff --git a/costmanager/info.json b/costmanager/info.json index 3ec571e..09d574c 100644 --- a/costmanager/info.json +++ b/costmanager/info.json @@ -4,7 +4,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Allow setting up costs for any commands of your bot, with user, and role hierarchy. Also allows setting roles who do not have to pay for commands. Has receptions DMed and updated to allow users to track their spending.", @@ -15,5 +15,6 @@ "tags": [ "brandons209", "redbot" - ] + ], + "end_user_data_statement": "This cog won't store anything for a user." } diff --git a/costmanager/manager.py b/costmanager/manager.py index 9548423..1852cb9 100644 --- a/costmanager/manager.py +++ b/costmanager/manager.py @@ -126,7 +126,8 @@ class CostManager(commands.Cog): except: if receipt != -1: # send mention if first time getting this message await ctx.send( - f"Hey {member.mention}, please turn on DMs from server members in your settings so I can send you receipts for purchase of commands." + f"Hey {member.mention}, please turn on DMs from server members in your settings so I can send you receipts for purchase of commands.", + allowed_mentions=discord.AllowedMentions.all(), ) await self.config.member(member).receipt.set(-1) @@ -400,7 +401,8 @@ class CostManager(commands.Cog): currency_name = await bank.get_currency_name(ctx.guild) balance = await bank.get_balance(ctx.author) message = await ctx.send( - f"Sorry {ctx.author.name}, you do not have enough {currency_name} to use that command. (Cost: {cost}, Balance: {balance})" + f"Sorry {ctx.author.name}, you do not have enough {currency_name} to use that command. (Cost: {cost}, Balance: {balance})", + allowed_mentions=discord.AllowedMentions.all(), ) await asyncio.sleep(10) await message.delete() diff --git a/disable/disable.py b/disable/disable.py index bd89969..df30b51 100644 --- a/disable/disable.py +++ b/disable/disable.py @@ -70,6 +70,8 @@ class Disable(commands.Cog): @commands.Cog.listener() async def on_command_error(self, ctx, exception): + if await self.bot.cog_disabled_in_guild(self, ctx.guild): + return if isinstance(exception, DisabledError): msg = await self.config.guild(ctx.guild).disabled_message() await ctx.send(msg.format(ctx.command.name)) diff --git a/disable/info.json b/disable/info.json index 98bd0b8..4488c19 100644 --- a/disable/info.json +++ b/disable/info.json @@ -4,7 +4,7 @@ ], "bot_version": [ 3, - 3, + 4, 0 ], "description": "Small cog that allows disabling all bot commands for everyone except Admins/owner in a guild. Nice for things like bot setup. You can also set the error message when a person trys using a command when its disabled.", @@ -15,5 +15,6 @@ "tags": [ "brandons209", "redbot" - ] + ], + "end_user_data_statement": "This cog won't store any data for users." } diff --git a/economytrickle/core.py b/economytrickle/core.py index d3a2da1..2b2dde0 100644 --- a/economytrickle/core.py +++ b/economytrickle/core.py @@ -49,6 +49,8 @@ class EconomyTrickle(commands.Cog): @commands.Cog.listener() async def on_message(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return if message.guild and await self.config.guild(message.guild).active(): self.recordhandler.proccess_message(message) diff --git a/economytrickle/info.json b/economytrickle/info.json index 4980ce6..cd65a7b 100644 --- a/economytrickle/info.json +++ b/economytrickle/info.json @@ -10,5 +10,6 @@ "short": "Trickle money into user's account on activity.", "description": "Trickle money into user's account on activity, modified by Brandons209 from Sinbad.", "hidden": false, - "min_bot_version": "3.1.8" + "min_bot_version": "3.4.0", + "end_user_data_statement": "This cog only stores internal variables per user." } diff --git a/emoji/info.json b/emoji/info.json index 309c46d..aebf00c 100644 --- a/emoji/info.json +++ b/emoji/info.json @@ -6,5 +6,7 @@ "INSTALL_MSG" : "Thanks for installing EveryoneEmoji.", "REQUIREMENTS" : [], "TAGS" : ["emoji", "EveryoneEmoji", "everyone"], - "DISABLED" : false + "DISABLED" : false, + "min_bot_version": "3.4.0", + "end_user_data_statement": "This cog stores no data." } diff --git a/isolate/info.json b/isolate/info.json index 3690ead..dd2c9eb 100644 --- a/isolate/info.json +++ b/isolate/info.json @@ -5,7 +5,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Provides a way to quickly remove a user for all chats and isolate them to a single channel. Supports setting times, automatic removal of isolate, modlog integration, custom role overrides, automatic server setup, and a lot more. This is different from punish as it always remove all a user's roles and by default makes the user not read all channels.", @@ -16,5 +16,6 @@ "tags": [ "brandons209", "isolate" - ] + ], + "end_user_data_statement": "This cog stores members who are currently isolated for moderation purposes." } diff --git a/isolate/isolate.py b/isolate/isolate.py index 643ba6b..08652a3 100644 --- a/isolate/isolate.py +++ b/isolate/isolate.py @@ -1306,6 +1306,8 @@ class Isolate(commands.Cog): @commands.Cog.listener() async def on_guild_channel_create(self, channel): """Run when new channels are created and set up role permissions""" + if await self.bot.cog_disabled_in_guild(self, channel.guild): + return role = await self.get_role(channel.guild, quiet=True) if not role: return @@ -1315,6 +1317,8 @@ class Isolate(commands.Cog): @commands.Cog.listener() async def on_member_update(self, before, after): """Remove scheduled unisolate when manually removed role""" + if await self.bot.cog_disabled_in_guild(self, after.guild): + return try: assert before.roles != after.roles guild_data = await self.config.guild(before.guild).ISOLATED() @@ -1343,6 +1347,8 @@ class Isolate(commands.Cog): @commands.Cog.listener() async def on_member_join(self, member): """Restore Isolation if isolated user leaves/rejoins""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild = member.guild isolated = await self.config.guild(guild).ISOLATED() data = isolated.get(str(member.id), {}) @@ -1366,6 +1372,8 @@ class Isolate(commands.Cog): @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return if not after.channel: return @@ -1386,6 +1394,8 @@ class Isolate(commands.Cog): @commands.Cog.listener() async def on_member_ban(self, member): """Remove Isolation record when member is banned.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild = member.guild data = await self.config.guild(guild).ISOLATED() member_data = data.get(str(member.id)) diff --git a/isolate/utils.py b/isolate/utils.py index a21700b..ac84a76 100644 --- a/isolate/utils.py +++ b/isolate/utils.py @@ -145,9 +145,9 @@ def role_from_string(guild, rolename, roles=None): if role: return role - - rolename = rolename.lower() - role = discord.utils.find(lambda r: r.name.lower() == rolename, roles) + else: + rolename = rolename.lower() + role = discord.utils.find(lambda r: r.name.lower() == rolename, roles) return role diff --git a/markov/info.json b/markov/info.json index 2593acd..7b4aa52 100644 --- a/markov/info.json +++ b/markov/info.json @@ -4,7 +4,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Uses markov chains to generate unique text in your guild! Text generated is based on what users say per channel. The markov model can be reset if needed as well per channel.", @@ -18,5 +18,6 @@ "markov", "generaton", "markov chain" - ] + ], + "end_user_data_statement": "This doesn't store any user data." } diff --git a/markov/markov.py b/markov/markov.py index f335414..79c881a 100644 --- a/markov/markov.py +++ b/markov/markov.py @@ -159,11 +159,13 @@ class Markov(commands.Cog): embed.set_thumbnail(url=avatar) embed.set_footer(text=f"Generated by {member.display_name}") - await ctx.send(embed=embed) + await ctx.send(embed=embed, allowed_mentions=discord.AllowedMentions.all()) # Listener @commands.Cog.listener() async def on_message(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return # updates model content = message.content guild = message.guild diff --git a/moreadmin/info.json b/moreadmin/info.json index 6e9fd0d..f3847e3 100644 --- a/moreadmin/info.json +++ b/moreadmin/info.json @@ -4,7 +4,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "More admin commands like purging inactive users, member count display for channel name, add roles based on author's current roles, log new user accounts joining, and more!", @@ -15,5 +15,6 @@ "tags": [ "brandons209", "redbot" - ] + ], + "end_user_data_statement": "This will store a user's last few messages (depending on configuration)" } diff --git a/moreadmin/moreadmin.py b/moreadmin/moreadmin.py index 3e8fa83..7a5c86a 100644 --- a/moreadmin/moreadmin.py +++ b/moreadmin/moreadmin.py @@ -170,6 +170,8 @@ class MoreAdmin(commands.Cog): SLEEP_TIME = 300 while True: for guild in self.bot.guilds: + if await self.bot.cog_disabled_in_guild(self, guild): + continue channel = await self.config.guild(guild).user_count_channel() if channel: channel = guild.get_channel(channel) @@ -799,13 +801,13 @@ class MoreAdmin(commands.Cog): @commands.command(hidden=True) @commands.guild_only() async def say(self, ctx, *, content: str): - await ctx.send(escape(content, mass_mentions=True), allowed_mentions=discord.AllowedMentions()) + await ctx.send(escape(content, mass_mentions=True), allowed_mentions=discord.AllowedMentions.all()) @commands.command(hidden=True) @commands.guild_only() async def selfdm(self, ctx, *, content: str): try: - await ctx.author.send(content) + await ctx.author.send(content, allowed_mentions=discord.AllowedMentions.all()) except: await ctx.send( "I couldn't send you the DM, make sure to turn on messages from server members! Here is the message:" @@ -827,7 +829,7 @@ class MoreAdmin(commands.Cog): return try: - await message.edit(content=msg) + await message.edit(content=msg, allowed_mentions=discord.AllowedMentions.all()) except: await ctx.send("Could not edit message.") @@ -839,7 +841,7 @@ class MoreAdmin(commands.Cog): Sends a message to a channel from Aurelia. """ try: - await channel.send(msg) # , allowed_mentions=discord.AllowedMentions()) + await channel.send(msg, allowed_mentions=discord.AllowedMentions.all()) except: await ctx.send("Could not send message in that channel.") @@ -974,6 +976,10 @@ class MoreAdmin(commands.Cog): @commands.Cog.listener() async def on_member_join(self, member): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return + if await self.bot.cog_disabled_in_guild(self, member.guild): + return sus_threshold = await self.config.guild(member.guild).sus_user_threshold() if not sus_threshold: return @@ -1003,6 +1009,8 @@ class MoreAdmin(commands.Cog): @commands.Cog.listener() async def on_message(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return # Set user's last message if not message.guild: return diff --git a/nitroemoji/info.json b/nitroemoji/info.json index f18f925..3f1319c 100644 --- a/nitroemoji/info.json +++ b/nitroemoji/info.json @@ -4,7 +4,7 @@ ], "bot_version": [ 3, - 3, + 4, 0 ], "description": "Allow nitro boosters to add an emoji to the server, with channel logging.", @@ -17,5 +17,6 @@ "nitro", "boost", "emoji" - ] + ], + "end_user_data_statement": "This cog will store a user's custom emojis in each guild." } diff --git a/nitroemoji/nitroemoji.py b/nitroemoji/nitroemoji.py index 0d770c6..db3d4c4 100644 --- a/nitroemoji/nitroemoji.py +++ b/nitroemoji/nitroemoji.py @@ -285,6 +285,8 @@ class NitroEmoji(commands.Cog): @commands.Cog.listener() async def on_member_update(self, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return # check if they stopped boosting if (before.premium_since != after.premium_since and after.premium_since is None) or before.roles != after.roles: boosts = await self.get_boosts(after) @@ -312,6 +314,8 @@ class NitroEmoji(commands.Cog): @commands.Cog.listener() async def on_member_leave(self, member): + if await self.bot.cog_disabled_in_guild(self, member.guild): + return # remove all member emojis on leave emojis = await self.config.member(member).emojis() for emoji in emojis: @@ -324,6 +328,8 @@ class NitroEmoji(commands.Cog): @commands.Cog.listener() async def on_guild_emojis_update(self, guild, before, after): + if await self.bot.cog_disabled_in_guild(self, guild): + return b_e = set(before) a_e = set(after) diff = b_e - a_e diff --git a/personalroles/info.json b/personalroles/info.json index 6d412f0..308c0f9 100644 --- a/personalroles/info.json +++ b/personalroles/info.json @@ -14,5 +14,7 @@ ], "requirements": [ "tabulate" - ] + ], + "min_bot_version": "3.4.0", + "end_user_data_statement": "This will store what a user's custom role is if they have one." } diff --git a/personalroles/personalroles.py b/personalroles/personalroles.py index 86d2faa..e642335 100644 --- a/personalroles/personalroles.py +++ b/personalroles/personalroles.py @@ -370,6 +370,8 @@ class PersonalRoles(commands.Cog): @commands.Cog.listener("on_member_join") async def role_persistance(self, member): """Automatically give already assigned roles on join""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return role = await self.config.member(member).role() if role: role = member.guild.get_role(role) @@ -382,6 +384,8 @@ class PersonalRoles(commands.Cog): @commands.Cog.listener("on_member_remove") async def remove_role(self, member): """ Delete personal role if member leaves.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return role = await self.config.member(member).role() auto = await self.config.member(member).auto_role() role = member.guild.get_role(role) @@ -396,6 +400,8 @@ class PersonalRoles(commands.Cog): @commands.Cog.listener("on_member_update") async def modify_roles(self, before, after): """ Delete personal role if member looses their auto role or looses their personal role """ + if await self.bot.cog_disabled_in_guild(self, after.guild): + return role = await self.config.member(after).role() role = before.guild.get_role(role) if not role: diff --git a/pony/info.json b/pony/info.json index ecc35b9..f7cf86c 100644 --- a/pony/info.json +++ b/pony/info.json @@ -6,7 +6,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Search derpibooru for images of ponies! Fully customizable filter list!", @@ -20,5 +20,6 @@ "pony", "mlp", "image" - ] + ], + "end_user_data_statement": "This doesn't store any data." } diff --git a/punish/info.json b/punish/info.json index d6bab2b..9bffdf4 100644 --- a/punish/info.json +++ b/punish/info.json @@ -5,7 +5,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Provides a way to quickly remove a user for all chats and isolate them to a single channel. Supports setting times, automatic removal of punish, modlog integration, removing roles so that role overrides work, custom role overrides, automatic server setup, and a lot more.", @@ -16,5 +16,6 @@ "tags": [ "brandons209", "punish" - ] + ], + "end_user_data_statement": "This will store who is currently punished." } diff --git a/punish/punish.py b/punish/punish.py index 688d48c..77d0b49 100644 --- a/punish/punish.py +++ b/punish/punish.py @@ -18,7 +18,7 @@ import textwrap log = logging.getLogger("red.punish") -__version__ = "3.0.0" +__version__ = "3.3.0" PURGE_MESSAGES = 1 # for cpunish @@ -1373,6 +1373,8 @@ class Punish(commands.Cog): # Listeners @commands.Cog.listener() async def on_guild_channel_create(self, channel): + if await self.bot.cog_disabled_in_guild(self, channel.guild): + return """Run when new channels are created and set up role permissions""" role = await self.get_role(channel.guild, quiet=True) if not role: @@ -1383,6 +1385,8 @@ class Punish(commands.Cog): @commands.Cog.listener() async def on_member_update(self, before, after): """Remove scheduled unpunish when manually removed role""" + if await self.bot.cog_disabled_in_guild(self, after.guild): + return try: assert before.roles != after.roles guild_data = await self.config.guild(before.guild).PUNISHED() @@ -1411,6 +1415,8 @@ class Punish(commands.Cog): @commands.Cog.listener() async def on_member_join(self, member): """Restore punishment if punished user leaves/rejoins""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild = member.guild punished = await self.config.guild(guild).PUNISHED() data = punished.get(str(member.id), {}) @@ -1434,6 +1440,8 @@ class Punish(commands.Cog): @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): + if await self.bot.cog_disabled_in_guild(self, after.guild): + return if not after.channel: return @@ -1454,6 +1462,8 @@ class Punish(commands.Cog): @commands.Cog.listener() async def on_member_ban(self, member): """Remove punishment record when member is banned.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild = member.guild data = await self.config.guild(guild).PUNISHED() member_data = data.get(str(member.id)) diff --git a/punish/utils.py b/punish/utils.py index a21700b..ac84a76 100644 --- a/punish/utils.py +++ b/punish/utils.py @@ -145,9 +145,9 @@ def role_from_string(guild, rolename, roles=None): if role: return role - - rolename = rolename.lower() - role = discord.utils.find(lambda r: r.name.lower() == rolename, roles) + else: + rolename = rolename.lower() + role = discord.utils.find(lambda r: r.name.lower() == rolename, roles) return role diff --git a/reactpoll/info.json b/reactpoll/info.json index 74e3a46..46b69e4 100644 --- a/reactpoll/info.json +++ b/reactpoll/info.json @@ -6,5 +6,7 @@ "INSTALL_MSG" : "Thanks for installing ReactPoll. Please make sure your bot has the 'Manage Messages' permission so it can manage emoji reactions on messages.", "REQUIREMENTS" : ["python-dateutil", "pytz"], "TAGS" : ["poll", "reaction", "emoji", "react"], - "DISABLED" : false + "DISABLED" : false, + "min_bot_version": "3.4.0", + "end_user_data_statement": "This cog won't store user data." } diff --git a/reactpoll/reactpoll.py b/reactpoll/reactpoll.py index a734311..f0717ed 100644 --- a/reactpoll/reactpoll.py +++ b/reactpoll/reactpoll.py @@ -135,6 +135,10 @@ class ReactPoll(commands.Cog): guild = self.bot.get_guild(payload.guild_id) if not guild: return + + if await self.bot.cog_disabled_in_guild(self, guild): + return + user = guild.get_member(payload.user_id) message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) # Listener is required to remove bad reactions diff --git a/rolemanagement/events.py b/rolemanagement/events.py index cc7b568..0ec60dd 100644 --- a/rolemanagement/events.py +++ b/rolemanagement/events.py @@ -43,6 +43,8 @@ class EventMixin(MixinMeta): Section has been optimized assuming member._roles remains an iterable containing snowflakes """ + if await self.bot.cog_disabled_in_guild(self, after.guild): + return await self.wait_for_ready() if before._roles == after._roles: return @@ -85,6 +87,8 @@ class EventMixin(MixinMeta): @commands.Cog.listener() async def on_member_join(self, member: discord.Member): await self.wait_for_ready() + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild = member.guild if not guild.me.guild_permissions.manage_roles: return @@ -134,6 +138,9 @@ class EventMixin(MixinMeta): await self.maybe_update_guilds(guild) else: return + + if await self.bot.cog_disabled_in_guild(self, guild): + return member = guild.get_member(payload.user_id) if member is None or member.bot: @@ -182,6 +189,8 @@ class EventMixin(MixinMeta): if not guild: # Where's it go? return + if await self.bot.cog_disabled_in_guild(self, guild): + return member = guild.get_member(payload.user_id) if not member or member.bot: return diff --git a/rolemanagement/info.json b/rolemanagement/info.json index f9585c1..88eac14 100644 --- a/rolemanagement/info.json +++ b/rolemanagement/info.json @@ -17,5 +17,6 @@ "massrole" ], "hidden": false, - "min_bot_version": "3.2.0a0.dev1" + "min_bot_version": "3.4.0", + "end_user_data_statement": "This will only store sticky roles for users." } diff --git a/rolemanagement/massmanager.py b/rolemanagement/massmanager.py index 7d6f6f8..e57916d 100644 --- a/rolemanagement/massmanager.py +++ b/rolemanagement/massmanager.py @@ -206,7 +206,11 @@ class MassManagementMixin(MixinMeta): embed = discord.Embed(description=description) if ctx.guild: embed.color = ctx.guild.me.color - await ctx.send(embed=embed, content=f"Search results for {ctx.author.mention}") + await ctx.send( + embed=embed, + content=f"Search results for {ctx.author.mention}", + allowed_mentions=discord.AllowedMentions.all(), + ) else: await self.send_maybe_chunked_csv(ctx, list(members)) @@ -251,6 +255,7 @@ class MassManagementMixin(MixinMeta): await ctx.send( content=f"Data for {ctx.author.mention}", files=[discord.File(data, filename=filename)], + allowed_mentions=discord.AllowedMentions.all(), ) csvf.close() data.close() diff --git a/roleplay/info.json b/roleplay/info.json new file mode 100644 index 0000000..4dad402 --- /dev/null +++ b/roleplay/info.json @@ -0,0 +1,19 @@ +{ + "author": [ + "TheBluekr" + ], + "bot_version": [ + 3, + 4, + 0 + ], + "description": "Roleplay commands for booping, hugging, etc.", + "hidden": false, + "install_msg": "Thanks for using my cog!", + "requirements": [], + "tags": [ + "brandons209", + "Som3thing" + ], + "end_user_data_statement": "No data is stored." +} diff --git a/roletracker/info.json b/roletracker/info.json index 0981f10..f9def53 100644 --- a/roletracker/info.json +++ b/roletracker/info.json @@ -4,16 +4,16 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], - "description": "", + "description": "Tracks specified roles on when they are added, removed, and who updates them.", "hidden": false, - "install_msg": "", + "install_msg": "Thank you for using my cog!", "requirements": [], - "short": "", "tags": [ "brandons209", "pancakesparkle" - ] -} \ No newline at end of file + ], + "end_user_data_statement": "Depending on setup, can log user messages, voice channel activity, audit actions in guilds, activity statistics per guild, user name changes, and any moderation actions per guild." +} diff --git a/roletracker/roletracker.py b/roletracker/roletracker.py index 8f91d26..8efd1f4 100644 --- a/roletracker/roletracker.py +++ b/roletracker/roletracker.py @@ -200,6 +200,8 @@ class RoleTracker(commands.Cog): """ Listens for role updates and more """ + if await self.bot.cog_disabled_in_guild(self, after.guild): + return if before.roles != after.roles: user = self.bot.user diff --git a/rules/info.json b/rules/info.json index f48e0cb..f335000 100644 --- a/rules/info.json +++ b/rules/info.json @@ -5,9 +5,10 @@ "install_msg": "Thanks for install.", "short": "Quickly list server and channel rules.", "description": "Quickly list server and channel rules.", - "min_bot_version": "3.2.1", + "min_bot_version": "3.4.0", "tags": [ "rules", "rule" - ] + ], + "end_user_data_statement": "This only stores rules added by admins of guilds." } diff --git a/scheduler/info.json b/scheduler/info.json index 801c6cd..2c015e5 100644 --- a/scheduler/info.json +++ b/scheduler/info.json @@ -16,6 +16,6 @@ "python-dateutil", "pytz" ], - "min_bot_version": "3.3.0", + "min_bot_version": "3.4.0", "end_user_data_statement": "This cog does not persistently store data or metadata about users. It does store commands provided for intended later use along with the user ID of the person who scheduled it.\nUsers may delete their own data with or without making a data request." } diff --git a/scheduler/scheduler.py b/scheduler/scheduler.py index 2468692..7176cec 100644 --- a/scheduler/scheduler.py +++ b/scheduler/scheduler.py @@ -577,7 +577,7 @@ class Scheduler(commands.Cog): @helpers.command(name="say") async def say(self, ctx: commands.GuildContext, *, content: str): - await ctx.send(content, allowed_mentions=discord.AllowedMentions()) + await ctx.send(content, allowed_mentions=discord.AllowedMentions.all()) @helpers.command(name="selfwhisper") async def swhisp(self, ctx: commands.GuildContext, *, content: str): diff --git a/sfx/info.json b/sfx/info.json index f71c10e..b80a8af 100644 --- a/sfx/info.json +++ b/sfx/info.json @@ -5,11 +5,12 @@ "install_msg": "Thanks for install.", "short": "Play sound effects!", "description": "Play sound effects, either via links or files. Integrates with economy and cost manager cog.", - "min_bot_version": "3.3.0", + "min_bot_version": "3.4.0", "requirements": ["tabulate"], "tags": [ "sfx", "saysound", "audio" - ] + ], + "end_user_data_statement": "This doesn't store any user data." } diff --git a/smartreact/info.json b/smartreact/info.json index 92fb953..75fef88 100644 --- a/smartreact/info.json +++ b/smartreact/info.json @@ -6,5 +6,7 @@ "INSTALL_MSG" : "Thanks for installing SmartReact.", "REQUIREMENTS" : [], "TAGS" : ["reaction", "smart", "auto"], - "DISABLED" : false + "DISABLED" : false, + "min_bot_version": "3.4.0", + "end_user_data_statement": "This doesn't store any user data." } diff --git a/smartreact/smartreact.py b/smartreact/smartreact.py index a41fe6c..8f81ed3 100644 --- a/smartreact/smartreact.py +++ b/smartreact/smartreact.py @@ -114,6 +114,8 @@ class SmartReact(commands.Cog): # Thanks irdumb#1229 for the help making this "more Pythonic" @commands.Cog.listener() async def on_message(self, message): + if await self.bot.cog_disabled_in_guild(self, message.guild): + return if not message.guild: return if message.author == self.bot.user: diff --git a/trickortreat/info.json b/trickortreat/info.json index a506124..2f8c18f 100644 --- a/trickortreat/info.json +++ b/trickortreat/info.json @@ -3,7 +3,7 @@ ], "bot_version": [ 3, - 0, + 4, 0 ], "description": "Trick or treat! Sometimes you get some credits, sometimes you get tricked and lose them!", @@ -14,4 +14,5 @@ "tags": [ "brandons209", "Halloween" -] +], +"end_user_data_statement": "This doesn't store any user data." diff --git a/welcome/info.json b/welcome/info.json index 6f3110f..605c3af 100644 --- a/welcome/info.json +++ b/welcome/info.json @@ -1,6 +1,7 @@ { "author": [ - "tmerc" + "tmerc", + "brandons209" ], "install_msg": "Thanks for installing!", "name": "Welcome", @@ -13,5 +14,7 @@ "leave", "ban", "utility" - ] + ], + "min_bot_version": "3.4.0", + "end_user_data_statement": "This cog doesn't store any user data." } diff --git a/welcome/welcome.py b/welcome/welcome.py index 805d7f2..40e42f4 100644 --- a/welcome/welcome.py +++ b/welcome/welcome.py @@ -570,6 +570,8 @@ class Welcome(commands.Cog): @commands.Cog.listener() async def on_member_join(self, member: discord.Member) -> None: """Listens for member joins.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return guild: discord.Guild = member.guild guild_settings = self.config.guild(guild) @@ -601,12 +603,16 @@ class Welcome(commands.Cog): @commands.Cog.listener() async def on_member_remove(self, member: discord.Member) -> None: """Listens for member leaves.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return await self.__handle_event(member.guild, member, "leave") @commands.Cog.listener() async def on_member_ban(self, guild: discord.Guild, member: discord.Member) -> None: """Listens for user bans.""" + if await self.bot.cog_disabled_in_guild(self, member.guild): + return await self.__handle_event(guild, member, "ban") @@ -804,7 +810,8 @@ class Welcome(commands.Cog): return await channel.send( format_str.format( member=user, server=guild, bot=user, count=count or "", plural=plural, roles=roles, stats=stats - ) + ), + allowed_mentions=discord.AllowedMentions.all(), ) except discord.Forbidden: log.error( @@ -848,7 +855,10 @@ class Welcome(commands.Cog): message_format = await self.config.guild(member.guild).join.whisper.message() try: - await member.send(message_format.format(member=member, server=member.guild)) + await member.send( + message_format.format(member=member, server=member.guild), + allowed_mentions=discord.AllowedMentions.all(), + ) except discord.Forbidden: log.error( f"Failed to send DM to member ID {member.id} (server ID {member.guild.id}): insufficient permissions"