Skip to content

Commit

Permalink
Added thru table for TrustGroup to allow for additional relation attr…
Browse files Browse the repository at this point in the history
…ibute. Fixed bug in Trust.get_or_create_settlor_default(). Improved Trust.__str__.
  • Loading branch information
thomasyip committed Oct 12, 2016
1 parent 49d06f4 commit db80543
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 23 deletions.
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#### 0.11.0

~Backward Incompatible~ ManyToMany relationship between Trust and Group is now related with a through table (ie, trusts.TrustGroup)

~Backward Incompatible~ Method `Trust.filter_by_user_perm()` is renamed to `Trust.filter_by_user_content_perm()`.

#### 0.10.3

CHANGES.md is initially added.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

setup(
name='django-trusts',
version='0.10.3',
version='0.11.0',
description='Django authorization add-on for multiple organizations and object-level permission settings',
author='Thomas Yip',
author_email='[email protected]',
Expand Down
12 changes: 12 additions & 0 deletions trusts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class Migration(migrations.Migration):
},
bases=(trusts.models.ReadonlyFieldsMixin, models.Model),
),
migrations.CreateModel(
name='TrustGroup',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('group', models.ForeignKey(related_name='trustgroups', to=GROUP_MODEL_NAME)),
('trust', models.ForeignKey(related_name='trustgroups', to='trusts.Trust')),
],
),
migrations.CreateModel(
name='TrustUserPermission',
fields=[
Expand Down Expand Up @@ -73,6 +81,10 @@ class Migration(migrations.Migration):
name='trust',
unique_together=set([('settlor', 'title')]),
),
migrations.AlterUniqueTogether(
name='trustgroup',
unique_together=set([('trust', 'group')]),
),
migrations.AlterUniqueTogether(
name='rolepermission',
unique_together=set([('role', 'permission')]),
Expand Down
57 changes: 43 additions & 14 deletions trusts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
)

class TrustManager(models.Manager):
def get_or_create_settlor_default(self, settlor, defaults={}, **kwargs):
def get_or_create_settlor_default(self, settlor, defaults=None, **kwargs):
if 'trust' in kwargs:
raise TypeError('"%s" are invalid keyword arguments' % 'trust')
if settlor is None:
Expand All @@ -28,22 +28,21 @@ def get_or_create_settlor_default(self, settlor, defaults={}, **kwargs):
# @TODO -- Handle anonymous settings
raise ValueError('Anonymous is not yet supported.')

if defaults is None:
defaults = {}

title = settlor.username if 'username' in dir(settlor) else ''
try:
return self.get(settlor=settlor, title='', **kwargs), False
return self.get(settlor=settlor, title=title, **kwargs), False
except Trust.DoesNotExist:
params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({'title': title})
params.update(defaults)
params.update({'title': '', 'trust_id': ROOT_PK, 'settlor': settlor})
params.update({'settlor': settlor})
trust = self.model(**params)
trust.save()
return trust, True

'''
@TODO -- Implement me. It is a dummy method. Need a real implemtation
'''
def get_or_create_content_default(self, settlor, content, defaults={}, **kwargs):
return self.get_or_create_settlor_default(settlor, defaults={}, **kwargs)

def get_root(self):
return self.get(pk=ROOT_PK)

Expand All @@ -69,11 +68,29 @@ def filter_by_content(self, obj):

return self.none()

def filter_by_user_perm(self, user, **kwargs):
def filter_by_user_content_perm(self, user, content, perm_name, exclude_root=True, **kwargs):
if 'group__user' in kwargs:
raise TypeError('"%s" are invalid keyword arguments' % 'group__user')

return self.filter(Q(groups__user=user) | Q(trustees__entity=user), **kwargs)
if Content.is_content_model(content):
fieldlookup = Content.get_content_fieldlookup(content)
if fieldlookup is None:
fieldlookup = '%s_content' % utils.get_short_model_name_lower(content).replace('.', '_')

permission = content.objects.get_permission(perm_name)

qs = self.filter(
Q(trust__trustees__entity=user, trust__trustees__permission=permission) |
Q(trust__groups__user=user, trust__groups__permissions=permission) |
Q(trust__settlor=user)
)

if exclude_root and ROOT_PK is not None:
qs = qs.exclude(id=ROOT_PK)

return qs.distinct()

return self.none()


class ReadonlyFieldsMixin(object):
Expand Down Expand Up @@ -200,6 +217,7 @@ class Trust(Content):
title = models.CharField(max_length=40, null=False, blank=False, verbose_name=_('title'))
settlor = models.ForeignKey(ENTITY_MODEL_NAME, default=DEFAULT_SETTLOR, null=ALLOW_NULL_SETTLOR, blank=False)
groups = models.ManyToManyField(GROUP_MODEL_NAME, related_name='trusts',
through='trusts.TrustGroup',
verbose_name=_('groups'),
help_text=_('The groups this trust grants permissions to. A user will'
'get all permissions granted to each of his/her group.'),
Expand All @@ -211,14 +229,25 @@ class Trust(Content):
class Meta:
unique_together = ('settlor', 'title')
default_permissions = ('add', 'change', 'delete', 'read',)
permission_conditions = (('own', lambda u, p, o: u == o.settlor), )
permission_conditions = (('own', lambda u, p, o: u == o.settlor),)

def __str__(self):
settlor_str = ' of %s' % str(self.settlor) if self.settlor is not None else ''
return 'Trust[%s]: "%s"' % (self.id, self.title)
settlor_str = self.title

if settlor_str is not None:
str(self.settlor)
return settlor_str
Content.register_content(Trust)


class TrustGroup(models.Model):
trust = models.ForeignKey('trusts.Trust', related_name='trustgroups', null=False, blank=False)
group = models.ForeignKey(GROUP_MODEL_NAME, related_name='trustgroups', null=False, blank=False)

class Meta:
unique_together = ('trust', 'group')


class Role(models.Model):
name = models.CharField(max_length=80, null=False, blank=False, unique=True,
help_text=_('The name of the role. Corresponds to the key of model\'s trusts option.'))
Expand Down
16 changes: 8 additions & 8 deletions trusts/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from trusts.backends import TrustModelBackend
from trusts.decorators import G, K, O, P, permission_required
from trusts.models import (Content, Junction, Role, RolePermission,
Trust, TrustManager, TrustUserPermission)
Trust, TrustGroup, TrustManager, TrustUserPermission)


def create_test_users(test):
Expand Down Expand Up @@ -105,7 +105,7 @@ def test_read_permissions_added(self):
codename='%s_%s' % ('read', ct.model)
))

def test_filter_by_user_perm(self):
def filter_by_user_content_perm(self):
self.trust1, created = Trust.objects.get_or_create_settlor_default(self.user)

self.trust2 = Trust(settlor=self.user, title='Title 0A', trust=Trust.objects.get_root())
Expand All @@ -127,12 +127,12 @@ def test_filter_by_user_perm(self):
self.group.save()
self.user.groups.add(self.group)

self.trust5.groups.add(self.group)
TrustGroup(trust=self.trust5, group=self.group).save()

self.trust6 = Trust(settlor=self.user1, title='Title 1C', trust=Trust.objects.get_root())
self.trust6.save()

trusts = Trust.objects.filter_by_user_perm(self.user)
trusts = Trust.objects.filter_by_user_content_perm(self.user)
trust_pks = [t.pk for t in trusts]
self.assertEqual(trusts.count(), 3)
self.assertTrue(self.trust2.id in trust_pks)
Expand Down Expand Up @@ -536,7 +536,7 @@ def test_user_in_group_has_perm(self):

reload_test_users(self)

self.trust.groups.add(self.group)
TrustGroup(trust=self.trust, group=self.group).save()

had = self.user.has_perm(self.get_perm_code(self.perm_change), self.content)
self.assertTrue(had)
Expand Down Expand Up @@ -665,7 +665,7 @@ def test_has_perm(self):
self.assertFalse(self.user.has_perm(self.get_perm_code(self.perm_read)))

self.group.user_set.add(self.user)
self.trust.groups.add(self.group)
TrustGroup(trust=self.trust, group=self.group).save()
Role.objects.get(name='public').groups.add(self.group)

self.assertTrue(self.user.has_perm(self.get_perm_code(self.perm_read), self.content1))
Expand All @@ -689,7 +689,7 @@ def test_has_perm_diff_roles_on_contents(self):
self.assertTrue(self.user.has_perm(self.get_perm_code(self.perm_read), self.content1))
self.assertFalse(self.user.has_perm(self.get_perm_code(self.perm_change), self.content1))

trust3.groups.add(self.group)
TrustGroup(trust=trust3, group=self.group).save()

reload_test_users(self)
self.assertTrue(self.user.has_perm(self.get_perm_code(self.perm_read), content3))
Expand Down Expand Up @@ -724,7 +724,7 @@ def test_has_perm_diff_group_on_contents(self):
group3 = Group(name='write group')
group3.save()
Role.objects.get(name='write').groups.add(group3)
self.trust.groups.add(group3)
TrustGroup(trust=self.trust, group=group3).save()

reload_test_users(self)
self.assertTrue(self.user.has_perm(self.get_perm_code(self.perm_read), self.content1))
Expand Down

0 comments on commit db80543

Please sign in to comment.