rm -f xnet/db.sqlite
$(MANAGE_PY) syncdb --noinput
+clean:
+ find . "(" -name "*.pyc" -or -name "*.pyo" -or -name "*.mo" ")" -delete
+ find . -type d -empty -delete
doc:
$(MAKE) -C doc html
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)
admin.site.unregister(auth_admin.Group)
# -*- coding: utf-8 -*-
-from django.contrib.webdesign import lorem_ipsum
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 = factory.InfiniteIterator(k[0] for k in models.XGroup.KIND_CHOICES)
- domain = models.XGroup.DOMAIN_REGION
- web = u"http://google.fr"
- description = factory.LazyAttribute(lambda _: lorem_ipsum.paragraph())
-
-
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
+ password = factory.PostGenerationMethodCall('set_password', '')
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
from xnet.utils.images.fields import ImageWithThumbsField as ImageField
-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, blank=True, verbose_name=u"domaine")
-
- dns = models.CharField(max_length=128, verbose_name=u"dns domain", blank=True)
-
- web = models.CharField(max_length=255, verbose_name=u"website", blank=True)
- #contact = models.ForeignKey('Account')
- description = models.TextField(blank=True)
- logo = ImageField(upload_to='logos', null=True, blank=True)
-
- class Meta:
- verbose_name = u"groupe"
- verbose_name_plural = u"groupes"
-
- def __unicode__(self):
- return self.name
-
-
class Account(auth_models.AbstractUser):
- xgroups = models.ManyToManyField(
- XGroup, related_name='users', through='Membership', verbose_name=u"groupes")
class Meta:
verbose_name = u"utilisateur"
def __unicode__(self):
return self.username
-
-
-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")
-
- class Meta:
- verbose_name = u"adhérent"
- verbose_name_plural = u"adhérents"
- unique_together = ['xgroup', 'xuser']
-
- def __unicode__(self):
- return u"{} {} de {} [{}]".format(self.xuser, self.get_level_display(), self.xgroup, self.state)
from . import BaseSetup
-from xnet.accounts import factories as accounts_factories
-from xnet.accounts import models as accounts_models
+from xnet.groups import factories as groups_factories
+from xnet.groups import models as groups_models
class Setup(BaseSetup):
self.setup_groups()
def setup_groups(self):
- accounts_factories.XGroupFactory(
+ groups_factories.XGroupFactory(
name='Polytechnique.org',
short='xorg',
- kind=accounts_models.XGroup.KIND_INSTIT,
+ kind=groups_models.XGroup.KIND_INSTIT,
domain='',
web='https://www.polytechnique.org/',
)
- accounts_factories.XGroupFactory(
+ groups_factories.XGroupFactory(
name='AX',
short='ax',
- kind=accounts_models.XGroup.KIND_INSTIT,
+ kind=groups_models.XGroup.KIND_INSTIT,
domain='',
web='https://www.polytechniciens.com/',
)
- accounts_factories.XGroupFactory(
+ groups_factories.XGroupFactory(
name='École polytechnique',
short='ecole',
- kind=accounts_models.XGroup.KIND_INSTIT,
+ kind=groups_models.XGroup.KIND_INSTIT,
domain='',
web='https://www.polytechnique.edu/',
)
- accounts_factories.XGroupFactory(
+ groups_factories.XGroupFactory(
name='FaëriX',
short='faerix',
- kind=accounts_models.XGroup.KIND_BINET,
- domain=accounts_models.XGroup.DOMAIN_LEISURE,
+ kind=groups_models.XGroup.KIND_BINET,
+ domain=groups_models.XGroup.DOMAIN_LEISURE,
web='http://www.faerix.net/',
)
- accounts_factories.XGroupFactory(
+ groups_factories.XGroupFactory(
name="Bal de l'X",
short='bal',
- kind=accounts_models.XGroup.KIND_BINET,
- domain=accounts_models.XGroup.DOMAIN_EVENTS,
+ kind=groups_models.XGroup.KIND_BINET,
+ domain=groups_models.XGroup.DOMAIN_EVENTS,
web='https://www.baldelx.com/',
)
from django_xworkflows import models as xwf_models
-import xnet.accounts.models as accounts_models
+from xnet.accounts import models as accounts_models
+from xnet.groups import models as groups_models
class Event(models.Model):
NOTIFICATION_RECIPIENT_CREATOR = 'creator'
help_text=_(u"Texte court utilisé dans les URLs."))
main_description = models.OneToOneField('events.EventPart', null=True, blank=True,
verbose_name=_(u"description principale"), related_name='+')
- group = models.ForeignKey(accounts_models.XGroup, verbose_name=_(u"groupe"), related_name='events')
+ group = models.ForeignKey(groups_models.XGroup, verbose_name=_(u"groupe"), related_name='events')
creator = models.ForeignKey(accounts_models.Account, verbose_name=_(u"créateur"), related_name='created_events')
simple = models.BooleanField(verbose_name=_(u"simple"),
help_text=_(u"Un événement simple a un seul composant. Permet une mise en page plus légère."))
--- /dev/null
+from django.contrib import admin
+
+from xnet.accounts import admin as accounts_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 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 accounts_admin.AccountAdmin.search_fields])
+
+admin.site.register(models.Membership, MembershipAdmin)
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.contrib.webdesign import lorem_ipsum
+
+import factory
+
+from xnet.accounts import factories as accounts_factories
+
+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 = factory.InfiniteIterator(k[0] for k in models.XGroup.KIND_CHOICES)
+ domain = models.XGroup.DOMAIN_REGION
+ web = u"http://google.fr"
+ description = factory.LazyAttribute(lambda _: lorem_ipsum.paragraph())
+
+
+class MembershipFactory(factory.DjangoModelFactory):
+ FACTORY_FOR = models.Membership
+
+ xgroup = factory.SubFactory(XGroupFactory)
+ xuser = factory.SubFactory(accounts_factories.AccountFactory)
+ state = models.MembershipWorkflow.states.enabled
+
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from django.db import models
+
+from django_xworkflows import models as xwf_models
+
+from xnet.accounts import models as accounts_models
+from xnet.utils.images.fields import ImageWithThumbsField as ImageField
+
+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, blank=True, verbose_name=u"domaine")
+
+ dns = models.CharField(max_length=128, verbose_name=u"dns domain", blank=True)
+
+ web = models.CharField(max_length=255, verbose_name=u"website", blank=True)
+ #contact = models.ForeignKey('Account')
+ description = models.TextField(blank=True)
+ logo = ImageField(upload_to='logos', null=True, blank=True)
+
+ members = models.ManyToManyField(accounts_models.Account,
+ related_name='xgroups', through='Membership', verbose_name=u"membres")
+
+ class Meta:
+ verbose_name = u"groupe"
+ verbose_name_plural = u"groupes"
+
+ def __unicode__(self):
+ return self.name
+
+
+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(accounts_models.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")
+
+ class Meta:
+ verbose_name = u"adhérent"
+ verbose_name_plural = u"adhérents"
+ unique_together = ['xgroup', 'xuser']
+
+ def __unicode__(self):
+ return u"{} {} de {} [{}]".format(self.xuser, self.get_level_display(), self.xgroup, self.state)
{% block sidebar %}
<ul class="nav nav-tabs nav-stacked">
<li {% if sidebar == 'list' %}class="active"{% endif %}>
- <a href="{% url 'accounts:group-list' %}">Tous les groupes</a>
+ <a href="{% url 'groups:group-list' %}">Tous les groupes</a>
</li>
</ul>
{% if group %}
<h3>{{ group }}</h3>
<ul class="nav nav-tabs nav-stacked">
<li {% if sidebar == 'home' %}class="active"{% endif %}>
- <a href="{% url 'accounts:group-home' group.short %}">Fiche</a>
+ <a href="{% url 'groups:group-home' group.short %}">Fiche</a>
</li>
<li {% if sidebar == 'directory' %}class="active"{% endif %}>
- <a href="{% url 'accounts:group-directory' group.short %}">Annuaire</a>
+ <a href="{% url 'groups:group-directory' group.short %}">Annuaire</a>
</li>
</ul>
{% endif %}
-{% extends "accounts/base.html" %}
+{% extends "groups/base.html" %}
{% load static %}
{% block content %}
</a>
{% if is_admin %}
<i class="icon-pencil"></i>
- <a href="{% url 'accounts:membership-delete' group.short memb.xuser.username %}">
+ <a href="{% url 'groups:membership-delete' group.short memb.xuser.username %}">
<i class="icon-trash"></i>
</a>
{% endif %}
-{% extends "accounts/base.html" %}
+{% extends "groups/base.html" %}
{% block content %}
<div class="group-desc">
-{% extends "accounts/base.html" %}
+{% extends "groups/base.html" %}
{% block js %}
<script type="text/javascript">
<input type="text" class="search-field input-block-level" data-target="{{ group.grouper }}_type" />
<ul class="unstyled">
{% for item in group.list %}
- <li><a href="{% url 'accounts:group-home' item.short %}">{{ item }}</a></li>
+ <li><a href="{% url 'groups:group-home' item.short %}">{{ item }}</a></li>
{% endfor %}
</ul>
</div>
urlpatterns = patterns(
- 'xnet.accounts.views',
+ 'xnet.groups.views',
url(r'^$', 'index', name='group-list'),
url(r'^(\w+)/$', 'home', name='group-home'),
url(r'^(\w+)/directory/?$', 'directory', name='group-directory'),
from django.contrib import messages
from django.shortcuts import get_object_or_404, render
-from xnet.accounts.decorators import group_required
-from xnet.accounts.models import XGroup, Membership
+from .decorators import group_required
+from .models import XGroup, Membership
def index(request):
- return render(request, 'accounts/index.html', {
+ return render(request, 'groups/index.html', {
'groups': XGroup.objects.order_by('kind'),
'sidebar': 'list',
})
def home(request, slug):
- return render(request, 'accounts/home.html', {
+ return render(request, 'groups/home.html', {
'group': get_object_or_404(XGroup, short=slug),
'sidebar': 'home',
})
@group_required()
def directory(request, group, membership=None):
- return render(request, 'accounts/directory.html', {
+ return render(request, 'groups/directory.html', {
'group': group,
'memberships': group.memberships. \
filter(state='enabled'). \
from MailMan import UserDesc as mailman_userdesc
from MailMan import MailList as mailman_mlist
-from accounts import models as accounts_models
+from groups import models as groups_models
class ListError(Exception):
def is_mlist_admin(mlist, user):
if user.is_superuser or user in mlist.owner:
return True
- if user.memberships.filter(group__dns=self.domain, level=accounts_models.Membership.LEVEL_ADMIN).exists():
+ if user.memberships.filter(group__dns=self.domain, level=groups_models.Membership.LEVEL_ADMIN).exists():
return True
return False
@property
def group(self):
try:
- return accounts_models.XGroup.objects.get(dns=self.domain)
- except accounts_models.XGroup.DoesNotExist:
+ return groups_models.XGroup.objects.get(dns=self.domain)
+ except groups_models.XGroup.DoesNotExist:
return None
# MailMan interactions
import factory
from . import models
-from xnet.accounts import factories as accountsFactories
+from xnet.accounts import factories as accounts_factories
+from xnet.groups import factories as groups_factories
class NewsFactory(factory.DjangoModelFactory):
FACTORY_FOR = models.News
title = factory.Sequence(lambda n: u"Annonce n°%s" % n)
content = u"Ceci est une annonce.\n\nC'est beau."
contacts = factory.Sequence(lambda n: u"pad%s@eltrai.net" % n)
- expiration = datetime.date.today() + datetime.timedelta(days=1)
- restricted = factory.Sequence(lambda n: n%2 == 0, type=int)
+ expiration = factory.LazyAttribute(lambda _: datetime.date.today() + datetime.timedelta(days=1))
+ restricted = factory.Sequence(lambda n: n % 2 == 0, type=int)
- author = factory.SubFactory(accountsFactories.AccountFactory)
- group = factory.SubFactory(accountsFactories.XGroupFactory)
+ author = factory.SubFactory(accounts_factories.AccountFactory)
+ group = factory.SubFactory(groups_factories.XGroupFactory)
from django.db import models
from django.utils.translation import ugettext_lazy as _
+
+from xnet.accounts import models as accounts_models
+from xnet.groups import models as groups_models
+
from xnet.utils.images.fields import ImageWithThumbsField
class News(models.Model):
restricted = models.BooleanField(default=True, verbose_name=u"visibilité restreinte")
- author = models.ForeignKey('accounts.Account', related_name='+', verbose_name=u"auteur")
- group = models.ForeignKey('accounts.XGroup', related_name='news', verbose_name=u"groupe associé")
+ author = models.ForeignKey(accounts_models.Account, related_name='+', verbose_name=u"auteur")
+ group = models.ForeignKey(groups_models.XGroup, related_name='news', verbose_name=u"groupe associé")
class Meta:
verbose_name = u"annonce"
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
- 'xnet.accounts.context_processors.xnet',
+ 'xnet.groups.context_processors.xnet',
)
SITE_ID = 1
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'xnet.accounts.middleware.XnetAccountMiddleware',
+ 'xnet.groups.middleware.XnetAccountMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_authgroupex',
'crispy_forms',
- 'xnet.site',
+
'xnet.accounts',
+ 'xnet.site',
+ 'xnet.groups',
'xnet.news',
'xnet.events',
'xnet.example',
<div class="nav-collapse collapse">
<ul class="nav">
<li{% if top == 'groups' %} class="active"{% endif %}>
- <a href="{% url 'accounts:group-list' %}">
+ <a href="{% url 'groups:group-list' %}">
{% trans "Groupes" %}
</a>
</li>
url(r'media/(?P<path>.*)', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
url(r'^$', 'xnet.site.views.home', name='home'),
url(r'^xorgauth/', include('django_authgroupex.urls', namespace='authgroupex')),
- url(r'^groups/', include('xnet.accounts.urls', namespace='accounts')),
+ url(r'^groups/', include('xnet.groups.urls', namespace='groups')),
url(r'^events/', include('xnet.events.urls', namespace='events')),
url(r'^admin/', include(admin.site.urls)),
)