5

I got two models:

class ContactGroup(models.Model):
    name = models.CharField(max_length=40)
    class Meta:
        permissions=(('view_group_contacts', 'View contacts from group'))


class Contact(models.Model):
    name = models.CharField(max_length=40)
    group = models.ForeignKey(ContactGroup)
    class Meta:
        permissions=(('view_contact', 'View contact'))        

How can I make django guardian consider ContactGroup permissions when I'm for example doing `get_objects_for_user(User, 'appname.view_contact) but still retain option for changing permission on individual Contact?(not for excluding, only to give permission to view single contact when user don't have the permission for whole group)

Lord_JABA
  • 2,545
  • 7
  • 31
  • 58
  • First idea was to override `has_perm` method to check `obj.contactgroup.has_perm` permissions if super has_perm returned false. But then I noticed that `get_objects_for_user` is not using has_perm so I would need to override it to - and probably all other guardian shortcuts functions. Second idea was to create custom `model.Manager` but I don't have access to request in Manager so it won't work. Now I'm thinking about automatically creating group for every contactGroup and storing permissions there but this may be nightmare to maintain. Maybe I should use different permission system? – Lord_JABA May 19 '14 at 11:16

2 Answers2

1

Sorry, such behaviour is not supported by django-guardian. As for has_perm - it would be extremely inefficient to use it for querysets as we would need to perform >=1 query for each row in a table.

You could however perform get_objects_for_user firstly for ContactGroup, then for Contact and extend last queryset with results from the first one. Something like:

contact_groups = get_objects_for_user(user, 'appname.view_group_contacts', ContactGroup)
contacts = get_objects_for_user(user, 'appname.view_contact', Contact)

There is still problem of merging those but well, it's possible.

lukaszb
  • 694
  • 1
  • 6
  • 15
1

Very ugly workaround, it does not take for account changes in individual objects (it resets all permission to ContactGroup permissions if remove= False). But It can be rewritten to preserve changes if needed. I plan to attach it to "Sync Permissions with group" button so it will be fired only at user request. Main pro is its working with get_objects_for_user as intended.

def syncPerms(source, remove=False):
if not isinstance(source, ContactGroup):
    return False

contacts= source.client_set.all()
user_perms=get_users_with_perms(source, attach_perms=True)
for contact in contacts:
    for user, perm in user_perms.iteritems():
        if u'view_group_contacts' in perm:
            assign_perm('view_contact', user,client)
        else:
            if remove:
                remove_perm('view_contact', user, client)
Lord_JABA
  • 2,545
  • 7
  • 31
  • 58