From 23600016d286ce1cdeef7123f2a8a36e32f4855b Mon Sep 17 00:00:00 2001
From: Őry Máté <ory.mate@cloud.bme.hu>
Date: Mon, 14 Oct 2013 22:38:43 +0200
Subject: [PATCH] acl: add models

---
 circle/acl/models.py | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 122 insertions(+), 2 deletions(-)

diff --git a/circle/acl/models.py b/circle/acl/models.py
index 71a8362..fd27f7f 100644
--- a/circle/acl/models.py
+++ b/circle/acl/models.py
@@ -1,3 +1,123 @@
-from django.db import models
+from django.contrib.auth.models import User, Group
+from django.contrib.contenttypes.generic import (
+    GenericForeignKey, GenericRelation
+)
+from django.contrib.contenttypes.models import ContentType
+from django.db.models import (
+    ManyToManyField, ForeignKey, CharField, Model, IntegerField
+)
 
-# Create your models here.
+
+class Level(Model):
+
+    """Definition of a permission level.
+
+    Instances are automatically populated based on AclBase.."""
+    name = CharField('name', max_length=50)
+    content_type = ForeignKey(ContentType)
+    codename = CharField('codename', max_length=100)
+    weight = IntegerField('weight', null=True)
+
+    class Meta:
+        unique_together = (('content_type', 'codename'),
+                           # ('content_type', 'weight'),
+                           # TODO find a way of temp. disabling this constr.
+                           )
+
+
+class ObjectLevel(Model):
+
+    """Permission level for a specific object."""
+    level = ForeignKey(Level)
+    content_type = ForeignKey(ContentType)
+    object_id = CharField(max_length=255)
+    content_object = GenericForeignKey()
+    users = ManyToManyField(User)
+    groups = ManyToManyField(Group)
+
+    class Meta:
+        unique_together = (('content_type', 'object_id', 'level'),)
+
+
+class AclBase(Model):
+
+    """Define permission levels for Users/Groups per object."""
+    object_level_set = GenericRelation(ObjectLevel)
+
+    def get_level_object(self, level):
+        ct = ContentType.objects.get_for_model(self)
+        return Level.objects.get(codename=level, content_type=ct)
+
+    def set_level(self, whom, level):
+        if isinstance(whom, User):
+            self.set_user_level(whom, level)
+        elif isinstance(whom, Group):
+            self.set_group_level(whom, level)
+        else:
+            raise AttributeError("Whom must be a User or Group object.")
+
+    def set_user_level(self, user, level):
+        if isinstance(level, basestring):
+            level = self.get_level_object(level)
+        if not self.object_level_set.filter(level_id=level.pk).exists():
+            self.object_level_set.create(level=level)
+        for i in self.object_level_set.all():
+            if i.level_id != level.pk:
+                i.users.remove(user)
+            else:
+                i.users.add(user)
+            i.save()
+
+    def set_group_level(self, group, level):
+        if isinstance(level, basestring):
+            level = self.get_level_object(level)
+        #self.object_level_set.get_or_create(level=level, content_object=self)
+        if not self.object_level_set.filter(level_id=level.pk).exists():
+            self.object_level_set.create(level=level)
+        for i in self.object_level_set.all():
+            if i.level_id != level.pk:
+                i.groups.remove(group)
+            else:
+                i.groups.add(group)
+            i.save()
+
+    def has_level(self, user, level, group_also=True):
+        if isinstance(level, basestring):
+            level = self.get_level_object(level)
+
+        object_levels = self.object_level_set.filter(
+            level__weight__gte=level.weight).all()
+        if group_also:
+            try:
+                groups = user.group_set.values_list('id', flat=True)
+            except AttributeError:
+                pass  # e.g. AnyonymousUser doesn't have group_set
+            else:
+                for i in object_levels:
+                    if i.users.filter(pk=user.pk).exists():
+                        return True
+                    if (group_also and
+                            i.groups.filter(pk__in=groups).exists()):
+                        return True
+        return False
+
+    def get_users_with_level(self):
+        object_levels = (self.object_level_set.select_related(
+            'users', 'level').all())
+        users = []
+        for object_level in object_levels:
+            name = object_level.level.codename
+            users.extend([(u, name) for u in object_level.users.all()])
+        return users
+
+    def get_groups_with_level(self):
+        object_levels = (self.object_level_set.select_related(
+            'groups', 'level').all())
+        groups = []
+        for object_level in object_levels:
+            name = object_level.level.codename
+            groups.extend([(g, name) for g in object_level.groups.all()])
+        return groups
+
+    class Meta:
+        abstract = True
--
libgit2 0.26.0