Repository: python-discord/sir-lancebot
Issue: Remove Member Intent Reliant Features From Lovefest

## Description
<!-- Describe the bug you've found -->
After discord introduced the intents  system, sir-lancebot no longer has access to the list of members for a role. This has led to a weird situation with some of the commands in the lovefest cog, as they relied on fetching members for a given role.


## Steps to Reproduce
<!-- Detail the exact list of steps to be able to encounter the bug -->
(Make sure your bot does not have the members intent enabled)
1. Sign up for the lovefest role.
2. Try to use one of the commands that rely on fetching members, such as `.bemyvalentine` with no arguments.


## Actual Behaviour
<!-- Outline what occurs instead of the expected behaviour, include screenshots if relevant -->
The member fetch now returns an empty list, making the intended purpose fail, or returns a list with very few members, causing them to be bombarded by pings.


## Possible Solutions
<!-- Detail any solutions you might have in mind to be able to resolve the bug -->
[Functions that rely on member intents](https://discordpy.readthedocs.io/en/latest/api.html#discord.Intents.members) being enabled should be removed from the lovefest cog.

(If you find other features that suffer from similar bugs, open a separate issue for them.)

## Would you like to implement a fix?

***Note: For high-priority or critical bugs, fixes may be implemented by staff.***
<!-- Replace [ ] with [x] with your choice -->

- [ ] I'd like to implement the bug fix
- [x] Anyone can implement the bug fix


Changed files:
bot/exts/valentines/lovecalculator.py, bot/exts/valentines/be_my_valentine.py

diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py
index 4db4d191..d79b28e8 100644
--- a/bot/exts/valentines/be_my_valentine.py
+++ b/bot/exts/valentines/be_my_valentine.py
@@ -2,13 +2,13 @@ import logging
 import random
 from json import load
 from pathlib import Path
-from typing import Optional, Tuple
+from typing import Tuple
 
 import discord
 from discord.ext import commands
 from discord.ext.commands.cooldowns import BucketType
 
-from bot.constants import Channels, Client, Colours, Lovefest, Month
+from bot.constants import Channels, Colours, Lovefest, Month
 from bot.utils.decorators import in_month
 
 log = logging.getLogger(__name__)
@@ -70,15 +70,14 @@ class BeMyValentine(commands.Cog):
     @commands.cooldown(1, 1800, BucketType.user)
     @commands.group(name='bemyvalentine', invoke_without_command=True)
     async def send_valentine(
-        self, ctx: commands.Context, user: Optional[discord.Member] = None, *, valentine_type: str = None
+        self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None
     ) -> None:
         """
-        Send a valentine to user, if specified, or to a random user with the lovefest role.
+        Send a valentine to a specified user with the lovefest role.
 
-        syntax: .bemyvalentine [user](optional) [p/poem/c/compliment/or you can type your own valentine message]
+        syntax: .bemyvalentine [user] [p/poem/c/compliment/or you can type your own valentine message]
         (optional)
 
-        example: .bemyvalentine (sends valentine as a poem or a compliment to a random user)
         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.
@@ -86,28 +85,23 @@ class BeMyValentine(commands.Cog):
         if ctx.guild is None:
             # This command should only be used in the server
             msg = "You are supposed to use this command in the server."
-            return await ctx.send(msg)
+            await ctx.send(msg)
+            return
 
-        if user:
-            if Lovefest.role_id not in [role.id for role in user.roles]:
-                message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!"
-                return await ctx.send(message)
+        if Lovefest.role_id not in [role.id for role in user.roles]:
+            message = f"You cannot send a valentine to {user} as they do not have the lovefest role!"
+            await ctx.send(message)
+            return
 
         if user == ctx.author:
             # Well a user can't valentine himself/herself.
-            return await ctx.send("Come on dude, you can't send a valentine to yourself :expressionless:")
+            await ctx.send("Come on, you can't send a valentine to yourself :expressionless:")
+            return
 
         emoji_1, emoji_2 = self.random_emoji()
-        lovefest_role = discord.utils.get(ctx.guild.roles, id=Lovefest.role_id)
         channel = self.bot.get_channel(Channels.community_bot_commands)
         valentine, title = self.valentine_check(valentine_type)
 
-        if user is None:
-            author = ctx.author
-            user = self.random_user(author, lovefest_role.members)
-            if user is None:
-                return await ctx.send("There are no users avilable to whome your valentine can be sent.")
-
         embed = discord.Embed(
             title=f'{emoji_1} {title} {user.display_name} {emoji_2}',
             description=f'{valentine} \\n **{emoji_2}From {ctx.author}{emoji_1}**',
@@ -118,47 +112,35 @@ class BeMyValentine(commands.Cog):
     @commands.cooldown(1, 1800, BucketType.user)
     @send_valentine.command(name='secret')
     async def anonymous(
-        self, ctx: commands.Context, user: Optional[discord.Member] = None, *, valentine_type: str = None
+        self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None
     ) -> None:
         """
-        Send an anonymous Valentine via DM to to a user, if specified, or to a random with the lovefest role.
-
-        **This command should be DMed to the bot.**
+        Send an anonymous Valentine via DM to to a specified user with the lovefest role.
 
-        syntax : .bemyvalentine secret [user](optional) [p/poem/c/compliment/or you can type your own valentine message]
+        syntax : .bemyvalentine secret [user] [p/poem/c/compliment/or you can type your own valentine message]
         (optional)
 
-        example : .bemyvalentine secret (sends valentine as a poem or a compliment to a random user in DM making you
-        anonymous)
         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 ctx.guild is not None:
-            # This command is only DM specific
-            msg = "You are not supposed to use this command in the server, DM the command to the bot."
-            return await ctx.send(msg)
-
-        if user:
-            if Lovefest.role_id not in [role.id for role in user.roles]:
-                message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!"
-                return await ctx.send(message)
+        if Lovefest.role_id not in [role.id for role in user.roles]:
+            message = f"You cannot send a valentine to {user} as they do not have the lovefest role!"
+            await ctx.message.delete()
+            try:
+                await ctx.author.send(message)
+            except discord.Forbidden:
+                await ctx.send(message)
+            return
 
         if user == ctx.author:
             # Well a user cant valentine himself/herself.
-            return await ctx.send('Come on dude, you cant send a valentine to yourself :expressionless:')
+            await ctx.send('Come on, you can\\'t send a valentine to yourself :expressionless:')
+            return
 
-        guild = self.bot.get_guild(id=Client.guild)
         emoji_1, emoji_2 = self.random_emoji()
-        lovefest_role = discord.utils.get(guild.roles, id=Lovefest.role_id)
         valentine, title = self.valentine_check(valentine_type)
 
-        if user is None:
-            author = ctx.author
-            user = self.random_user(author, lovefest_role.members)
-            if user is None:
-                return await ctx.send("There are no users avilable to whome your valentine can be sent.")
-
         embed = discord.Embed(
             title=f'{emoji_1}{title} {user.display_name}{emoji_2}',
             description=f'{valentine} \\n **{emoji_2}From anonymous{emoji_1}**',
@@ -166,8 +148,9 @@ class BeMyValentine(commands.Cog):
         )
         try:
             await user.send(embed=embed)
+            await ctx.message.delete()
         except discord.Forbidden:
-            await ctx.author.send(f"{user} has DMs disabled, so I couldn't send the message. Sorry!")
+            await ctx.send(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}")
 
@@ -190,18 +173,6 @@ class BeMyValentine(commands.Cog):
             title = 'A message for'
         return valentine, title
 
-    @staticmethod
-    def random_user(author: discord.Member, members: discord.Member) -> None:
-        """
-        Picks a random member from the list provided in `members`.
-
-        The invoking author is ignored.
-        """
-        if author in members:
-            members.remove(author)
-
-        return random.choice(members) if members else None
-
     @staticmethod
     def random_emoji() -> Tuple[str, str]:
         """Return two random emoji from the module-defined constants."""
diff --git a/bot/exts/valentines/lovecalculator.py b/bot/exts/valentines/lovecalculator.py
index c75ea6cf..966acc82 100644
--- a/bot/exts/valentines/lovecalculator.py
+++ b/bot/exts/valentines/lovecalculator.py
@@ -4,15 +4,13 @@ import json
 import logging
 import random
 from pathlib import Path
-from typing import Union
+from typing import Coroutine, Union
 
 import discord
 from discord import Member
 from discord.ext import commands
 from discord.ext.commands import BadArgument, Cog, clean_content
 
-from bot.constants import Roles
-
 log = logging.getLogger(__name__)
 
 with Path("bot/resources/valentines/love_matches.json").open(encoding="utf8") as file:
@@ -46,14 +44,11 @@ class LoveCalculator(Cog):
 
         If you want to use multiple words for one argument, you must include quotes.
           .love "Zes Vappa" "morning coffee"
-
-        If only one argument is provided, the subject will become one of the helpers at random.
         """
         if whom is None:
-            staff = ctx.guild.get_role(Roles.helpers).members
-            whom = random.choice(staff)
+            whom = ctx.author
 
-        def normalize(arg: Union[Member, str]) -> str:
+        def normalize(arg: Union[Member, str]) -> Coroutine:
             if isinstance(arg, Member):
                 # If we are given a member, return name#discrim without any extra changes
                 arg = str(arg)