accounts - add user models
authorBrice Gelineau <brice.gelineau@m4x.org>
Sat, 2 Feb 2013 14:02:42 +0000 (15:02 +0100)
committerBrice Gelineau <brice.gelineau@m4x.org>
Sat, 2 Feb 2013 14:09:00 +0000 (15:09 +0100)
Makefile
requirements.txt
xnet/accounts/__init__.py [moved from xnet/group/__init__.py with 100% similarity]
xnet/accounts/admin.py [new file with mode: 0644]
xnet/accounts/factories.py [new file with mode: 0644]
xnet/accounts/models.py [new file with mode: 0644]
xnet/accounts/tests.py [new file with mode: 0644]
xnet/group/admin.py [deleted file]
xnet/group/factories.py [deleted file]
xnet/group/models.py [deleted file]
xnet/settings.py

index f16d22d..1753aa2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ shell:
        $(MANAGE_PY) shell
 
 test:
-       $(MANAGE_PY) test example
+       $(MANAGE_PY) test example accounts site
 
 resetdb:
        rm -f xnet/db.sqlite
index f93c72c..e7a7ee3 100644 (file)
@@ -1,2 +1,3 @@
 https://www.djangoproject.com/download/1.5c1/tarball/
 django_authgroupex
+django-xworkflows
diff --git a/xnet/accounts/admin.py b/xnet/accounts/admin.py
new file mode 100644 (file)
index 0000000..3023220
--- /dev/null
@@ -0,0 +1,28 @@
+from django.contrib import admin
+from django.contrib.auth import admin as auth_admin
+
+from . import models
+
+
+class XGroupAdmin(admin.ModelAdmin):
+    list_display = ['short', 'name', 'kind', 'domain', 'dns']
+    list_filter = ['kind', 'domain']
+    search_fields = ['name', 'short', 'dns']
+
+admin.site.register(models.XGroup, XGroupAdmin)
+
+
+class AccountAdmin(auth_admin.UserAdmin):
+    pass
+
+admin.site.register(models.Account, AccountAdmin)
+
+
+class MembershipAdmin(admin.ModelAdmin):
+    list_display = ['xuser', 'xgroup', 'level']
+    list_filter = ['level']
+    search_fields = (
+        ['xgroup__{0}'.format(field) for field in XGroupAdmin.search_fields]
+        + ['offer__{0}'.format(field) for field in AccountAdmin.search_fields])
+
+admin.site.register(models.Membership, MembershipAdmin)
diff --git a/xnet/accounts/factories.py b/xnet/accounts/factories.py
new file mode 100644 (file)
index 0000000..4cb8b00
--- /dev/null
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+import factory
+
+from . import models
+
+
+class XGroupFactory(factory.DjangoModelFactory):
+    FACTORY_FOR = models.XGroup
+
+    name = factory.Sequence(lambda n: u"Groupe n°%s" % n)
+    short = factory.Sequence(lambda n: u"Groupe%s" % n)
+    kind = models.XGroup.KIND_GROUP
+    domain = models.XGroup.DOMAIN_REGION
+
+
+class AccountFactory(factory.DjangoModelFactory):
+    FACTORY_FOR = models.Account
+
+    username = factory.Sequence('mr_robinson{0}'.format)
+    first_name = u"John"
+    last_name = factory.Sequence(lambda n: u"D%se" % ((n % 10) * u"o"), type=int)
+    password = None
+    is_staff = True
+
+    @classmethod
+    def _prepare(cls, create, **kwargs):
+        password = kwargs.pop('password', None)
+        user = super(AccountFactory, cls)._prepare(create, **kwargs)
+        if password is not None:
+            user.set_password(password)
+        if create:
+            user.save()
+        return user
+
+
+class SuperAccountFactory(AccountFactory):
+    is_superuser = True
+
+
+class MembershipFactory(factory.DjangoModelFactory):
+    FACTORY_FOR = models.Membership
+
+    xgroup = factory.SubFactory(XGroupFactory)
+    xuser = factory.SubFactory(AccountFactory)
+    state = models.MembershipWorkflow.states.enabled
diff --git a/xnet/accounts/models.py b/xnet/accounts/models.py
new file mode 100644 (file)
index 0000000..e4f83ab
--- /dev/null
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+
+from django.contrib.auth import models as auth_models
+from django.db import models
+
+from django_xworkflows import models as xwf_models
+
+
+class MembershipWorkflow(xwf_models.Workflow):
+    states = (
+        ('pending', u"En attente"),
+        ('enabled', u"Actif"),
+        ('removed', u"Supprimé"),
+    )
+    transitions = (
+        ('accept', ['pending'], 'enabled'),
+        ('remove', ['pending', 'enabled'], 'removed'),
+    )
+    initial_state = 'pending'
+
+    log_model = ''  # We don't want logs
+
+
+class XGroup(models.Model):
+    """A model for an XGroup."""
+    KIND_PROMO = 'promo'
+    KIND_GROUP = 'group'
+    KIND_BINET = 'binet'
+    KIND_INSTIT = 'instit'
+
+    KIND_CHOICES = (
+        (KIND_PROMO, u"Promo"),
+        (KIND_GROUP, u"Groupe"),
+        (KIND_BINET, u"Binet"),
+        (KIND_INSTIT, u"Institution"),
+    )
+
+    DOMAIN_HISTORY = 'history'
+    DOMAIN_INTERNATIONAL = 'international'
+    DOMAIN_EVENTS = 'events'
+    DOMAIN_LEISURE = 'leisure'
+    DOMAIN_SPORTS = 'sports'
+    DOMAIN_PRO = 'pro'
+    DOMAIN_REGION = 'region'
+
+    DOMAIN_CHOICES = (
+        (DOMAIN_HISTORY, u"Histoire"),
+        (DOMAIN_INTERNATIONAL, u"International"),
+        (DOMAIN_EVENTS, u"Événements"),
+        (DOMAIN_LEISURE, u"Loisirs"),
+        (DOMAIN_SPORTS, u"Sports"),
+        (DOMAIN_PRO, u"Pro"),
+        (DOMAIN_REGION, u"Région"),
+    )
+
+    name = models.CharField(max_length=100, verbose_name=u"nom", unique=True)
+    short = models.SlugField(max_length=10, verbose_name=u"nom court", unique=True)
+    kind = models.CharField(max_length=10, choices=KIND_CHOICES, verbose_name=u"type")
+    domain = models.CharField(max_length=20, choices=DOMAIN_CHOICES, verbose_name=u"domaine")
+
+    dns = models.CharField(max_length=128, verbose_name=u"dns domain", blank=True)
+
+    class Meta:
+        verbose_name = u"group"
+        verbose_name_plural = u"groups"
+
+
+class Account(auth_models.AbstractUser):
+    xgroups = models.ManyToManyField(
+        XGroup, related_name='users', through='Membership', verbose_name=u"groupes")
+
+
+class Membership(xwf_models.WorkflowEnabled, models.Model):
+    LEVEL_MEMBER = 0
+    LEVEL_ADMIN = 10
+    LEVEL_CHOICES = (
+        (LEVEL_MEMBER, u"membre"),
+        (LEVEL_ADMIN, u"administrateur"),
+    )
+
+    xgroup = models.ForeignKey(XGroup, related_name='memberships', verbose_name=u"groupe")
+    xuser = models.ForeignKey(Account, related_name='memberships', verbose_name=u"utilisateur")
+
+    level = models.IntegerField(choices=LEVEL_CHOICES, default=LEVEL_MEMBER, verbose_name=u"droits")
+    state = xwf_models.StateField(MembershipWorkflow, verbose_name=u"état")
diff --git a/xnet/accounts/tests.py b/xnet/accounts/tests.py
new file mode 100644 (file)
index 0000000..5a3a491
--- /dev/null
@@ -0,0 +1,11 @@
+
+from django import test
+
+from . import admin  # pylint: disable=W0611
+from . import factories
+
+
+class SimpleTest(test.TestCase):
+
+    def test_factories(self):
+        factories.MembershipFactory()
diff --git a/xnet/group/admin.py b/xnet/group/admin.py
deleted file mode 100644 (file)
index 1ac2240..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from django.contrib import admin
-
-from . import models
-
-
-class GroupAdmin(admin.ModelAdmin):
-    list_display = ['short', 'name', 'kind', 'domain', 'dns']
-    list_filter = ['kind', 'domain']
-    search_fields = ['name', 'short', 'dns']
-
-admin.site.register(models.Group, GroupAdmin)
diff --git a/xnet/group/factories.py b/xnet/group/factories.py
deleted file mode 100644 (file)
index 6ce1657..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import factory
-
-from . import models
-
-
-class GroupFactory(factory.DjangoModelFactory):
-    FACTORY_FOR = models.Group
-
-    name = factory.Sequence(lambda n: u"Groupe n°%s" % n)
-    short = factory.Sequence(lambda n: u"Groupe%s" % n)
-    kind = models.Group.KIND_GROUP
-    domain = models.Group.DOMAIN_REGION
-
diff --git a/xnet/group/models.py b/xnet/group/models.py
deleted file mode 100644 (file)
index a2c273d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-from django.db import models
-from django.utils.translation import ugettext_lazy as _
-
-
-class Group(models.Model):
-    KIND_PROMO = 'promo'
-    KIND_GROUP = 'group'
-    KIND_BINET = 'binet'
-    KIND_INSTIT = 'instit'
-
-    KIND_CHOICES = (
-        (KIND_PROMO, _(u"Promo")),
-        (KIND_GROUP, _(u"Group")),
-        (KIND_BINET, _(u"Binet")),
-        (KIND_INSTIT, _(u"Institution")),
-    )
-
-    DOMAIN_HISTORY = 'history'
-    DOMAIN_INTERNATIONAL = 'international'
-    DOMAIN_EVENTS = 'events'
-    DOMAIN_LEISURE = 'leisure'
-    DOMAIN_SPORTS = 'sports'
-    DOMAIN_PRO = 'pro'
-    DOMAIN_REGION = 'region'
-
-    DOMAIN_CHOICES = (
-        (DOMAIN_HISTORY, _(u"History")),
-        (DOMAIN_INTERNATIONAL, _(u"International")),
-        (DOMAIN_EVENTS, _(u"Events")),
-        (DOMAIN_LEISURE, _(u"Leisure")),
-        (DOMAIN_SPORTS, _(u"Sports")),
-        (DOMAIN_PRO, _(u"Pro")),
-        (DOMAIN_REGION, _(u"Region")),
-    )
-
-    name = models.CharField(max_length=100, verbose_name=_(u"name"), unique=True)
-    short = models.SlugField(max_length=10, verbose_name=_(u"short name"), unique=True)
-    kind = models.CharField(max_length=10, choices=KIND_CHOICES, verbose_name=_(u"kind"))
-    domain = models.CharField(max_length=20, choices=DOMAIN_CHOICES, verbose_name=_(u"domain"))
-
-    dns = models.CharField(max_length=128, verbose_name=_(u"dns domain"), blank=True)
-
-    class Meta:
-        verbose_name = _(u"group")
-        verbose_name_plural = _(u"groups")
-
-    def __unicode__(self):
-        return self.name
index 0d0fccc..cc5b9b8 100644 (file)
@@ -30,9 +30,12 @@ AUTHENTICATION_BACKENDS = (
 AUTHGROUPEX_KEY = read_pass('authgroupex.key')
 AUTHGROUPEX_FIELDS = ('username', 'firstname', 'lastname', 'perms')
 AUTHGROUPEX_SUPERADMIN_PERMS = ('admin',)
+AUTHGROUPEX_USER_MODEL = 'accounts.Account'
 LOGIN_URL = '/xorgauth/'
 LOGIN_REDIRECT_URL = '/'
 
+AUTH_USER_MODEL = 'accounts.Account'
+
 # Local time zone for this installation. Choices can be found here:
 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
 # although not all choices may be available on all operating systems.
@@ -138,7 +141,7 @@ INSTALLED_APPS = (
 
     'django_authgroupex',
     'xnet.site',
-    'xnet.group',
+    'xnet.accounts',
     'xnet.example',
 )