Skip to content

Commit

Permalink
wrapped up bitwise AND expressions in function for Postgres compatibi…
Browse files Browse the repository at this point in the history
…lity
  • Loading branch information
m.semenov committed May 13, 2020
1 parent 5ea0eea commit bbb883c
Showing 1 changed file with 56 additions and 18 deletions.
74 changes: 56 additions & 18 deletions protector/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import connection
from protector.query import Query

ADD_PERMISSION_PERMISSION = 'add_permission'
Expand All @@ -25,14 +26,14 @@ def get_permission_owners_query():
Should select perms that assigned to any role
"""
owners_query = """
{group_table_name!s} gug LEFT JOIN
{owner_table_name!s} op ON
gug.group_id = op.owner_object_id AND
gug.group_content_type_id = op.owner_content_type_id AND
gug.roles & op.roles LEFT JOIN
{global_table_name!s} gl ON
gl.content_type_id = gug.group_content_type_id AND
gl.roles & gug.roles
{group_table_name!s} gug
LEFT JOIN {owner_table_name!s} op
ON gug.group_id = op.owner_object_id
AND gug.group_content_type_id = op.owner_content_type_id
AND {gug_op_roles_compare}
LEFT JOIN {global_table_name!s} gl
ON gl.content_type_id = gug.group_content_type_id
AND {gl_gug_roles_compare}
"""
OwnerToPermission = apps.get_model('protector', 'OwnerToPermission')
GenericUserToGroup = apps.get_model('protector', 'GenericUserToGroup')
Expand All @@ -41,31 +42,57 @@ def get_permission_owners_query():
owner_table_name=OwnerToPermission._meta.db_table,
group_table_name=GenericUserToGroup._meta.db_table,
global_table_name=GenericGlobalPerm._meta.db_table,
gug_op_roles_compare=_get_bit_comparision('gug.roles', 'op.roles'),
gl_gug_roles_compare=_get_bit_comparision('gl.roles', 'gug.roles')
)


def _get_filter_by_perm_condition(qset, user_id, perm_id, obj_id_field, ctype_id_field):
# here we brake some rules about sql sanitizing
# it is a shame, but this is an internal function so we can live with it
is_postgres = connection.vendor == 'postgresql'
condition = "EXISTS ("
if ctype_id_field is not None:
condition += """
SELECT gl.id as pid FROM protector_genericusertogroup gug LEFT JOIN protector_genericglobalperm gl ON gl.content_type_id = gug.group_content_type_id AND gl.roles & gug.roles
WHERE gug.user_id = {user_id!s} AND gl.permission_id = {perm_id!s} AND gl.content_type_id = {ctype_id!s} AND gug.group_id = {obj_id!s} )
OR EXISTS (
SELECT op.id as pid
FROM protector_genericusertogroup gug LEFT JOIN protector_ownertopermission op ON gug.group_id = op.owner_object_id AND gug.group_content_type_id = op.owner_content_type_id AND gug.roles & op.roles
WHERE gug.user_id = {user_id!s} AND op.permission_id = {perm_id!s} AND op.content_type_id = {ctype_id!s} AND op.object_id = {obj_id!s} )
OR EXISTS (
SELECT gl.id as pid
FROM protector_genericusertogroup gug
LEFT JOIN protector_genericglobalperm gl
ON gl.content_type_id = gug.group_content_type_id
AND {gl_gug_roles_compare}
WHERE gug.user_id = {user_id!s}
AND gl.permission_id = {perm_id!s}
AND gl.content_type_id = {ctype_id!s}
AND gug.group_id = {obj_id!s} )
OR EXISTS (
SELECT op.id as pid
FROM protector_genericusertogroup gug
LEFT JOIN protector_ownertopermission op
ON gug.group_id = op.owner_object_id
AND gug.group_content_type_id = op.owner_content_type_id
AND {gug_op_roles_compare}
WHERE gug.user_id = {user_id!s}
AND op.permission_id = {perm_id!s}
AND op.content_type_id = {ctype_id!s}
AND op.object_id = {obj_id!s}
) OR EXISTS (
"""
condition += """
SELECT op.id as pid FROM protector_genericusertogroup gug LEFT JOIN protector_ownertopermission op ON gug.group_id = op.owner_object_id AND gug.group_content_type_id = op.owner_content_type_id AND gug.roles & op.roles
SELECT op.id as pid
FROM protector_genericusertogroup gug
LEFT JOIN protector_ownertopermission op
ON gug.group_id = op.owner_object_id
AND gug.group_content_type_id = op.owner_content_type_id
AND {gug_op_roles_compare}
WHERE gug.user_id = {user_id!s} AND op.permission_id = {perm_id!s} AND op.content_type_id IS NULL
)
"""
result = condition.format(
user_id=user_id, perm_id=perm_id,
ctype_id=ctype_id_field, obj_id=obj_id_field,
user_id=user_id,
perm_id=perm_id,
ctype_id=ctype_id_field,
obj_id=obj_id_field,
gl_gug_roles_compare=_get_bit_comparision('gl.roles', 'gug.roles'),
gug_op_roles_compare=_get_bit_comparision('gug.roles', 'op.roles')
)
return result

Expand Down Expand Up @@ -163,3 +190,14 @@ def get_default_group_ctype():

def get_user_ctype():
return ContentType.objects.get_for_model(get_user_model())


def _get_bit_comparision(item1, item2):
"""
Wrapper for postrgres compatibility.
"""
postgres_compability = connection.vendor == 'postgresql'
comparision_query = '{} & {}'.format(item1, item2)
if postgres_compability:
return '({})::boolean'.format(comparision_query)
return comparision_query

0 comments on commit bbb883c

Please sign in to comment.