How do I add multiple roles form a list to a user? - discord.py

I have a command that adds all the current roles of a user to a Database (MongoDB).
The code:
def add_roles_to_db(self):
check = cursor.find_one({"_id": self.ctx.author.id})
if check is None:
cursor.insert_one({"_id": self.ctx.author.id, "roles": [str(r) for r in self.ctx.author.roles[1:]]})
else:
cursor.update_one({"_id": self.ctx.author.id}, {"$set": {"roles": [str(r) for r in self.ctx.author.roles[1:]]}})
The code to get the roles:
def get_roles_from_db(self):
return cursor.find_one({"_id": self.ctx.author.id})["roles"]
When I get the roles from the DB I get a list, everything I've tried led to an error. Error: "AttributeError: 'str' object has no attribute 'id'"
if len(roles) != 0:
await author.add_roles(*roles)
I saw a other post where someone added roles via a list but that didn't work

You're passing a list of strings, not a list of Roles. Turn them into discord.Role instances using the id's first, and then pass them to add_roles.
You can get them using Guild.get_role, or Guild.roles.

await author.add_roles(*[discord.Object(role_id) for role_id in roles])

One good way of adding multiple roles to a user is to have the list of role IDs into a list. You would have to look at your code and figure out how to do that bit, as I don't know either but I reckon just append it into a list. Then interate through each item in that list (each ID) and append it.
Example code:
guild = client.get_guild(1234) #replace 1234 with your guild ID
guild = ctx.guild #this is another way of doing it, chose the one above or this
role_ids = [] #your role ids would be in this list
for id in role_ids:
role = guild.get_role(id)
await author.add_roles(role)
await ctx.send("Given you all the roles!")
I haven't tried this myself, but I don't see why it wouldn't work.
If you need any more clarification, please ask me and if this has worked, please mark it as correct! :)

Related

i want auto role in jda, (when member join, add role by id)

i want when user join some discord guild, bot will add role by id to newcomer.
i have already use this code block, but that isn't work!
`
if (((GuildMemberJoinEvent) event).getGuild().getName().equals("something name")){ System.out.println(((GuildMemberJoinEvent) event).getMember().getUser().getName() +((GuildMemberJoinEvent) event).getGuild()); Role r = ((GuildMemberJoinEvent) event).getGuild().getRoleById("1019811149602107402"); ((GuildMemberJoinEvent) event).getMember().getGuild().addRoleToMember(((GuildMemberJoinEvent) event).getMember().getUser(),r); }
`
This is how to grant roles by id:
event.getGuild().addRoleToMember(member, event.getGuild().getRoleById("1034143551568752682")).queue();
Just put this in onGuildMemberJoin and check for guild name like you have here.
Also please make your code readable

Im trying to find if a member in the server has a specific role and then remove the role from him but i dont know how, here's the code:

#client.command()
async def find(ctx):
guild = ctx.message.guild
role = discord.utils.get(ctx.guild.roles,name="Palpatin")
for member in guild.members:
if role in member.roles :
await ctx.send(f'{member}')
await member.remove_roles(role)
When I try to use the code there are no errors but the bot doesn't send what member has the role either removes the role from that member
As #Weylyn said, your variable role might be None if there is no role named exactly Palpatin, if that is the case, your if will always be evaluated to False since None in any list will always be False, this might be why you do not get any message nor any error.
Also, your for might not work if you do not have the member intents enabled (check here https://discordpy.readthedocs.io/en/stable/intents.html )

django rest framework: SlugRelatedField options- limit by user

Note: I'm new to django rest framework. First project with it. My model has a foreign key which in the serializer I link by a SlugRelatedField. This related model is a small list of options that can be selected however what is available for selection depends on the user (or more specifically the user group).
I have found this question that says how to get the user into a serilaizer. But this doesn't seem to help as the field definition is static right?
Removing the irrelevant parts I have:
class MyModelSerializer(serializers.ModelSerializer):
sequence = serializers.SlugRelatedField(
many=False,
read_only=False,
slug_field='prefix',
queryset=Sequence.objects.filter(active=True,
sequence_groups__sequence_group_id__in=SequenceGroup.objects.filter(users=serializers.CurrentUserDefault()))
)
This query works as I also use it in a normal form. When I start the dev. server I get an exception:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'CurrentUserDefault'
So my question is how can I get the current user into the queryset of the SlugRelatedField?
It's funny how after hours of trying, writing down the question leads one to a working solution.
Add request to sterilizer context in ModelViewSet
Simply add below method to the ModelViewSet:
def get_serializer_context(self):
return {"request": self.request}
Adjust the queryset of the SlugRelatedField in the constructor of the Serializer
def __init__(self, *args, **kwargs):
super(MyModelSerializer, self).__init__(*args, **kwargs)
# superuser can choose from all sequences, normal users can only choose from
# active sequences he is assigned to
request = self.context.get("request")
if request and hasattr(request, "user"):
sequence = self.fields['sequence']
if request.user.is_superuser:
sequence.queryset = Sequence.objects.all()
else:
sequence.queryset = Sequence.objects.filter(active=True,
sequence_groups__sequence_group_id__in=SequenceGroup.objects.filter(users=request.user))
In my case the admin should be able to select any of the available options hence the extra condition.

discord.py | how to get list user banned name and id

Discord.py
user banned by me, i want to see a list of banned user and id to remove the ban from user.
!banlist
- for made list of banned user name and id
In version 0.16.12 you can use client.get_bans(serverID) which returns a list of User objects. You can then iterate through the list and get the id and name from each user. If you wanted to have the bot list the banned users' names and ids, you could do something like:
bannnedUsers = await client.get_bans(serverID)
for user in bannedUsers:
await client.send_message(channelID, user.name + ' ' + user.id)
In the rewrite branch it's a little more complicated. You would use guild.bans() to get a list of tuples with each tuple containing a user object and a string with the reason for the ban. For the same result as before, you would do something like:
bans = await guild.bans()
for ban in bans:
await channel.send(ban[0].name + ' ' + ban[0].id)
It should be mentioned that the bot will need the ban_users permission to be able to access these coroutines.

What is the best way pre filter user access for sqlalchemy queries?

I have been looking at the sqlalchemy recipes on their wiki, but don't know which one is best to implement what I am trying to do.
Every row on in my tables have an user_id associated with it. Right now, for every query, I queried by the id of the user that's currently logged in, then query by the criteria I am interested in. My concern is that the developers might forget to add this filter to the query (a huge security risk). Therefore, I would like to set a global filter based on the current user's admin rights to filter what the logged in user could see.
Appreciate your help. Thanks.
Below is simplified redefined query constructor to filter all model queries (including relations). You can pass it to as query_cls parameter to sessionmaker. User ID parameter don't need to be global as far as session is constructed when it's already available.
class HackedQuery(Query):
def get(self, ident):
# Use default implementation when there is no condition
if not self._criterion:
return Query.get(self, ident)
# Copied from Query implementation with some changes.
if hasattr(ident, '__composite_values__'):
ident = ident.__composite_values__()
mapper = self._only_mapper_zero(
"get() can only be used against a single mapped class.")
key = mapper.identity_key_from_primary_key(ident)
if ident is None:
if key is not None:
ident = key[1]
else:
from sqlalchemy import util
ident = util.to_list(ident)
if ident is not None:
columns = list(mapper.primary_key)
if len(columns)!=len(ident):
raise TypeError("Number of values doen't match number "
'of columns in primary key')
params = {}
for column, value in zip(columns, ident):
params[column.key] = value
return self.filter_by(**params).first()
def QueryPublic(entities, session=None):
# It's not directly related to the problem, but is useful too.
query = HackedQuery(entities, session).with_polymorphic('*')
# Version for several entities needs thorough testing, so we
# don't use it yet.
assert len(entities)==1, entities
cls = _class_to_mapper(entities[0]).class_
public_condition = getattr(cls, 'public_condition', None)
if public_condition is not None:
query = query.filter(public_condition)
return query
It works for single model queries only, and there is a lot of work to make it suitable for other cases. I'd like to see an elaborated version since it's MUST HAVE functionality for most web applications. It uses fixed condition stored in each model class, so you have to modify it to your needs.
Here is a very naive implementation that assumes there is the attribute/property self.current_user logged in user has stored.
class YourBaseRequestHandler(object):
#property
def current_user(self):
"""The current user logged in."""
pass
def query(self, session, entities):
"""Use this method instead of :method:`Session.query()
<sqlalchemy.orm.session.Session.query>`.
"""
return session.query(entities).filter_by(user_id=self.current_user.id)
I wrote an SQLAlchemy extension that I think does what you are describing: https://github.com/mwhite/multialchemy
It does this by proxying changes to the Query._from_obj and QueryContext._froms properties, which is where the tables to select from ultimately get set.

Resources