import logging import random from json import load from pathlib import Path from typing import Tuple import discord from discord.ext import commands from discord.ext.commands.cooldowns import BucketType from bot.constants import Channels, Colours, Lovefest, Month from bot.utils.decorators import in_month from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"] class BeMyValentine(commands.Cog): """A cog that sends Valentines to other users!""" def __init__(self, bot: commands.Bot): self.bot = bot self.valentines = self.load_json() @staticmethod def load_json() -> dict: """Load Valentines messages from the static resources.""" p = Path("bot/resources/valentines/bemyvalentine_valentines.json") with p.open(encoding="utf8") as json_data: valentines = load(json_data) return valentines @in_month(Month.FEBRUARY) @commands.group(name="lovefest") async def lovefest_role(self, ctx: commands.Context) -> None: """ Subscribe or unsubscribe from the lovefest role. The lovefest role makes you eligible to receive anonymous valentines from other users. 1) use the command \".lovefest sub\" to get the lovefest role. 2) use the command \".lovefest unsub\" to get rid of the lovefest role. """ if not ctx.invoked_subcommand: await invoke_help_command(ctx) @lovefest_role.command(name="sub") async def add_role(self, ctx: commands.Context) -> None: """Adds the lovefest role.""" user = ctx.author role = discord.utils.get(ctx.guild.roles, id=Lovefest.role_id) if Lovefest.role_id not in [role.id for role in ctx.message.author.roles]: await user.add_roles(role) await ctx.send("The Lovefest role has been added !") else: await ctx.send("You already have the role !") @lovefest_role.command(name="unsub") async def remove_role(self, ctx: commands.Context) -> None: """Removes the lovefest role.""" user = ctx.author role = discord.utils.get(ctx.guild.roles, id=Lovefest.role_id) if Lovefest.role_id not in [role.id for role in ctx.message.author.roles]: await ctx.send("You dont have the lovefest role.") else: await user.remove_roles(role) await ctx.send("The lovefest role has been successfully removed !") @commands.cooldown(1, 1800, BucketType.user) @commands.group(name='bemyvalentine', invoke_without_command=True) async def send_valentine( self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ Send a valentine to a specified user with the lovefest role. syntax: .bemyvalentine [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) example: .bemyvalentine Iceman#6508 p (sends a poem to Iceman) example: .bemyvalentine Iceman Hey I love you, wanna hang around ? (sends the custom message to Iceman) NOTE : AVOID TAGGING THE USER MOST OF THE TIMES.JUST TRIM THE '@' when using this command. """ if ctx.guild is None: # This command should only be used in the server raise commands.UserInputError("You are supposed to use this command in the server.") if Lovefest.role_id not in [role.id for role in user.roles]: raise commands.UserInputError( f"You cannot send a valentine to {user} as they do not have the lovefest role!" ) if user == ctx.author: # Well a user can't valentine himself/herself. raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") emoji_1, emoji_2 = self.random_emoji() channel = self.bot.get_channel(Channels.community_bot_commands) valentine, title = self.valentine_check(valentine_type) embed = discord.Embed( title=f'{emoji_1} {title} {user.display_name} {emoji_2}', description=f'{valentine} \n **{emoji_2}From {ctx.author}{emoji_1}**', color=Colours.pink ) await channel.send(user.mention, embed=embed) @commands.cooldown(1, 1800, BucketType.user) @send_valentine.command(name='secret') async def anonymous( self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ Send an anonymous Valentine via DM to to a specified user with the lovefest role. syntax : .bemyvalentine secret [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) example : .bemyvalentine secret Iceman#6508 p (sends a poem to Iceman in DM making you anonymous) example : .bemyvalentine secret Iceman#6508 Hey I love you, wanna hang around ? (sends the custom message to Iceman in DM making you anonymous) """ if Lovefest.role_id not in [role.id for role in user.roles]: await ctx.message.delete() raise commands.UserInputError( f"You cannot send a valentine to {user} as they do not have the lovefest role!" ) if user == ctx.author: # Well a user cant valentine himself/herself. raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") emoji_1, emoji_2 = self.random_emoji() valentine, title = self.valentine_check(valentine_type) embed = discord.Embed( title=f'{emoji_1}{title} {user.display_name}{emoji_2}', description=f'{valentine} \n **{emoji_2}From anonymous{emoji_1}**', color=Colours.pink ) await ctx.message.delete() try: await user.send(embed=embed) except discord.Forbidden: raise commands.UserInputError(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") else: await ctx.author.send(f"Your message has been sent to {user}") def valentine_check(self, valentine_type: str) -> Tuple[str, str]: """Return the appropriate Valentine type & title based on the invoking user's input.""" if valentine_type is None: valentine, title = self.random_valentine() elif valentine_type.lower() in ['p', 'poem']: valentine = self.valentine_poem() title = 'A poem dedicated to' elif valentine_type.lower() in ['c', 'compliment']: valentine = self.valentine_compliment() title = 'A compliment for' else: # in this case, the user decides to type his own valentine. valentine = valentine_type title = 'A message for' return valentine, title @staticmethod def random_emoji() -> Tuple[str, str]: """Return two random emoji from the module-defined constants.""" emoji_1 = random.choice(HEART_EMOJIS) emoji_2 = random.choice(HEART_EMOJIS) return emoji_1, emoji_2 def random_valentine(self) -> Tuple[str, str]: """Grabs a random poem or a compliment (any message).""" valentine_poem = random.choice(self.valentines['valentine_poems']) valentine_compliment = random.choice(self.valentines['valentine_compliments']) random_valentine = random.choice([valentine_compliment, valentine_poem]) if random_valentine == valentine_poem: title = 'A poem dedicated to' else: title = 'A compliment for ' return random_valentine, title def valentine_poem(self) -> str: """Grabs a random poem.""" valentine_poem = random.choice(self.valentines['valentine_poems']) return valentine_poem def valentine_compliment(self) -> str: """Grabs a random compliment.""" valentine_compliment = random.choice(self.valentines['valentine_compliments']) return valentine_compliment def setup(bot: commands.Bot) -> None: """Be my Valentine Cog load.""" bot.add_cog(BeMyValentine(bot))