Skip to content

Instantly share code, notes, and snippets.

@3noch
Last active November 25, 2015 19:10
Show Gist options
  • Select an option

  • Save 3noch/4ea50639f0806954bf82 to your computer and use it in GitHub Desktop.

Select an option

Save 3noch/4ea50639f0806954bf82 to your computer and use it in GitHub Desktop.
permissions.py
import sqlalchemy as sa
import sqlalchemy.orm as saorm
from keg.db import db
permission_child_map = db.Table(
'permission_child_map',
sa.Column(
'permission_id',
sa.Integer(),
sa.ForeignKey('permissions.id', ondelete='CASCADE'),
nullable=False,
primary_key=True),
sa.Column(
'child_permission_id',
sa.Integer(),
sa.ForeignKey('permissions.id', ondelete='CASCADE'),
nullable=False,
primary_key=True),
)
class Permission(db.Model):
__tablename__ = 'permissions'
id = sa.Column(sa.Integer(), primary_key=True)
token = sa.Column(sa.String(), unique=True)
description = sa.Column(sa.Unicode(), nullable=False)
namespace = sa.Column(sa.Enum('bundle', 'user-group', name='permission_namespace'))
children = saorm.relationship(
lambda: Permission,
secondary=permission_child_map,
primaryjoin=id == permission_child_map.c.permission_id,
secondaryjoin=id == permission_child_map.c.child_permission_id,
backref='parents')
def get_transitive_closure(self):
return get_transitive_closure({self})
def get_transitive_closure(parents, seen=frozenset()):
"""Calculate the transitive closure for a set of permissions.
:param perms: must be a set of Permission objects.
"""
seen = seen | parents # We've seen this set of parents.
children = frozenset(Permission.query.join(
permission_child_map,
Permission.id == permission_child_map.c.child_permission_id
).filter(
permission_child_map.c.permission_id.in_([perm.id for perm in parents])
).all())
remaining_parents = children - seen # Handle circular references by filtering out seen parents.
return get_transitive_closure(remaining_parents, seen) if remaining_parents else seen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment