Refactor ExtendedAudio and Shop classes to improve attribute access and enhance user interaction handling. Update duration calculation in ExtendedAudio to handle track length in milliseconds, and modify PendingView in Shop to pass context for user selection, ensuring accurate user identification.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-28 01:52:41 -04:00
parent a48f60ec86
commit 22fcd8420a
11 changed files with 3927 additions and 11 deletions

View file

@ -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
)

View file

@ -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}!"
Can't render this file because it contains an unexpected character in line 41 and column 237.

View file

@ -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

12
welcome/__init__.py Normal file
View file

@ -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)

548
welcome/events.py Normal file
View file

@ -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,
)

28
welcome/info.json Normal file
View file

@ -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"
}

717
welcome/locales/fr-FR.po Normal file
View file

@ -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"
" `<set_to>` 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"
" `<days>` 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 ""

View file

@ -0,0 +1,293 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""

717
welcome/locales/sv-SE.po Normal file
View file

@ -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"
" `<set_to>` 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"
" `<days>` 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 ""

600
welcome/menus.py Normal file
View file

@ -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

959
welcome/welcome.py Normal file
View file

@ -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
`<set_to>` 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.
- `<days>` 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
`<set_to>` 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()