diff --git a/extendedaudio/extendedaudio.py b/extendedaudio/extendedaudio.py index b73eba3..8916c03 100644 --- a/extendedaudio/extendedaudio.py +++ b/extendedaudio/extendedaudio.py @@ -193,13 +193,13 @@ class ExtendedAudio(commands.Cog): format_str = await self.config.guild(guild).status_format() # Prepare variables - duration = track.get("length", 0) - minutes = duration // 60 - seconds = duration % 60 + duration = track.length if hasattr(track, "length") else 0 + minutes = duration // 60000 # Convert milliseconds to minutes + seconds = (duration % 60000) // 1000 # Convert remaining milliseconds to seconds duration_str = f"{minutes}:{seconds:02d}" new_name = format_str.format( - title=track.get("title", "Unknown"), + title=track.title if hasattr(track, "title") else "Unknown", requester=requester.display_name, duration=duration_str ) diff --git a/shop/data/community_shop.csv b/shop/data/community_shop.csv new file mode 100644 index 0000000..7b72b4e --- /dev/null +++ b/shop/data/community_shop.csv @@ -0,0 +1,41 @@ +Shop,Item,Type,Cost,Qty,Info,Role,Messages +VIP Lounge,VIP Status,role,5000,50,Get access to exclusive VIP channels and special perks!,VIP, +VIP Lounge,Custom Color Role,role,3000,100,Choose your own color for your name!,ColorMaster, +VIP Lounge,Premium Badge,role,10000,25,Show off your premium status with a special badge role!,PremiumMember, +VIP Lounge,Welcome Message,auto,1000,5,Get a special welcome message when you join!,,"Welcome to our amazing VIP member {user}!, Greetings noble VIP {user}!, A wild VIP {user} has appeared!, Everyone welcome our distinguished VIP {user}!, The legendary {user} has joined our ranks!" + +Fun Shop,Mystery Box,random,1500,50,Contains random valuable items! Try your luck!,, +Fun Shop,Lottery Ticket,basic,500,100,Enter the weekly lottery draw for a chance to win big!,, +Fun Shop,Custom Emoji Slot,basic,2500,10,Add your own custom emoji to the server!,, +Fun Shop,Game Night Host,role,2000,20,Host official game nights and special events!,GameHost, +Fun Shop,Meme Lord,role,1500,30,Post in the meme channel and get special reactions!,MemeLord, + +Power Ups,Voice VIP,role,3000,25,Get a special color in voice channels and priority speaker!,VoiceVIP, +Power Ups,Message Highlights,role,5000,10,Your messages get a special background color!,Highlighted, +Power Ups,Rich Presence,role,15000,5,Show a special rich presence status in the member list!,RichPresence, +Power Ups,Priority Support,role,10000,3,Get priority support from staff members!,PrioritySupport, +Power Ups,Chat Unlocks,role,4000,15,Access to special chat channels and features!,ChatUnlocked, + +Special Items,Server Boost,basic,20000,5,Get one month of server boost benefits!,, +Special Items,Custom Title,role,7500,20,Get a custom title role made just for you!,CustomTitle, +Special Items,Event Pass,basic,5000,50,Get access to all events for one month!,, +Special Items,Gif Master,role,3500,25,Post gifs in any channel!,GifMaster, +Special Items,DJ Role,role,2500,30,Control the music bot and create playlists!,DJ, + +Cosmetic Shop,Rainbow Name,role,4000,40,Your name changes colors like a rainbow!,RainbowName, +Cosmetic Shop,Sparkles Effect,role,3000,35,Add sparkles ✨ around your name!,Sparkles, +Cosmetic Shop,Dark Mode,role,3500,30,Get a sleek dark-colored name!,DarkMode, +Cosmetic Shop,Neon Style,role,3500,30,Make your name glow with neon colors!,NeonStyle, +Cosmetic Shop,Custom Emote Pack,basic,2000,25,Get a pack of 5 custom emotes for reactions!,, + +Community Shop,Thank You Token,basic,100,1000,Send a thank you message with special effects!,, +Community Shop,Reputation Point,basic,500,200,Give someone a reputation point!,, +Community Shop,Server Badge,role,5000,10,Show your dedication with a special server badge!,ServerVeteran, +Community Shop,Mentor Status,role,7500,15,Help new members and get special recognition!,Mentor, +Community Shop,Community Leader,role,12000,5,Become an official community leader!,CommunityLeader, + +Seasonal Shop,Summer Vibes,role,2000,50,Get a summer-themed name color!,SummerVibes, +Seasonal Shop,Winter Wonder,role,2000,50,Get a winter-themed name color!,WinterWonder, +Seasonal Shop,Halloween Spirit,role,2000,50,Get a spooky name color!,HalloweenSpirit, +Seasonal Shop,Party Animal,role,3000,30,Get special access to all seasonal events!,PartyAnimal, +Seasonal Shop,Holiday Pack,auto,1000,5,Get a special holiday message!,,"🎄 Happy Holidays {user}!,🎃 Spooky greetings {user}!,🌞 Summer fun awaits {user}!,🍁 Fall festivities for {user}!,❄️ Winter wonderland welcomes {user}!" \ No newline at end of file diff --git a/shop/shop.py b/shop/shop.py index f58a6d0..ea6f225 100644 --- a/shop/shop.py +++ b/shop/shop.py @@ -539,16 +539,17 @@ class Shop(commands.Cog): data = await instance.Pending.all() class PendingView(discord.ui.View): - def __init__(self, cog, data, timeout=60): + def __init__(self, cog, ctx, data, timeout=60): super().__init__(timeout=timeout) self.cog = cog + self.ctx = ctx self.data = data self.setup_user_select() def setup_user_select(self): options = [] for user_id, items in self.data.items(): - user = self.cog.bot.get_user(int(user_id)) + user = self.ctx.bot.get_user(int(user_id)) if user: desc = f"{len(items)} pending items" options.append(discord.SelectOption( @@ -567,7 +568,7 @@ class Shop(commands.Cog): self.add_item(user_select) async def user_selected(self, interaction: discord.Interaction): - if interaction.user != ctx.author: + if interaction.user != self.ctx.author: return await interaction.response.send_message("This menu is not for you!", ephemeral=True) user_id = interaction.data["values"][0] @@ -599,11 +600,11 @@ class Shop(commands.Cog): await interaction.response.edit_message(view=self) async def item_selected(self, interaction: discord.Interaction): - if interaction.user != ctx.author: + if interaction.user != self.ctx.author: return await interaction.response.send_message("This menu is not for you!", ephemeral=True) user_id, item_id = interaction.data["values"][0].split(":") - user = self.cog.bot.get_user(int(user_id)) + user = self.ctx.bot.get_user(int(user_id)) item_data = self.data[user_id][item_id] # Create confirmation view @@ -676,8 +677,8 @@ class Shop(commands.Cog): await interaction.response.edit_message(content="Action cancelled.", embed=None, view=None) self.stop() - # Start the pending menu - view = PendingView(self, data) + # Start the pending menu with ctx passed + view = PendingView(self, ctx, data) await ctx.send( "Select a user to view their pending items:", view=view diff --git a/welcome/__init__.py b/welcome/__init__.py new file mode 100644 index 0000000..8b40963 --- /dev/null +++ b/welcome/__init__.py @@ -0,0 +1,12 @@ +import json +from pathlib import Path + +from .welcome import Welcome + +with open(Path(__file__).parent / "info.json") as fp: + __red_end_user_data_statement__ = json.load(fp)["end_user_data_statement"] + + +async def setup(bot): + n = Welcome(bot) + await bot.add_cog(n) diff --git a/welcome/events.py b/welcome/events.py new file mode 100644 index 0000000..bbd8ac0 --- /dev/null +++ b/welcome/events.py @@ -0,0 +1,548 @@ +import re +from datetime import datetime, timedelta, timezone +from random import choice as rand_choice +from typing import List, Optional, Pattern, Union, cast + +import discord +from red_commons.logging import getLogger +from redbot import VersionInfo, version_info +from redbot.core import Config, commands +from redbot.core.bot import Red +from redbot.core.i18n import Translator, cog_i18n +from redbot.core.utils.chat_formatting import humanize_list + +RE_CTX: Pattern = re.compile(r"{([^}]+)\}") +RE_POS: Pattern = re.compile(r"{((\d+)[^.}]*(\.[^:}]+)?[^}]*)\}") +_ = Translator("Welcome", __file__) +log = getLogger("red.trusty-cogs.Welcome") + + +@cog_i18n(_) +class Events: + def __init__(self): + self.bot: Red + self.config: Config + self.joined: dict + self.today_count: dict + + @staticmethod + def transform_arg(result: str, attr: str, obj: Union[discord.Guild, discord.Member]) -> str: + attr = attr[1:] # strip initial dot + if not attr: + return str(obj) + raw_result = "{" + result + "}" + # forbid private members and nested attr lookups + if attr.startswith("_") or "." in attr: + return raw_result + return str(getattr(obj, attr, raw_result)) + + async def convert_parms( + self, + member: Union[discord.Member, List[discord.Member]], + guild: discord.Guild, + msg: str, + is_welcome: bool, + ) -> str: + results = RE_POS.findall(msg) + raw_response = msg + user_count = self.today_count[guild.id] if guild.id in self.today_count else 1 + raw_response = raw_response.replace("{count}", str(user_count)) + has_filter = self.bot.get_cog("Filter") + filter_setting = await self.config.guild(guild).FILTER_SETTING() or "[Redacted]" + if isinstance(member, list): + username = humanize_list(member) + else: + username = str(member) + for result in results: + if int(result[1]) == 1: + param = self.transform_arg(result[0], result[2], guild) + elif int(result[1]) == 0: + if isinstance(member, discord.Member): + param = self.transform_arg(result[0], result[2], member) + else: + params = [] + for m in member: + params.append(self.transform_arg(result[0], result[2], m)) + if len(params) > 1: + param = humanize_list(params) + else: + param = params[0] + raw_response = raw_response.replace("{" + result[0] + "}", param) + if has_filter: + if version_info < VersionInfo.from_str("3.5.10"): + bad_name = await has_filter.filter_hits(username, guild) + else: + bad_name = await has_filter.filter_hits(guild, username) + if bad_name: + for word in bad_name: + raw_response = re.sub(rf"(?i){word}", filter_setting, raw_response) + if isinstance(member, list): + raw_response = re.sub( + "|".join(m.mention for m in member), filter_setting, raw_response + ) + else: + raw_response = re.sub( + rf"(?i){member.mention}", filter_setting, raw_response + ) + if await self.config.guild(guild).JOINED_TODAY() and is_welcome: + raw_response = _("{raw_response}\n\n{count} users joined today!").format( + raw_response=raw_response, count=user_count + ) + return raw_response + + async def make_embed( + self, + member: Union[discord.Member, List[discord.Member]], + guild: discord.Guild, + msg: str, + is_welcome: bool, + ) -> discord.Embed: + EMBED_DATA = await self.config.guild(guild).EMBED_DATA() + converted_msg = await self.convert_parms(member, guild, msg, is_welcome) + has_filter = self.bot.get_cog("Filter") + username = str(member) + if has_filter: + replace_word = await self.config.guild(guild).FILTER_SETTING() or "[Redacted]" + if version_info < VersionInfo.from_str("3.5.10"): + bad_words = await has_filter.filter_hits(username, guild) + else: + bad_words = await has_filter.filter_hits(guild, username) + if bad_words: + for word in bad_words: + username = username.replace(word, replace_word) + em = discord.Embed(description=converted_msg[:4096]) + colour = EMBED_DATA.get("colour", 0) + goodbye_colour = EMBED_DATA.get("colour_goodbye", 0) + em.colour = colour + if not is_welcome: + em.colour = goodbye_colour or colour + + if EMBED_DATA["title"]: + em.title = await self.convert_parms(member, guild, EMBED_DATA["title"], False) + if EMBED_DATA["footer"]: + em.set_footer( + text=await self.convert_parms(member, guild, EMBED_DATA["footer"], False) + ) + if EMBED_DATA["thumbnail"]: + url = EMBED_DATA["thumbnail"] + if url == "guild": + url = str(guild.icon.url) if guild.icon else "" + elif url == "splash": + url = str(guild.splash) if guild.splash else "" + elif url == "avatar": + url = str(member.display_avatar) if isinstance(member, discord.Member) else "" + em.set_thumbnail(url=url) + if EMBED_DATA["image"] or EMBED_DATA["image_goodbye"]: + url = "" + if EMBED_DATA["image"] and is_welcome: + url = EMBED_DATA["image"] + if EMBED_DATA["image_goodbye"] and not is_welcome: + url = EMBED_DATA["image_goodbye"] + if url == "guild": + url = str(guild.icon.url) if guild.icon else "" + elif url == "splash": + url = str(guild.splash) if guild.splash else "" + elif url == "avatar": + url = str(member.display_avatar) if isinstance(member, discord.Member) else "" + em.set_image(url=url) + if EMBED_DATA["icon_url"]: + url = EMBED_DATA["icon_url"] + if url == "guild": + url = str(guild.icon.url) if guild.icon else "" + elif url == "splash": + url = str(guild.splash) if guild.splash else "" + elif url == "avatar": + url = str(member.display_avatar) if isinstance(member, discord.Member) else "" + em.set_author(name=username, icon_url=url) + if EMBED_DATA["timestamp"]: + em.timestamp = datetime.now(timezone.utc) + if EMBED_DATA["author"] and isinstance(member, discord.Member): + em.set_author(name=username, icon_url=str(member.display_avatar)) + return em + + @commands.Cog.listener() + async def on_member_join(self, member: discord.Member) -> None: + guild = member.guild + if not await self.config.guild(guild).ON(): + return + if guild is None: + return + if await self.bot.cog_disabled_in_guild(self, guild): + return + if member.bot and await self.config.guild(guild).BOTS_MSG() is not None: + return await self.bot_welcome(member, guild) + td = timedelta(days=await self.config.guild(guild).MINIMUM_DAYS()) + if (datetime.now(timezone.utc) - member.created_at) <= td: + log.info("Member joined with an account newer than required days.") + return + has_filter = self.bot.get_cog("Filter") + filter_setting = await self.config.guild(guild).FILTER_SETTING() + if has_filter and filter_setting is None: + if version_info < VersionInfo.from_str("3.5.10"): + if await has_filter.filter_hits(member.name, guild): + log.info("Member joined with a bad username.") + return + else: + if await has_filter.filter_hits(guild, member.name): + log.info("Member joined with a bad username.") + return + + if datetime.now(timezone.utc).date() > self.today_count["now"].date(): + self.today_count = {"now": datetime.now(timezone.utc)} + # reset the daily count when a user joins the following day or when the cog is reloaded + + if guild.id not in self.today_count: + self.today_count[guild.id] = 1 + else: + self.today_count[guild.id] += 1 + + if await self.config.guild(guild).GROUPED(): + if guild.id not in self.joined: + self.joined[guild.id] = [] + log.debug("member joined") + if member not in self.joined[guild.id]: + return self.joined[guild.id].append(member) + await self.send_member_join(member, guild) + + async def bot_welcome(self, member: discord.Member, guild: discord.Guild): + bot_welcome = await self.config.guild(guild).BOTS_MSG() + bot_role = await self.config.guild(guild).BOTS_ROLE() + msg = bot_welcome or rand_choice(await self.config.guild(guild).GREETING()) + channel = await self.get_welcome_channel(member, guild) + is_embed = await self.config.guild(guild).EMBED() + mentions = await self.config.guild(guild).MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + + if bot_role: + try: + role = cast(discord.abc.Snowflake, guild.get_role(bot_role)) + await member.add_roles(role, reason=_("Automatic Bot Role")) + except Exception: + log.error( + "welcome.py: unable to add a role. %s %s", + bot_role, + member, + exc_info=True, + ) + else: + log.debug("welcome.py: added %s role to bot, %s", role, member) + if bot_welcome: + # finally, welcome them + if not channel: + return + if is_embed and channel.permissions_for(guild.me).embed_links: + em = await self.make_embed(member, guild, msg, False) + if await self.config.guild(guild).EMBED_DATA.mention(): + await channel.send(member.mention, embed=em, allowed_mentions=allowed_mentions) + else: + await channel.send(embed=em, allowed_mentions=allowed_mentions) + else: + await channel.send( + await self.convert_parms(member, guild, bot_welcome, False), + allowed_mentions=allowed_mentions, + ) + + async def get_welcome_channel( + self, member: Union[discord.Member, List[discord.Member]], guild: discord.Guild + ) -> Optional[discord.TextChannel]: + # grab the welcome channel + # guild_settings = await self.config.guild(guild).guild_settings() + c_id = await self.config.guild(guild).CHANNEL() + channel = cast(discord.TextChannel, guild.get_channel(c_id)) + only_whisper = await self.config.guild(guild).WHISPER() is True + if channel is None: # complain even if only whisper + if not only_whisper: + log.info( + "welcome.py: Channel not found. It was most likely deleted. User joined: %s", + member, + ) + return None + else: + # We will not complain here since some people only want the bot to whisper at times + return None + # we can stop here + + if not channel.permissions_for(guild.me).send_messages: + log.info("Permissions Error. User that joined: %s", member) + log.info( + "Bot doesn't have permissions to send messages to %s's $%s", + guild.name, + channel.name, + ) + return None + return channel + + async def send_member_join( + self, member: Union[discord.Member, List[discord.Member]], guild: discord.Guild + ) -> None: + only_whisper = await self.config.guild(guild).WHISPER() is True + channel = await self.get_welcome_channel(member, guild) + msgs = await self.config.guild(guild).GREETING() + if not msgs: + return + msg = rand_choice(msgs) + is_embed = await self.config.guild(guild).EMBED() + delete_after = await self.config.guild(guild).DELETE_AFTER_GREETING() + save_msg = None + mentions = await self.config.guild(guild).MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + + if await self.config.guild(guild).DELETE_PREVIOUS_GREETING(): + old_id = await self.config.guild(guild).LAST_GREETING() + if channel is not None and old_id is not None: + old_msg = None + try: + old_msg = await channel.fetch_message(old_id) + except discord.errors.NotFound: + pass + except discord.errors.Forbidden: + await self.config.guild(guild).DELETE_PREVIOUS_GREETING.set(False) + if old_msg: + await old_msg.delete() + # whisper the user if needed + if not await self.config.guild(guild).GROUPED(): + if await self.config.guild(guild).WHISPER(): + try: + if is_embed: + em = await self.make_embed(member, guild, msg, True) + if await self.config.guild(guild).EMBED_DATA.mention(): + await member.send(member.mention, embed=em) # type: ignore + else: + await member.send(embed=em) # type: ignore + else: + await member.send(await self.convert_parms(member, guild, msg, False)) # type: ignore + except discord.errors.Forbidden: + log.info( + "welcome.py: unable to whisper %s. Probably " "doesn't want to be PM'd", + member, + ) + except Exception: + log.error("error sending member join message", exc_info=True) + if only_whisper: + return + if not channel: + return + if is_embed and channel.permissions_for(guild.me).embed_links: + em = await self.make_embed(member, guild, msg, True) + if await self.config.guild(guild).EMBED_DATA.mention(): + if await self.config.guild(guild).GROUPED(): + members = cast(List[discord.Member], member) + save_msg = await channel.send( + humanize_list([m.mention for m in members]), + embed=em, + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + else: + member = cast(discord.Member, member) + save_msg = await channel.send( + str(member.mention), + embed=em, + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + else: + save_msg = await channel.send( + embed=em, + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + else: + save_msg = await channel.send( + await self.convert_parms(member, guild, msg, True), + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + if save_msg is not None: + await self.config.guild(guild).LAST_GREETING.set(save_msg.id) + + @commands.Cog.listener() + async def on_member_remove(self, member: discord.Member) -> None: + guild = member.guild + if guild is None: + return + + if await self.bot.cog_disabled_in_guild(self, guild): + return + if await self.config.guild(guild).GROUPED(): + if guild.id not in self.joined: + self.joined[guild.id] = [] + if member in self.joined[guild.id]: + self.joined[guild.id].remove(member) + + if not await self.config.guild(guild).LEAVE_ON(): + return + if member.bot and await self.config.guild(guild).BOTS_GOODBYE_MSG(): + await self.bot_leave(member, guild) + return + msgs = await self.config.guild(guild).GOODBYE() + if not msgs: + return + msg = rand_choice(msgs) + is_embed = await self.config.guild(guild).EMBED() + delete_after = await self.config.guild(guild).DELETE_AFTER_GOODBYE() + save_msg = None + mentions = await self.config.guild(guild).GOODBYE_MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + + # grab the welcome channel + # guild_settings = await self.config.guild(guild).guild_settings() + channel = self.bot.get_channel(await self.config.guild(guild).LEAVE_CHANNEL()) + if channel is None: # complain even if only whisper + log.debug("welcome.py: Channel not found in %s. It was most likely deleted.", guild) + return + # we can stop here + if await self.config.guild(guild).DELETE_PREVIOUS_GOODBYE(): + old_id = await self.config.guild(guild).LAST_GOODBYE() + if channel is not None and old_id is not None: + old_msg = None + try: + old_msg = await channel.fetch_message(old_id) + except discord.errors.NotFound: + log.debug("Message not found for deletion.") + pass + except discord.errors.Forbidden: + await self.config.guild(guild).DELETE_PREVIOUS_GOODBYE.set(False) + if old_msg: + await old_msg.delete() + + if not channel.permissions_for(guild.me).send_messages: + log.info("Permissions Error in {guild}") + return + elif not member.bot: + if is_embed and channel.permissions_for(guild.me).embed_links: + em = await self.make_embed(member, guild, msg, False) + if await self.config.guild(guild).EMBED_DATA.mention(): + save_msg = await channel.send( + member.mention, + embed=em, + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + else: + save_msg = await channel.send( + embed=em, delete_after=delete_after, allowed_mentions=allowed_mentions + ) + else: + save_msg = await channel.send( + await self.convert_parms(member, guild, msg, False), + delete_after=delete_after, + allowed_mentions=allowed_mentions, + ) + if save_msg is not None: + await self.config.guild(guild).LAST_GOODBYE.set(save_msg.id) + + async def bot_leave(self, member: discord.Member, guild: discord.Guild): + bot_welcome = await self.config.guild(guild).BOTS_GOODBYE_MSG() + msg = bot_welcome or rand_choice(await self.config.guild(guild).GOODBYE()) + channel = self.bot.get_channel(await self.config.guild(guild).LEAVE_CHANNEL()) + if channel is None: + return + is_embed = await self.config.guild(guild).EMBED() + mentions = await self.config.guild(guild).MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + if bot_welcome: + # finally, welcome them + if is_embed and channel.permissions_for(guild.me).embed_links: + em = await self.make_embed(member, guild, msg, False) + if await self.config.guild(guild).EMBED_DATA.mention(): + await channel.send(member.mention, embed=em, allowed_mentions=allowed_mentions) + else: + await channel.send(embed=em, allowed_mentions=allowed_mentions) + else: + await channel.send( + await self.convert_parms(member, guild, bot_welcome, False), + allowed_mentions=allowed_mentions, + ) + + async def send_testing_msg( + self, ctx: commands.Context, bot: bool = False, msg: str = None, leave: bool = False + ) -> None: + # log.info(leave) + default_greeting = "Welcome {0.name} to {1.name}!" + default_goodbye = "See you later {0.name}!" + default_bot_msg = "Hello {0.name}, fellow bot!" + guild = cast(discord.Guild, ctx.message.guild) + guild_settings = await self.config.guild(guild).get_raw() + # log.info(guild_settings) + mentions = await self.config.guild(guild).MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + channel = guild.get_channel(guild_settings["CHANNEL"]) + if leave: + channel = guild.get_channel(guild_settings["LEAVE_CHANNEL"]) + choices = guild_settings["GREETING"] or [default_greeting] + + if leave: + choices = guild_settings["GOODBYE"] or [default_goodbye] + rand_msg = rand_choice(choices) + if bot and guild_settings["BOTS_MSG"]: + rand_msg = guild_settings["BOTS_MSG"] + + if rand_msg is None and msg is None: + rand_msg = default_greeting + if rand_msg is None and bot: + rand_msg = default_bot_msg + if rand_msg is None and leave: + rand_msg = default_goodbye + is_welcome = not leave + is_embed = guild_settings["EMBED"] + member = cast(discord.Member, ctx.message.author) + members = cast(List[discord.Member], [ctx.author, ctx.me]) + whisper_settings = guild_settings["WHISPER"] + if channel is None and whisper_settings not in ["BOTH", True]: + msg = _("I can't find the specified channel. It might have been deleted.") + await ctx.send(msg) + return + msg = _("Sending test message to {location}. ").format( + location="DM" if channel is None else channel.mention + ) + if not guild_settings["GREETING"] and not leave: + msg += _("Using default greeting because there are none saved.") + elif not guild_settings["GOODBYE"] and leave: + msg += _("Using default goodbye because there are none saved.") + await ctx.send(msg, allowed_mentions=allowed_mentions) + if not bot and guild_settings["WHISPER"]: + if is_embed: + em = await self.make_embed(member, guild, rand_msg, is_welcome) + await ctx.author.send(embed=em, delete_after=60) + else: + await ctx.author.send( + await self.convert_parms(member, guild, rand_msg, is_welcome), + delete_after=60, + allowed_mentions=allowed_mentions, + ) + if guild_settings["WHISPER"] != "BOTH": + return + if bot or whisper_settings is not True: + if not channel: + return + + if is_embed and channel.permissions_for(guild.me).embed_links: + if guild_settings["GROUPED"]: + em = await self.make_embed(members, guild, rand_msg, is_welcome) + # only pass the list of members to simulate a grouped welcome + else: + em = await self.make_embed(member, guild, rand_msg, is_welcome) + + if await self.config.guild(guild).EMBED_DATA.mention(): + if guild_settings["GROUPED"]: + await channel.send( + humanize_list([m.mention for m in members]), embed=em, delete_after=60 + ) + else: + await channel.send( + member.mention, + embed=em, + delete_after=60, + allowed_mentions=allowed_mentions, + ) + else: + await channel.send( + embed=em, delete_after=60, allowed_mentions=allowed_mentions + ) + else: + await channel.send( + await self.convert_parms(members, guild, rand_msg, is_welcome), + delete_after=60, + allowed_mentions=allowed_mentions, + ) diff --git a/welcome/info.json b/welcome/info.json new file mode 100644 index 0000000..b7181d5 --- /dev/null +++ b/welcome/info.json @@ -0,0 +1,28 @@ +{ + "author": [ + "irdumb", + "TrustyJAID" + ], + "description": "Welcome new users to the server or say goodbye when they leave.", + "disabled": false, + "end_user_data_statement": "This cog does not persistently store data or metadata about users.", + "hidden": false, + "install_msg": "Use `[p]welcomeset` to see what options are available.", + "max_bot_version": "0.0.0", + "min_bot_version": "3.5.0", + "min_python_version": [ + 3, + 7, + 2 + ], + "name": "Welcome", + "permissions": [], + "required_cogs": {}, + "requirements": [], + "short": "Welcome new users to the server", + "tags": [ + "welcome", + "utility" + ], + "type": "COG" +} diff --git a/welcome/locales/fr-FR.po b/welcome/locales/fr-FR.po new file mode 100644 index 0000000..8b29da0 --- /dev/null +++ b/welcome/locales/fr-FR.po @@ -0,0 +1,717 @@ +msgid "" +msgstr "" +"Project-Id-Version: trusty-cogs\n" +"POT-Creation-Date: 2023-05-04 02:38+0000\n" +"PO-Revision-Date: 2023-05-10 16:09\n" +"Last-Translator: \n" +"Language-Team: French\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: redgettext 3.4.2\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Crowdin-Project: trusty-cogs\n" +"X-Crowdin-Project-ID: 510866\n" +"X-Crowdin-Language: fr\n" +"X-Crowdin-File: /dpy-2.0/welcome/locales/messages.pot\n" +"X-Crowdin-File-ID: 512\n" +"Language: fr_FR\n" + +#: welcome/events.py:88 +msgid "{raw_response}\n\n" +"{count} users joined today!" +msgstr "" + +#: welcome/events.py:169 +msgid "Member joined with an account newer than required days." +msgstr "" + +#: welcome/events.py:175 +msgid "Member joined with a bad username." +msgstr "" + +#: welcome/events.py:210 +msgid "Automatic Bot Role" +msgstr "" + +#: welcome/events.py:213 +msgid "welcome.py: unable to add a role. " +msgstr "" + +#: welcome/events.py:218 +msgid "welcome.py: added " +msgstr "" + +#: welcome/events.py:218 +msgid " role to " +msgstr "" + +#: welcome/events.py:218 +msgid "bot, " +msgstr "" + +#: welcome/events.py:246 +msgid "welcome.py: Channel not found. It was most likely deleted. User joined: " +msgstr "" + +#: welcome/events.py:256 +msgid "Permissions Error. User that joined: " +msgstr "" + +#: welcome/events.py:258 +msgid "Bot doesn't have permissions to send messages to " +msgstr "" + +#: welcome/events.py:305 +msgid "welcome.py: unable to whisper a user. Probably doesn't want to be PM'd" +msgstr "" + +#: welcome/events.py:385 +msgid "welcome.py: Channel not found in {guild}. It was most likely deleted." +msgstr "" + +#: welcome/events.py:406 +msgid "Permissions Error in {guild}" +msgstr "" + +#: welcome/events.py:460 +msgid "I can't find the specified channel. It might have been deleted." +msgstr "" + +#: welcome/events.py:464 welcome/events.py:467 +msgid "`Sending a testing message to " +msgstr "" + +#: welcome/welcome.py:64 +#, docstring +msgid "Welcomes new members and goodbye those who leave to the guild\n" +" in the default channel rewritten for V3 from\n" +" https://github.com/irdumbs/Dumb-Cogs/blob/master/welcome/welcome.py" +msgstr "" + +#: welcome/welcome.py:115 +#, docstring +msgid "Sets welcome module settings" +msgstr "" + +#: welcome/welcome.py:120 +#, docstring +msgid "\n" +" Show the servers welcome settings\n" +" " +msgstr "" + +#: welcome/welcome.py:126 +msgid "Random Greeting " +msgstr "" + +#: welcome/welcome.py:127 +msgid "Random Goodbye " +msgstr "" + +#: welcome/welcome.py:128 +msgid "Grouped welcomes " +msgstr "" + +#: welcome/welcome.py:129 +msgid "Welcomes On " +msgstr "" + +#: welcome/welcome.py:130 +msgid "Channel " +msgstr "" + +#: welcome/welcome.py:131 +msgid "Goodbyes On " +msgstr "" + +#: welcome/welcome.py:132 +msgid "Leaving Channel " +msgstr "" + +#: welcome/welcome.py:133 +msgid "Previous greeting deleted " +msgstr "" + +#: welcome/welcome.py:134 +msgid "Previous goodbye deleted " +msgstr "" + +#: welcome/welcome.py:135 +msgid "Greeting deleted after " +msgstr "" + +#: welcome/welcome.py:136 +msgid "Goodbye deleted after " +msgstr "" + +#: welcome/welcome.py:137 +msgid "Minimum days old to welcome " +msgstr "" + +#: welcome/welcome.py:138 +msgid "Whisper " +msgstr "" + +#: welcome/welcome.py:139 +msgid "Bots message " +msgstr "" + +#: welcome/welcome.py:140 +msgid "Bots role " +msgstr "" + +#: welcome/welcome.py:141 +msgid "Embeds " +msgstr "" + +#: welcome/welcome.py:146 +msgid "Welcome settings for " +msgstr "" + +#: welcome/welcome.py:161 welcome/welcome.py:168 +msgid " None" +msgstr "" + +#: welcome/welcome.py:184 +#, docstring +msgid "\n" +" Manage welcome messages\n" +" " +msgstr "" + +#: welcome/welcome.py:195 welcome/welcome.py:483 +#, docstring +msgid "\n" +" Determine the bots allowed mentions for welcomes\n\n" +" `` What to set the allowed mentions to either `True` or `False`.\n" +" `[allowed...]` must be either `everyone`, `users`, or `roles` and can include more than one.\n\n" +" Note: This will only function on Red 3.4.0 or higher.\n" +" " +msgstr "" + +#: welcome/welcome.py:205 welcome/welcome.py:210 welcome/welcome.py:493 +#: welcome/welcome.py:498 +msgid "You must provide either `users`, `roles` or `everyone`." +msgstr "" + +#: welcome/welcome.py:218 welcome/welcome.py:506 +msgid "I don't have mention everyone permissions so these settings may not work properly." +msgstr "" + +#: welcome/welcome.py:226 welcome/welcome.py:514 +msgid "Mention settings have been set to {set_to} for {settings}" +msgstr "" + +#: welcome/welcome.py:235 +#, docstring +msgid "Set whether to group welcome messages" +msgstr "" + +#: welcome/welcome.py:238 +msgid "I will now group welcomes." +msgstr "" + +#: welcome/welcome.py:240 +msgid "I will no longer group welcomes." +msgstr "" + +#: welcome/welcome.py:246 +#, docstring +msgid "\n" +" Adds a welcome message format for the guild to be chosen at random\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" Default is set to:\n" +" Welcome {0.name} to {1.name}!\n\n" +" Example formats:\n" +" {0.mention}.. What are you doing here?\n" +" {1.name} has a new member! {0.name}#{0.discriminator} - {0.id}\n" +" Someone new joined! Who is it?! D: IS HE HERE TO HURT US?!\n" +" " +msgstr "" + +#: welcome/welcome.py:264 +msgid "Welcome message added for the guild." +msgstr "" + +#: welcome/welcome.py:268 +#, docstring +msgid "Removes a welcome message from the random message list" +msgstr "" + +#: welcome/welcome.py:271 +msgid "Choose a welcome message to delete:\n\n" +msgstr "" + +#: welcome/welcome.py:284 welcome/welcome.py:562 +msgid "That's not a number in the list :/" +msgstr "" + +#: welcome/welcome.py:289 welcome/welcome.py:567 +msgid "**This message was deleted:**\n" +msgstr "" + +#: welcome/welcome.py:293 +#, docstring +msgid "\n" +" Lists the welcome messages of this guild\n" +" " +msgstr "" + +#: welcome/welcome.py:297 +msgid "Welcome messages:\n\n" +msgstr "" + +#: welcome/welcome.py:306 +#, docstring +msgid "\n" +" Turns on/off welcoming new users to the guild\n" +" " +msgstr "" + +#: welcome/welcome.py:313 +msgid "I will now welcome new users to the guild." +msgstr "" + +#: welcome/welcome.py:315 +msgid "I will no longer welcome new users." +msgstr "" + +#: welcome/welcome.py:320 welcome/welcome.py:620 +#, docstring +msgid "\n" +" Turns on/off deleting the previous welcome message when a user joins\n" +" " +msgstr "" + +#: welcome/welcome.py:328 +msgid "I will now delete the previous welcome message when a new user joins." +msgstr "" + +#: welcome/welcome.py:334 +msgid "I will stop deleting the previous welcome message when a new user joins." +msgstr "" + +#: welcome/welcome.py:342 +#, docstring +msgid "\n" +" Turns on/off showing how many users join each day.\n\n" +" This resets 24 hours after the cog was loaded.\n" +" " +msgstr "" + +#: welcome/welcome.py:352 +msgid "I will now show how many people join the server each day." +msgstr "" + +#: welcome/welcome.py:356 +msgid "I will stop showing how many people join the server each day." +msgstr "" + +#: welcome/welcome.py:364 +#, docstring +msgid "\n" +" Set the minimum number of days a user account must be to show up in the welcome message\n\n" +" `` number of days old the account must be, set to 0 to not require this.\n" +" " +msgstr "" + +#: welcome/welcome.py:374 +msgid "I will now show users joining who are {days} days old." +msgstr "" + +#: welcome/welcome.py:383 +#, docstring +msgid "\n" +" Set what to do when a username matches the bots filter.\n\n" +" `[replacement]` replaces usernames that are found by cores filter with this word.\n\n" +" If left blank, this will prevent welcome messages for usernames matching cores filter.\n\n" +" " +msgstr "" + +#: welcome/welcome.py:396 +msgid "I will now replace usernames matching cores filter with `{replacement}`" +msgstr "" + +#: welcome/welcome.py:402 welcome/welcome.py:415 +msgid "Filter is not loaded, run `{prefix}load filter` and add some words to filter for this to work" +msgstr "" + +#: welcome/welcome.py:409 +msgid "I will not post welcome messages for usernames that match cores filter." +msgstr "" + +#: welcome/welcome.py:425 welcome/welcome.py:642 +#, docstring +msgid "\n" +" Set the time after which a welcome message is deleted in seconds.\n\n" +" Providing no input will set the bot to not delete after any time.\n" +" " +msgstr "" + +#: welcome/welcome.py:432 +msgid "I will now delete welcome messages after {time} seconds." +msgstr "" + +#: welcome/welcome.py:437 welcome/welcome.py:654 +msgid "I will not delete welcome messages after a set time." +msgstr "" + +#: welcome/welcome.py:444 +#, docstring +msgid "\n" +" Sets the channel to send the welcome message\n\n" +" If channel isn\"t specified, the guild's default channel will be used\n" +" " +msgstr "" + +#: welcome/welcome.py:454 welcome/welcome.py:607 +msgid "I do not have permissions to send messages to {channel}" +msgstr "" + +#: welcome/welcome.py:461 +msgid "I will now send welcome messages to {channel}" +msgstr "" + +#: welcome/welcome.py:468 +#, docstring +msgid "Test the welcome message deleted after 60 seconds" +msgstr "" + +#: welcome/welcome.py:473 +#, docstring +msgid "\n" +" Manage goodbye messages\n" +" " +msgstr "" + +#: welcome/welcome.py:523 +#, docstring +msgid "\n" +" Adds a goodbye message format for the guild to be chosen at random\n\n" +" {0} is user\n" +" {1} is guild\n" +" Default is set to:\n" +" See you later {0.name}!\n\n" +" Example formats:\n" +" {0.mention}.. well, bye.\n" +" {1.name} has lost a member. {0.name}#{0.discriminator} - {0.id}\n" +" Someone has quit the server! Who is it?! D:\n" +" " +msgstr "" + +#: welcome/welcome.py:540 +msgid "Goodbye message added for the guild." +msgstr "" + +#: welcome/welcome.py:544 +#, docstring +msgid "\n" +" Removes a goodbye message from the random message list\n" +" " +msgstr "" + +#: welcome/welcome.py:549 +msgid "Choose a goodbye message to delete:\n\n" +msgstr "" + +#: welcome/welcome.py:571 +#, docstring +msgid "\n" +" Lists the goodbye messages of this guild\n" +" " +msgstr "" + +#: welcome/welcome.py:575 +msgid "Goodbye messages:\n\n" +msgstr "" + +#: welcome/welcome.py:584 +#, docstring +msgid "\n" +" Turns on/off goodbying users who leave to the guild\n" +" " +msgstr "" + +#: welcome/welcome.py:591 +msgid "I will now say goodbye when a member leaves the server." +msgstr "" + +#: welcome/welcome.py:594 +msgid "I will no longer say goodbye to members leaving the server." +msgstr "" + +#: welcome/welcome.py:602 +#, docstring +msgid "\n" +" Sets the channel to send the goodbye message\n" +" " +msgstr "" + +#: welcome/welcome.py:613 +msgid "I will now send goodbye messages to {channel}" +msgstr "" + +#: welcome/welcome.py:628 +msgid "I will now delete the previous goodbye message when user leaves." +msgstr "" + +#: welcome/welcome.py:632 +msgid "I will stop deleting the previous goodbye message when a user leaves." +msgstr "" + +#: welcome/welcome.py:649 +msgid "I will now delete goodbye messages after {time} seconds." +msgstr "" + +#: welcome/welcome.py:659 +#, docstring +msgid "Test the goodbye message deleted after 60 seconds" +msgstr "" + +#: welcome/welcome.py:664 +#, docstring +msgid "\n" +" Special welcome for bots\n" +" " +msgstr "" + +#: welcome/welcome.py:671 +#, docstring +msgid "Test the bot joining message" +msgstr "" + +#: welcome/welcome.py:678 +#, docstring +msgid "Set the welcome msg for bots.\n\n" +" Leave blank to reset to regular user welcome" +msgstr "" + +#: welcome/welcome.py:686 +msgid "Bot message reset. Bots will now be welcomed as regular users." +msgstr "" + +#: welcome/welcome.py:689 +msgid "Bot welcome message set for the guild." +msgstr "" + +#: welcome/welcome.py:696 +#, docstring +msgid "\n" +" Set the role to put bots in when they join.\n\n" +" Leave blank to not give them a role.\n" +" " +msgstr "" + +#: welcome/welcome.py:705 +msgid "I cannot assign roles higher than my own." +msgstr "" + +#: welcome/welcome.py:708 +msgid "Bots that join this guild will be given " +msgstr "" + +#: welcome/welcome.py:710 +msgid "Bots that join this guild will not be given a role." +msgstr "" + +#: welcome/welcome.py:717 +#, docstring +msgid "Sets whether or not a DM is sent to the new user\n\n" +" Options:\n" +" off - turns off DMs to users\n" +" only - only send a DM to the user, don\"t send a welcome to the channel\n" +" both - send a message to both the user and the channel\n\n" +" If Option isn't specified, toggles between \"off\" and \"only\"\n" +" DMs will not be sent to bots" +msgstr "" + +#: welcome/welcome.py:732 +msgid "You must select either `off`, `only`, or `both`." +msgstr "" + +#: welcome/welcome.py:738 +msgid "I will no longer send DMs to new users" +msgstr "" + +#: welcome/welcome.py:741 +msgid "I will now send welcome messages to {channel} as well as to the new user in a DM" +msgstr "" + +#: welcome/welcome.py:746 +msgid "I will now only send welcome messages to the new user as a DM" +msgstr "" + +#: welcome/welcome.py:752 +#, docstring +msgid "\n" +" Set various embed options\n" +" " +msgstr "" + +#: welcome/welcome.py:759 +#, docstring +msgid "\n" +" Toggle embed messages\n" +" " +msgstr "" + +#: welcome/welcome.py:766 welcome/welcome.py:982 welcome/welcome.py:997 +#: welcome/welcome.py:1012 +msgid "off" +msgstr "" + +#: welcome/welcome.py:768 welcome/welcome.py:984 welcome/welcome.py:999 +#: welcome/welcome.py:1014 +msgid "on" +msgstr "" + +#: welcome/welcome.py:769 +msgid "Welcome embeds turned {verb}" +msgstr "" + +#: welcome/welcome.py:773 +#, docstring +msgid "\n" +" Set the embed colour\n\n" +" This accepts hex codes and integer value colours\n" +" " +msgstr "" + +#: welcome/welcome.py:783 +#, docstring +msgid "\n" +" Set the embed title\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" " +msgstr "" + +#: welcome/welcome.py:795 +#, docstring +msgid "\n" +" Set the embed footer\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" " +msgstr "" + +#: welcome/welcome.py:809 +#, docstring +msgid "\n" +" Set the embed thumbnail image\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:837 welcome/welcome.py:875 welcome/welcome.py:922 +#: welcome/welcome.py:966 +msgid "That's not a valid option. You must provide a link, `avatar` or `server`." +msgstr "" + +#: welcome/welcome.py:843 +msgid "Thumbnail cleared." +msgstr "" + +#: welcome/welcome.py:847 +#, docstring +msgid "\n" +" Set the embed icon image\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:881 +msgid "Icon cleared." +msgstr "" + +#: welcome/welcome.py:885 +#, docstring +msgid "\n" +" Set embed image options\n" +" " +msgstr "" + +#: welcome/welcome.py:894 +#, docstring +msgid "\n" +" Set the embed image link for greetings\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:928 +msgid "Greeting image cleared." +msgstr "" + +#: welcome/welcome.py:934 +#, docstring +msgid "\n" +" Set the embed image link for goodbyes\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:972 +msgid "Goodbye image cleared." +msgstr "" + +#: welcome/welcome.py:976 +#, docstring +msgid "\n" +" Toggle the timestamp in embeds\n" +" " +msgstr "" + +#: welcome/welcome.py:985 +msgid "Timestamps turned {verb}" +msgstr "" + +#: welcome/welcome.py:989 +#, docstring +msgid "\n" +" Toggle the author field being filled in the embed\n\n" +" Note: This will override the icon image if it is set\n" +" " +msgstr "" + +#: welcome/welcome.py:1000 +msgid "Author field turned {verb}" +msgstr "" + +#: welcome/welcome.py:1004 +#, docstring +msgid "\n" +" Toggle mentioning the user when they join\n\n" +" This will add a mention outside the embed so they actually get the mention.\n" +" " +msgstr "" + +#: welcome/welcome.py:1015 +msgid "Mentioning the user turned {verb}" +msgstr "" + diff --git a/welcome/locales/messages.pot b/welcome/locales/messages.pot new file mode 100644 index 0000000..53a039f --- /dev/null +++ b/welcome/locales/messages.pot @@ -0,0 +1,293 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2018-12-14 18:28-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: redgettext 2.1\n" + + +#: welcome.py:24 +#, docstring +msgid "" +"Welcomes new members to the guild in the default channel rewritten for V3 from\n" +" https://github.com/irdumbs/Dumb-Cogs/blob/master/welcome/welcome.py" +msgstr "" + +#: welcome.py:36 +#, docstring +msgid "Sets welcome module settings" +msgstr "" + +#: welcome.py:40 +msgid "Random Greeting " +msgstr "" + +#: welcome.py:41 +msgid "On " +msgstr "" + +#: welcome.py:42 +msgid "Channel " +msgstr "" + +#: welcome.py:43 +msgid "Whisper " +msgstr "" + +#: welcome.py:44 +msgid "Bots message " +msgstr "" + +#: welcome.py:45 +msgid "Bots role " +msgstr "" + +#: welcome.py:46 +msgid "Embeds " +msgstr "" + +#: welcome.py:49 +msgid "Welcome settings for " +msgstr "" + +#: welcome.py:76 +#, docstring +msgid "" +"\n" +" Manage welcome messages\n" +" " +msgstr "" + +#: welcome.py:83 +#, docstring +msgid "" +"\n" +" Adds a welcome message format for the guild to be chosen at random\n" +"\n" +" {0} is user\n" +" {1} is guild\n" +" Default is set to:\n" +" Welcome {0.name} to {1.name}!\n" +"\n" +" Example formats:\n" +" {0.mention}.. What are you doing here?\n" +" {1.name} has a new member! {0.name}#{0.discriminator} - {0.id}\n" +" Someone new joined! Who is it?! D: IS HE HERE TO HURT US?!\n" +" " +msgstr "" + +#: welcome.py:100 +msgid "Welcome message added for the guild." +msgstr "" + +#: welcome.py:105 +#, docstring +msgid "" +"Removes a welcome message from the random message list\n" +" " +msgstr "" + +#: welcome.py:110 +msgid "" +"Choose a welcome message to delete:\n" +"\n" +msgstr "" + +#: welcome.py:125 +msgid "That's not a number in the list :/" +msgstr "" + +#: welcome.py:130 +msgid "" +"**This message was deleted:**\n" +msgstr "" + +#: welcome.py:134 +#, docstring +msgid "" +"\n" +" Lists the welcome messages of this guild\n" +" " +msgstr "" + +#: welcome.py:138 +msgid "" +"Welcome messages:\n" +"\n" +msgstr "" + +#: welcome.py:147 +#, docstring +msgid "" +"\n" +" Turns on/off welcoming new users to the guild\n" +" " +msgstr "" + +#: welcome.py:154 +msgid "I will now welcome new users to the guild." +msgstr "" + +#: welcome.py:157 +msgid "I will no longer welcome new users." +msgstr "" + +#: welcome.py:162 +#, docstring +msgid "" +"\n" +" Sets the channel to send the welcome message\n" +"\n" +" If channel isn\"t specified, the guild\"s default channel will be used\n" +" " +msgstr "" + +#: welcome.py:172 +msgid "I do not have permissions to send messages to " +msgstr "" + +#: welcome.py:179 +msgid "I will now send welcome messages to " +msgstr "" + +#: welcome.py:186 +#, docstring +msgid "" +"\n" +" Special welcome for bots\n" +" " +msgstr "" + +#: welcome.py:193 +#, docstring +msgid "" +"Set the welcome msg for bots.\n" +"\n" +" Leave blank to reset to regular user welcome" +msgstr "" + +#: welcome.py:201 +msgid "Bot message reset. Bots will now be welcomed as regular users." +msgstr "" + +#: welcome.py:205 +msgid "Bot welcome message set for the guild." +msgstr "" + +#: welcome.py:211 +#, docstring +msgid "" +"\n" +" Set the role to put bots in when they join.\n" +"\n" +" Leave blank to not give them a role.\n" +" " +msgstr "" + +#: welcome.py:220 +msgid "Bots that join this guild will be given " +msgstr "" + +#: welcome.py:225 +#, docstring +msgid "" +"Sets whether or not a DM is sent to the new user\n" +"\n" +" Options:\n" +" off - turns off DMs to users\n" +" only - only send a DM to the user, don\"t send a welcome to the channel\n" +" both - send a message to both the user and the channel\n" +"\n" +" If Option isn\"t specified, toggles between \"off\" and \"only\"\n" +" DMs will not be sent to bots" +msgstr "" + +#: welcome.py:247 +msgid "I will no longer send DMs to new users" +msgstr "" + +#: welcome.py:249 +msgid "I will now send welcome " +msgstr "" + +#: welcome.py:250 +msgid "messages to " +msgstr "" + +#: welcome.py:251 +msgid " as well as to the new user in a DM" +msgstr "" + +#: welcome.py:254 +msgid "I will now only send welcome messages to the new user as a DM" +msgstr "" + +#: welcome.py:262 +#, docstring +msgid "" +"\n" +" Turns on/off embed messages\n" +" " +msgstr "" + +#: welcome.py:270 +msgid "I will now welcome new users to the guild in embeds." +msgstr "" + +#: welcome.py:313 +msgid "welcome.py: unable to whisper a user. Probably doesn't want to be PM'd" +msgstr "" + +#: welcome.py:319 +msgid "welcome.py: Channel not found. It was most likely deleted. User joined: " +msgstr "" + +#: welcome.py:325 +msgid "Permissions Error. User that joined: " +msgstr "" + +#: welcome.py:327 +msgid "Bot doesn't have permissions to send messages to " +msgstr "" + +#: welcome.py:337 +msgid "welcome.py: unable to add a role. " +msgstr "" + +#: welcome.py:340 +msgid "welcome.py: added " +msgstr "" + +#: welcome.py:340 +msgid " role to " +msgstr "" + +#: welcome.py:341 +msgid "bot, " +msgstr "" + +#: welcome.py:382 +msgid "I can't find the specified channel. It might have been deleted." +msgstr "" + +#: welcome.py:386 +msgid "`Sending a testing message to " +msgstr "" + +#: welcome.py:404 +msgid "I do not have permissions " +msgstr "" + +#: welcome.py:405 +msgid "to send messages to " +msgstr "" + diff --git a/welcome/locales/sv-SE.po b/welcome/locales/sv-SE.po new file mode 100644 index 0000000..33859b7 --- /dev/null +++ b/welcome/locales/sv-SE.po @@ -0,0 +1,717 @@ +msgid "" +msgstr "" +"Project-Id-Version: trusty-cogs\n" +"POT-Creation-Date: 2023-05-04 02:38+0000\n" +"PO-Revision-Date: 2023-05-10 16:10\n" +"Last-Translator: \n" +"Language-Team: Swedish\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: redgettext 3.4.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: trusty-cogs\n" +"X-Crowdin-Project-ID: 510866\n" +"X-Crowdin-Language: sv-SE\n" +"X-Crowdin-File: /dpy-2.0/welcome/locales/messages.pot\n" +"X-Crowdin-File-ID: 512\n" +"Language: sv_SE\n" + +#: welcome/events.py:88 +msgid "{raw_response}\n\n" +"{count} users joined today!" +msgstr "" + +#: welcome/events.py:169 +msgid "Member joined with an account newer than required days." +msgstr "" + +#: welcome/events.py:175 +msgid "Member joined with a bad username." +msgstr "" + +#: welcome/events.py:210 +msgid "Automatic Bot Role" +msgstr "" + +#: welcome/events.py:213 +msgid "welcome.py: unable to add a role. " +msgstr "" + +#: welcome/events.py:218 +msgid "welcome.py: added " +msgstr "" + +#: welcome/events.py:218 +msgid " role to " +msgstr "" + +#: welcome/events.py:218 +msgid "bot, " +msgstr "" + +#: welcome/events.py:246 +msgid "welcome.py: Channel not found. It was most likely deleted. User joined: " +msgstr "" + +#: welcome/events.py:256 +msgid "Permissions Error. User that joined: " +msgstr "" + +#: welcome/events.py:258 +msgid "Bot doesn't have permissions to send messages to " +msgstr "" + +#: welcome/events.py:305 +msgid "welcome.py: unable to whisper a user. Probably doesn't want to be PM'd" +msgstr "" + +#: welcome/events.py:385 +msgid "welcome.py: Channel not found in {guild}. It was most likely deleted." +msgstr "" + +#: welcome/events.py:406 +msgid "Permissions Error in {guild}" +msgstr "" + +#: welcome/events.py:460 +msgid "I can't find the specified channel. It might have been deleted." +msgstr "" + +#: welcome/events.py:464 welcome/events.py:467 +msgid "`Sending a testing message to " +msgstr "" + +#: welcome/welcome.py:64 +#, docstring +msgid "Welcomes new members and goodbye those who leave to the guild\n" +" in the default channel rewritten for V3 from\n" +" https://github.com/irdumbs/Dumb-Cogs/blob/master/welcome/welcome.py" +msgstr "" + +#: welcome/welcome.py:115 +#, docstring +msgid "Sets welcome module settings" +msgstr "" + +#: welcome/welcome.py:120 +#, docstring +msgid "\n" +" Show the servers welcome settings\n" +" " +msgstr "" + +#: welcome/welcome.py:126 +msgid "Random Greeting " +msgstr "" + +#: welcome/welcome.py:127 +msgid "Random Goodbye " +msgstr "" + +#: welcome/welcome.py:128 +msgid "Grouped welcomes " +msgstr "" + +#: welcome/welcome.py:129 +msgid "Welcomes On " +msgstr "" + +#: welcome/welcome.py:130 +msgid "Channel " +msgstr "" + +#: welcome/welcome.py:131 +msgid "Goodbyes On " +msgstr "" + +#: welcome/welcome.py:132 +msgid "Leaving Channel " +msgstr "" + +#: welcome/welcome.py:133 +msgid "Previous greeting deleted " +msgstr "" + +#: welcome/welcome.py:134 +msgid "Previous goodbye deleted " +msgstr "" + +#: welcome/welcome.py:135 +msgid "Greeting deleted after " +msgstr "" + +#: welcome/welcome.py:136 +msgid "Goodbye deleted after " +msgstr "" + +#: welcome/welcome.py:137 +msgid "Minimum days old to welcome " +msgstr "" + +#: welcome/welcome.py:138 +msgid "Whisper " +msgstr "" + +#: welcome/welcome.py:139 +msgid "Bots message " +msgstr "" + +#: welcome/welcome.py:140 +msgid "Bots role " +msgstr "" + +#: welcome/welcome.py:141 +msgid "Embeds " +msgstr "" + +#: welcome/welcome.py:146 +msgid "Welcome settings for " +msgstr "" + +#: welcome/welcome.py:161 welcome/welcome.py:168 +msgid " None" +msgstr "" + +#: welcome/welcome.py:184 +#, docstring +msgid "\n" +" Manage welcome messages\n" +" " +msgstr "" + +#: welcome/welcome.py:195 welcome/welcome.py:483 +#, docstring +msgid "\n" +" Determine the bots allowed mentions for welcomes\n\n" +" `` What to set the allowed mentions to either `True` or `False`.\n" +" `[allowed...]` must be either `everyone`, `users`, or `roles` and can include more than one.\n\n" +" Note: This will only function on Red 3.4.0 or higher.\n" +" " +msgstr "" + +#: welcome/welcome.py:205 welcome/welcome.py:210 welcome/welcome.py:493 +#: welcome/welcome.py:498 +msgid "You must provide either `users`, `roles` or `everyone`." +msgstr "" + +#: welcome/welcome.py:218 welcome/welcome.py:506 +msgid "I don't have mention everyone permissions so these settings may not work properly." +msgstr "" + +#: welcome/welcome.py:226 welcome/welcome.py:514 +msgid "Mention settings have been set to {set_to} for {settings}" +msgstr "" + +#: welcome/welcome.py:235 +#, docstring +msgid "Set whether to group welcome messages" +msgstr "" + +#: welcome/welcome.py:238 +msgid "I will now group welcomes." +msgstr "" + +#: welcome/welcome.py:240 +msgid "I will no longer group welcomes." +msgstr "" + +#: welcome/welcome.py:246 +#, docstring +msgid "\n" +" Adds a welcome message format for the guild to be chosen at random\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" Default is set to:\n" +" Welcome {0.name} to {1.name}!\n\n" +" Example formats:\n" +" {0.mention}.. What are you doing here?\n" +" {1.name} has a new member! {0.name}#{0.discriminator} - {0.id}\n" +" Someone new joined! Who is it?! D: IS HE HERE TO HURT US?!\n" +" " +msgstr "" + +#: welcome/welcome.py:264 +msgid "Welcome message added for the guild." +msgstr "" + +#: welcome/welcome.py:268 +#, docstring +msgid "Removes a welcome message from the random message list" +msgstr "" + +#: welcome/welcome.py:271 +msgid "Choose a welcome message to delete:\n\n" +msgstr "" + +#: welcome/welcome.py:284 welcome/welcome.py:562 +msgid "That's not a number in the list :/" +msgstr "" + +#: welcome/welcome.py:289 welcome/welcome.py:567 +msgid "**This message was deleted:**\n" +msgstr "" + +#: welcome/welcome.py:293 +#, docstring +msgid "\n" +" Lists the welcome messages of this guild\n" +" " +msgstr "" + +#: welcome/welcome.py:297 +msgid "Welcome messages:\n\n" +msgstr "" + +#: welcome/welcome.py:306 +#, docstring +msgid "\n" +" Turns on/off welcoming new users to the guild\n" +" " +msgstr "" + +#: welcome/welcome.py:313 +msgid "I will now welcome new users to the guild." +msgstr "" + +#: welcome/welcome.py:315 +msgid "I will no longer welcome new users." +msgstr "" + +#: welcome/welcome.py:320 welcome/welcome.py:620 +#, docstring +msgid "\n" +" Turns on/off deleting the previous welcome message when a user joins\n" +" " +msgstr "" + +#: welcome/welcome.py:328 +msgid "I will now delete the previous welcome message when a new user joins." +msgstr "" + +#: welcome/welcome.py:334 +msgid "I will stop deleting the previous welcome message when a new user joins." +msgstr "" + +#: welcome/welcome.py:342 +#, docstring +msgid "\n" +" Turns on/off showing how many users join each day.\n\n" +" This resets 24 hours after the cog was loaded.\n" +" " +msgstr "" + +#: welcome/welcome.py:352 +msgid "I will now show how many people join the server each day." +msgstr "" + +#: welcome/welcome.py:356 +msgid "I will stop showing how many people join the server each day." +msgstr "" + +#: welcome/welcome.py:364 +#, docstring +msgid "\n" +" Set the minimum number of days a user account must be to show up in the welcome message\n\n" +" `` number of days old the account must be, set to 0 to not require this.\n" +" " +msgstr "" + +#: welcome/welcome.py:374 +msgid "I will now show users joining who are {days} days old." +msgstr "" + +#: welcome/welcome.py:383 +#, docstring +msgid "\n" +" Set what to do when a username matches the bots filter.\n\n" +" `[replacement]` replaces usernames that are found by cores filter with this word.\n\n" +" If left blank, this will prevent welcome messages for usernames matching cores filter.\n\n" +" " +msgstr "" + +#: welcome/welcome.py:396 +msgid "I will now replace usernames matching cores filter with `{replacement}`" +msgstr "" + +#: welcome/welcome.py:402 welcome/welcome.py:415 +msgid "Filter is not loaded, run `{prefix}load filter` and add some words to filter for this to work" +msgstr "" + +#: welcome/welcome.py:409 +msgid "I will not post welcome messages for usernames that match cores filter." +msgstr "" + +#: welcome/welcome.py:425 welcome/welcome.py:642 +#, docstring +msgid "\n" +" Set the time after which a welcome message is deleted in seconds.\n\n" +" Providing no input will set the bot to not delete after any time.\n" +" " +msgstr "" + +#: welcome/welcome.py:432 +msgid "I will now delete welcome messages after {time} seconds." +msgstr "" + +#: welcome/welcome.py:437 welcome/welcome.py:654 +msgid "I will not delete welcome messages after a set time." +msgstr "" + +#: welcome/welcome.py:444 +#, docstring +msgid "\n" +" Sets the channel to send the welcome message\n\n" +" If channel isn\"t specified, the guild's default channel will be used\n" +" " +msgstr "" + +#: welcome/welcome.py:454 welcome/welcome.py:607 +msgid "I do not have permissions to send messages to {channel}" +msgstr "" + +#: welcome/welcome.py:461 +msgid "I will now send welcome messages to {channel}" +msgstr "" + +#: welcome/welcome.py:468 +#, docstring +msgid "Test the welcome message deleted after 60 seconds" +msgstr "" + +#: welcome/welcome.py:473 +#, docstring +msgid "\n" +" Manage goodbye messages\n" +" " +msgstr "" + +#: welcome/welcome.py:523 +#, docstring +msgid "\n" +" Adds a goodbye message format for the guild to be chosen at random\n\n" +" {0} is user\n" +" {1} is guild\n" +" Default is set to:\n" +" See you later {0.name}!\n\n" +" Example formats:\n" +" {0.mention}.. well, bye.\n" +" {1.name} has lost a member. {0.name}#{0.discriminator} - {0.id}\n" +" Someone has quit the server! Who is it?! D:\n" +" " +msgstr "" + +#: welcome/welcome.py:540 +msgid "Goodbye message added for the guild." +msgstr "" + +#: welcome/welcome.py:544 +#, docstring +msgid "\n" +" Removes a goodbye message from the random message list\n" +" " +msgstr "" + +#: welcome/welcome.py:549 +msgid "Choose a goodbye message to delete:\n\n" +msgstr "" + +#: welcome/welcome.py:571 +#, docstring +msgid "\n" +" Lists the goodbye messages of this guild\n" +" " +msgstr "" + +#: welcome/welcome.py:575 +msgid "Goodbye messages:\n\n" +msgstr "" + +#: welcome/welcome.py:584 +#, docstring +msgid "\n" +" Turns on/off goodbying users who leave to the guild\n" +" " +msgstr "" + +#: welcome/welcome.py:591 +msgid "I will now say goodbye when a member leaves the server." +msgstr "" + +#: welcome/welcome.py:594 +msgid "I will no longer say goodbye to members leaving the server." +msgstr "" + +#: welcome/welcome.py:602 +#, docstring +msgid "\n" +" Sets the channel to send the goodbye message\n" +" " +msgstr "" + +#: welcome/welcome.py:613 +msgid "I will now send goodbye messages to {channel}" +msgstr "" + +#: welcome/welcome.py:628 +msgid "I will now delete the previous goodbye message when user leaves." +msgstr "" + +#: welcome/welcome.py:632 +msgid "I will stop deleting the previous goodbye message when a user leaves." +msgstr "" + +#: welcome/welcome.py:649 +msgid "I will now delete goodbye messages after {time} seconds." +msgstr "" + +#: welcome/welcome.py:659 +#, docstring +msgid "Test the goodbye message deleted after 60 seconds" +msgstr "" + +#: welcome/welcome.py:664 +#, docstring +msgid "\n" +" Special welcome for bots\n" +" " +msgstr "" + +#: welcome/welcome.py:671 +#, docstring +msgid "Test the bot joining message" +msgstr "" + +#: welcome/welcome.py:678 +#, docstring +msgid "Set the welcome msg for bots.\n\n" +" Leave blank to reset to regular user welcome" +msgstr "" + +#: welcome/welcome.py:686 +msgid "Bot message reset. Bots will now be welcomed as regular users." +msgstr "" + +#: welcome/welcome.py:689 +msgid "Bot welcome message set for the guild." +msgstr "" + +#: welcome/welcome.py:696 +#, docstring +msgid "\n" +" Set the role to put bots in when they join.\n\n" +" Leave blank to not give them a role.\n" +" " +msgstr "" + +#: welcome/welcome.py:705 +msgid "I cannot assign roles higher than my own." +msgstr "" + +#: welcome/welcome.py:708 +msgid "Bots that join this guild will be given " +msgstr "" + +#: welcome/welcome.py:710 +msgid "Bots that join this guild will not be given a role." +msgstr "" + +#: welcome/welcome.py:717 +#, docstring +msgid "Sets whether or not a DM is sent to the new user\n\n" +" Options:\n" +" off - turns off DMs to users\n" +" only - only send a DM to the user, don\"t send a welcome to the channel\n" +" both - send a message to both the user and the channel\n\n" +" If Option isn't specified, toggles between \"off\" and \"only\"\n" +" DMs will not be sent to bots" +msgstr "" + +#: welcome/welcome.py:732 +msgid "You must select either `off`, `only`, or `both`." +msgstr "" + +#: welcome/welcome.py:738 +msgid "I will no longer send DMs to new users" +msgstr "" + +#: welcome/welcome.py:741 +msgid "I will now send welcome messages to {channel} as well as to the new user in a DM" +msgstr "" + +#: welcome/welcome.py:746 +msgid "I will now only send welcome messages to the new user as a DM" +msgstr "" + +#: welcome/welcome.py:752 +#, docstring +msgid "\n" +" Set various embed options\n" +" " +msgstr "" + +#: welcome/welcome.py:759 +#, docstring +msgid "\n" +" Toggle embed messages\n" +" " +msgstr "" + +#: welcome/welcome.py:766 welcome/welcome.py:982 welcome/welcome.py:997 +#: welcome/welcome.py:1012 +msgid "off" +msgstr "" + +#: welcome/welcome.py:768 welcome/welcome.py:984 welcome/welcome.py:999 +#: welcome/welcome.py:1014 +msgid "on" +msgstr "" + +#: welcome/welcome.py:769 +msgid "Welcome embeds turned {verb}" +msgstr "" + +#: welcome/welcome.py:773 +#, docstring +msgid "\n" +" Set the embed colour\n\n" +" This accepts hex codes and integer value colours\n" +" " +msgstr "" + +#: welcome/welcome.py:783 +#, docstring +msgid "\n" +" Set the embed title\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" " +msgstr "" + +#: welcome/welcome.py:795 +#, docstring +msgid "\n" +" Set the embed footer\n\n" +" {0} is user\n" +" {1} is guild\n" +" {count} can be used to display number of users who have joined today.\n" +" " +msgstr "" + +#: welcome/welcome.py:809 +#, docstring +msgid "\n" +" Set the embed thumbnail image\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:837 welcome/welcome.py:875 welcome/welcome.py:922 +#: welcome/welcome.py:966 +msgid "That's not a valid option. You must provide a link, `avatar` or `server`." +msgstr "" + +#: welcome/welcome.py:843 +msgid "Thumbnail cleared." +msgstr "" + +#: welcome/welcome.py:847 +#, docstring +msgid "\n" +" Set the embed icon image\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:881 +msgid "Icon cleared." +msgstr "" + +#: welcome/welcome.py:885 +#, docstring +msgid "\n" +" Set embed image options\n" +" " +msgstr "" + +#: welcome/welcome.py:894 +#, docstring +msgid "\n" +" Set the embed image link for greetings\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:928 +msgid "Greeting image cleared." +msgstr "" + +#: welcome/welcome.py:934 +#, docstring +msgid "\n" +" Set the embed image link for goodbyes\n\n" +" `[link]` must be a valid image link\n" +" You may also specify:\n" +" `member`, `user` or `avatar` to use the members avatar\n" +" `server` or `guild` to use the servers icon\n" +" `splash` to use the servers splash image if available\n" +" if nothing is provided the defaults are used.\n" +" " +msgstr "" + +#: welcome/welcome.py:972 +msgid "Goodbye image cleared." +msgstr "" + +#: welcome/welcome.py:976 +#, docstring +msgid "\n" +" Toggle the timestamp in embeds\n" +" " +msgstr "" + +#: welcome/welcome.py:985 +msgid "Timestamps turned {verb}" +msgstr "" + +#: welcome/welcome.py:989 +#, docstring +msgid "\n" +" Toggle the author field being filled in the embed\n\n" +" Note: This will override the icon image if it is set\n" +" " +msgstr "" + +#: welcome/welcome.py:1000 +msgid "Author field turned {verb}" +msgstr "" + +#: welcome/welcome.py:1004 +#, docstring +msgid "\n" +" Toggle mentioning the user when they join\n\n" +" This will add a mention outside the embed so they actually get the mention.\n" +" " +msgstr "" + +#: welcome/welcome.py:1015 +msgid "Mentioning the user turned {verb}" +msgstr "" + diff --git a/welcome/menus.py b/welcome/menus.py new file mode 100644 index 0000000..269d480 --- /dev/null +++ b/welcome/menus.py @@ -0,0 +1,600 @@ +from __future__ import annotations + +import re +from enum import Enum +from typing import Any, List, Optional, Union + +import discord +from red_commons.logging import getLogger +from redbot.core import commands +from redbot.core.i18n import Translator +from redbot.core.utils.chat_formatting import box, escape +from redbot.vendored.discord.ext import menus + +IMAGE_LINKS = re.compile(r"(http[s]?:\/\/[^\"\']*\.(?:png|jpg|jpeg|gif|png|webp))") + + +class EventType(Enum): + greeting = 0 + goodbye = 1 + + def get_name(self): + return {EventType.greeting: _("greeting"), EventType.goodbye: _("goodbye")}.get(self) + + def __str__(self): + return self.get_name() + + def key(self): + return self.name.upper() + + +log = getLogger("red.Trusty-cogs.welcome") +_ = Translator("Welcome", __file__) + + +class WelcomePages(menus.ListPageSource): + def __init__(self, pages: List[str]): + super().__init__(pages, per_page=1) + self.pages = pages + self.select_options = [] + for count, page in enumerate(pages): + self.select_options.append(discord.SelectOption(label=f"Page {count+1}", value=count)) + self.current_page = None + self.current_selection = None + + def is_paginating(self): + return True + + async def format_page(self, view: BaseMenu, page: str): + self.current_page = view.current_page + config = view.cog.config + msgs = await config.guild(view.ctx.guild).get_raw(view.event_type.key()) + try: + raw_text = msgs[self.current_page] + view.enable_extra_buttons() + except IndexError: + raw_text = _("Deleted Greeting") + view.disable_extra_buttons() + self.current_selection = raw_text + is_welcome = view.event_type is EventType.greeting + colour = await config.guild(view.ctx.guild).EMBED_DATA.colour() + colour_goodbye = await config.guild(view.ctx.guild).EMBED_DATA.colour_goodbye() + em_colour = discord.Colour(colour) + if not is_welcome: + em_colour = colour_goodbye or colour + + if view.show_preview: + grouped = await config.guild(view.ctx.guild).GROUPED() + members = view.ctx.author if not grouped else [view.ctx.author, view.ctx.me] + if await config.guild(view.ctx.guild).EMBED(): + return await view.cog.make_embed(members, view.ctx.guild, raw_text, is_welcome) + else: + return await view.cog.convert_parms(members, view.ctx.guild, raw_text, is_welcome) + display_text = raw_text + if view.show_raw: + display_text = escape(display_text, formatting=True) + display_text = re.sub(r"(<@?[!&#]?[0-9]{17,20}>)", r"\\\1", display_text) + if view.ctx.channel.permissions_for(view.ctx.guild.me).embed_links: + em = discord.Embed( + title=_("{event_type} message {count}").format( + event_type=view.event_type.get_name().title(), count=view.current_page + 1 + ), + description=display_text, + colour=em_colour, + ) + em.set_footer(text=f"Page {view.current_page + 1}/{self.get_max_pages()}") + return em + return display_text + + +class StopButton(discord.ui.Button): + def __init__( + self, + style: discord.ButtonStyle, + row: Optional[int], + ): + super().__init__(style=style, row=row) + self.style = style + self.emoji = "\N{HEAVY MULTIPLICATION X}\N{VARIATION SELECTOR-16}" + + async def callback(self, interaction: discord.Interaction): + self.view.stop() + await self.view.message.delete() + + +class _NavigateButton(discord.ui.Button): + # Borrowed from myself mainly + # https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/develop/redbot/core/utils/views.py#L44 + def __init__( + self, style: discord.ButtonStyle, emoji: Union[str, discord.PartialEmoji], direction: int + ): + super().__init__(style=style, emoji=emoji) + self.direction = direction + + async def callback(self, interaction: discord.Interaction): + if self.direction == 0: + self.view.current_page = 0 + elif self.direction == self.view.source.get_max_pages(): + self.view.current_page = self.view.source.get_max_pages() - 1 + else: + self.view.current_page += self.direction + await self.view.show_checked_page(self.view.current_page, interaction) + + +class ToggleButton(discord.ui.Button): + def __init__(self, attr_toggle: str, style: discord.ButtonStyle, label: str): + super().__init__(style=style, label=label) + self.attr_toggle = attr_toggle + + async def callback(self, interaction: discord.Interaction): + current = getattr(self.view, self.attr_toggle) + self.style = discord.ButtonStyle.blurple if not current else discord.ButtonStyle.grey + setattr(self.view, self.attr_toggle, not current) + await self.view.show_checked_page(self.view.current_page, interaction) + + +class WelcomeEditModal(discord.ui.Modal): + def __init__( + self, welcome_message: str, index: int, button: discord.ui.Button, event_type: EventType + ): + super().__init__( + title=_("Edit {event_type} {count}").format( + event_type=event_type.get_name(), count=index + ) + ) + self.text = discord.ui.TextInput( + style=discord.TextStyle.paragraph, + label=_("{style} text").format(style=event_type.get_name().title()), + default=welcome_message, + max_length=2000, + ) + self.add_item(self.text) + self.og_button = button + self.index = index + self.original_welcome = welcome_message + self.event_type = event_type + + async def on_submit(self, interaction: discord.Interaction): + edited_text = False + guild = interaction.guild + config = self.og_button.view.cog.config + if self.original_welcome != self.text.value: + self.original_welcome = self.text.value + edited_text = True + try: + settings = await config.guild(guild).get_raw(self.event_type.key()) + settings[self.index] = self.text.value + await config.guild(guild).set_raw(self.event_type.key(), value=settings) + except IndexError: + await interaction.response.send_message( + _("There was an error editing this {event_type} message.").format( + event_type=self.event_type.get_name() + ) + ) + + if edited_text: + await interaction.response.send_message( + _("I have edited {style} {number}.").format( + style=self.event_type.get_name(), number=self.index + 1 + ) + ) + else: + await interaction.response.send_message(_("None of the values have changed.")) + await self.og_button.view.show_checked_page(self.og_button.view.current_page, interaction) + + async def interaction_check(self, interaction: discord.Interaction): + """Just extends the default reaction_check to use owner_ids""" + owner_id = interaction.guild.owner.id + if interaction.user.id not in ( + owner_id, + *interaction.client.owner_ids, + ): + await interaction.response.send_message( + content=_("You are not authorized to interact with this."), ephemeral=True + ) + return False + return True + + +class EmbedEditModal(discord.ui.Modal): + def __init__(self, embed_settings: dict, button: discord.ui.Button, event_type: EventType): + super().__init__(title=_("Edit Embed Settings")) + self.old_settings = embed_settings + self.event_type = event_type + self.embed_title = discord.ui.TextInput( + style=discord.TextStyle.short, + label=_("Embed Title"), + default=embed_settings["title"], + max_length=256, + placeholder="The title of the embed", + required=False, + ) + self.embed_footer = discord.ui.TextInput( + style=discord.TextStyle.short, + label=_("Embed Footer"), + default=embed_settings["footer"], + max_length=256, + placeholder="The footer of the embed", + required=False, + ) + self.embed_thumbnail = discord.ui.TextInput( + style=discord.TextStyle.short, + label=_("Embed Thumbnail"), + default=embed_settings["thumbnail"], + max_length=256, + placeholder="guild, splash, avatar, or a custom url", + required=False, + ) + self.embed_image = discord.ui.TextInput( + style=discord.TextStyle.short, + label=_("Embed Image"), + default=embed_settings["image"] + if self.event_type is EventType.greeting + else embed_settings["image_goodbye"], + max_length=256, + placeholder="guild, splash, avatar, or a custom url", + required=False, + ) + self.embed_icon_url = discord.ui.TextInput( + style=discord.TextStyle.short, + label=_("Embed Icon URL"), + default=embed_settings["icon_url"], + max_length=256, + placeholder="guild, splash, avatar, or a custom url", + required=False, + ) + self.add_item(self.embed_title) + self.add_item(self.embed_footer) + self.add_item(self.embed_thumbnail) + self.add_item(self.embed_image) + self.add_item(self.embed_icon_url) + self.og_button = button + + async def on_submit(self, interaction: discord.Interaction): + items = { + "title": self.embed_title, + "footer": self.embed_footer, + "thumbnail": self.embed_thumbnail, + # "image": self.embed_image, + "icon_url": self.embed_icon_url, + } + if self.event_type is EventType.greeting: + items["image"] = self.embed_image + else: + items["image_goodbye"] = self.embed_image + changes = set() + config = self.og_button.view.cog.config + invalid = set() + for key, item in items.items(): + if self.old_settings[key] != item.value: + if key in ("title", "footer"): + changes.add(key) + await config.guild(interaction.guild).EMBED_DATA.set_raw(key, value=item.value) + else: + if item.value in ("guild", "splash", "avatar", ""): + set_to = item.value + if not item.value: + set_to = None + if set_to != self.old_settings[key]: + changes.add(key) + await config.guild(interaction.guild).EMBED_DATA.set_raw( + key, value=set_to + ) + else: + search = IMAGE_LINKS.search(item.value) + if not search: + invalid.add( + _( + "`{key}` must contain guild, splash, avatar, or a valid image URL." + ).format(key=key) + ) + else: + if search.group(1) != self.old_settings[key]: + changes.add(key) + await config.guild(interaction.guild).EMBED_DATA.set_raw( + key, value=search.group(1) + ) + + if not changes: + await interaction.response.send_message( + _("None of the values have changed.\n") + "\n".join(f"- {i}" for i in invalid) + ) + else: + changes_str = "\n".join(f"- {i}" for i in changes) + await interaction.response.send_message( + _("I have edited the following embed settings:\n{changes}").format( + changes=changes_str + ) + ) + await self.og_button.view.show_checked_page(self.og_button.view.current_page, interaction) + + async def interaction_check(self, interaction: discord.Interaction): + """Just extends the default reaction_check to use owner_ids""" + owner_id = interaction.guild.owner.id + if interaction.user.id not in ( + owner_id, + *interaction.client.owner_ids, + ): + await interaction.response.send_message( + content=_("You are not authorized to interact with this."), ephemeral=True + ) + return False + return True + + +class WelcomeEditButton(discord.ui.Button): + def __init__( + self, + event_type: EventType, + style: discord.ButtonStyle, + row: Optional[int], + ): + super().__init__(style=style, row=row) + self.style = style + self.emoji = "\N{GEAR}\N{VARIATION SELECTOR-16}" + self.label = _("Edit {event_type}").format(event_type=event_type.get_name().title()) + self.event_type = event_type + + async def callback(self, interaction: discord.Interaction): + modal = WelcomeEditModal( + self.view.source.current_selection, + self.view.source.current_page, + self, + self.event_type, + ) + await interaction.response.send_modal(modal) + + +class EmbedEditButton(discord.ui.Button): + def __init__( + self, + event_type: EventType, + style: discord.ButtonStyle, + row: Optional[int], + ): + super().__init__(style=style, row=row) + self.style = style + self.emoji = "\N{GEAR}\N{VARIATION SELECTOR-16}" + self.label = _("Edit Embed Settings") + self.event_type = event_type + + async def callback(self, interaction: discord.Interaction): + settings = await self.view.cog.config.guild(interaction.guild).EMBED_DATA() + modal = EmbedEditModal(settings, self, self.event_type) + await interaction.response.send_modal(modal) + + +class DeleteWelcomeButton(discord.ui.Button): + def __init__( + self, + event_type: EventType, + style: discord.ButtonStyle, + row: Optional[int], + ): + self.event_type = event_type + super().__init__( + style=style, + row=row, + label=_("Delete {event_type}").format(event_type=event_type.get_name().title()), + ) + self.style = style + self.emoji = "\N{PUT LITTER IN ITS PLACE SYMBOL}" + + async def keep_trigger(self, interaction: discord.Interaction): + await interaction.response.edit_message( + content=_("Okay this {event_type} will not be deleted.").format( + event_type=self.event_type.get_name() + ), + view=None, + ) + + async def delete_trigger(self, interaction: discord.Interaction): + config = self.view.cog.config + guild = interaction.guild + settings = await config.guild(guild).get_raw(self.event_type.key()) + settings.pop(self.view.source.current_page) + await config.guild(guild).set_raw(self.event_type.key(), value=settings) + await interaction.response.edit_message( + content=_("This {event_type} has been deleted.").format( + event_type=self.event_type.get_name() + ), + view=None, + ) + self.view.disable_extra_buttons() + await self.view.show_checked_page(self.view.current_page, interaction=None) + + async def callback(self, interaction: discord.Interaction): + """Enables and disables triggers""" + new_view = discord.ui.View() + approve_button = discord.ui.Button(style=discord.ButtonStyle.green, label=_("Yes")) + approve_button.callback = self.delete_trigger + deny_button = discord.ui.Button(style=discord.ButtonStyle.red, label=_("No")) + deny_button.callback = self.keep_trigger + new_view.add_item(approve_button) + new_view.add_item(deny_button) + await interaction.response.send_message( + _("Are you sure you want to delete {event_type} {name}?").format( + event_type=self.event_type.get_name(), name=self.view.source.current_page + 1 + ), + ephemeral=True, + view=new_view, + ) + if not interaction.response.is_done(): + await interaction.response.defer() + + +class BaseMenu(discord.ui.View): + def __init__( + self, + source: menus.PageSource, + cog: commands.Cog, + *, + message: Optional[discord.Message] = None, + clear_reactions_after: bool = True, + delete_message_after: bool = False, + timeout: int = 180, + raw: bool = False, + event_type: EventType = EventType.greeting, + **kwargs: Any, + ) -> None: + super().__init__( + timeout=timeout, + ) + self.cog = cog + self.bot = None + self.message = message + self._source = source + self.ctx = None + self.event_type = event_type + self.current_page = kwargs.get("page_start", 0) + self.forward_button = _NavigateButton( + discord.ButtonStyle.grey, + "\N{BLACK RIGHT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", + direction=1, + ) + self.backward_button = _NavigateButton( + discord.ButtonStyle.grey, + "\N{BLACK LEFT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", + direction=-1, + ) + self.first_button = _NavigateButton( + discord.ButtonStyle.grey, + "\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", + direction=0, + ) + self.last_button = _NavigateButton( + discord.ButtonStyle.grey, + "\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", + direction=self.source.get_max_pages(), + ) + self.stop_button = StopButton(discord.ButtonStyle.red, 0) + self.add_item(self.stop_button) + self.add_item(self.first_button) + self.add_item(self.backward_button) + self.add_item(self.forward_button) + self.add_item(self.last_button) + + self.delete_after = delete_message_after + self.clear_after = clear_reactions_after + self.show_raw = raw + self.raw_button = ToggleButton( + "show_raw", + discord.ButtonStyle.blurple if raw else discord.ButtonStyle.grey, + _("Show Raw"), + ) + self.add_item(self.raw_button) + self.preview_button = ToggleButton( + "show_preview", + discord.ButtonStyle.grey, + _("Show Preview"), + ) + self.add_item(self.preview_button) + self.edit_button = WelcomeEditButton(self.event_type, discord.ButtonStyle.grey, 2) + self.edit_embed_button = EmbedEditButton(self.event_type, discord.ButtonStyle.grey, 2) + self.add_item(self.edit_button) + self.add_item(self.edit_embed_button) + self.delete_button = DeleteWelcomeButton(self.event_type, discord.ButtonStyle.red, 2) + self.add_item(self.delete_button) + self.show_preview = False + + @property + def source(self): + return self._source + + async def on_timeout(self): + if self.message is None: + return + if self.clear_after and not self.delete_after: + await self.message.edit(view=None) + elif self.delete_after: + await self.message.delete() + + def disable_extra_buttons(self): + self.raw_button.disabled = True + self.preview_button.disabled = True + self.edit_button.disabled = True + self.edit_embed_button.disabled = True + self.delete_button.disabled = True + + def enable_extra_buttons(self): + self.raw_button.disabled = False + self.preview_button.disabled = False + self.edit_button.disabled = False + self.edit_embed_button.disabled = False + self.delete_button.disabled = False + + async def start(self, ctx: commands.Context): + self.ctx = ctx + self.bot = self.cog.bot + # await self.source._prepare_once() + self.message = await self.send_initial_message(ctx) + + async def _get_kwargs_from_page(self, page: int): + value = await discord.utils.maybe_coroutine(self._source.format_page, self, page) + if self.event_type is EventType.greeting: + mentions = await self.cog.config.guild(self.ctx.guild).MENTIONS() + else: + mentions = await self.cog.config.guild(self.ctx.guild).GOODBYE_MENTIONS() + allowed_mentions = discord.AllowedMentions(**mentions) + if isinstance(value, dict): + value.update({"allowed_mentions": discord.AllowedMentions(**mentions)}) + return value + elif isinstance(value, str): + return {"content": value, "embeds": [], "allowed_mentions": allowed_mentions} + elif isinstance(value, discord.Embed): + return {"embeds": [value], "content": None, "allowed_mentions": allowed_mentions} + + async def send_initial_message(self, ctx: commands.Context): + """|coro| + The default implementation of :meth:`Menu.send_initial_message` + for the interactive pagination session. + This implementation shows the first page of the source. + """ + self.author = ctx.author + if self.ctx is None: + self.ctx = ctx + page = await self._source.get_page(self.current_page) + kwargs = await self._get_kwargs_from_page(page) + self.message = await ctx.send(**kwargs, view=self) + return self.message + + async def show_page(self, page_number: int, interaction: Optional[discord.Interaction]): + page = await self._source.get_page(page_number) + self.current_page = self.source.pages.index(page) + kwargs = await self._get_kwargs_from_page(page) + + if interaction is None or interaction.response.is_done(): + await self.message.edit(**kwargs, view=self) + else: + await interaction.response.edit_message(**kwargs, view=self) + # await self.message.edit(**kwargs) + + async def show_checked_page( + self, page_number: int, interaction: Optional[discord.Interaction] + ) -> None: + max_pages = self._source.get_max_pages() + try: + if max_pages is None: + # If it doesn't give maximum pages, it cannot be checked + await self.show_page(page_number, interaction) + elif page_number >= max_pages: + await self.show_page(0, interaction) + elif page_number < 0: + await self.show_page(max_pages - 1, interaction) + elif max_pages > page_number >= 0: + await self.show_page(page_number, interaction) + except IndexError: + # An error happened that can be handled, so ignore it. + pass + + async def interaction_check(self, interaction: discord.Interaction): + """Just extends the default reaction_check to use owner_ids""" + if interaction.user.id not in ( + *interaction.client.owner_ids, + self.author.id, + ): + await interaction.response.send_message( + content=_("You are not authorized to interact with this."), ephemeral=True + ) + return False + return True diff --git a/welcome/welcome.py b/welcome/welcome.py new file mode 100644 index 0000000..2a4e21f --- /dev/null +++ b/welcome/welcome.py @@ -0,0 +1,959 @@ +from datetime import datetime, timezone +from typing import Literal, Optional + +import discord +from discord.ext import tasks +from red_commons.logging import getLogger +from redbot.core import Config, checks, commands +from redbot.core.i18n import Translator, cog_i18n +from redbot.core.utils.chat_formatting import humanize_list + +from .events import Events +from .menus import IMAGE_LINKS, BaseMenu, EventType, WelcomePages + +default_greeting = "Welcome {0.name} to {1.name}!" +default_goodbye = "See you later {0.name}!" +default_bot_msg = "Hello {0.name}, fellow bot!" +default_settings = { + "GREETING": [default_greeting], + "ON": False, + "LEAVE_ON": False, + "LEAVE_CHANNEL": None, + "GROUPED": False, + "GOODBYE": [default_goodbye], + "CHANNEL": None, + "WHISPER": False, + "BOTS_MSG": default_bot_msg, + "BOTS_GOODBYE_MSG": "Goodbye {0.name}, fellow bot!", + "BOTS_ROLE": None, + "EMBED": False, + "JOINED_TODAY": False, + "MINIMUM_DAYS": 0, + "DELETE_PREVIOUS_GREETING": False, + "DELETE_AFTER_GREETING": None, + "DELETE_PREVIOUS_GOODBYE": False, + "DELETE_AFTER_GOODBYE": None, + "LAST_GREETING": None, + "FILTER_SETTING": None, + "LAST_GOODBYE": None, + "MENTIONS": {"users": True, "roles": False, "everyone": False}, + "GOODBYE_MENTIONS": {"users": True, "roles": False, "everyone": False}, + "EMBED_DATA": { + "title": None, + "colour": 0, + "colour_goodbye": 0, + "footer": None, + "thumbnail": "avatar", + "image": None, + "image_goodbye": None, + "icon_url": None, + "author": True, + "timestamp": True, + "mention": False, + }, +} + +_ = Translator("Welcome", __file__) +log = getLogger("red.trusty-cogs.Welcome") + + +@cog_i18n(_) +class Welcome(Events, commands.Cog): + """Welcomes new members and goodbye those who leave to the guild + in the default channel rewritten for V3 from + https://github.com/irdumbs/Dumb-Cogs/blob/master/welcome/welcome.py""" + + __author__ = ["irdumb", "TrustyJAID"] + __version__ = "2.5.3" + + def __init__(self, bot): + self.bot = bot + self.config = Config.get_conf(self, 144465786453, force_registration=True) + self.config.register_guild(**default_settings) + self.joined = {} + self.today_count = {"now": datetime.now(timezone.utc)} + self.group_welcome.start() + + def format_help_for_context(self, ctx: commands.Context) -> str: + """ + Thanks Sinbad! + """ + pre_processed = super().format_help_for_context(ctx) + return f"{pre_processed}\n\nCog Version: {self.__version__}" + + async def red_delete_data_for_user(self, **kwargs): + """ + Nothing to delete + """ + return + + @tasks.loop(seconds=10) + async def group_welcome(self) -> None: + # log.debug("Checking for new welcomes") + clear_guilds = [] + for guild_id, members in self.joined.items(): + if members: + last_time_id = await self.config.guild_from_id(guild_id).LAST_GREETING() + if last_time_id is not None: + last_time = ( + datetime.now(timezone.utc) - discord.utils.snowflake_time(last_time_id) + ).total_seconds() + if len(members) > 1 and last_time <= 30.0: + continue + try: + await self.send_member_join(members, self.bot.get_guild(guild_id)) + clear_guilds.append(guild_id) + except Exception: + log.exception("Error in group welcome:") + for guild_id in clear_guilds: + try: + del self.joined[guild_id] + except KeyError: + pass + + @group_welcome.before_loop + async def before_group_welcome(self): + await self.bot.wait_until_red_ready() + + @commands.group() + @checks.admin_or_permissions(manage_channels=True) + @commands.guild_only() + async def welcomeset(self, ctx: commands.Context) -> None: + """Sets welcome module settings""" + pass + + @welcomeset.command(name="settings") + async def welcome_settings(self, ctx: commands.Context) -> None: + """ + Show the servers welcome settings + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).get_raw() + setting_names = { + "GREETING": _("Random Greeting "), + "GOODBYE": _("Random Goodbye "), + "GROUPED": _("Grouped greetings "), + "ON": _("Greetings enabled "), + "CHANNEL": _("Greeting Channel "), + "LEAVE_ON": _("Goodbyes enabled "), + "LEAVE_CHANNEL": _("Goodbye Channel "), + "DELETE_PREVIOUS_GREETING": _("Previous greeting deleted "), + "DELETE_PREVIOUS_GOODBYE": _("Previous goodbye deleted "), + "DELETE_AFTER_GREETING": _("Greeting deleted after "), + "DELETE_AFTER_GOODBYE": _("Goodbye deleted after "), + "MINIMUM_DAYS": _("Minimum days old to greet "), + "WHISPER": _("Whisper "), + "BOTS_MSG": _("Bots message "), + "BOTS_ROLE": _("Bots role "), + "EMBED": _("Embeds "), + } + msg = "" + if ctx.channel.permissions_for(ctx.me).embed_links: + embed = discord.Embed(colour=await ctx.embed_colour()) + embed.set_author(name=_("Welcome settings for ") + guild.name) + # embed.description = "\n".join(g for g in guild_settings["GREETING"]) + for attr, name in setting_names.items(): + if attr in ["GREETING", "GOODBYE"]: + embed.add_field( + name=name, + value="\n".join(g for g in guild_settings[attr])[:1024], + inline=False, + ) + continue + if attr in ["CHANNEL", "LEAVE_CHANNEL"]: + chan = guild.get_channel(guild_settings[attr]) + if chan is not None: + msg += f"**{name}**: {chan.mention}\n" + else: + msg += f"**{name}**:" + _(" None") + "\n" + continue + if attr == "BOTS_ROLE": + role = guild.get_role(guild_settings["BOTS_ROLE"]) + if role is not None: + msg += f"**{name}**: {role.mention}\n" + else: + msg += f"**{name}**:" + _(" None") + "\n" + continue + else: + msg += f"**{name}**: {guild_settings[attr]}\n" + embed.description = msg + await ctx.send(embed=embed) + + else: + msg = "```\n" + for attr, name in setting_names.items(): + msg += name + str(guild_settings[attr]) + "\n" + msg += "```" + await ctx.send(msg) + + @welcomeset.group(name="greeting", aliases=["welcome"]) + async def welcomeset_greeting(self, ctx: commands.Context) -> None: + """ + Manage welcome messages + """ + pass + + @welcomeset_greeting.command() + @checks.mod_or_permissions(mention_everyone=True) + @checks.bot_has_permissions(mention_everyone=True) + async def allowedmentions( + self, ctx: commands.Context, set_to: bool, *allowed: Literal["users", "roles", "everyone"] + ) -> None: + """ + Determine the bots allowed mentions for greetings + + `` What to set the allowed mentions to either `True` or `False`. + `[allowed...]` must be either `everyone`, `users`, or `roles` and can include more than one. + + Note: This will only function on Red 3.4.0 or higher. + """ + if not allowed: + await ctx.send(_("You must provide either `users`, `roles` or `everyone`.")) + return + for i in set(allowed): + if i not in ["everyone", "users", "roles"]: + await ctx.send(_("You must provide either `users`, `roles` or `everyone`.")) + return + if ( + "everyone" in set(allowed) + or "roles" in set(allowed) + and not ctx.guild.me.guild_permissions.mention_everyone + ): + await ctx.send( + _( + "I don't have mention everyone permissions so these settings may not work properly." + ) + ) + async with self.config.guild(ctx.guild).MENTIONS() as mention_settings: + for setting in set(allowed): + mention_settings[setting] = set_to + await ctx.send( + _("Mention settings have been set to {set_to} for {settings}").format( + set_to=str(set_to), settings=humanize_list(list(set(allowed))) + ) + ) + + @welcomeset_greeting.command(name="grouped") + async def welcomeset_greeting_grouped(self, ctx: commands.Context, grouped: bool) -> None: + """Set whether to group greeting messages + + This is useful if you have a high frequency of member joins. + """ + await self.config.guild(ctx.guild).GROUPED.set(grouped) + if grouped: + await ctx.send(_("I will now group greetings.")) + else: + await ctx.send(_("I will no longer group greetings.")) + + @welcomeset_greeting.command(name="add") + async def welcomeset_greeting_add(self, ctx: commands.Context, *, format_msg: str) -> None: + """ + Adds a greeting message format for the guild to be chosen at random + + {0} is member + {1} is guild + {count} can be used to display number of users who have joined today. + Default is set to: + Welcome {0.name} to {1.name}! + + Example formats: + {0.mention}.. What are you doing here? + {1.name} has a new member! {0.name} - {0.id} + Someone new joined! Who is it?! D: IS HE HERE TO HURT US?! + [Available attributes for member](https://discordpy.readthedocs.io/en/latest/api.html#member) + [Available attributes for guild](https://discordpy.readthedocs.io/en/latest/api.html#guild) + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).GREETING() + guild_settings.append(format_msg) + await self.config.guild(guild).GREETING.set(guild_settings) + await ctx.send(_("Greeting message added for the guild.")) + + @welcomeset_greeting.command(name="list", aliases=["edit", "delete", "del"]) + async def welcomeset_greeting_list(self, ctx: commands.Context, raw: bool = False) -> None: + """ + Lists the greeting messages of this guild and allows editing the settings. + + - `[raw=False]` Whether to show the raw text. This can be toggled afterwards. + """ + guild_settings = await self.config.guild(ctx.guild).GREETING() + if not guild_settings: + await ctx.send(_("You have no saved greetings.")) + return + source = WelcomePages(guild_settings) + menu = BaseMenu(source, self, raw=raw) + log.debug({c.custom_id for c in menu.children}) + await menu.start(ctx) + + @welcomeset_greeting.command(name="toggle") + async def welcomeset_greeting_toggle(self, ctx: commands.Context) -> None: + """ + Turns on/off welcoming new users to the guild. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).ON() + guild_settings = not guild_settings + if guild_settings: + await ctx.send(_("I will now greet new users to the guild.")) + else: + await ctx.send(_("I will no longer greet new users.")) + await self.config.guild(guild).ON.set(guild_settings) + + @welcomeset_greeting.command(name="deleteprevious") + async def welcomeset_greeting_delete_previous(self, ctx: commands.Context) -> None: + """ + Turns on/off deleting the previous greeting message when a user joins. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).DELETE_PREVIOUS_GREETING() + guild_settings = not guild_settings + if guild_settings: + await ctx.send( + _("I will now delete the previous greeting message when a new user joins.") + ) + else: + await ctx.send( + _("I will stop deleting the previous greeting message when a new user joins.") + ) + await self.config.guild(guild).DELETE_PREVIOUS_GREETING.set(guild_settings) + + @welcomeset_greeting.command(name="count") + async def welcomeset_greeting_count(self, ctx: commands.Context) -> None: + """ + Turns on/off showing how many users join each day. + + This resets 24 hours after the cog was loaded. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).JOINED_TODAY() + guild_settings = not guild_settings + if guild_settings: + await ctx.send(_("I will now show how many people join the server each day.")) + else: + await ctx.send(_("I will stop showing how many people join the server each day.")) + await self.config.guild(guild).JOINED_TODAY.set(guild_settings) + + @welcomeset_greeting.command(name="minimumage", aliases=["age"]) + async def welcomeset_greeting_minimum_days(self, ctx: commands.Context, days: int) -> None: + """ + Set the minimum number of days a user account must be to show up in the greeting message. + + - `` number of days old the account must be, set to 0 to not require this. + """ + guild = ctx.message.guild + if days < 0: + days = 0 + await self.config.guild(guild).MINIMUM_DAYS.set(days) + await ctx.send( + _("I will now show users joining who are {days} days old.").format(days=days) + ) + + @welcomeset_greeting.command(name="filter") + async def welcomeset_greeting_filter( + self, ctx: commands.Context, replacement: Optional[str] = None + ) -> None: + """ + Set what to do when a username matches the bots filter. + + - `[replacement]` replaces usernames that are found by cores filter with this word. + + If left blank this will replace bad words with [Redacted] on grouped messages. + """ + + await self.config.guild(ctx.guild).FILTER_SETTING.set(replacement) + if replacement: + await ctx.send( + _( + "I will now replace usernames matching cores filter with `{replacement}`" + ).format(replacement=replacement) + ) + else: + await ctx.send( + _("I will not post greeting messages for usernames that match cores filter.") + ) + if not self.bot.get_cog("Filter"): + await ctx.send( + _( + "Filter is not loaded, run `{prefix}load filter` and add " + "some words to filter for this to work" + ).format(prefix=ctx.clean_prefix) + ) + + @welcomeset_greeting.command(name="deleteafter") + async def welcomeset_greeting_delete_after( + self, ctx: commands.Context, delete_after: Optional[int] = None + ) -> None: + """ + Set the time after which a greeting message is deleted in seconds. + + Providing no input will set the bot to not delete after any time. + """ + if delete_after: + await ctx.send( + _("I will now delete greeting messages after {time} seconds.").format( + time=delete_after + ) + ) + else: + await ctx.send(_("I will not delete greeting messages after a set time.")) + await self.config.guild(ctx.guild).DELETE_AFTER_GREETING.set(delete_after) + + @welcomeset_greeting.command(name="channel") + async def welcomeset_greeting_channel( + self, ctx: commands.Context, channel: discord.TextChannel + ) -> None: + """ + Sets the channel to send the greeting message. + + If channel isn"t specified, the guild's default channel will be used + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).CHANNEL() + if channel is None: + channel = ctx.message.channel + if not channel.permissions_for(ctx.me).send_messages: + msg = _("I do not have permissions to send messages to {channel}").format( + channel=channel.mention + ) + await ctx.send(msg) + return + guild_settings = channel.id + await self.config.guild(guild).CHANNEL.set(guild_settings) + msg = _("I will now send greeting messages to {channel}").format(channel=channel.mention) + await ctx.send(msg) + + @welcomeset_greeting.command() + async def test(self, ctx: commands.Context) -> None: + """Test the greeting message deleted after 60 seconds.""" + await self.send_testing_msg(ctx) + + @welcomeset.group(name="goodbye", aliases=["leave"]) + async def welcomeset_goodbye(self, ctx: commands.Context) -> None: + """ + Manage goodbye messages. + """ + pass + + @welcomeset_goodbye.command(name="allowedmentions") + @checks.mod_or_permissions(mention_everyone=True) + async def goodbye_allowedmentions( + self, ctx: commands.Context, set_to: bool, *allowed: Literal["users", "roles", "everyone"] + ) -> None: + """ + Determine the bots allowed mentions for greetings + + `` What to set the allowed mentions to either `True` or `False`. + `[allowed...]` must be either `everyone`, `users`, or `roles` and can include more than one. + + Note: This will only function on Red 3.4.0 or higher. + """ + if not allowed: + await ctx.send(_("You must provide either `users`, `roles` or `everyone`.")) + return + for i in set(allowed): + if i not in ["everyone", "users", "roles"]: + await ctx.send(_("You must provide either `users`, `roles` or `everyone`.")) + return + if ( + "everyone" in set(allowed) + or "roles" in set(allowed) + and not ctx.guild.me.guild_permissions.mention_everyone + ): + await ctx.send( + _( + "I don't have mention everyone permissions so these settings may not work properly." + ) + ) + async with self.config.guild(ctx.guild).GOODBYE_MENTIONS() as mention_settings: + for setting in set(allowed): + mention_settings[setting] = set_to + await ctx.send( + _("Mention settings have been set to {set_to} for {settings}").format( + set_to=str(set_to), settings=humanize_list(list(set(allowed))) + ) + ) + + @welcomeset_goodbye.command(name="add") + async def welcomeset_goodbye_add(self, ctx: commands.Context, *, format_msg: str) -> None: + """ + Adds a goodbye message format for the guild to be chosen at random + + {0} is member + {1} is guild + Default is set to: + See you later {0.name}! + + Example formats: + {0.mention}.. well, bye. + {1.name} has lost a member. {0.name} - {0.id} + Someone has quit the server! Who is it?! D: + [Available attributes for member](https://discordpy.readthedocs.io/en/latest/api.html#member) + [Available attributes for guild](https://discordpy.readthedocs.io/en/latest/api.html#guild) + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).GOODBYE() + guild_settings.append(format_msg) + await self.config.guild(guild).GOODBYE.set(guild_settings) + await ctx.send(_("Goodbye message added for the guild.")) + + @welcomeset_goodbye.command(name="list", aliases=["edit", "delete", "del"]) + async def welcomeset_goodbye_list(self, ctx: commands.Context, raw: bool = False) -> None: + """ + Lists the goodbye messages of this guild and allows editing the settings. + + - `[raw=False]` Whether to show the raw text. This can be toggled afterwards. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).GOODBYE() + if not guild_settings: + await ctx.send(_("You have no saved goodbyes.")) + return + source = WelcomePages(guild_settings) + menu = BaseMenu(source, self, raw=raw, event_type=EventType.goodbye) + log.debug({c.custom_id for c in menu.children}) + await menu.start(ctx) + + @welcomeset_goodbye.command(name="toggle") + async def welcomeset_goodbye_toggle(self, ctx: commands.Context) -> None: + """ + Turns on/off sending goodbye messages to users who leave to the guild. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).LEAVE_ON() + guild_settings = not guild_settings + if guild_settings: + await ctx.send(_("I will now say goodbye when a member leaves the server.")) + else: + await ctx.send(_("I will no longer say goodbye to members leaving the server.")) + await self.config.guild(guild).LEAVE_ON.set(guild_settings) + + @welcomeset_goodbye.command(name="channel") + async def welcomeset_goodbye_channel( + self, ctx: commands.Context, channel: discord.TextChannel + ) -> None: + """ + Sets the channel to send the goodbye message. + """ + guild = ctx.message.guild + if not channel.permissions_for(ctx.me).send_messages: + msg = _("I do not have permissions to send messages to {channel}").format( + channel=channel.mention + ) + await ctx.send(msg) + return + await self.config.guild(guild).LEAVE_CHANNEL.set(channel.id) + msg = _("I will now send goodbye messages to {channel}").format(channel=channel.mention) + await ctx.send(msg) + + @welcomeset_goodbye.command(name="deleteprevious") + async def welcomeset_goodbye_delete_previous(self, ctx: commands.Context) -> None: + """ + Turns on/off deleting the previous greeting message when a user joins. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).DELETE_PREVIOUS_GOODBYE() + guild_settings = not guild_settings + if guild_settings: + await ctx.send(_("I will now delete the previous goodbye message when user leaves.")) + else: + await ctx.send( + _("I will stop deleting the previous goodbye message when a user leaves.") + ) + await self.config.guild(guild).DELETE_PREVIOUS_GOODBYE.set(guild_settings) + + @welcomeset_goodbye.command(name="deleteafter") + async def welcomeset_goodbye_delete_after( + self, ctx: commands.Context, delete_after: Optional[int] = None + ) -> None: + """ + Set the time after which a greeting message is deleted in seconds. + + Providing no input will set the bot to not delete after any time. + """ + if delete_after: + await ctx.send( + _("I will now delete goodbye messages after {time} seconds.").format( + time=delete_after + ) + ) + else: + await ctx.send(_("I will not delete greeting messages after a set time.")) + await self.config.guild(ctx.guild).DELETE_AFTER_GOODBYE.set(delete_after) + + @welcomeset_goodbye.command(name="test") + async def welcomeset_goodbye_test(self, ctx: commands.Context) -> None: + """Test the goodbye message deleted after 60 seconds""" + await self.send_testing_msg(ctx, leave=True) + + @welcomeset.group(name="bot") + async def welcomeset_bot(self, ctx: commands.Context) -> None: + """ + Special greeting for bots. + """ + pass + + @welcomeset_bot.command(name="test") + async def welcomeset_bot_test(self, ctx: commands.Context) -> None: + """Test the bot joining message""" + await self.send_testing_msg(ctx, bot=True) + + @welcomeset_bot.command(name="msg") + async def welcomeset_bot_msg( + self, ctx: commands.Context, *, format_msg: Optional[str] = None + ) -> None: + """Set the greeting msg for bots. + + Leave blank to reset to regular user greeting""" + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).BOTS_MSG() + guild_settings = format_msg + await self.config.guild(guild).BOTS_MSG.set(guild_settings) + if format_msg is None: + msg = _("Bot message reset. Bots will now be greeted as regular users.") + await ctx.send(msg) + else: + await ctx.send(_("Bot greeting message set for the guild.")) + + @welcomeset_bot.command(name="goodbyemsg", aliases=["goodbyemessage"]) + async def welcomeset_bot_goodbye_msg( + self, ctx: commands.Context, *, format_msg: Optional[str] = None + ) -> None: + """Set the goodbye msg for bots. + + Leave blank to reset to regular user goodbye""" + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).BOTS_GOODBYE_MSG() + guild_settings = format_msg + await self.config.guild(guild).BOTS_GOODBYE_MSG.set(guild_settings) + if format_msg is None: + msg = _("Bot goodbye message reset. Bots will now leave as regular users.") + await ctx.send(msg) + else: + await ctx.send(_("Bot goodbye message set for the guild.")) + + @welcomeset_bot.command(name="role") + @commands.bot_has_permissions(manage_roles=True) + async def welcomeset_bot_role( + self, ctx: commands.Context, *, role: Optional[discord.Role] = None + ) -> None: + """ + Set the role to put bots in when they join. + + Leave blank to not give them a role. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).BOTS_ROLE() + guild_settings = role.id if role is not None else role + if role is not None and role >= guild.me.top_role: + await ctx.send(_("I cannot assign roles higher than my own.")) + return + await self.config.guild(guild).BOTS_ROLE.set(guild_settings) + if role: + msg = _("Bots that join this guild will be given ") + role.name + else: + msg = _("Bots that join this guild will not be given a role.") + await ctx.send(msg) + + @welcomeset.command() + async def whisper(self, ctx: commands.Context, choice: Optional[str] = None) -> None: + """Sets whether or not a DM is sent to the new user + + Options: + off - turns off DMs to users + only - only send a DM to the user, don"t send a greeting to the channel + both - send a message to both the user and the channel + + If Option isn't specified, toggles between "off" and "only" + DMs will not be sent to bots""" + options = {"off": False, "only": True, "both": "BOTH"} + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).WHISPER() + if choice is None: + guild_settings = not guild_settings + elif choice.lower() not in options: + await ctx.send(_("You must select either `off`, `only`, or `both`.")) + return + else: + guild_settings = options[choice.lower()] + await self.config.guild(guild).WHISPER.set(guild_settings) + if not guild_settings: + await ctx.send(_("I will no longer send DMs to new users")) + elif guild_settings == "BOTH": + channel = guild.get_channel(await self.config.guild(guild).CHANNEL()) + msg = _( + "I will now send greeting messages to {channel} as well as to the new user in a DM" + ).format(channel=channel) + await ctx.send(msg) + else: + msg = _("I will now only send greeting messages to the new user as a DM") + await ctx.send(msg) + await self.send_testing_msg(ctx) + + @welcomeset.group(name="embed") + async def _embed(self, ctx: commands.Context) -> None: + """ + Set various embed options. + """ + pass + + @_embed.command() + async def toggle(self, ctx: commands.Context) -> None: + """ + Toggle embed messages. + """ + guild = ctx.message.guild + guild_settings = await self.config.guild(guild).EMBED() + await self.config.guild(guild).EMBED.set(not guild_settings) + if guild_settings: + verb = _("off") + else: + verb = _("on") + await ctx.send(_("Greeting embeds turned {verb}").format(verb=verb)) + + @_embed.command(aliases=["color"]) + @commands.bot_has_permissions(embed_links=True) + async def colour(self, ctx: commands.Context, colour: discord.Colour) -> None: + """ + Set the embed colour. + + This accepts hex codes and integer value colours. + """ + await self.config.guild(ctx.guild).EMBED_DATA.colour.set(colour.value) + em = discord.Embed( + colour=colour, description=_("Welcome colour set to `{colour}`").format(colour=colour) + ) + await ctx.send(embed=em) + + @_embed.command(aliases=["gcolor", "goodbyecolor", "gcolour"]) + @commands.bot_has_permissions(embed_links=True) + async def goodbyecolour(self, ctx: commands.Context, colour: discord.Colour) -> None: + """ + Set the embed colour. + + This accepts hex codes and integer value colours. + """ + await self.config.guild(ctx.guild).EMBED_DATA.colour_goodbye.set(colour.value) + em = discord.Embed( + colour=colour, description=_("Goodbye colour set to `{colour}`").format(colour=colour) + ) + await ctx.send(embed=em) + + @_embed.command() + async def title(self, ctx: commands.Context, *, title: str = "") -> None: + """ + Set the embed title. + + {0} is member. + {1} is guild. + {count} can be used to display number of users who have joined today. + [Available attributes for member](https://discordpy.readthedocs.io/en/latest/api.html#member) + [Available attributes for guild](https://discordpy.readthedocs.io/en/latest/api.html#guild) + """ + await self.config.guild(ctx.guild).EMBED_DATA.title.set(title[:256]) + await ctx.tick() + + @_embed.command() + async def footer(self, ctx: commands.Context, *, footer: str = "") -> None: + """ + Set the embed footer. + + {0} is member. + {1} is guild. + {count} can be used to display number of users who have joined today. + [Available attributes for member](https://discordpy.readthedocs.io/en/latest/api.html#member) + [Available attributes for guild](https://discordpy.readthedocs.io/en/latest/api.html#guild) + """ + await self.config.guild(ctx.guild).EMBED_DATA.footer.set(footer[:256]) + await ctx.tick() + + @_embed.command() + async def thumbnail(self, ctx: commands.Context, link: Optional[str] = None) -> None: + """ + Set the embed thumbnail image. + + `[link]` must be a valid image link. + You may also specify: + - `member`, `user` or `avatar` to use the members avatar. + - `server` or `guild` to use the servers icon. + - `splash` to use the servers splash image if available. + if nothing is provided the defaults are used. + """ + if link is not None: + link_search = IMAGE_LINKS.search(link) + if link_search: + await self.config.guild(ctx.guild).EMBED_DATA.thumbnail.set(link_search.group(0)) + await ctx.tick() + elif link in ["member", "user", "avatar"]: + await self.config.guild(ctx.guild).EMBED_DATA.thumbnail.set("avatar") + await ctx.tick() + elif link in ["server", "guild"]: + await self.config.guild(ctx.guild).EMBED_DATA.thumbnail.set("guild") + await ctx.tick() + elif link == "splash": + await self.config.guild(ctx.guild).EMBED_DATA.thumbnail.set("splash") + await ctx.tick() + else: + await ctx.send( + _("That's not a valid option. You must provide a link, `avatar` or `server`.") + ) + else: + await self.config.guild(ctx.guild).EMBED_DATA.thumbnail.set(None) + await ctx.send(_("Thumbnail cleared.")) + + @_embed.command() + async def icon(self, ctx: commands.Context, link: Optional[str] = None) -> None: + """ + Set the embed icon image. + + `[link]` must be a valid image link. + You may also specify: + - `member`, `user` or `avatar` to use the members avatar. + - `server` or `guild` to use the servers icon. + - `splash` to use the servers splash image if available. + if nothing is provided the defaults are used. + """ + if link is not None: + link_search = IMAGE_LINKS.search(link) + if link_search: + await self.config.guild(ctx.guild).EMBED_DATA.icon_url.set(link_search.group(0)) + await ctx.tick() + elif link in ["author", "avatar"]: + await self.config.guild(ctx.guild).EMBED_DATA.icon_url.set("avatar") + await ctx.tick() + elif link in ["server", "guild"]: + await self.config.guild(ctx.guild).EMBED_DATA.icon_url.set("guild") + await ctx.tick() + elif link == "splash": + await self.config.guild(ctx.guild).EMBED_DATA.icon_url.set("splash") + await ctx.tick() + else: + await ctx.send( + _("That's not a valid option. You must provide a link, `avatar` or `server`.") + ) + else: + await self.config.guild(ctx.guild).EMBED_DATA.icon_url.set(None) + await ctx.send(_("Icon cleared.")) + + @_embed.group(name="image") + async def _image(self, ctx: commands.Context) -> None: + """ + Set embed image options. + """ + pass + + @_image.command(name="greeting") + async def image_greeting(self, ctx: commands.Context, link: Optional[str] = None) -> None: + """ + Set the embed image link for greetings. + + `[link]` must be a valid image link. + You may also specify: + - `member`, `user` or `avatar` to use the members avatar. + - `server` or `guild` to use the servers icon. + - `splash` to use the servers splash image if available. + if nothing is provided the defaults are used. + """ + if link is not None: + link_search = IMAGE_LINKS.search(link) + if link_search: + await self.config.guild(ctx.guild).EMBED_DATA.image.set(link_search.group(0)) + await ctx.tick() + elif link in ["author", "avatar"]: + await self.config.guild(ctx.guild).EMBED_DATA.image.set("avatar") + await ctx.tick() + elif link in ["server", "guild"]: + await self.config.guild(ctx.guild).EMBED_DATA.image.set("guild") + await ctx.tick() + elif link == "splash": + await self.config.guild(ctx.guild).EMBED_DATA.image.set("splash") + await ctx.tick() + else: + await ctx.send( + _("That's not a valid option. You must provide a link, `avatar` or `server`.") + ) + else: + await self.config.guild(ctx.guild).EMBED_DATA.image.set(None) + await ctx.send(_("Greeting image cleared.")) + + @_image.command(name="goodbye") + async def image_goodbye(self, ctx: commands.Context, link: Optional[str] = None) -> None: + """ + Set the embed image link for goodbyes. + + `[link]` must be a valid image link. + You may also specify: + - `member`, `user` or `avatar` to use the members avatar. + - `server` or `guild` to use the servers icon. + - `splash` to use the servers splash image if available. + if nothing is provided the defaults are used. + """ + if link is not None: + link_search = IMAGE_LINKS.search(link) + if link_search: + await self.config.guild(ctx.guild).EMBED_DATA.image_goodbye.set( + link_search.group(0) + ) + await ctx.tick() + elif link in ["author", "avatar"]: + await self.config.guild(ctx.guild).EMBED_DATA.image_goodbye.set("avatar") + await ctx.tick() + elif link in ["server", "guild"]: + await self.config.guild(ctx.guild).EMBED_DATA.image_goodbye.set("guild") + await ctx.tick() + elif link == "splash": + await self.config.guild(ctx.guild).EMBED_DATA.image_goodbye.set("splash") + await ctx.tick() + else: + await ctx.send( + _("That's not a valid option. You must provide a link, `avatar` or `server`.") + ) + else: + await self.config.guild(ctx.guild).EMBED_DATA.image_goodbye.set(None) + await ctx.send(_("Goodbye image cleared.")) + + @_embed.command() + async def timestamp(self, ctx: commands.Context) -> None: + """ + Toggle the timestamp in embeds. + """ + cur_setting = await self.config.guild(ctx.guild).EMBED_DATA.timestamp() + await self.config.guild(ctx.guild).EMBED_DATA.timestamp.set(not cur_setting) + if cur_setting: + verb = _("off") + else: + verb = _("on") + await ctx.send(_("Timestamps turned {verb}").format(verb=verb)) + + @_embed.command() + async def author(self, ctx: commands.Context) -> None: + """ + Toggle the author field being filled in the embed. + + Note: This will override the icon image if it is set. + """ + cur_setting = await self.config.guild(ctx.guild).EMBED_DATA.author() + await self.config.guild(ctx.guild).EMBED_DATA.author.set(not cur_setting) + if cur_setting: + verb = _("off") + else: + verb = _("on") + await ctx.send(_("Author field turned {verb}").format(verb=verb)) + + @_embed.command() + async def mention(self, ctx: commands.Context) -> None: + """ + Toggle mentioning the user when they join. + + This will add a mention outside the embed so they actually get the mention. + """ + cur_setting = await self.config.guild(ctx.guild).EMBED_DATA.mention() + await self.config.guild(ctx.guild).EMBED_DATA.mention.set(not cur_setting) + if cur_setting: + verb = _("off") + else: + verb = _("on") + await ctx.send(_("Mentioning the user turned {verb}").format(verb=verb)) + + async def cog_unload(self): + # self.group_check.cancel() + self.group_welcome.cancel()