Removing a reaction on adding a reaction - python-3.x

Hi I'm wanting to remove a reaction when another reaction is adeed. For example if user had reacted to emoji 1 but reacts to emoji 2 then emoji 1 is removed or if the user had react to emoji 1 but reacts to emoji 4 instead then emoji 1 is removed.
I'm using a async def on_raw_reaction_add(): event and defined the emojis I'd like to use however if I dide:
await member.add_roles(role, reason='Added role')
await message.remove_reaction(one, user)
await message.remove_reaction(two, user)
await message.remove_reaction(three, user)
This would remove all the emojis including the emoji the user selected.
Here is what I'm working with:
one = "1\N{COMBINING ENCLOSING KEYCAP}"
two = "2\N{COMBINING ENCLOSING KEYCAP}"
three = "3\N{COMBINING ENCLOSING KEYCAP}"
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
message_ids = [649600853048688642, ]
channel = self.bot.get_channel(634023419482079232)
message = await channel.fetch_message(649600853048688642)
user = self.bot.get_user(payload.user_id)
if not payload.guild_id:
return
if payload.message_id not in message_ids:
return
guild = self.bot.get_guild(payload.guild_id) # You need the guild to get the member who reacted
member = guild.get_member(payload.user_id) # Now you have the key part, the member who should receive the role
restricted_role = discord.utils.get(guild.roles, name="Commands Revoked")
role_name = emoji_role_map.get(payload.emoji.name)
if restricted_role in member.roles:
return
if role_name: # None if not found
role = discord.utils.get(guild.roles, name=role_name)
await member.add_roles(role, reason='Added role')
await message.remove_reaction(one, user)
await message.remove_reaction(two, user)
await message.remove_reaction(three, user)
Help appreciated.

Related

Discord py mute command specifying reason without time

So I made a mute command and converted it to an optional tempmute yesterday, it worked fine except for when I specified a reason and no time. Obviously that would create a problem but sadly I could not figure out how to fix it. i.e: N?mute user time reason works but N?mute user reason doesn't. If I don't specify the reason nor time it mutes them for 2 years. I want to be able to perm mute people with a reason and also temp mute people with a reason (already works). Hereby the code:
#commands.command()
#commands.has_permissions(manage_roles=True)
async def mute(self, ctx, member: discord.Member, time="670d", *, reason="no reason provided"):
role = discord.utils.get(ctx.guild.roles, name="Muted")
admin = discord.utils.get(ctx.guild.roles, name="Admin")
mod = discord.utils.get(ctx.guild.roles, name="Moderator")
guild = ctx.guild
pfp = member.avatar_url
time_convert = {"s":1, "m":60, "h":3600,"d":86400}
tempmute= int(time[0]) * time_convert[time[-1]]
if admin in member.roles or mod in member.roles:
embed = discord.Embed(title="Mute failed", description="Staff cannot be muted.", color=0xff4654)
await ctx.channel.send(embed=embed)
return
if role in member.roles:
embed = discord.Embed(title="Mute failed", description="**{0}** is already muted!".format(member), color=0xff4654)
await ctx.channel.send(embed=embed)
if role not in guild.roles:
perms = discord.Permissions(send_messages=False, speak=False)
await guild.create_role(name="Muted", permissions=perms)
await member.add_roles(role, reason=reason) #User muted
embed = discord.Embed(title="User muted!", description="**{0}** was succesfully muted by **{1}** for **{2}**.".format(member, ctx.message.author, reason), color=0xff4654)
await ctx.channel.send(embed=embed)
channel = discord.utils.get(guild.channels, name="logs")
embed = discord.Embed(title=" ", description="**{0}** was muted by **{1}**. Reason: **{2}**".format(member, ctx.message.author, reason), color=0xff4654)
embed.set_author(name="{0}".format(member), icon_url=pfp)
await channel.send(embed=embed) #Log
await asyncio.sleep(tempmute)
await member.remove_roles(role)
else:
await member.add_roles(role, reason=reason) #User muted
embed = discord.Embed(title="User muted!", description="**{0}** was succesfully muted by **{1}** for **{2}**.".format(member, ctx.message.author, reason), color=0xff4654)
await ctx.channel.send(embed=embed)
channel = discord.utils.get(guild.text_channels, name="logs")
embed = discord.Embed(title=" ", description="<#{0}> was muted by <#{1}>. Reason: **{2}**".format(member.id, ctx.message.author.id, reason), color=0xff4654)
embed.set_author(name="{0}".format(member), icon_url=pfp)
await channel.send(embed=embed) #Log
await asyncio.sleep(tempmute)
await member.remove_roles(role)
I tried doing time: Optional[int] as someone else suggested but alas it broke it entirely.
To answer bluntly, there isn't a nice way of doing this. What I recommend is that you split the command into two separate ones, mute and tempmute.
If you really do want it as one function, you could do something like this:
import re
async def mute(self, ctx, member: discord.Member, *options):
if len(options) == 2: # User specified date and reason
expiry, reason = options
if len(options) == 1: # User specified one of the above so we need to find out which
if re.match(r"\d+\D", options[0]):
# Regex to check for one or more digit then a single non-digit
expiry = options[0]
reason = None
else:
expiry = None
reason = options[0]
On a slightly unrelated note, you should not do await asyncio.sleep(tempmute). Long sleeps are innacurate and if the bot restarts, the person will never be unmuted. You should create a database with datetimes of when the user should be unmuted and have a looping task which queries the database and unmutes users when their time is up.

How can I remove from the invites from a user that has left the guild?

This is my current code :
#client.event
async def on_member_join(member):
guild = client.get_guild(761604402142248960)
channel = client.get_channel(762721485193740348)
inviter = await tracker.fetch_inviter(member)
emoji = discord.utils.get(guild.emojis, name='verify')
totalInvites = 0
for i in await guild.invites():
if i.inviter == inviter:
totalInvites += i.uses
await channel.send(f"{member.mention} a été invité par {inviter} qui possède désormais {totalInvites} invitations {emoji} !")
But I don't know how to remove the users that left the guild. Can anybody help?
As derw said in his reply, you will want to use the on_member_remove event. You will also want to iterate through the guild invites, find the one who's inviter id matches the invite id, and delete the invite.
#client.event
async def on_member_remove(member):
for i in member.guild.invites: # Iterate through every invite...
if i.inviter.id == member.id: # Check if the invite's inviter id is the member id
await invite.delete(reason="User left the guild") # Delete the invite!

Error await keeps creating multiple channels instead of checking

Hi I'm having an issue where my code is creating more than one channels. The function of the code should:
Check to see if the channel exists
If Channel does exist don't create a new one.
Otherwise, if the channel does not exist create one.
In a nutshell, how it supposed to work, The on_message event checks for a response from a user in a direct message sent to the bot, their message is then relayed to a guild channel that either already exists otherwise a new one is created before the message is sent.
In this is the issue is that I can't get around it with a check to see if the channel exists, it sure does but it just duplicates everytime a message is sent:
I have tried both these methods to check:
#Check 1
for channel in guild.text_channels:
if channel.name == f"{message.author.name.lower()}{message.author.discriminator}" and channel.name is not None:
await channel.send(embed=embed)
else:
channel_non = await guild.create_text_channel(f'{message.author.name}{message.author.discriminator}', overwrites=overwrites, category=self.bot.get_channel(744944688271720518))
await channel_non.send(embed=embed)
#Check 2
channel_present = False
for channel in guild.text_channels:
if channel.name == f"{message.author.name.lower()}{message.author.discriminator}":
await channel.send(embed=embed)
channel_present = True
if channel_present:
channel_non = await guild.create_text_channel(f'{message.author.name}{message.author.discriminator}', overwrites=overwrites, category=self.bot.get_channel(744944688271720518))
await channel_non.send(embed=embed)
The check 2 code causes the on_message event to do nothing. Help would be much appreciated I don't know where I'm going wrong here.
Honestly, I would just do it by a command.
#client.command()
async def command(ctx):
author = ctx.message.author
guild = ctx.guild
for channel in guild.text_channels:
if channel.name == ctx.message.author:
await channel.send(embed = embed)
return
channel = await guild.create_text_channel(f"{ctx.message.author}", overwrites = overwrites, category = self.bot.get_channel(744944688271720518))
await channel.send(embed = embed)

Role issuance system

There is a command to request a role. I don't understand how to set some functions for reactions.
#client.command()
async def role(ctx):
role = ctx.guild.get_role(703596629860548643)
zapros_chanell = client.get_channel(729733881129074768 )
zapros2_chanell = client.get_channel(703596629923725339 )
embed = discord.Embed(title="Запрос роли")
embed.add_field(name='Запросивший роль', value=ctx.message.author.mention)
embed.add_field(name='Роль для выдачи', value=role.mention)
embed.set_thumbnail(url=ctx.guild.icon_url)
message = await zapros_chanell.send(embed=embed)
await zapros2_chanell.send(embed = discord.Embed(description = f'{ctx.message.author.mention}, `запрос на выдачу роли был успешно отправлен, ожидайте его рассмотрения модерацией Discord`', color=discord.Color.purple()))
await message.add_reaction('✅')
await message.add_reaction('❎')
The bottom line is that if when you click on ✅, the role was issued and a text was written to the person in zapros2_chanell.
When you click on ❎, the person was not given a role, therefore, but a certain text was also written in zapros2_chanell.
I used an event called on_raw_reaction_add. Made a check to the reaction, keep in mind the will give the role to any message in the guild with ✅.It it just a proof of concept.
You can make it only accept reactions on certain channel, or even only for given message IDs
#client.command()
async def role(ctx):
zapros_chanell = client.get_channel(729733881129074768)
embed = discord.Embed(title="Запрос роли")
embed.add_field(name='Запросивший роль', value=ctx.message.author.mention)
embed.add_field(name='Роль для выдачи', value=role.mention)
embed.set_thumbnail(url=ctx.guild.icon_url)
message = await zapros_chanell.send(embed=embed)
await zapros2_chanell.send(embed = discord.Embed(description = f'{ctx.message.author.mention}, `запрос на выдачу роли был успешно отправлен, ожидайте его рассмотрения модерацией Discord`', color=discord.Color.purple()))
await message.add_reaction('✅')
await message.add_reaction('❎')
#client.event
async def on_raw_reaction_add(payload):
channel = await client.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await client.fetch_user(payload.user_id)
emoji = payload.emoji.name
guild = client.get_guild(ID_HERE)
role = guild.get_role(703596629860548643)
zapros2_chanell = client.get_channel(703596629923725339 )
if user.id != bot.user.id: # bot to count itself
if emoji == '✅':
await client.add_roles(user, role)
await zapros2_chanell.send(f'{user.name} has been given {role.name}')
elif emoji == '❎':
await zapros2_chanell.send(f'{user.name} did not want {role.name}')

Attribute Error Issue 'User' object has no attribute 'roles'

I'm having a slight issue checking for roles a user has. I'm currently getting a
if member_role in message.author.roles]
AttributeError: 'User' object has no attribute 'roles'
It seems I cannot pass roles with the message argument when checking to see if the message author has them roles.
Help Appreciated.
Here is my code I'm working with:
async def on_message(self, message):
if not isinstance(message.channel, discord.DMChannel) or
message.author.id == self.bot.user.id:
# not a DM, or it's just the bot itself
return
channel = self.bot.get_channel(578731262550736910)
if not channel:
print("Mail channel not found! Reconfigure bot!")
time = datetime.utcnow()
guild = self.bot.get_guild(555844758778544158)
member_role = get(guild.roles, name='Members')
muted_role = get(guild.roles, name='Modmail Muted')
content = message.clean_content
verified = [member for member in guild.members
if member_role in message.author.roles]
muted = [member for member in guild.members
if muted_role in message.author.roles]
if muted:
await message.channel.send("You're not allowed to use modmail.")
return
if verified:
embed = discord.Embed(title="📬 You've got modmail!")
embed.add_field(name="Sent by:", value=f"{message.author.mention} ({message.author.id})" ,inline=False)
embed.add_field(name="Message:", value=content[:1000] or "blank")
embed.set_footer(text="Mods: React with icon below this message to notify us that you're dealing with this modmail. (First reaction already set by the bot)")
if message.attachments:
embed.add_field(name="Attachments", value=", ".join([i.url for i in message.attachments]))
if len(content[1000:]) > 0:
embed.add_field(name="Message (continued):", value=content[1000:])
msg = await channel.send(embed=embed)
await msg.add_reaction('📤')
try:
embed = discord.Embed(title=f"Thanks {message.author.display_name}! your message has been sent to the Mods.", timestamp=time)
embed.set_footer(text="Message Sent")
await message.add_reaction('📬')
await message.channel.send(embed=embed)
except discord.ext.commands.errors.CommandInvokeError:
await message.channel.send('📬')
else:
await message.channel.send("Only members can use modmail.")
as suggested by #Patrick Haugh in replies I used get_member.
user_id = message.author.id
author = guild.get_member(user_id)

Resources