Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add/Remove member only for a specific group #533

Closed
Allan-Nava opened this issue Nov 20, 2017 · 35 comments
Closed

Add/Remove member only for a specific group #533

Allan-Nava opened this issue Nov 20, 2017 · 35 comments

Comments

@Allan-Nava
Copy link

Hi,I need to have a permission, that let the users of a specific group to add, delete or remove only for the belonging group.

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

No problem, you have to create such permissions and manually implement access control with django-guardian support.

@Allan-Nava
Copy link
Author

Access control like?

How can I implement this functionality?

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

Django-guardian is an access control library for any object. Such object may also be groups. See access control in example project. See https://github.com/django-guardian/django-guardian/blob/devel/example_project/articles/views.py#L35 .

@Allan-Nava
Copy link
Author

Perfect!

This is my snippet code:

def create_user_profile(sender, instance, created, **kwargs):
    print("create_user_profile")
    try:
        print("created: "+ str(created))
        if created:
            Profile.objects.create(user=instance)
            print("Member.objects.get_or_create(django_user=instance)")
            #Create a user into groups_manager_member
            member = Member.objects.create(django_user=instance, first_name=instance.first_name, last_name=instance.last_name, username=instance.username, email=instance.email)
            print("member instance created")
            print(member)
            print("Group.objects.create(name=ID_GROUP+instance.username)")

            #Create a group into groups_manager_group
            group = Group.objects.create(name=ID_GROUP+instance.username)
            print("group instance created")
            print(group)
            #Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")
            
    except Exception as e:
        print("Exception: "+str(e))
        pass


def save_user_profile(sender, instance, **kwargs):
    print("save_user_profile")
    try:
        instance.profile.save()

    except Exception as e:
        print("Exception: "+str(e))
        pass

post_save.connect(create_user_profile, sender=User)
post_save.connect(save_user_profile, sender=User)

I need to have the permission to add/remove for all users of the group.

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

I don't know where do you have a problem. You need something like:

class ProtectedGroupUpdateView(PermissionRequiredMixin, GroupUpdateView):
    permission_required = ['change_group', ]
    ...

and assign permission to group when created.

@Allan-Nava
Copy link
Author

I tried to add the permission "can add member", but so it is possible for all groups and not for staff.

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

I am not sure what do you mean. The django-guardian privileges are always granted to users or groups of users. It is not possible to grant privileges based on role or special conditions. If you want to grant staff members permission to manage the "X" group, create a "Staff" group, add staff members to it, add the "X" group, and give the "Staff" group the permission to manage "X" group.

@Allan-Nava
Copy link
Author

I would need a user who belongs to a group
"X" can add or remove only for group "X", unfortunately now it is not so if you have the permission "you can add users" can do it for all groups and not that of apprentice.

Sorry for my bad english

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

Unfortunately, I can not understand your expectations. Examine the example project carefully. This should be sufficient in such a case.

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

"X" can add or remove only for group "X" mean:

  1. create group X,
  2. add members of group X
  3. assign group X permission to manage group X.

@Allan-Nava
Copy link
Author

I actually need to make sure that a user who belongs to a group "x" would be able to add or remove only other users from his own group

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

@Allan-Nava , The django-guardian privileges are always granted to users or groups of users. It is not possible to grant privileges based on role or special conditions. If you want users to manage their groups, give the group permission to manage that group as an object.

Do you understand how to assign & check "X" group permission to manage "X" group?

@Allan-Nava
Copy link
Author

It should be like netflix(but all members have possibility to login): every user should have a personal group where he can add or remove the users according to what he preferes. The issue is that if you give this permission add users, and this influences all the other groups, not users who belong to that one

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

The issue is that if you give this permission add users, and this influences all the other groups, not users who belong to that one

It's definitly not true. This sentence is true for Django core. If you are using the correct Django-guardian permission granted to the management group X for the group X apply only to group X. Just as in an example project, giving the right to manage a particular article does not mean that other articles can be edited by that user.

@Allan-Nava
Copy link
Author

Allan-Nava commented Nov 20, 2017

I want to create a single permission that allows to all the users to add other people to their membership group. Everytime i create a new user, with his membership group 'X', I want a new permission to be created , called 'Can add group for X', and that permission have to have the group 'X' as object.

Like this:


def create_user_profile(sender, instance, created, **kwargs):
    print("create_user_profile")
    try:
        print("created: "+ str(created))
        if created:
            Profile.objects.create(user=instance)
            print("Member.objects.get_or_create(django_user=instance)")
            #Create a user into groups_manager_member
            member = Member.objects.create(django_user=instance, first_name=instance.first_name, last_name=instance.last_name, username=instance.username, email=instance.email)
            print("member instance created")
            print(member)
            print("Group.objects.create(name=ID_GROUP+instance.username)")

            #Create a group into groups_manager_group
            group = Group.objects.create(name=ID_GROUP+instance.username)
            print("group instance created")
            print(group)
            #Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")
            UserObjectPermission.objects.assign_perm('can_add_member_for_xgroup', member, obj=group)
            
    except Exception as e:
        print("Exception: "+str(e))
        pass


def save_user_profile(sender, instance, **kwargs):
    print("save_user_profile")
    try:
        instance.profile.save()

    except Exception as e:
        print("Exception: "+str(e))
        pass

post_save.connect(create_user_profile, sender=User)
post_save.connect(save_user_profile, sender=User)



@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

Abnormal is the creation of a thousand permission. assign_perm('manage_group',group,group) or assign_perm('manage_group',user,group) it should be enough. The rest is to validate whether the user has the authority to manage a particular group.

@Allan-Nava
Copy link
Author

Ok perfect, but in the templare view how can i check?

{{ perms.groups_manager.canaddmemberx2}}

@ad-m
Copy link
Member

ad-m commented Nov 20, 2017

@Allan-Nava , again, examine the example project carefully, especially templates and RTFD.

@Allan-Nava
Copy link
Author

@ad-m Ok thanks, so my snippet code:

from guardian.shortcuts import assign_perm

def create_user_profile(sender, instance, created, **kwargs):
    print("create_user_profile")
    try:
        print("created: "+ str(created))
        if created:
            Profile.objects.create(user=instance)
            print("Member.objects.get_or_create(django_user=instance)")
            #Create a user into groups_manager_member
            member = Member.objects.create(django_user=instance, first_name=instance.first_name, last_name=instance.last_name, username=instance.username, email=instance.email)
            print("member instance created")
            print(member)
            print("Group.objects.create(name=ID_GROUP+instance.username)")

            #Create a group into groups_manager_group
            group = Group.objects.create(name=ID_GROUP+instance.username)
            print("group instance created")
            print(group)
            #Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")
            #UserObjectPermission.objects.assign_perm('can_add_member_for_xgroup', member, obj=group)
            assign_perm('groups_manager.can_add_member_custom', member, group)
            
    except Exception as e:
        print("Exception: "+str(e))
        pass


def save_user_profile(sender, instance, **kwargs):
    print("save_user_profile")
    try:
        instance.profile.save()

    except Exception as e:
        print("Exception: "+str(e))
        pass

post_save.connect(create_user_profile, sender=User)
post_save.connect(save_user_profile, sender=User)

@Allan-Nava
Copy link
Author

Allan-Nava commented Nov 21, 2017

@ad-m I tried this code, but I got exception.

#Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")
            
            #Assign permission for the groups
            assign_perm('groups_manager.can_add_member_custom', member, group)
            print("assign_perm('groups_manager.can_add_member_custom', member, group)")

screen shot 2017-11-21 at 10 14 30

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

@Allan-Nava , what is not clear to you in the error message?

@Allan-Nava
Copy link
Author

Allan-Nava commented Nov 21, 2017

@ad-m
I got this bug:

def create_user_profile(sender, instance, created, **kwargs):
    print("create_user_profile")
    try:
        print("created: "+ str(created))
        if created:
            Profile.objects.create(user=instance)
            print("Member.objects.get_or_create(django_user=instance)")
            #Create a user into groups_manager_member
            member = Member.objects.create(django_user=instance, first_name=instance.first_name, last_name=instance.last_name, username=instance.username, email=instance.email)
            print("member instance created")
            print(member)
            print("Group.objects.create(name=ID_GROUP+instance.username)")

            #Create a group into groups_manager_group
            group = Group.objects.create(name=ID_GROUP+instance.username)
            print("group instance created")
            print(group)
            #Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")

            #Assign permission for the groups
            assign_perm('groups_manager.can_add_member_custom', instance, group)
            print("assign_perm('groups_manager.can_add_member_custom', instance, group)")

    except Exception as e:
        print("Exception: "+str(e))
        pass

screen shot 2017-11-21 at 12 53 38

@ad-m ad-m closed this as completed Nov 21, 2017
@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

@Allan-Nava , what is not clear to you in the error message?

@Allan-Nava
Copy link
Author

@ad-m I don't understand where is the problem

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

@Allan-Nava , there is no this kind of permission. Read the docs what permission exists.

@Allan-Nava
Copy link
Author

Ok i read, but I need to create N permission for N groups/users when I create a new user?

content_type = ContentType.objects.get_for_model(Group)
permission = Permission.objects.create(
    codename='can_add_member_custom',
    name='Can Add Member Custom',
    content_type=content_type,
)

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

As said before:

Abnormal is the creation of a thousand permission.

One permission per action type.

@Allan-Nava
Copy link
Author

As said before:
Abnormal is the creation of a thousand permission.
One permission per action type.

Ok, but how can I create the general permission?

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

As Django core docs said. Linked above.

@Allan-Nava
Copy link
Author

Ok, I use Django Groups Manager:

This is my model Group:

class Group(GroupMixin):

    group_type = models.ForeignKey(GroupType, null=True, blank=True, on_delete=models.SET_NULL,
                                   related_name='%(app_label)s_%(class)s_set')
    group_entities = models.ManyToManyField(GroupEntity, blank=True,
                                            related_name='%(app_label)s_%(class)s_set')

    django_group = models.ForeignKey(DjangoGroup, null=True, blank=True, on_delete=models.SET_NULL)
    group_members = models.ManyToManyField(Member, through='GroupMember',
                                           related_name='%(app_label)s_%(class)s_set')

    # this is just required for easy explanation
    class Meta(GroupMixin.Meta):
        abstract = False
        permissions = (
            ('can_add_member_custom', 'Can Add Member Custom'),
        )

And this is my model Profile:

from __future__ import unicode_literals

import hashlib
import os.path
import urllib

from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.utils.encoding import python_2_unicode_compatible

from bootcamp.activities.models import Notification
#Custom class - ParentsProfile
from bootcamp.parents.models import ParentsProfile
#Custom class - MemberMixin TO CREATE INTO groups_manager_member
from bootcamp.groups_manager.models import MemberMixin, Member, Group
#Import django guardian assign_perm
from guardian.shortcuts import assign_perm
#import UserObjectPermission
from guardian.models import UserObjectPermission

import datetime

ID_GROUP = "Group_"

'''
User Model - Authentication
'''
@python_2_unicode_compatible
class Profile(models.Model):
    user = models.OneToOneField(User)
    location = models.CharField(max_length=50, null=True, blank=True)
    url = models.CharField(max_length=50, null=True, blank=True)
    job_title = models.CharField(max_length=50, null=True, blank=True)

    #I need to delete the parents application

    #Other tascout attributes
    birthdate = models.DateField(default=datetime.date.today)
    address = models.CharField(max_length=255, null=True, blank=True)
    main_role = models.CharField(max_length=255, null=True, blank=True)
    other_roles = models.CharField(max_length=255, null=True, blank=True)
    mobile = models.CharField(max_length=255, null=True, blank=True)
    background_photo = models.CharField(max_length=255, null=True, blank=True)
    profile_photo = models.CharField(max_length=255, null=True, blank=True)
    biography = models.TextField(null=True, blank=True)
    idols = models.TextField(null=True, blank=True)
    weight = models.IntegerField(default=0)
    height = models.IntegerField(default=0)
    favorite_team = models.CharField(max_length=255, null=True, blank=True)
    level = models.IntegerField(default=0)
    sex = models.CharField(max_length=1, default="M")
    nationality = models.CharField(max_length=255, null=True, blank=True)
    city = models.CharField(max_length=255, null=True, blank=True)
    postal_code = models.CharField(max_length=255, null=True, blank=True)
    province = models.CharField(max_length=255, null=True, blank=True)
    number = models.CharField(max_length=255, null=True, blank=True)
    latitude = models.DecimalField( null=True, blank=True, max_digits=9, decimal_places=6)
    longitude = models.DecimalField( null=True, blank=True, max_digits=9, decimal_places=6)

    class Meta:
        db_table = 'auth_profile'

    def __str__(self):
        return self.user.username

    def get_url(self):
        url = self.url
        if "http://" not in self.url and "https://" not in self.url and len(self.url) > 0:  # noqa: E501
            url = "http://" + str(self.url)

        return url

    def get_picture(self):
        no_picture = settings.MEDIA_URL +'/profile_pictures/user.png'
        try:
            filename = settings.MEDIA_ROOT + '/profile_pictures/' +\
                self.user.username + '.jpg'
            picture_url = settings.MEDIA_URL + 'profile_pictures/' +\
                self.user.username + '.jpg'
            if os.path.isfile(filename):  # pragma: no cover
                return picture_url
            else:  # pragma: no cover
                gravatar_url = 'http://www.gravatar.com/avatar/{0}?{1}'.format(
                    hashlib.md5(self.user.email.lower()).hexdigest(),
                    urllib.urlencode({'d': no_picture, 's': '256'})
                    )
                return gravatar_url

        except Exception:
            return no_picture

    #Retrieve users' cover
    def get_cover(self):
        no_cover = settings.MEDIA_ROOT +'profile_covers/cover.jpg'
        try:
            filename = settings.MEDIA_ROOT + '/profile_covers/' +\
                self.user.username + '.jpg'
            cover_url = settings.MEDIA_URL + 'profile_covers/' +\
                self.user.username + '.jpg'
            if os.path.isfile(filename) and os.path.exists(filename):  # pragma: no cover
                if cover_url != None:
                    return cover_url
                else:
                    return no_cover
            else:
                no_cover
        except Exception:
            return no_cover
            
    def get_screen_name(self):
        try:
            if self.user.get_full_name():
                return self.user.get_full_name()
            else:
                return self.user.username
        except:
            return self.user.username

    def notify_liked(self, feed):
        if self.user != feed.user:
            Notification(notification_type=Notification.LIKED,
                         from_user=self.user, to_user=feed.user,
                         feed=feed).save()

    def unotify_liked(self, feed):
        if self.user != feed.user:
            Notification.objects.filter(notification_type=Notification.LIKED,
                                        from_user=self.user, to_user=feed.user,
                                        feed=feed).delete()

    def notify_commented(self, feed):
        if self.user != feed.user:
            Notification(notification_type=Notification.COMMENTED,
                         from_user=self.user, to_user=feed.user,
                         feed=feed).save()

    def notify_also_commented(self, feed):
        comments = feed.get_comments()
        users = []
        for comment in comments:
            if comment.user != self.user and comment.user != feed.user:
                users.append(comment.user.pk)

        users = list(set(users))
        for user in users:
            Notification(notification_type=Notification.ALSO_COMMENTED,
                         from_user=self.user,
                         to_user=User(id=user), feed=feed).save()

    def notify_favorited(self, question):
        if self.user != question.user:
            Notification(notification_type=Notification.FAVORITED,
                         from_user=self.user, to_user=question.user,
                         question=question).save()

    def unotify_favorited(self, question):
        if self.user != question.user:
            Notification.objects.filter(
                notification_type=Notification.FAVORITED,
                from_user=self.user,
                to_user=question.user,
                question=question).delete()

    def notify_answered(self, question):
        if self.user != question.user:
            Notification(notification_type=Notification.ANSWERED,
                         from_user=self.user,
                         to_user=question.user,
                         question=question).save()

    def notify_accepted(self, answer):
        if self.user != answer.user:
            Notification(notification_type=Notification.ACCEPTED_ANSWER,
                         from_user=self.user,
                         to_user=answer.user,
                         answer=answer).save()

    def unotify_accepted(self, answer):
        if self.user != answer.user:
            Notification.objects.filter(
                notification_type=Notification.ACCEPTED_ANSWER,
                from_user=self.user,
                to_user=answer.user,
                answer=answer).delete()

def create_user_profile(sender, instance, created, **kwargs):
    print("create_user_profile")
    try:
        print("created: "+ str(created))
        if created:
            Profile.objects.create(user=instance)
            print("Member.objects.get_or_create(django_user=instance)")
            #Create a user into groups_manager_member
            member = Member.objects.create(django_user=instance, first_name=instance.first_name, last_name=instance.last_name, username=instance.username, email=instance.email)
            print("member instance created")
            print(member)
            print("Group.objects.create(name=ID_GROUP+instance.username)")

            #Create a group into groups_manager_group
            group = Group.objects.create(name=ID_GROUP+instance.username)
            print("group instance created")
            print(group)
            #Add member into the group correct
            group.add_member(member=member)
            print("member added into the group correct")

            #Assign permission for the groups
            assign_perm('can_add_member_custom', instance, group)
            #print("assign_perm('can_add_member_custom', instance, group)")

    except Exception as e:
        print("Exception: "+str(e))
        pass


def save_user_profile(sender, instance, **kwargs):
    print("save_user_profile")
    try:
        instance.profile.save()

    except Exception as e:
        print("Exception: "+str(e))
        pass

post_save.connect(create_user_profile, sender=User)
post_save.connect(save_user_profile, sender=User)

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

Django-guardian is per single object permission management, so grant single user/group permission to single object.

@Allan-Nava
Copy link
Author

Ok perfect, but is still not working though I added the permission in model Group

@ad-m
Copy link
Member

ad-m commented Nov 21, 2017

What doesn't work?

@Allan-Nava
Copy link
Author

Allan-Nava commented Nov 21, 2017

This line:

#Assign permission for the groups
            assign_perm('can_add_member_custom', instance, group)
            print("assign_perm('can_add_member_custom', instance, group)")

instance is the user object but I add into the Group model the permission

# this is just required for easy explanation
    class Meta(GroupMixin.Meta):
        abstract = False
        permissions = (
            ('can_add_member_custom', 'Can Add Member Custom'),
        )

I used this django-groups-manager

@Allan-Nava
Copy link
Author

Allan-Nava commented Nov 21, 2017

I'm stupid, I have to makemigrations and migrate:

python3 manage.py makemigrations
python3 manage.py migrate

Thanks for patience 👍 @ad-m

But in the template view, how can I check ?
this:
jack.has_perm('change_group', admins)

With django shell it works:
screen shot 2017-11-21 at 16 42 17

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants