First usable version..
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.
This commit is contained in:
parent
2610c6a0cb
commit
cc17d0a6d4
|
@ -0,0 +1,3 @@
|
|||
dd_example
|
||||
*.pyc
|
||||
local.db
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
Reference in New Issue