Blacklist a role in Discord.py - python

after trying so many thing I came up with the idea to ask you intelligent people out there! I want to blacklist 3 roles for a single command. But everything I tried failed.
Here's the code I wrote:
member = ctx.message.author
roleA = get(member.guild.roles, name="Rote Birdys")
roleB = get(member.guild.roles, name="Grüne Birdys")
roleC = get(member.guild.roles, name="Blaue Birdys")
if commands.has_any_role(roleA, roleB, roleC):
return
Nothing worked, I tried some more things but they didn't work either. May I'm really stupid but I need to finish this projekt in a few weeks and I'm stuck here.
I hope you can help me :)

This is just the has_any_role check but backwards. I also created a new error like MissingAnyRole:
from discord.ext.commands import check, CheckFailure
import discord.utils
class HasForbiddenRole(CheckFailure):
def __init__(self, forbidden_roles):
self.forbidden_roles = forbidden_roles
forbidden= ["'{}'".format(role) for role in forbidden_roles]
if len(missing) > 2:
fmt = '{}, or {}'.format(", ".join(forbidden[:-1]), forbidden[-1])
else:
fmt = ' or '.join(forbidden)
message = "You have at least one of the forbidden roles: {}".format(fmt)
super().__init__(message)
def lacks_every_role(*items):
def predicate(ctx):
if not isinstance(ctx.channel, discord.abc.GuildChannel):
raise NoPrivateMessage()
getter = functools.partial(discord.utils.get, ctx.author.roles)
if not any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items):
return True
raise HasForbiddenRole(items)
return check(predicate)
Usage would be like any of the other checks:
#lacks_every_role("Rote Birdys", "Grüne Birdys", "Blaue Birdys") # You could also use role ids
#bot.command()
async def comm(ctx):
...

Related

discord.py warning system checking warnings

So I'm still making a warning system but in the process I am having this issue with the embed showing the warning multiple times. Shown in the image provided.
https://i.stack.imgur.com/ks4Gm.png I'm not sure what could be causing this but I think it might be the for loop I made?
#client.hybrid_command(name = "warnings", with_app_command=True, description="View the warnings of a member", aliases=["punishments"])
async def warnings(ctx, member: discord.Member = None):
if member == None:
await ctx.reply("A Member is required")
else:
check = warndb.warn_logs.find_one({"user_id": member.id})
if check is None:
await ctx.reply("This user has no warns")
else:
reason = check["reason"]
moderator_id = check["moderator_id"]
embed = discord.Embed(color=embedcolor, title=f"{member.name}'s warnings")
for w in check:
embed.add_field(name=f"{reason}", value=f"<#{moderator_id}>", inline=False)
await ctx.send(embed=embed)
There is no error and it works fine it just shows the warning(s) multiple times
You query with find_one so there is no point in looping over check.
I would try to just remove the line for w in check:.
If it's suppose to be an array(change to find_all), maybe you manually adding data to the table when testing and it's displaying all previous warns you've added.
I figured it out finally. The issue is you need to turn the check = warndb.warn_logs.find_one({"user_id": member.id}) into a list by doing check = list(warndb.warn_logs.find_one({"user_id": member.id})). Once you do that you should use the .get() function to get the values of the keys
In this case:
for w in check:
reason = w.get('reason')
moderatorid = w.get('moderator_id')
guildid = w.get('guild_id')
caseid = w.get('_id')
embed.add_field(name=f"Case ID: {caseid}—Reason: {reason}", value=f"<#{moderatorid}>", inline=False)

Slash command autocompletion in pycord

I want to start working with SlashCommand autocompletion in pycord. Since I think that my request in the previous question is impossible, I thought to myself that maybe I can change the autocomplete based on the user's choice in one of the slash-command entries and display the desired entry to the user earlier.
I'm asking this because I don't found any good resource for learning this and I don't understand docs
there is an example from the Pycord documents, I think if you experiment with this part of the code, you will understand how it can work
https://github.com/Pycord-Development/pycord/blob/master/examples/app_commands/slash_autocomplete.py
If you want use them in cogs
there's my part for cogs
import discord
from discord import option
from discord.ext import commands
mycolors = ["red", "white", "yellow"]
class ExampleAutocompletion(commands.Cog):
ctx_parse = discord.ApplicationContext
def __init__(self, bot: discord.Bot):
self.bot = bot.user
#staticmethod
def colorAutocomplete(self: discord.AutocompleteContext):
return mycolors
#staticmethod
def flowertypeAutocomplete(self: discord.AutocompleteContext):
chosen_color = self.options["color"]
match chosen_color:
case "red":
return ["Rose", "Georgina"]
case "white":
return ["Chrisantem", "Gortensia"]
case "yellow":
return ["Sunflower", "Narciss"]
case _:
return ["There is no flower with this color"]
#commands.slash_command(
guild_ids=["Your Guild ID for test"],
description="")
#option("color", description="What's your favourite color?",
autocomplete=colorAutocomplete)
#option("flowertype", description="and that's your flower shape!",
autocomplete=flowertypeAutocomplete)
async def beautyflowers(self, ctx: ctx_parse,
color: str, flowertype: str):
await ctx.respond(f"My flower is {flowertype} and its color is {color}!")
def setup(bot):
bot.add_cog(ExampleAutocompletion(bot))

How do you get a user avatar from a mentioned with discord.py?

i made an avatar command for my bot but it doest work with mentioions, im trying to not use ' #client.command ' because it causes problems for the rest of the code
if message.content.startswith('+avatar'):
sender = message.author
name = sender.display_name
avatar_url = sender.avatar_url
embedVar = discord.Embed(title="**{}**".format(sender), description="Username: {}".format(name), color=0xec9e36)
embedVar.set_image(url = avatar_url)
await message.channel.send(embed=embedVar)
is what i have written and i cant find any ways of making it work, any kind of help would be appreciated!
I am guessing you are trying to do something like
+avatar #mention
A mention is basically a string marking that contains ID of the user.
import re
def is_mention(s):
'''Check if the string is a valid 'mention' string for Discord'''
try:
return bool(re.match(r'<#!?(\d+)>', s))
except Exception:
return None
def mention_to_id(s):
'''Extract user-id from the mention'''
if is_mention(s):
return int(re.sub(r'[<>!#]', '', s))
return None
You can first extract the mention string using mention_str = message.content.split()[1], and then call mention_to_id function to extract the ID from mention string.
After that, call get_user on your bot (client) object to get the user, which will return a User object which has avatar_url field.
To summarize,
if message.content.startswith('+avatar'):
message_parts = message.content.split()
if len(message_parts) > 1:
mention_str = message.content.split()[1]
if is_mention(mention_str):
user = client.get_user(mention_to_id(mention_str)
# do whatever with user.avatar_url
else:
# Warn about invalid mention
else:
# Whatever you want to do when there's no mention
References:
get_user: https://discordpy.readthedocs.io/en/latest/api.html#discord.Client.get_user
User: https://discordpy.readthedocs.io/en/latest/api.html#discord.User
I used message.mentions to find if someone is mentioned in the message and if mentioned i took the mentioned user's name and avatar_url else i took the sender's name and avatar_url
if message.content.startswith('+avatar'):
if( len(message.mentions) > 0 ): #checking if someone is mentioned
#mesage.mentions[0] is the first mentioned user in the message
name = message.mentions[0].display_name
avatar_url = message.mentions[0].avatar_url
else: #no one is mentioned
name = sender.display_name
avatar_url = sender.avatar_url
embedVar = discord.Embed(title="Username: {}".format(name), color=0xec9e36)
embedVar.set_image(url = avatar_url)
await message.channel.send(embed=embedVar)

from_queryset_single vs from_tortoise_orm in tortoise (fast api)

I am new to Fast API and I am trying to create an api to return the students in the database.
This below code seems to work
#app.get("/{id}")
async def get_student(id:int):
return await stud_pydantic.from_queryset_single(Student.get(id=id))
this too seems to work
#app.get("/{id}")
async def get_student(id:int):
stud_obj = Student.get(id=id)
return await stud_pydantic.from_tortoise_orm(stud_obj)
But, This does not work
#app.get("/{id}")
async def get_student(id:int):
stud_obj = Student.get(id=id)
return await stud_pydantic.from_queryset_single(stud_obj)
But, Both are basically trying to return a student object. right ? so, what's the difference.
It seems like I don't understand the differance between the methods from_queryset_single and from_tortoise_orm
Here is my Student Model
class Student(models.Model):
name = fields.CharField(50,unique=True)
age = fields.IntField()
id = fields.IntField(pk=True)
stud_pydantic = pydantic_model_creator(Student,name="student")
studRO_pydantic = pydantic_model_creator(Student,name="studentRO",exclude_readonly=True)
Thanks in Advance
I think you need to await the process of fetching data from the database.
#app.get("/{id}")
async def get_student(id:int):
stud_obj = await Student.get(id=id)
return await stud_pydantic.from_queryset_single(stud_obj)

I want to update a dictionary/json key instead of appending a new one?

Alright, So I am using discord.py and JSON and I am trying to make a ticket counter, the client refuses to use a database so I have to use JSON. But every time the code updates the file it create a second key and then it uses that key instead of the first one. If anyone wants to see it happen in action friend me (Jpac14#8237) and I'll show you what happens. I will also attach my code and the JSON file.
Also do you think I could you Collections Module for this.
Code:
from discord.ext import commands
import discord
import json
class TicketSystem(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.create_ticket_msgs = []
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
for create_ticket_msg in self.create_ticket_msgs:
if reaction.message.id == create_ticket_msg.id and user != self.bot.user:
await reaction.message.channel.send(f"{user} reacted")
await reaction.message.remove_reaction("📩", user)
ticket_counter_dict = {}
try:
with open("json/ticket_counter.json", "r") as ticket_counter_json:
ticket_counter_dict = json.load(ticket_counter_json)
except json.JSONDecodeError:
print("JSONDecodeError")
current_ticket_counter = ticket_counter_dict.get(str(reaction.message.guild.id))
if current_ticket_counter == None:
current_ticket_counter = 1
ticket_catergory = discord.utils.get(reaction.message.guild.categories, name="Tickets")
if reaction.message.guild.id == 660156957486874645:
support_team_role = discord.utils.get(reaction.message.guild.roles, name="Staff")
else:
support_team_role = discord.utils.get(reaction.message.guild.roles, name="Support")
ticket_channel_overwrites = {
support_team_role: discord.PermissionOverwrite(read_messages=True),
user: discord.PermissionOverwrite(read_messages=True),
reaction.message.guild.default_role: discord.PermissionOverwrite(read_messages=False)
}
users_ticket_channel = await ticket_catergory.create_text_channel(f"ticket-{current_ticket_counter}", overwrites=ticket_channel_overwrites)
current_ticket_counter += 1
ticket_counter_dict.update({reaction.message.guild.id: current_ticket_counter})
with open("json/ticket_counter.json", "w") as ticket_counter_json:
json.dump(ticket_counter_dict, ticket_counter_json)
embedMessage = discord.Embed(description="Support will be with you shortly.\nTo close the ticket type ?close", color=discord.colour.Colour.green())
embedMessage.set_footer(text=f"Created By Nexus Developments - https://discord.gg/YmdugDf", icon_url="https://i.imgur.com/MRBsIpe.png")
await users_ticket_channel.send(embed=embedMessage)
#commands.command(name="ticketmsg")
async def send_create_ticket_msg(self, ctx, channel: discord.TextChannel):
embedMessage = discord.Embed(title="Create A Ticket", description="To create a ticket react with 📩", timestamp=ctx.message.created_at, color=discord.colour.Colour.green())
embedMessage.set_footer(text=f"Created By Nexus Developments - https://discord.gg/YmdugDf", icon_url="https://i.imgur.com/MRBsIpe.png")
create_ticket_msg = await channel.send(embed=embedMessage)
await create_ticket_msg.add_reaction("📩")
self.create_ticket_msgs.append(create_ticket_msg)
def setup(bot):
bot.add_cog(TicketSystem(bot))
JSON File:
{"665930890039394305": 6, "665930890039394305": 7}
reaction.message.guild.id is an int.
When you write ticket_counter_dict.update({reaction.message.guild.id: current_ticket_counter}), you create a new int key in your dict, which doesn't override the str key that exists from loading the json file.
See this example:
import json
d = {1: 'a', '1': 'b'}
json.dumps(d)
>>> '{"1": "b", "1": "a"}'
The dict can hold both 1 and '1' as keys as they are different objects. But the json serialization will turn both into strings, as json uses strings as keys.
I supposed there is room for improvement in the json module as it doesn't seem to check that the stringified keys are all unique.
You can fix your code by making sure you use a string for the key in your dict:
ticket_counter_dict.update({str(reaction.message.guild.id): current_ticket_counter})

Categories

Resources