Role issuance system - bots

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}')

Related

Time out after x amount of seconds discord.py rewrite

I'm making a bot in discord.py rewrite and made a embed creator in your dm's and want to make it so if you dont respond in x amount of seconds the bot says "Where did you go? We can try this again later."
Here is my current code:
#client.command()
async def embed(ctx):
user = ctx.author
if ctx.message.author.guild_permissions.manage_messages:
await ctx.channel.purge(limit=1)
em = discord.Embed(description=f"Embed Creation started in dm {ctx.author.mention}",color = discord.Colour.red())
await ctx.send(embed=em, delete_after=3)
em = discord.Embed(description='What would you like the title to be?', color = discord.Colour.red())
await user.send(embed=em)
msg = await client.wait_for('message', check=lambda message: message.author == ctx.author)
title = msg.content
em = discord.Embed(description='What would you like the Description to be?', color = discord.Colour.red())
await user.send(embed=em)
msg = await client.wait_for('message', check=lambda message: message.author == ctx.author)
desc = msg.content
get_channel = ctx.channel
em = discord.Embed(title="**Set Channel for Embed to send**", description = f"1 - `{get_channel}`\n2 - Other Location.", color = discord.Colour.red())
await user.send(embed=em)
msg = await client.wait_for('message', check=lambda message: message.author == ctx.author)
if msg.content == "1":
channel = ctx.channel
em = discord.Embed(title=title, description=desc,color=discord.Colour.red())
em.set_footer(icon_url = ctx.author.avatar_url, text = f"Embed Created by: {ctx.author.name}")
await ctx.channel.send(embed = em)
elif msg.content == "2":
em = discord.Embed(description="Enter Channel ID", color = discord.Colour.red())
await user.send(embed=em)
text_channel = await client.wait_for('message', check=lambda message: message.author == ctx.author)
channel = discord.utils.get(ctx.guild.text_channels, name=text_channel)
em = discord.Embed(title=title, description=desc,color=discord.Colour.red())
em.set_footer(icon_url = ctx.author.avatar_url, text = f"Embed Created by: {ctx.author.name}")
await ctx.send(embed=em)
return
else:
em = discord.Embed(title = "Permissions Required!", description = f"{ctx.author.name} You do not have the required Permissions to use this command", color = discord.Colour.red())
await ctx.send(embed=em)
You can use timeout argument in client.wait_for, and you will get something like that.
You must import asyncio, to make it work
try:
msg = await client.wait_for('message', check=lambda message: message.author == ctx.author, timeout=x) #x - your seconds
except asyncio.TimeoutError:
await ctx.send("Where did you go? We can try this again later.")
else:
#your code, if the user managed to enter values

Translation with reactions not working on python

I'm trying to do a bot translation using reactions. Although something is not working.
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
if user == self.client:
return
if reaction.emoji == ":flag_us:":
text = reaction.message.id
translate_text = google_translator.translate(text, lang_tgt='en')
await self.client.send_message(translate_text.channel)
elif reaction.emoji == ":flag_cn:":
text = reaction.message.id
translate_text = google_translator.translate(text, lang_tgt='zh')
await self.client.send_message(translate_text.channel)
else:
return
No error returned and no action made
This is because reaction.emoji isn't a string, but is an object itself. You're probably looking for reaction.emoji.name.
Also, there are a few issues within the if/elif clauses that would prevent your code from running, even if the original issue was fixed.
reaction.message.id is an integer, so passing it to google_translator.translate() will result in an error.
The name of an emoji tends not to be the name you would enter in Discord. The best practice would be to put the unicode of the emoji.
To send a message to channel, you should use TextChannel.send()
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
if payload.member == self.client:
return
if payload.emoji.name == u"\U0001f1fa\U0001f1f8":
message = await self.client.fetch_message(payload.message_id)
translate_text = google_translator.translate(message.content, lang_tgt='en')
channel = await self.client.fetch_channel(payload.channel_id)
await channel.send(translate_text)
elif payload.emoji.name == u"\U0001F1E8\U0001F1F3":
message = await self.client.fetch_message(payload.message_id)
translate_text = google_translator.translate(message.content, lang_tgt='zh')
channel = await self.client.fetch_channel(payload.channel_id)
await channel.send(translate_text)
This would work, but I would recommend taking all of the various calls outside of the if/elif clauses:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
if payload.member == self.client:
return
emoji_to_language = {
u"\U0001f1fa\U0001f1f8": "en",
u"\U0001F1E8\U0001F1F3": "zh"
}
lang = emoji_to_language.get(payload.emoji.name)
if lang is None:
break
message = await self.client.fetch_message(payload.message_id)
translate_text = google_translator.translate(message.content, lang_tgt=lang')
channel = await self.client.fetch_channel(payload.channel_id)
await channel.send(translate_text)

'TextChannel' object is not iterable | channel check not working

Hi I'm trying to check to see if a channel already exists instead of creating a new one each time a member sends a modmail request. The error I get is
File "C:\Users\User\Desktop\Build 1.0.2\cogs\modmail.py", line 145, in on_message
if get(modmailchannel, name=f"{message.author.name.lower()}{message.author.discriminator}"):
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\discord\utils.py", line 271, in get
for elem in iterable:
TypeError: 'TextChannel' object is not iterable
enter code here
not sure why or the method is incorrect some how. The channel name that is created is the users name and discriminator. What I'm trying to achieve is if that channel already exists don't create another channel/post in the same channel.
Help appreicated
Here is the code I'm working with:
#commands.Cog.listener()
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
bucket = self._cd.get_bucket(message)
retry_after = bucket.update_rate_limit()
seconds = bucket.update_rate_limit()
seconds = round(seconds, 2)
hours, remainder = divmod(int(seconds), 3600)
minutes, seconds = divmod(remainder, 60)
if retry_after:
pass
else:
channel = self.bot.get_channel(744311308509249610)
if not channel:
print("Mail channel not found! Reconfigure bot!")
time = datetime.utcnow()
guild = self.bot.get_guild(715288565877309521)
member_role = get(guild.roles, name='Members')
mod_role = get(guild.roles, name='Members')
muted_role = get(guild.roles, name='Modmail Muted')
user_id = message.author.id
author = guild.get_member(user_id)
content = message.clean_content
if muted_role in author.roles:
await message.channel.send("You're not allowed to use modmail.")
return
if len(message.content) < 0:
await message.channel.send("Your message should be atleast 50 characters in length.")
return
if member_role in author.roles:
emoji1 = '📨'
emoji2 = '🗑️'
message_confirm = "You're about to send a message to the mod team, react with :incoming_envelope: to confirm otherwise :wastebasket: to discard your message."
embed = discord.Embed(description=message_confirm, colour=0x5539cc)
embed.title = "Confirm Message"
confirm = await message.channel.send(embed=embed)
await confirm.add_reaction(emoji1)
await confirm.add_reaction(emoji2)
check = reaction_check(message=confirm, author=message.author, emoji=(emoji1, emoji2))
try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=60.0, check=check)
if reaction.emoji == emoji1:
embed = discord.Embed(title=f"Message Sent", description=f"Hello {message.author.display_name}! We have received your message and we will get back to you as soon as possible. You can send another message in **{minutes}m {seconds}s**.", timestamp=time, colour=0x5539cc)
await message.channel.send(embed=embed)
elif reaction.emoji == emoji2:
embed = discord.Embed(title=f"Message Not Sent", description=f"Your message has not been sent. You can send another message in **{minutes}m {seconds}s**.", timestamp=time, colour=0x5539cc)
await message.channel.send(embed=embed)
return
except asyncio.TimeoutError:
await message.channel.send(f'Sorry, you took too long to confirm your message. Try again in **{minutes}m {seconds}s**.')
return
overwrites = {
guild.default_role: discord.PermissionOverwrite(read_messages=False),
guild.me: discord.PermissionOverwrite(read_messages=True),
member_role: discord.PermissionOverwrite(read_messages=False),
mod_role: discord.PermissionOverwrite(read_messages=True)}
embed = discord.Embed(title=f"Modmail message request from — {message.author.name}#{message.author.discriminator}", colour=0xff8100)
embed.add_field(name="Member:", value=f"{message.author.mention}" ,inline=True)
embed.add_field(name="Reply ID:", value=f"{message.author.id}" ,inline=True)
embed.add_field(name="Message:", value=content[:1000] or "blank", inline=False)
embed.set_footer(text=f"C&P Command: !reply {message.author.id}")
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:])
modmailchannel = await guild.create_text_channel(f'{message.author.name}{message.author.discriminator}', overwrites=overwrites, category=self.bot.get_channel(744944688271720518))
await modmailchannel.send(embed=embed)
if get(modmailchannel, name=f"{message.author.name.lower()}{message.author.discriminator}"):
await modmailchannel.send(embed=embed)
else:
await message.channel.send("Only members can use modmail.")
Instead of if get(modmailchannel, name=f"{message.author.name.lower()}{message.author.discriminator}"): use:
if modmailchannel.name == f"{message.author.name.lower()}{message.author.discriminator}":

Removing a reaction on adding a reaction

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.

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