Add ACL filter support for case 6

Support inherited field of a related field that is Generic
Foreign Key.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-08-19 23:16:09 -04:00
parent 4dd270e75b
commit 0917bd57b3
2 changed files with 39 additions and 21 deletions

View File

@@ -21,22 +21,6 @@ class ModelPermission(object):
# TODO: Find method to revert the add_to_class('acls'...)
# delattr doesn't work.
@classmethod
def register(cls, model, permissions):
from django.contrib.contenttypes.fields import GenericRelation
cls._registry.setdefault(model, [])
for permission in permissions:
cls._registry[model].append(permission)
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
model.add_to_class(
name='acls', value=GenericRelation(AccessControlList)
)
@classmethod
def get_classes(cls, as_content_type=False):
ContentType = apps.get_model(
@@ -116,6 +100,22 @@ class ModelPermission(object):
def get_manager_name(cls, model):
return cls._manager_names[model]
@classmethod
def register(cls, model, permissions):
from django.contrib.contenttypes.fields import GenericRelation
cls._registry.setdefault(model, [])
for permission in permissions:
cls._registry[model].append(permission)
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
model.add_to_class(
name='acls', value=GenericRelation(AccessControlList)
)
@classmethod
def register_function(cls, model, function):
cls._functions[model] = function

View File

@@ -45,8 +45,8 @@ class AccessControlListManager(models.Manager):
# 4: No related field, but has an inherited related field, solved by
# recursion, branches to #2 or #3.
# 5: Inherited field of a related field
# -- Not addressed yet --
# 6: Inherited field of a related field that is Generic Foreign Key
# -- Not addressed yet --
# 7: Has a related function
result = []
@@ -58,10 +58,28 @@ class AccessControlListManager(models.Manager):
if isinstance(related_field, GenericForeignKey):
# Case 3: Generic Foreign Key, multiple ContentTypes + object
# id combinations
# Also handles case #6 using the parent related field
# reference template.
# Craft a double underscore reference to a previous related
# field in the case where multiple related fields are
# associated.
# Example: object_layer__content_type
recuisive_related_reference = '__'.join(related_field_name.split('__')[0:-1])
# If there is at least one parent related field we add a
# double underscore to make it a valid filter template.
if recuisive_related_reference:
recuisive_related_reference = '{}__'.format(recuisive_related_reference)
content_type_object_id_queryset = queryset.annotate(
ct_fk_combination=Concat(
related_field.ct_field, Value('-'),
related_field.fk_field, output_field=CharField()
'{}{}'.format(
recuisive_related_reference, related_field.ct_field
), Value('-'),
'{}{}'.format(
recuisive_related_reference, related_field.fk_field
), output_field=CharField()
)
).values('ct_fk_combination')
@@ -75,8 +93,7 @@ class AccessControlListManager(models.Manager):
ct_fk_combination__in=content_type_object_id_queryset
).values('object_id')
field_lookup = 'object_id__in'
field_lookup = '{}object_id__in'.format(recuisive_related_reference)
result.append(Q(**{field_lookup: acl_filter}))
else:
# Case 2: Related field of a single type, single ContentType,
@@ -97,6 +114,7 @@ class AccessControlListManager(models.Manager):
# Case 5: Related field, has an inherited related field itself
# Bubble up permssion check
# Recurse and reduce
# TODO: Add relationship support: OR or AND
# TODO: OR for document pages, version, doc, and types
# TODO: AND for new cabinet levels ACLs