summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2012-04-16 07:51:37 (GMT)
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2012-04-16 07:51:37 (GMT)
commitcc17d0a6d40bbf8db7ca85497333aae080f7738c (patch)
tree1e9be276e53a3314dc463b711f33201c0dfd01a9
parent2610c6a0cbd3f31387eb50756be259c0da9014e7 (diff)
downloaddjango-directory-master.zip
django-directory-master.tar.gz
django-directory-master.tar.bz2
First usable version..HEADmaster
The object model supports schema, views (aggregation of attributes for view/edition purpose), attributes and relations. The addition of relation make it a bit more powerful than the classical LDAP object model. To map an LDAP schema, you can use oid URN for attribute names.
-rw-r--r--.gitignore3
-rw-r--r--README.rst4
-rw-r--r--django_directory/admin.py44
-rw-r--r--django_directory/models.py40
-rw-r--r--django_directory/signals.py1
5 files changed, 76 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0356801
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+dd_example
+*.pyc
+local.db
diff --git a/README.rst b/README.rst
index bb714a5..c7aaca9 100644
--- a/README.rst
+++ b/README.rst
@@ -35,3 +35,7 @@ using any attribute with any instance at the database level but schema can be
used to constrain user interface when editing or creating an instance.
Django directory is especially adapted for identity management solutions.
+
+It should be simple to create connector allowing to synchronize a django
+directory and an external directory or to provide a virtual view of an external
+directory.
diff --git a/django_directory/admin.py b/django_directory/admin.py
index 6612c34..f037bd6 100644
--- a/django_directory/admin.py
+++ b/django_directory/admin.py
@@ -1,11 +1,34 @@
from django.contrib.admin import AdminSite, ModelAdmin, site, TabularInline
-from django.db import models
+from django.utils.translation import gettext_lazy as _
from .schema import get_schemas, schemas_update_subscribe
-from models import (Schema, View, ViewMember, Attribute, Principal,
+from .models import (Schema, View, ViewMember, Attribute, Principal,
Predicate, Relation, AttributeValue, PrincipalUser)
+class AttributeValueInlineAdmin(TabularInline):
+ model = AttributeValue
+
+class ChildRelationsInlineAdmin(TabularInline):
+ model = Relation
+ fk_name = 'object'
+ verbose_name_plural = _('Child relations')
+
+class ParentRelationsInlineAdmin(TabularInline):
+ model = Relation
+ fk_name = 'value'
+ verbose_name_plural = _('Parent relations')
+
+class PrincipalModelAdmin(ModelAdmin):
+ inlines = [ AttributeValueInlineAdmin, ChildRelationsInlineAdmin,
+ ParentRelationsInlineAdmin ]
+
+class ViewMemberInlineAdmin(TabularInline):
+ model = ViewMember
+
+class ViewModelAdmin(ModelAdmin):
+ inlines = [ ViewMemberInlineAdmin]
+
class DirectoryAdmin(AdminSite):
def __init__(self, *args, **kwargs):
super(DirectoryAdmin, self).__init__(*args, **kwargs)
@@ -40,7 +63,7 @@ class DirectoryAdmin(AdminSite):
qs = qs.filter(schema=schema)
qs.prefetch_related('attributes', 'child_relations', 'parent_relations')
return qs
- model_admin = type(model_admin_name, (ModelAdmin,), dict(queryset=queryset))
+ model_admin = type(model_admin_name, (PrincipalModelAdmin,), dict(queryset=queryset))
return model_admin
def regenerate_proxy_models(self):
@@ -73,21 +96,10 @@ class DirectoryAdmin(AdminSite):
site = DirectoryAdmin()
-class AttributeValueInlineAdmin(TabularInline):
- model = AttributeValue
-
-class PrincipalModelAdmin(ModelAdmin):
- inlines = [ AttributeValueInlineAdmin ]
-class ViewMemberInlineAdmin(TabularInline):
- model = ViewMember
-
-class ViewModelAdmin(ModelAdmin):
- inlines = [ ViewMemberInlineAdmin]
+site.register(Principal, PrincipalModelAdmin)
+site.register(View, ViewModelAdmin)
for model in (Schema, Attribute, Predicate, Relation,
AttributeValue, PrincipalUser):
site.register(model)
-
-site.register(Principal, PrincipalModelAdmin)
-site.register(View, ViewModelAdmin)
diff --git a/django_directory/models.py b/django_directory/models.py
index 595c645..3db31f6 100644
--- a/django_directory/models.py
+++ b/django_directory/models.py
@@ -276,16 +276,55 @@ class DirectoryUser(User):
class Predicate(models.Model):
name = models.CharField(max_length=128, unique=True)
display_name = models.CharField(max_length=256)
+ symmetric = models.BooleanField(blank=True)
+ transitive = models.BooleanField(blank=True)
def __unicode__(self):
return self.display_name or self.name
+class RelationManager(models.Manager):
+ def closure(self, filter_field=None, filter_value=None, predicate=None,
+ field=None, seen=None):
+ '''Compute transitive closure of relations'''
+ kwargs = { filter_field: filter_value }
+ qs = self.filter(predicate=predicate, **kwargs).values_list(field, flat=True)
+ traverse = set(qs) - seen
+ seen |= traverse
+ if predicate.transitive:
+ for value in traverse:
+ self.closure(filter_field=filter_field, filter_value=value, predicate=predicate,
+ field=field, seen=seen)
+ return seen
+
+ def values1(self, instance, predicate):
+ return self.closure(filter_field='object', filter_value=instance,
+ predicate=predicate, field='value', seen=set())
+
+ def objects1(self, instance, predicate):
+ return self.closure(filter_field='value', filter_value=instance,
+ predicate=predicate, field='object', seen=set())
+
+ def values(self, instance, predicate):
+ seen = self.values1(instance, predicate)
+ if predicate.symmetric:
+ seen |= self.objects1(instance, predicate)
+ return seen
+
+ def objects(self, instance, predicate):
+ seen = self.objects1(instance, predicate)
+ if predicate.symmetric:
+ seen |= self.values1(instance, predicate)
+ return seen
+
class Relation(models.Model):
'''State a relation between two principals'''
object = models.ForeignKey(Principal, related_name='child_relations')
predicate = models.ForeignKey(Predicate, related_name='relations')
value = models.ForeignKey(Principal, related_name='parent_relations')
+ class Meta:
+ unique_together = (('object', 'predicate', 'value'),)
+
def update_schema(sender, **kwargs):
from . import schema
print 'update schema', kwargs
@@ -297,3 +336,4 @@ for model in (Schema, View, ViewMember, Attribute, Predicate, Relation):
post_delete.connect(update_schema, sender=model,
dispatch_uid='schema-rebuild')
+import signals
diff --git a/django_directory/signals.py b/django_directory/signals.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/django_directory/signals.py
@@ -0,0 +1 @@
+