From 53722fb0210e40eaacb5f80e1d8964b7708cefc5 Mon Sep 17 00:00:00 2001 From: Brice Gelineau Date: Sat, 2 Feb 2013 15:02:42 +0100 Subject: [PATCH] accounts - add user models --- Makefile | 2 +- requirements.txt | 1 + xnet/{group => accounts}/__init__.py | 0 xnet/accounts/admin.py | 28 ++++++++++++ xnet/accounts/factories.py | 46 +++++++++++++++++++ xnet/accounts/models.py | 85 ++++++++++++++++++++++++++++++++++++ xnet/accounts/tests.py | 11 +++++ xnet/group/admin.py | 11 ----- xnet/group/factories.py | 13 ------ xnet/group/models.py | 48 -------------------- xnet/settings.py | 5 ++- 11 files changed, 176 insertions(+), 74 deletions(-) rename xnet/{group => accounts}/__init__.py (100%) create mode 100644 xnet/accounts/admin.py create mode 100644 xnet/accounts/factories.py create mode 100644 xnet/accounts/models.py create mode 100644 xnet/accounts/tests.py delete mode 100644 xnet/group/admin.py delete mode 100644 xnet/group/factories.py delete mode 100644 xnet/group/models.py diff --git a/Makefile b/Makefile index f16d22d..1753aa2 100644 --- 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 diff --git a/requirements.txt b/requirements.txt index f93c72c..e7a7ee3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ https://www.djangoproject.com/download/1.5c1/tarball/ django_authgroupex +django-xworkflows diff --git a/xnet/group/__init__.py b/xnet/accounts/__init__.py similarity index 100% rename from xnet/group/__init__.py rename to xnet/accounts/__init__.py diff --git a/xnet/accounts/admin.py b/xnet/accounts/admin.py new file mode 100644 index 0000000..3023220 --- /dev/null +++ b/xnet/accounts/admin.py @@ -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 index 0000000..4cb8b00 --- /dev/null +++ b/xnet/accounts/factories.py @@ -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 index 0000000..e4f83ab --- /dev/null +++ b/xnet/accounts/models.py @@ -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 index 0000000..5a3a491 --- /dev/null +++ b/xnet/accounts/tests.py @@ -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 index 1ac2240..0000000 --- a/xnet/group/admin.py +++ /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 index 6ce1657..0000000 --- a/xnet/group/factories.py +++ /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 index a2c273d..0000000 --- a/xnet/group/models.py +++ /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 diff --git a/xnet/settings.py b/xnet/settings.py index 0d0fccc..cc5b9b8 100644 --- a/xnet/settings.py +++ b/xnet/settings.py @@ -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', ) -- 2.1.4