AutoRole Discord.py - discord.py

so I make a simple auto role, is good and work as well
this is my code
#bot.event
async def on_member_join(member):
role = discord.utils.get(member.guild.roles, name="Member")
await member.add_roles(role)
if discord.utils.get(member.guild.roles, name="Fruits"):
role = discord.utils.get(member.guild.roles, name="Fruits")
await member.remove_roles(role)
and I want if the user gets role name "Fruits" the role name "Member" will automatically remove from the user, but this doesn't work for me, so after the user gets role name "Fruits" the role name "Member" doesn't remove from the user
I hope u guys can help me solve this problem
Thank You!

From your code:
Member = discord.utils.get(member.guild.roles, name="Member")
await member.add_roles(Member)
if discord.utils.get(member.guild.roles, name="Fruits"):
Fruits = discord.utils.get(member.guild.roles, name="Fruits")
await member.remove_roles(Fruits)
You first define role as the "Member" role, and then reassign the variable for "Fruits" role, so in the last line (await member.remove_roles(role)) the role which is removed is "Fruits", not "Members". Simply use different variables for both role.
Hope I was clear with my answer

Related

Add temporary guest (Ephemeral user) to Django Rest Framework

I need the following:
Regular User creates a Guest . This guest must have the ability to POST and GET from two Views.
I've created the following Guest Model:
class Guest(models.Model):
reservation = models.ForeignKey(Reservation, related_name='guests', on_delete=models.CASCADE)
keys = models.ManyToManyField(Key)
email = models.EmailField(blank=False)
phone = models.DecimalField(decimal_places=0, max_digits=10)
name = models.CharField(max_length=64)
created = models.DateTimeField(default=timezone.now)
state = models.IntegerField(default=1,validators=[MaxValueValidator(1),MinValueValidator(0)])
class Meta:
ordering = ['created']
This guest "user" is a short-lived one (After a few days is deleted) . I'd like to avoid having to create an User instance for each guest.
My approach would be to allow anonymous users on ViewA and ViewB, then, i'd check request['guest'] to get the guest's ID , retrieve it from database and compare request['headers'] token value.
As for permissions on DRF (Pseudo-code to get the idea)
class IsGuestActive(permissions.BasePermission):
def has_permission(self, request, view):
if request.user.is_anonymous()
guest_id = request['guest']
token = request['headers'].token
return (Guest.objects.get(pk=guest_id, token=token) is not None)
I'm very new to Django, my main questions are:
is my approach viable?
Should i create an User with foreign key to Guest and use groups instead?
I really appreciate any tips on what's the best way to create Ephemeral users like i need to.
Edit (1)
Regarding safety, it really is dangerous using a duct tape type of solution, because no middleware would be responsible for authenticating a guest (Making the system prone to inadvertently giving permissions). But the approach of analyzing the headers within a permission class is not that unfeasible. From official documentation:
class BlocklistPermission(permissions.BasePermission):
"""
Global permission check for blocked IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
We can see here, that META is used to validate an access .
I'll need to dig further.
I found a solution, that i think is viable, to create a temporary controlled access to a View, without having to create a custom User:
Exclaimer: This method seems to be somewhat secure, considering the ephemeral nature of the guests using the system. It does not address the issue of controlling sessions, or retrieving access.
The use-case: You need a guest to access Views, but guest needs special authorization. This Guest will be short-lived.
middleware.py
Create a middleware where you define request.guest = None
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.guest = None
models.py
Now, we'll define our guest to have primary key as a token value:
class Guest(models.Model):
reservation = models.ForeignKey(Reservation, related_name='guests', on_delete=models.CASCADE)
token = models.CharField(max_length=40, primary_key=True)
...
class Meta:
ordering = ['created']
verbose_name = 'Guest'
verbose_name_plural = 'Guests'
def save(self, *args, **kwargs):
if not self.token:
self.token = self.generate_key()
return super().save(*args, **kwargs)
def generate_key(self):
return binascii.hexlify(os.urandom(20)).decode()
def __str__(self):
return self.token
In my case, i send the guest a link with a token as a parameter.
As you don't want to store the token on localstorage or any other place that isn't an httpOnly cookie to avoid XSS attacks, define a View to respond to the first click of the link on the email:
class SetGuest(APIView):
authentication_classes = []
permission_classes = [permissions.AllowAny]
def get(self, request, token, format=None):
response = HttpResponse("", status=308)
response['Location'] = "http://localhost/index.html?redirect&action=confirm&status=success"
response.set_cookie(key='guest_token', value=token, path='/', samesite='Lax', max_age=3600*24*7, secure=False, httponly=True)
return response
This View will redirect your guest to a page, and set up the CSRF and guest_token cookie.
Define the decorator creating a decorators.py:
def validate_guest(view_func):
def wrapper(self, request, *args, **kwargs):
try:
token = request.COOKIES.get('guest_token')
request.guest = Guest.objects.get(token=token)
except Exception as e:
logger.debug(str(e))
return redirect('/api/')
return view_func(self, request, *args, **kwargs)
return wrapper
Now, to protect the view so it only works for guests with a token:
class GuestGetKeys(APIView):
authentication_classes = []
permission_classes = [IsGuest]
dec_list = [ensure_csrf_cookie]
#validate_guest
def get(self, request, format=None):
return Response({'status': 'valid', 'success': 'Guest is logged'}, status=status.HTTP_200_OK)
One can achieve the same without using the decorator, but permissions.py instead.
The reason i prefer not to, is because through decorators i can control redirects in a cleaner way.
why defining the new dict value using a middleware? I tried modifying the request object directly on the Decorator and on the permissions class, it simply doesn't work.
There are a few short-comings from this approach, like session revoking issues, there's no other way of starting a "session" other than accessing the link sent to the guest, tokens are plain text and a database breach would allow anyone access as guests. Sessions don't expire, and so on.

How to delete roles using discord.py?

I am trying to create a command that deletes a specified role when you type it in. But it doesn't work. I've searched up solutions but only found tutorials in async, and I am using rewrite. Can anyone help me? Here is my code:
#client.command()
async def delrole(ctx, *, name):
await ctx.guild.remove_roles(name)
await ctx.send(f"Succesfully deleted the {name} role")
First, get the role using one of discord.py's utility functions (https://discordpy.readthedocs.io/en/latest/api.html#discord.utils.get):
role = discord.utils.get(ctx.guild.roles, name=name)
Then delete the role (https://discordpy.readthedocs.io/en/latest/api.html#discord.Role.delete):
await role.delete()
Probably like this
role = discord.utils.get(ctx.guild.roles, name = "role_name")
await bot.delete_role(ctx.guild, role)
await bot.send(f"Succesfully deleted the {role.name} role")
remove_role is for removing roles from a Member.
To delete a role you need to use delete_role
An example as follows:
guild = ctx.guild
role = discord.utils.get(guild.roles, name = "role's name")
await client.delete_role(guild, role)

last_login does not update by API in django rest

I created a simple endpoint to create and update users. It's work fine except for the field last_login that not update when a user login by API.
My example:
My urls:
router.register(r"user", foo.UserViewSet)
My Serializer:
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
email=validated_data["email"],
last_login=validated_data["last_login"],
)
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = User
exclude = (
"groups",
"user_permissions",
)
My View:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
pagination_class = StandardPagination
serializer_class = UserSerializer
model = User
def update(self, request, *args, **kwargs):
user = self.get_object()
serializer = self.get_serializer(
user, data=request.data, partial=True
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
When I log with any user (in API) the field last_login is always null. By django admin is ok.
Update
I had some progress and problems putting the code in my UserViewSet:
def perform_authentication(self, request):
user = request.user
user.last_login = timezone.now()
user.save()
return user
Ok. last_login is registering, but only in user endpoint and every request in this endpoint.
As far as my own investigation on this issue goes, it turns out that last_login field is tightly coupled with default Django authentication system (session authentication), that is why this field is updated when you use Django Admin, as Admin uses session authentication.
In your case, it looks like some other type of authentication is used, and the signal which updates this field is not triggered. See the link below where the signal is handled:
https://github.com/django/django/blob/5f8495a40ab1554e81ac845484da890dd390e1d8/django/contrib/auth/models.py#L14
So, in order to update this field properly you should probably do it manually.
Here is one more discussion on this matter:
last_login field is not updated when authenticating using Tokenauthentication in Django Rest Framework
Maybe it could be the default setting, try this in settings.py:
SIMPLE_JWT = {
// ...
'UPDATE_LAST_LOGIN': True,
// ...
}
source: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

Insert user role with user id and role id in abp permission table

In Asp.net Boilerplate I am looking for a method to insert permission of a user with user id and role id. I check some reference but still did not find a way to achieve it.
Please suggest.
var role = await _roleManager.GetRoleByIdAsync(roleId);
await _roleManager.SetGrantedPermissionsAsync(role, permissions);
This will grant the persiossions to the role
In ASP.NET Core, UserManager<TUser>.AddToRoleAsync(TUser, String) adds to a role by its name.
In ASP.NET Boilerplate, you can get the role by its int roleId and then pass on the role.Name.
public async Task<IdentityResult> AddToRoleAsync(long userId, int roleId)
{
var user = await _userManager.GetUserByIdAsync(userId);
var role = await _roleManager.GetRoleByIdAsync(roleId);
return await _userManager.AddToRoleAsync(user, role.Name);
}
Related: What is the difference between Roles and Permissions in ASP.NET Boilerplate Template?

Discord.py creating role off of a list

Ive seen examples on how to give a role to a user, but those are hard coding the role into the add_role function. I would like help in writing a command that allows a user to assign a role themselves based off a list.
#client.command(pass_context = True)
async def assign(ctx, role):
member = ctx.message.author
role = discord.utils.get(member.server.roles, name = role)
await client.add_roles(member, role)
await client.say("Role added! {}".format(member.mention))
this is the code i got, but this assigns any role in the server, since thats what ive assigned role to apparently. Ive played around with other things but ive gotten an error, 'str' object has no attribute 'id' error.
You can define a whitelist of role names, then check against that list before assigning the role. In the below I also use a converter, but you could look up the name as well.
roles_whitelist = ['librarian', 'treasurer', 'secretary']
#client.command(pass_context = True)
async def assign(ctx, role: discord.Role):
member = ctx.message.author
if role.name.lower() in roles_whitelist:
await client.add_roles(member, role)
await client.say("Role added! {}".format(member.mention))
else:
await client.say("Cannot add that role")

Resources