forked from DGNum/gestioCOF
Merge branch 'Kerl/supportBDS/events' into supportBDS
Move event-related models from 'cof' app to 'gestion' app. Add 'Association' model to register name, related groups (buro, members), etc. Club is now associated with a single Association instance. Migrations take care of these changes.
This commit is contained in:
commit
3842b5d160
22 changed files with 1061 additions and 466 deletions
30
bds/apps.py
30
bds/apps.py
|
@ -1,6 +1,36 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.db.models.signals import post_migrate
|
||||||
|
|
||||||
|
|
||||||
|
def setup_groups(sender, apps, **kwargs):
|
||||||
|
"""
|
||||||
|
Add the appropriate permissions to the "member" and "buro" groups after the
|
||||||
|
`post_migrate` signal since the permissions will only be inserted in the
|
||||||
|
database at the very end of the migrations.
|
||||||
|
"""
|
||||||
|
Group = apps.get_model("auth", "Group")
|
||||||
|
Permission = apps.get_model("auth", "Permission")
|
||||||
|
|
||||||
|
# Buro members have perms bds.* and gestion.*
|
||||||
|
buro, _ = Group.objects.get_or_create(name="bds_buro")
|
||||||
|
app_perms = Permission.objects.filter(
|
||||||
|
content_type__app_label__in=["cof", "gestion"]
|
||||||
|
)
|
||||||
|
buro.permissions.add(*app_perms)
|
||||||
|
|
||||||
|
# Members have perm bds.member
|
||||||
|
members, _ = Group.objects.get_or_create(name="bds_members")
|
||||||
|
perm = Permission.objects.get(
|
||||||
|
codename="member",
|
||||||
|
content_type__app_label="bds"
|
||||||
|
)
|
||||||
|
members.permissions.add(perm)
|
||||||
|
|
||||||
|
|
||||||
class BDSConfig(AppConfig):
|
class BDSConfig(AppConfig):
|
||||||
name = "bds"
|
name = "bds"
|
||||||
verbose_name = "Application de gestion du BDS"
|
verbose_name = "Application de gestion du BDS"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
# https://docs.djangoproject.com/en/1.11/ref/signals/#post-migrate
|
||||||
|
post_migrate.connect(setup_groups, sender=self)
|
||||||
|
|
44
cof/admin.py
44
cof/admin.py
|
@ -9,9 +9,7 @@ from .petits_cours_models import PetitCoursDemande, \
|
||||||
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
||||||
PetitCoursAttributionCounter
|
PetitCoursAttributionCounter
|
||||||
from .models import (
|
from .models import (
|
||||||
SurveyQuestionAnswer, SurveyQuestion, CofProfile, EventOption,
|
SurveyQuestionAnswer, SurveyQuestion, CofProfile, Survey
|
||||||
EventOptionChoice, Event, EventCommentField, EventRegistration,
|
|
||||||
Survey
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,43 +60,6 @@ class SurveyAdmin(admin.ModelAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class EventOptionChoiceInline(admin.TabularInline):
|
|
||||||
model = EventOptionChoice
|
|
||||||
|
|
||||||
|
|
||||||
@add_link_field(desc_text=lambda x: "Choix",
|
|
||||||
link_text=lambda x: "Éditer les choix")
|
|
||||||
class EventOptionInline(admin.TabularInline):
|
|
||||||
model = EventOption
|
|
||||||
|
|
||||||
|
|
||||||
class EventCommentFieldInline(admin.TabularInline):
|
|
||||||
model = EventCommentField
|
|
||||||
|
|
||||||
|
|
||||||
class EventOptionAdmin(admin.ModelAdmin):
|
|
||||||
search_fields = ('event__title', 'name')
|
|
||||||
inlines = [
|
|
||||||
EventOptionChoiceInline,
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class EventAdmin(admin.ModelAdmin):
|
|
||||||
search_fields = ('title', 'location', 'description')
|
|
||||||
inlines = [
|
|
||||||
EventOptionInline,
|
|
||||||
EventCommentFieldInline,
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class EventRegistrationAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('__unicode__' if six.PY2 else '__str__', 'event', 'user',
|
|
||||||
'paid')
|
|
||||||
list_filter = ('paid',)
|
|
||||||
search_fields = ('user__username', 'user__first_name', 'user__last_name',
|
|
||||||
'user__email', 'event__title')
|
|
||||||
|
|
||||||
|
|
||||||
class PetitCoursAbilityAdmin(admin.ModelAdmin):
|
class PetitCoursAbilityAdmin(admin.ModelAdmin):
|
||||||
list_display = ('user', 'matiere', 'niveau', 'agrege')
|
list_display = ('user', 'matiere', 'niveau', 'agrege')
|
||||||
search_fields = ('user__username', 'user__first_name', 'user__last_name',
|
search_fields = ('user__username', 'user__first_name', 'user__last_name',
|
||||||
|
@ -133,8 +94,6 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
admin.site.register(Survey, SurveyAdmin)
|
admin.site.register(Survey, SurveyAdmin)
|
||||||
admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
|
admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
|
||||||
admin.site.register(Event, EventAdmin)
|
|
||||||
admin.site.register(EventOption, EventOptionAdmin)
|
|
||||||
admin.site.register(CofProfile)
|
admin.site.register(CofProfile)
|
||||||
admin.site.register(PetitCoursSubject)
|
admin.site.register(PetitCoursSubject)
|
||||||
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
||||||
|
@ -142,4 +101,3 @@ admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
||||||
admin.site.register(PetitCoursAttributionCounter,
|
admin.site.register(PetitCoursAttributionCounter,
|
||||||
PetitCoursAttributionCounterAdmin)
|
PetitCoursAttributionCounterAdmin)
|
||||||
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)
|
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)
|
||||||
admin.site.register(EventRegistration, EventRegistrationAdmin)
|
|
||||||
|
|
30
cof/apps.py
30
cof/apps.py
|
@ -1,6 +1,36 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.db.models.signals import post_migrate
|
||||||
|
|
||||||
|
|
||||||
|
def setup_groups(sender, apps, **kwargs):
|
||||||
|
"""
|
||||||
|
Add the appropriate permissions to the "member" and "buro" groups after the
|
||||||
|
`post_migrate` signal since the permissions will only be inserted in the
|
||||||
|
database at the very end of the migrations.
|
||||||
|
"""
|
||||||
|
Group = apps.get_model("auth", "Group")
|
||||||
|
Permission = apps.get_model("auth", "Permission")
|
||||||
|
|
||||||
|
# Buro members have perms cof.* and gestion.*
|
||||||
|
buro, _ = Group.objects.get_or_create(name="cof_buro")
|
||||||
|
app_perms = Permission.objects.filter(
|
||||||
|
content_type__app_label__in=["cof", "gestion"]
|
||||||
|
)
|
||||||
|
buro.permissions.add(*app_perms)
|
||||||
|
|
||||||
|
# Members have perm cof.member
|
||||||
|
members, _ = Group.objects.get_or_create(name="cof_members")
|
||||||
|
perm = Permission.objects.get(
|
||||||
|
codename="member",
|
||||||
|
content_type__app_label="cof"
|
||||||
|
)
|
||||||
|
members.permissions.add(perm)
|
||||||
|
|
||||||
|
|
||||||
class COFConfig(AppConfig):
|
class COFConfig(AppConfig):
|
||||||
name = "cof"
|
name = "cof"
|
||||||
verbose_name = "Application de gestion du COF"
|
verbose_name = "Application de gestion du COF"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
# https://docs.djangoproject.com/en/1.11/ref/signals/#post-migrate
|
||||||
|
post_migrate.connect(setup_groups, sender=self)
|
||||||
|
|
|
@ -67,63 +67,6 @@
|
||||||
"model": "cof.surveyquestionanswer",
|
"model": "cof.surveyquestionanswer",
|
||||||
"pk": 5
|
"pk": 5
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"old": false,
|
|
||||||
"description": "On va casser du romain.",
|
|
||||||
"end_date": "2016-09-12T00:00:00Z",
|
|
||||||
"title": "Bataille de Gergovie",
|
|
||||||
"image": "",
|
|
||||||
"location": "Gergovie",
|
|
||||||
"registration_open": true,
|
|
||||||
"start_date": "2016-09-09T00:00:00Z"
|
|
||||||
},
|
|
||||||
"model": "cof.event",
|
|
||||||
"pk": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"default": "",
|
|
||||||
"event": 1,
|
|
||||||
"fieldtype": "text",
|
|
||||||
"name": "Commentaires"
|
|
||||||
},
|
|
||||||
"model": "cof.eventcommentfield",
|
|
||||||
"pk": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"multi_choices": true,
|
|
||||||
"event": 1,
|
|
||||||
"name": "Potion magique"
|
|
||||||
},
|
|
||||||
"model": "cof.eventoption",
|
|
||||||
"pk": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"event_option": 1,
|
|
||||||
"value": "Je suis alergique"
|
|
||||||
},
|
|
||||||
"model": "cof.eventoptionchoice",
|
|
||||||
"pk": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"event_option": 1,
|
|
||||||
"value": "J'en veux"
|
|
||||||
},
|
|
||||||
"model": "cof.eventoptionchoice",
|
|
||||||
"pk": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fields": {
|
|
||||||
"event_option": 1,
|
|
||||||
"value": "Je suis tomb\u00e9 dans la marmite quand j'\u00e9tais petit"
|
|
||||||
},
|
|
||||||
"model": "cof.eventoptionchoice",
|
|
||||||
"pk": 3
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Bagarre"
|
"name": "Bagarre"
|
||||||
|
|
47
cof/forms.py
47
cof/forms.py
|
@ -12,58 +12,15 @@ from django.forms.formsets import BaseFormSet, formset_factory
|
||||||
from django.db.models import Max
|
from django.db.models import Max
|
||||||
from django.core.validators import MinLengthValidator
|
from django.core.validators import MinLengthValidator
|
||||||
|
|
||||||
from .models import CofProfile, EventCommentValue, CalendarSubscription
|
from .models import CofProfile, CalendarSubscription
|
||||||
from .widgets import TriStateCheckbox
|
from .widgets import TriStateCheckbox
|
||||||
|
|
||||||
from gestion.models import Profile
|
from gestion.models import Profile, EventCommentValue
|
||||||
from gestion.shared import lock_table, unlock_table
|
from gestion.shared import lock_table, unlock_table
|
||||||
|
|
||||||
from bda.models import Spectacle
|
from bda.models import Spectacle
|
||||||
|
|
||||||
|
|
||||||
class EventForm(forms.Form):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
event = kwargs.pop("event")
|
|
||||||
self.event = event
|
|
||||||
current_choices = kwargs.pop("current_choices", None)
|
|
||||||
super(EventForm, self).__init__(*args, **kwargs)
|
|
||||||
choices = {}
|
|
||||||
if current_choices:
|
|
||||||
for choice in current_choices.all():
|
|
||||||
if choice.event_option.id not in choices:
|
|
||||||
choices[choice.event_option.id] = [choice.id]
|
|
||||||
else:
|
|
||||||
choices[choice.event_option.id].append(choice.id)
|
|
||||||
all_choices = choices
|
|
||||||
for option in event.options.all():
|
|
||||||
choices = [(choice.id, choice.value)
|
|
||||||
for choice in option.choices.all()]
|
|
||||||
if option.multi_choices:
|
|
||||||
initial = [] if option.id not in all_choices \
|
|
||||||
else all_choices[option.id]
|
|
||||||
field = forms.MultipleChoiceField(
|
|
||||||
label=option.name,
|
|
||||||
choices=choices,
|
|
||||||
widget=CheckboxSelectMultiple,
|
|
||||||
required=False,
|
|
||||||
initial=initial)
|
|
||||||
else:
|
|
||||||
initial = None if option.id not in all_choices \
|
|
||||||
else all_choices[option.id][0]
|
|
||||||
field = forms.ChoiceField(label=option.name,
|
|
||||||
choices=choices,
|
|
||||||
widget=RadioSelect,
|
|
||||||
required=False,
|
|
||||||
initial=initial)
|
|
||||||
field.option_id = option.id
|
|
||||||
self.fields["option_%d" % option.id] = field
|
|
||||||
|
|
||||||
def choices(self):
|
|
||||||
for name, value in self.cleaned_data.items():
|
|
||||||
if name.startswith('option_'):
|
|
||||||
yield (self.fields[name].option_id, value)
|
|
||||||
|
|
||||||
|
|
||||||
class SurveyForm(forms.Form):
|
class SurveyForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
survey = kwargs.pop("survey")
|
survey = kwargs.pop("survey")
|
||||||
|
|
|
@ -23,27 +23,16 @@ def create_profile(apps, schema_editor):
|
||||||
|
|
||||||
|
|
||||||
def preserve_perms(apps, schema_editor):
|
def preserve_perms(apps, schema_editor):
|
||||||
# from django.contrib.auth.management import create_permissions
|
COFProfile = apps.get_model("cof", "CofProfile")
|
||||||
|
|
||||||
# apps.models_module = True
|
# create the groups for COF members and staff
|
||||||
# create_permissions(apps, verbosity=0)
|
|
||||||
# apps.models_module = None
|
|
||||||
|
|
||||||
CofProfile = apps.get_model("cof", "CofProfile")
|
|
||||||
# memberp = Permission.objects.get(codename='member')
|
|
||||||
# burop = Permission.objects.get(codename='buro')
|
|
||||||
|
|
||||||
# creates the groups for COF members and
|
|
||||||
member = Group.objects.create(name='cof_members')
|
member = Group.objects.create(name='cof_members')
|
||||||
buro = Group.objects.create(name='cof_buro')
|
buro = Group.objects.create(name='cof_buro')
|
||||||
|
|
||||||
# associate permissions to the respective groups.
|
cprofiles = COFProfile.objects.select_related("profile__user")
|
||||||
# buro.permissions = [burop, memberp]
|
for cofp in cprofiles.filter(is_cof=True):
|
||||||
# member.permissions = [memberp]
|
|
||||||
|
|
||||||
for cofp in CofProfile.objects.filter(is_cof=True):
|
|
||||||
cofp.profile.user.groups.add(member)
|
cofp.profile.user.groups.add(member)
|
||||||
for cofp in CofProfile.objects.filter(is_buro=True):
|
for cofp in cprofiles.filter(is_buro=True):
|
||||||
cofp.profile.user.groups.add(buro)
|
cofp.profile.user.groups.add(buro)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
def create_cof_group(apps, schema_editor):
|
|
||||||
Group = apps.get_model("auth", "Group")
|
|
||||||
Group.objects.get_or_create(name="cof_members")
|
|
||||||
|
|
||||||
|
|
||||||
def create_buro_group(apps, schema_editor):
|
|
||||||
Group = apps.get_model("auth", "Group")
|
|
||||||
Group.objects.get_or_create(name="cof_buro")
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('cof', '0009_generic_profiles'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(create_cof_group, migrations.RunPython.noop),
|
|
||||||
migrations.RunPython(create_buro_group, migrations.RunPython.noop),
|
|
||||||
]
|
|
|
@ -7,7 +7,7 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('cof', '0010_create_cof_group'),
|
('cof', '0009_generic_profiles'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|
96
cof/migrations/0013_move_events_to_gestion.py
Normal file
96
cof/migrations/0013_move_events_to_gestion.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.3 on 2017-07-26 18:29
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cof', '0012_remove_club'),
|
||||||
|
("gestion", "0003_association_and_events")
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventcommentfield',
|
||||||
|
name='event',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventcommentvalue',
|
||||||
|
name='commentfield',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventcommentvalue',
|
||||||
|
name='registration',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventoption',
|
||||||
|
name='event',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventoptionchoice',
|
||||||
|
name='event_option',
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='eventregistration',
|
||||||
|
unique_together=set([]),
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventregistration',
|
||||||
|
name='event',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventregistration',
|
||||||
|
name='filledcomments',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventregistration',
|
||||||
|
name='options',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventregistration',
|
||||||
|
name='user',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='petitcoursattribution',
|
||||||
|
name='matiere',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cof.PetitCoursSubject', verbose_name='Matière'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='petitcoursattributioncounter',
|
||||||
|
name='matiere',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cof.PetitCoursSubject', verbose_name='Matiere'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='petitcoursattributioncounter',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='petitcoursdemande',
|
||||||
|
name='traitee_par',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Event',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventCommentField',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventCommentValue',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventOption',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventOptionChoice',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventRegistration',
|
||||||
|
),
|
||||||
|
]
|
120
cof/models.py
120
cof/models.py
|
@ -17,11 +17,6 @@ TYPE_COTIZ_CHOICES = (
|
||||||
('exterieur', _("Extérieur")),
|
('exterieur', _("Extérieur")),
|
||||||
)
|
)
|
||||||
|
|
||||||
TYPE_COMMENT_FIELD = (
|
|
||||||
('text', _("Texte long")),
|
|
||||||
('char', _("Texte court")),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CofProfile(models.Model):
|
class CofProfile(models.Model):
|
||||||
profile = models.OneToOneField(Profile,
|
profile = models.OneToOneField(Profile,
|
||||||
|
@ -79,121 +74,6 @@ class CofProfile(models.Model):
|
||||||
return self.profile.user.username
|
return self.profile.user.username
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Event(models.Model):
|
|
||||||
title = models.CharField("Titre", max_length=200)
|
|
||||||
location = models.CharField("Lieu", max_length=200)
|
|
||||||
start_date = models.DateTimeField("Date de début", blank=True, null=True)
|
|
||||||
end_date = models.DateTimeField("Date de fin", blank=True, null=True)
|
|
||||||
description = models.TextField("Description", blank=True)
|
|
||||||
image = models.ImageField("Image", blank=True, null=True,
|
|
||||||
upload_to="imgs/events/")
|
|
||||||
registration_open = models.BooleanField("Inscriptions ouvertes",
|
|
||||||
default=True)
|
|
||||||
old = models.BooleanField("Archiver (événement fini)", default=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Événement"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return six.text_type(self.title)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class EventCommentField(models.Model):
|
|
||||||
event = models.ForeignKey(
|
|
||||||
Event,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="commentfields"
|
|
||||||
)
|
|
||||||
name = models.CharField("Champ", max_length=200)
|
|
||||||
fieldtype = models.CharField("Type", max_length=10,
|
|
||||||
choices=TYPE_COMMENT_FIELD, default="text")
|
|
||||||
default = models.TextField("Valeur par défaut", blank=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Champ"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return six.text_type(self.name)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class EventCommentValue(models.Model):
|
|
||||||
commentfield = models.ForeignKey(
|
|
||||||
EventCommentField,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="values"
|
|
||||||
)
|
|
||||||
registration = models.ForeignKey(
|
|
||||||
"EventRegistration",
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="comments"
|
|
||||||
)
|
|
||||||
content = models.TextField("Contenu", blank=True, null=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Commentaire de %s" % self.commentfield
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class EventOption(models.Model):
|
|
||||||
event = models.ForeignKey(
|
|
||||||
Event,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="options"
|
|
||||||
)
|
|
||||||
name = models.CharField("Option", max_length=200)
|
|
||||||
multi_choices = models.BooleanField("Choix multiples", default=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Option"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return six.text_type(self.name)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class EventOptionChoice(models.Model):
|
|
||||||
event_option = models.ForeignKey(
|
|
||||||
EventOption,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="choices"
|
|
||||||
)
|
|
||||||
value = models.CharField("Valeur", max_length=200)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Choix"
|
|
||||||
verbose_name_plural = "Choix"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return six.text_type(self.value)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class EventRegistration(models.Model):
|
|
||||||
user = models.ForeignKey(
|
|
||||||
User,
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
event = models.ForeignKey(
|
|
||||||
Event,
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
options = models.ManyToManyField(EventOptionChoice)
|
|
||||||
filledcomments = models.ManyToManyField(EventCommentField,
|
|
||||||
through=EventCommentValue)
|
|
||||||
paid = models.BooleanField("A payé", default=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Inscription"
|
|
||||||
unique_together = ("user", "event")
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Inscription de %s à %s" % (six.text_type(self.user),
|
|
||||||
six.text_type(self.event.title))
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Survey(models.Model):
|
class Survey(models.Model):
|
||||||
title = models.CharField("Titre", max_length=200)
|
title = models.CharField("Titre", max_length=200)
|
||||||
|
|
|
@ -9,16 +9,6 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="home-menu row">
|
<div class="home-menu row">
|
||||||
<div class="{% if user.profile.cof.is_buro %}col-sm-6 {% else %}col-sm-8 col-sm-offset-2 col-xs-12 {%endif%}normal-user-hm">
|
<div class="{% if user.profile.cof.is_buro %}col-sm-6 {% else %}col-sm-8 col-sm-offset-2 col-xs-12 {%endif%}normal-user-hm">
|
||||||
<!-- {% if open_events %}
|
|
||||||
<h3 class="block-title">Événements<span class="pull-right glyphicon glyphicon-calendar"></span></h3>
|
|
||||||
<div class="hm-block">
|
|
||||||
<ul>
|
|
||||||
{% for event in open_events %}
|
|
||||||
<li><a href="{% url "event" event.id %}">{{ event.title }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endif %} -->
|
|
||||||
{% if open_surveys %}
|
{% if open_surveys %}
|
||||||
<h3 class="block-title">Sondages en cours<span class="pull-right glyphicon glyphicon-stats"></span></h3>
|
<h3 class="block-title">Sondages en cours<span class="pull-right glyphicon glyphicon-stats"></span></h3>
|
||||||
<div class="hm-block">
|
<div class="hm-block">
|
||||||
|
|
|
@ -53,15 +53,6 @@ surveys_patterns = [
|
||||||
name="survey"),
|
name="survey"),
|
||||||
]
|
]
|
||||||
|
|
||||||
events_patterns = [
|
|
||||||
url(r'^(?P<event_id>\d+)$',
|
|
||||||
views.event,
|
|
||||||
name="event"),
|
|
||||||
url(r'^(?P<event_id>\d+)/status$',
|
|
||||||
views.event_status,
|
|
||||||
name="event.status"),
|
|
||||||
]
|
|
||||||
|
|
||||||
calendar_patterns = [
|
calendar_patterns = [
|
||||||
url(r'^subscription$',
|
url(r'^subscription$',
|
||||||
views.calendar,
|
views.calendar,
|
||||||
|
|
155
cof/views.py
155
cof/views.py
|
@ -15,18 +15,19 @@ from django.utils import timezone
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
import django.utils.six as six
|
import django.utils.six as six
|
||||||
|
|
||||||
|
from gestion.models import (
|
||||||
|
Event, EventRegistration, EventOption, EventOptionChoice,
|
||||||
|
EventCommentField, EventCommentValue
|
||||||
|
)
|
||||||
|
|
||||||
from .models import Survey, SurveyAnswer, SurveyQuestion, \
|
from .models import Survey, SurveyAnswer, SurveyQuestion, \
|
||||||
SurveyQuestionAnswer
|
SurveyQuestionAnswer, CalendarSubscription
|
||||||
from .models import Event, EventRegistration, EventOption, \
|
|
||||||
EventOptionChoice
|
|
||||||
from .models import EventCommentField, EventCommentValue, \
|
|
||||||
CalendarSubscription
|
|
||||||
from .models import CofProfile
|
from .models import CofProfile
|
||||||
from .decorators import buro_required, cof_required
|
from .decorators import buro_required, cof_required
|
||||||
from .forms import (
|
from .forms import (
|
||||||
EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
|
SurveyForm, SurveyStatusFilterForm,
|
||||||
RegistrationUserForm, RegistrationProfileForm, RegistrationCofProfileForm,
|
RegistrationUserForm, RegistrationProfileForm, RegistrationCofProfileForm,
|
||||||
EventForm, CalendarForm, EventFormset, RegistrationPassUserForm
|
CalendarForm, EventFormset, RegistrationPassUserForm
|
||||||
)
|
)
|
||||||
|
|
||||||
from bda.models import Tirage, Spectacle
|
from bda.models import Tirage, Spectacle
|
||||||
|
@ -37,7 +38,6 @@ from gestion.models import Profile
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
data = {"surveys": Survey.objects.filter(old=False).all(),
|
data = {"surveys": Survey.objects.filter(old=False).all(),
|
||||||
"events": Event.objects.filter(old=False).all(),
|
|
||||||
"open_surveys":
|
"open_surveys":
|
||||||
Survey.objects.filter(survey_open=True, old=False).all(),
|
Survey.objects.filter(survey_open=True, old=False).all(),
|
||||||
"open_events":
|
"open_events":
|
||||||
|
@ -125,72 +125,6 @@ def survey(request, survey_id):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def get_event_form_choices(event, form):
|
|
||||||
all_choices = []
|
|
||||||
for option_id, choices_ids in form.choices():
|
|
||||||
option = get_object_or_404(EventOption, id=option_id,
|
|
||||||
event=event)
|
|
||||||
if type(choices_ids) != list:
|
|
||||||
choices_ids = [choices_ids]
|
|
||||||
if not option.multi_choices and len(choices_ids) > 1:
|
|
||||||
raise Http404
|
|
||||||
for choice_id in choices_ids:
|
|
||||||
if not choice_id:
|
|
||||||
continue
|
|
||||||
choice_id = int(choice_id)
|
|
||||||
choice = EventOptionChoice.objects.get(
|
|
||||||
id=choice_id,
|
|
||||||
event_option=option)
|
|
||||||
all_choices.append(choice)
|
|
||||||
return all_choices
|
|
||||||
|
|
||||||
|
|
||||||
def update_event_form_comments(event, form, registration):
|
|
||||||
for commentfield_id, value in form.comments():
|
|
||||||
field = get_object_or_404(EventCommentField, id=commentfield_id,
|
|
||||||
event=event)
|
|
||||||
if value == field.default:
|
|
||||||
continue
|
|
||||||
(storage, _) = EventCommentValue.objects.get_or_create(
|
|
||||||
commentfield=field,
|
|
||||||
registration=registration)
|
|
||||||
storage.content = value
|
|
||||||
storage.save()
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def event(request, event_id):
|
|
||||||
event = get_object_or_404(Event, id=event_id)
|
|
||||||
if (not event.registration_open) or event.old:
|
|
||||||
raise Http404
|
|
||||||
success = False
|
|
||||||
if request.method == "POST":
|
|
||||||
form = EventForm(request.POST, event=event)
|
|
||||||
if form.is_valid():
|
|
||||||
all_choices = get_event_form_choices(event, form)
|
|
||||||
(current_registration, _) = \
|
|
||||||
EventRegistration.objects.get_or_create(user=request.user,
|
|
||||||
event=event)
|
|
||||||
current_registration.options = all_choices
|
|
||||||
current_registration.save()
|
|
||||||
success = True
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
current_registration = \
|
|
||||||
EventRegistration.objects.get(user=request.user, event=event)
|
|
||||||
form = EventForm(event=event,
|
|
||||||
current_choices=current_registration.options)
|
|
||||||
except EventRegistration.DoesNotExist:
|
|
||||||
form = EventForm(event=event)
|
|
||||||
# Messages
|
|
||||||
if success:
|
|
||||||
messages.success(request, "Votre inscription a bien été enregistrée ! "
|
|
||||||
"Vous pouvez cependant la modifier jusqu'à "
|
|
||||||
"la fin des inscriptions.")
|
|
||||||
return render(request, "cof/event.html",
|
|
||||||
{"event": event, "form": form})
|
|
||||||
|
|
||||||
|
|
||||||
def clean_post_for_status(initial):
|
def clean_post_for_status(initial):
|
||||||
d = initial.copy()
|
d = initial.copy()
|
||||||
for k, v in d.items():
|
for k, v in d.items():
|
||||||
|
@ -200,46 +134,6 @@ def clean_post_for_status(initial):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def event_status(request, event_id):
|
|
||||||
event = get_object_or_404(Event, id=event_id)
|
|
||||||
registrations_query = EventRegistration.objects.filter(event=event)
|
|
||||||
post_data = clean_post_for_status(request.POST)
|
|
||||||
form = EventStatusFilterForm(post_data or None, event=event)
|
|
||||||
if form.is_valid():
|
|
||||||
for option_id, choice_id, value in form.filters():
|
|
||||||
if option_id == "has_paid":
|
|
||||||
if value == "yes":
|
|
||||||
registrations_query = registrations_query.filter(paid=True)
|
|
||||||
elif value == "no":
|
|
||||||
registrations_query = registrations_query.filter(
|
|
||||||
paid=False)
|
|
||||||
continue
|
|
||||||
choice = get_object_or_404(EventOptionChoice, id=choice_id,
|
|
||||||
event_option__id=option_id)
|
|
||||||
if value == "none":
|
|
||||||
continue
|
|
||||||
if value == "yes":
|
|
||||||
registrations_query = registrations_query.filter(
|
|
||||||
options__id__exact=choice.id)
|
|
||||||
elif value == "no":
|
|
||||||
registrations_query = registrations_query.exclude(
|
|
||||||
options__id__exact=choice.id)
|
|
||||||
user_choices = registrations_query.prefetch_related("user").all()
|
|
||||||
options = EventOption.objects.filter(event=event).all()
|
|
||||||
choices_count = {}
|
|
||||||
for option in options:
|
|
||||||
for choice in option.choices.all():
|
|
||||||
choices_count[choice.id] = 0
|
|
||||||
for user_choice in user_choices:
|
|
||||||
for choice in user_choice.options.all():
|
|
||||||
choices_count[choice.id] += 1
|
|
||||||
return render(request, "event_status.html",
|
|
||||||
{"event": event, "user_choices": user_choices,
|
|
||||||
"options": options, "choices_count": choices_count,
|
|
||||||
"form": form})
|
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def survey_status(request, survey_id):
|
def survey_status(request, survey_id):
|
||||||
survey = get_object_or_404(Survey, id=survey_id)
|
survey = get_object_or_404(Survey, id=survey_id)
|
||||||
|
@ -342,6 +236,39 @@ def registration_form2(request, login_clipper=None, username=None,
|
||||||
"event_formset": event_formset})
|
"event_formset": event_formset})
|
||||||
|
|
||||||
|
|
||||||
|
def get_event_form_choices(event, form):
|
||||||
|
all_choices = []
|
||||||
|
for option_id, choices_ids in form.choices():
|
||||||
|
option = get_object_or_404(EventOption, id=option_id,
|
||||||
|
event=event)
|
||||||
|
if type(choices_ids) != list:
|
||||||
|
choices_ids = [choices_ids]
|
||||||
|
if not option.multi_choices and len(choices_ids) > 1:
|
||||||
|
raise Http404
|
||||||
|
for choice_id in choices_ids:
|
||||||
|
if not choice_id:
|
||||||
|
continue
|
||||||
|
choice_id = int(choice_id)
|
||||||
|
choice = EventOptionChoice.objects.get(
|
||||||
|
id=choice_id,
|
||||||
|
event_option=option)
|
||||||
|
all_choices.append(choice)
|
||||||
|
return all_choices
|
||||||
|
|
||||||
|
|
||||||
|
def update_event_form_comments(event, form, registration):
|
||||||
|
for commentfield_id, value in form.comments():
|
||||||
|
field = get_object_or_404(EventCommentField, id=commentfield_id,
|
||||||
|
event=event)
|
||||||
|
if value == field.default:
|
||||||
|
continue
|
||||||
|
(storage, _) = EventCommentValue.objects.get_or_create(
|
||||||
|
commentfield=field,
|
||||||
|
registration=registration)
|
||||||
|
storage.content = value
|
||||||
|
storage.save()
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration(request):
|
def registration(request):
|
||||||
if request.POST:
|
if request.POST:
|
||||||
|
|
|
@ -43,6 +43,7 @@ INSTALLED_APPS = (
|
||||||
'channels',
|
'channels',
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
'custommail',
|
'custommail',
|
||||||
|
'nested_admin',
|
||||||
'bda.apps.BdAConfig',
|
'bda.apps.BdAConfig',
|
||||||
'bds.apps.BDSConfig',
|
'bds.apps.BDSConfig',
|
||||||
'cof.apps.COFConfig',
|
'cof.apps.COFConfig',
|
||||||
|
|
|
@ -16,7 +16,7 @@ from django.contrib.auth import views as django_views
|
||||||
|
|
||||||
from cof import views as cof_views
|
from cof import views as cof_views
|
||||||
from cof.urls import export_patterns, petitcours_patterns, \
|
from cof.urls import export_patterns, petitcours_patterns, \
|
||||||
surveys_patterns, events_patterns, calendar_patterns
|
surveys_patterns, calendar_patterns
|
||||||
from cof.autocomplete import autocomplete
|
from cof.autocomplete import autocomplete
|
||||||
|
|
||||||
from gestion import views as gestion_views
|
from gestion import views as gestion_views
|
||||||
|
@ -40,8 +40,6 @@ urlpatterns = [
|
||||||
url(r'^petitcours/', include(petitcours_patterns)),
|
url(r'^petitcours/', include(petitcours_patterns)),
|
||||||
# Les sondages
|
# Les sondages
|
||||||
url(r'^survey/', include(surveys_patterns)),
|
url(r'^survey/', include(surveys_patterns)),
|
||||||
# Evenements
|
|
||||||
url(r'^event/', include(events_patterns)),
|
|
||||||
# Calendrier
|
# Calendrier
|
||||||
url(r'^calendar/', include(calendar_patterns)),
|
url(r'^calendar/', include(calendar_patterns)),
|
||||||
# Infos persos
|
# Infos persos
|
||||||
|
@ -83,6 +81,7 @@ urlpatterns = [
|
||||||
cof_views.liste_bdarevente,
|
cof_views.liste_bdarevente,
|
||||||
name="liste_bdarevente"),
|
name="liste_bdarevente"),
|
||||||
url(r'^k-fet/', include(kfet.urls)),
|
url(r'^k-fet/', include(kfet.urls)),
|
||||||
|
url(r"^_nested_admin/", include("nested_admin.urls")),
|
||||||
]
|
]
|
||||||
|
|
||||||
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
import nested_admin
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.forms.models import modelform_factory
|
||||||
|
|
||||||
from .models import Profile, Club
|
from .models import (
|
||||||
|
Association, Profile, Club, Event, Location,
|
||||||
|
EventOption, EventCommentField, EventOptionChoice
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
|
@ -19,7 +25,6 @@ class UserProfileAdmin(UserAdmin):
|
||||||
ProfileInline,
|
ProfileInline,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User, UserProfileAdmin)
|
admin.site.register(User, UserProfileAdmin)
|
||||||
|
|
||||||
|
@ -38,3 +43,62 @@ class ClubAdmin(admin.ModelAdmin):
|
||||||
ClubUserInline,
|
ClubUserInline,
|
||||||
]
|
]
|
||||||
exclude = ('members',)
|
exclude = ('members',)
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Events
|
||||||
|
# ---
|
||||||
|
|
||||||
|
class EventOptionChoiceInline(nested_admin.NestedTabularInline):
|
||||||
|
model = EventOptionChoice
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
class EventOptionInline(nested_admin.NestedTabularInline):
|
||||||
|
model = EventOption
|
||||||
|
extra = 1
|
||||||
|
inlines = [EventOptionChoiceInline]
|
||||||
|
|
||||||
|
|
||||||
|
class EventCommentFieldInline(nested_admin.NestedTabularInline):
|
||||||
|
model = EventCommentField
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Event)
|
||||||
|
class EventAdmin(nested_admin.NestedModelAdmin):
|
||||||
|
search_fields = ['title', 'location', 'description']
|
||||||
|
inlines = [
|
||||||
|
EventOptionInline,
|
||||||
|
EventCommentFieldInline,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
"""Restrict the event you can edit"""
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
else:
|
||||||
|
assocs = Association.objects.filter(staff_group__user=request.user)
|
||||||
|
return qs.filter(associations__in=assocs)
|
||||||
|
|
||||||
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
|
"""Restrict the applications you can attach to an event"""
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return super().get_form(request, obj, **kwargs)
|
||||||
|
else:
|
||||||
|
assocs = Association.objects.filter(staff_group__user=request.user)
|
||||||
|
|
||||||
|
def formfield_callback(f, **kwargs):
|
||||||
|
if f.name == "associations":
|
||||||
|
kwargs["queryset"] = assocs
|
||||||
|
return f.formfield(**kwargs)
|
||||||
|
|
||||||
|
return modelform_factory(
|
||||||
|
Event,
|
||||||
|
exclude=[],
|
||||||
|
formfield_callback=formfield_callback
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Location)
|
||||||
|
|
193
gestion/fixtures/events.json
Normal file
193
gestion/fixtures/events.json
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"model": "gestion.location",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"name": "Gergovie"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.location",
|
||||||
|
"pk": 2,
|
||||||
|
"fields": {
|
||||||
|
"name": "Lut\u00e8ce"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.event",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"title": "Bataille de gergovie",
|
||||||
|
"location": 1,
|
||||||
|
"start_date": "2017-06-25T18:00:00Z",
|
||||||
|
"end_date": "2017-06-27T18:00:00Z",
|
||||||
|
"description": "Bataille historique \u00e0 ne pas manquer.\r\nOpen sanglier \u00e0 la fin.",
|
||||||
|
"image": "",
|
||||||
|
"registration_open": true,
|
||||||
|
"old": false,
|
||||||
|
"associations": [
|
||||||
|
["COF"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.event",
|
||||||
|
"pk": 2,
|
||||||
|
"fields": {
|
||||||
|
"title": "Course de chars",
|
||||||
|
"location": 2,
|
||||||
|
"start_date": "2017-06-25T13:00:00Z",
|
||||||
|
"end_date": "2017-06-25T16:00:00Z",
|
||||||
|
"description": "Finale de la league nationale de char \u00e0 b\u0153ufs",
|
||||||
|
"image": "",
|
||||||
|
"registration_open": true,
|
||||||
|
"old": false,
|
||||||
|
"associations": [
|
||||||
|
["BDS"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventcommentfield",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"event": 1,
|
||||||
|
"name": "Commentaires",
|
||||||
|
"fieldtype": "text",
|
||||||
|
"default": "",
|
||||||
|
"ordering": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoption",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"event": 1,
|
||||||
|
"name": "Potion magique",
|
||||||
|
"multi_choices": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoption",
|
||||||
|
"pk": 2,
|
||||||
|
"fields": {
|
||||||
|
"event": 1,
|
||||||
|
"name": "Extras pendant le buffet",
|
||||||
|
"multi_choices": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoption",
|
||||||
|
"pk": 3,
|
||||||
|
"fields": {
|
||||||
|
"event": 2,
|
||||||
|
"name": "Type de si\u00e8ge",
|
||||||
|
"multi_choices": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoption",
|
||||||
|
"pk": 4,
|
||||||
|
"fields": {
|
||||||
|
"event": 2,
|
||||||
|
"name": "Forfaits suppl\u00e9mentaires",
|
||||||
|
"multi_choices": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 1,
|
||||||
|
"value": "Oui"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 2,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 1,
|
||||||
|
"value": "Non"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 3,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 1,
|
||||||
|
"value": "Je suis tomb\u00e9 dans la marmitte quand j'\u00e9tais petit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 4,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 2,
|
||||||
|
"value": "Sanglier"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 5,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 2,
|
||||||
|
"value": "Cervoise"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 6,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 2,
|
||||||
|
"value": "Pot\u00e9e auvergnate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 7,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 2,
|
||||||
|
"value": "Saint Nectaire"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 8,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 3,
|
||||||
|
"value": "Debout"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 9,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 3,
|
||||||
|
"value": "Assis standard"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 10,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 3,
|
||||||
|
"value": "Premier rang"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 11,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 4,
|
||||||
|
"value": "Popcorn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gestion.eventoptionchoice",
|
||||||
|
"pk": 12,
|
||||||
|
"fields": {
|
||||||
|
"event_option": 4,
|
||||||
|
"value": "Coussin moelleux"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
289
gestion/migrations/0003_association_and_events.py
Normal file
289
gestion/migrations/0003_association_and_events.py
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.3 on 2017-07-26 18:29
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def create_apps(apps, schema_editor):
|
||||||
|
Association = apps.get_model("gestion", "Association")
|
||||||
|
Group = apps.get_model("auth", "Group")
|
||||||
|
|
||||||
|
cof_m = Group.objects.get(name="cof_members")
|
||||||
|
cof_b = Group.objects.get(name="cof_buro")
|
||||||
|
bds_m = Group.objects.get(name="bds_members")
|
||||||
|
bds_b = Group.objects.get(name="bds_buro")
|
||||||
|
|
||||||
|
Association.objects.bulk_create([
|
||||||
|
Association(id=1, name="COF", staff_group=cof_b, members_group=cof_m),
|
||||||
|
Association(id=2, name="BDS", staff_group=bds_b, members_group=bds_m),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def import_events(apps, schema_editor):
|
||||||
|
# Fetching the models that have be moved from cof to gestion
|
||||||
|
model_names = [
|
||||||
|
"Event", "EventCommentField", "EventCommentValue", "EventOption",
|
||||||
|
"EventOptionChoice", "EventRegistration"
|
||||||
|
]
|
||||||
|
models = [
|
||||||
|
(apps.get_model("cof", name), apps.get_model("gestion", name))
|
||||||
|
for name in model_names
|
||||||
|
]
|
||||||
|
|
||||||
|
# The old Event.location field becomes a table: we need to create an entry
|
||||||
|
# in this table for each value of the old `location` field.
|
||||||
|
OldEvent, NewEvent = models[0]
|
||||||
|
Location = apps.get_model("gestion", "Location")
|
||||||
|
locations = set() # A set to prevent duplicate entries
|
||||||
|
events = []
|
||||||
|
for event in OldEvent.objects.values():
|
||||||
|
locations.add(event["location"])
|
||||||
|
events.append(event)
|
||||||
|
Location.objects.bulk_create([Location(name=name) for name in locations])
|
||||||
|
map_loc = {
|
||||||
|
loc.name: loc
|
||||||
|
for loc in Location.objects.all()
|
||||||
|
}
|
||||||
|
for event in events:
|
||||||
|
event["location"] = map_loc[event["location"]]
|
||||||
|
NewEvent.objects.bulk_create([
|
||||||
|
NewEvent(**event)
|
||||||
|
for event in events
|
||||||
|
])
|
||||||
|
|
||||||
|
# Do not forget to link all the existing event to the COF group
|
||||||
|
cof = apps.get_model("gestion", "Association").objects.get(name="COF")
|
||||||
|
for event in NewEvent.objects.all():
|
||||||
|
event.associations.add(cof)
|
||||||
|
|
||||||
|
# Migrating the other models is straigtforward
|
||||||
|
for OldModel, NewModel in models[1:]:
|
||||||
|
NewModel.objects.bulk_create([
|
||||||
|
NewModel(**values)
|
||||||
|
for values in OldModel.objects.values()
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def restore_events(apps, schema_editor):
|
||||||
|
# TODO?
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('auth', '0008_alter_user_username_max_length'),
|
||||||
|
('gestion', '0002_club_support'),
|
||||||
|
("cof", "0009_generic_profiles"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Association',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=30, unique=True, verbose_name="nom de l'association")),
|
||||||
|
('members_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='member_group_of', to='auth.Group', verbose_name='groupe des membres')),
|
||||||
|
('staff_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='staff_group_of', to='auth.Group', verbose_name='groupe des membres du bureau')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'association',
|
||||||
|
'verbose_name_plural': 'associations',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Event',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=200, verbose_name='titre')),
|
||||||
|
('start_date', models.DateTimeField(blank=True, null=True, verbose_name="début de l'événement")),
|
||||||
|
('end_date', models.DateTimeField(blank=True, null=True, verbose_name="fin de l'événement")),
|
||||||
|
('description', models.TextField(blank=True, verbose_name='description')),
|
||||||
|
('image', models.ImageField(blank=True, null=True, upload_to='public/imgs/events/', verbose_name='image')),
|
||||||
|
('registration_open', models.NullBooleanField(default=True, help_text="Indéfini signifie « l'inscription n'est pas requise\xa0»", verbose_name='les inscriptions sont ouvertes')),
|
||||||
|
('old', models.BooleanField(default=False, verbose_name='archiver (événement fini)')),
|
||||||
|
('associations', models.ManyToManyField(related_name='events', to='gestion.Association', verbose_name='associations')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'événement',
|
||||||
|
'verbose_name_plural': 'événements',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventCommentField',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='nom du champ')),
|
||||||
|
('fieldtype', models.CharField(choices=[('text', 'Texte long'), ('char', 'Texte court')], default='text', max_length=10, verbose_name='type de champ')),
|
||||||
|
('default', models.TextField(blank=True, verbose_name='valeur par défaut')),
|
||||||
|
('ordering', models.IntegerField(default=False, help_text='plus petit en premier, ordre alphabétique sur le nom si ambiguïté', verbose_name='ordre des champs')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='commentfields', to='gestion.Event', verbose_name='événement')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'champ',
|
||||||
|
'verbose_name_plural': 'champs',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventCommentValue',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('content', models.TextField(blank=True, verbose_name='contenu')),
|
||||||
|
('commentfield', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='values', to='gestion.EventCommentField')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventOption',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='option')),
|
||||||
|
('multi_choices', models.BooleanField(default=False, verbose_name='choix multiples')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='gestion.Event', verbose_name='événement')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'option des événements',
|
||||||
|
'verbose_name_plural': 'options des événements',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventOptionChoice',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('value', models.CharField(max_length=200, verbose_name='Valeur')),
|
||||||
|
('event_option', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='choices', to='gestion.EventOption', verbose_name='événement')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'choix',
|
||||||
|
'verbose_name_plural': 'choix',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventRegistration',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('paid', models.BooleanField(default=False, verbose_name='a payé')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion.Event', verbose_name='événement')),
|
||||||
|
('filledcomments', models.ManyToManyField(through='gestion.EventCommentValue', to='gestion.EventCommentField', verbose_name='commentaires')),
|
||||||
|
('options', models.ManyToManyField(to='gestion.EventOptionChoice', verbose_name='choix')),
|
||||||
|
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='utilisateur')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'inscription',
|
||||||
|
'verbose_name_plural': 'inscriptions',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Location',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='nom du lieu')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'lieu',
|
||||||
|
'verbose_name_plural': 'lieux',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='profile',
|
||||||
|
options={'verbose_name': 'profil', 'verbose_name_plural': 'profils'},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='club',
|
||||||
|
name='associations',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='cotisation_frequency',
|
||||||
|
field=models.CharField(blank=True, choices=[('ANN', 'Annuel'), ('SEM', 'Semestriel'), ('COU', 'Au cours')], default='ANN', max_length=3, verbose_name='fréquence de la cotisation'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(blank=True, verbose_name='description'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='members',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='in_clubs', through='gestion.ClubUser', to=settings.AUTH_USER_MODEL, verbose_name='membres du club'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=200, unique=True, verbose_name='nom'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='price',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=5, verbose_name='cotisation (€)'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='clubuser',
|
||||||
|
name='has_paid',
|
||||||
|
field=models.BooleanField(verbose_name='a payé sa cotisation'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='clubuser',
|
||||||
|
name='is_respo',
|
||||||
|
field=models.BooleanField(verbose_name='est responsable du club'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True, verbose_name="commentaires visibles par l'utilisateur"),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='departement',
|
||||||
|
field=models.CharField(blank=True, max_length=50, verbose_name='département'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='login_clipper',
|
||||||
|
field=models.CharField(blank=True, max_length=8, verbose_name='login clipper'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='occupation',
|
||||||
|
field=models.CharField(choices=[('exterieur', 'Extérieur'), ('1A', '1A'), ('2A', '2A'), ('3A', '3A'), ('4A', '4A'), ('archicube', 'Archicube'), ('doctorant', 'Doctorant'), ('CST', 'CST')], default='1A', max_length=9, verbose_name='occupation'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='phone',
|
||||||
|
field=models.CharField(blank=True, max_length=20, verbose_name='téléphone'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='user',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL, verbose_name='utilisateur'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='eventcommentvalue',
|
||||||
|
name='registration',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='gestion.EventRegistration'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='location',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='gestion.Location', verbose_name='lieux'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='club',
|
||||||
|
name='association',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, related_name='clubs', to='gestion.Association', verbose_name='association'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='eventregistration',
|
||||||
|
unique_together=set([('user', 'event')]),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='eventcommentvalue',
|
||||||
|
unique_together=set([('commentfield', 'registration')]),
|
||||||
|
),
|
||||||
|
migrations.RunPython(create_apps, migrations.RunPython.noop),
|
||||||
|
migrations.RunPython(import_events, restore_events),
|
||||||
|
]
|
26
gestion/migrations/0004_event_location_not_mandatory.py
Normal file
26
gestion/migrations/0004_event_location_not_mandatory.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11b1 on 2017-08-07 19:49
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gestion', '0003_association_and_events'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
to='gestion.Location',
|
||||||
|
verbose_name='lieux'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -7,6 +7,11 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from cof.petits_cours_models import choices_length
|
from cof.petits_cours_models import choices_length
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# User management
|
||||||
|
# ---
|
||||||
|
|
||||||
OCCUPATION_CHOICES = (
|
OCCUPATION_CHOICES = (
|
||||||
('exterieur', _("Extérieur")),
|
('exterieur', _("Extérieur")),
|
||||||
('1A', _("1A")),
|
('1A', _("1A")),
|
||||||
|
@ -23,23 +28,29 @@ class Profile(models.Model):
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
User,
|
User,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name="profile"
|
related_name="profile",
|
||||||
|
verbose_name=_("utilisateur"),
|
||||||
)
|
)
|
||||||
login_clipper = models.CharField("Login clipper", max_length=8, blank=True)
|
login_clipper = models.CharField(
|
||||||
phone = models.CharField("Téléphone", max_length=20, blank=True)
|
_("login clipper"),
|
||||||
occupation = models.CharField(_("Occupation"),
|
max_length=8,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
phone = models.CharField(_("téléphone"), max_length=20, blank=True)
|
||||||
|
occupation = models.CharField(_("occupation"),
|
||||||
default="1A",
|
default="1A",
|
||||||
choices=OCCUPATION_CHOICES,
|
choices=OCCUPATION_CHOICES,
|
||||||
max_length=choices_length(
|
max_length=choices_length(
|
||||||
OCCUPATION_CHOICES))
|
OCCUPATION_CHOICES))
|
||||||
departement = models.CharField(_("Département"), max_length=50,
|
departement = models.CharField(_("département"), max_length=50,
|
||||||
blank=True)
|
blank=True)
|
||||||
comments = models.TextField(
|
comments = models.TextField(
|
||||||
"Commentaires visibles par l'utilisateur", blank=True)
|
_("commentaires visibles par l'utilisateur"), blank=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Profil"
|
verbose_name = _("profil")
|
||||||
verbose_name_plural = "Profils"
|
verbose_name_plural = _("profils")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
|
@ -56,6 +67,49 @@ def post_delete_user(sender, instance, *args, **kwargs):
|
||||||
instance.user.delete()
|
instance.user.delete()
|
||||||
|
|
||||||
|
|
||||||
|
class AssociationManager(models.Manager):
|
||||||
|
def get_by_natural_key(self, name):
|
||||||
|
return self.get(name=name)
|
||||||
|
|
||||||
|
|
||||||
|
class Association(models.Model):
|
||||||
|
objects = AssociationManager()
|
||||||
|
|
||||||
|
name = models.CharField(
|
||||||
|
_("nom de l'association"),
|
||||||
|
unique=True,
|
||||||
|
max_length=30
|
||||||
|
)
|
||||||
|
staff_group = models.ForeignKey(
|
||||||
|
Group,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name="staff_group_of",
|
||||||
|
blank=True, null=True,
|
||||||
|
verbose_name=_("groupe des membres du bureau"),
|
||||||
|
)
|
||||||
|
members_group = models.ForeignKey(
|
||||||
|
Group,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name="member_group_of",
|
||||||
|
blank=True, null=True,
|
||||||
|
verbose_name=_("groupe des membres"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def natural_key(self):
|
||||||
|
return [self.name]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("association")
|
||||||
|
verbose_name_plural = _("associations")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Clubs
|
||||||
|
# ---
|
||||||
|
|
||||||
class Club(models.Model):
|
class Club(models.Model):
|
||||||
ANNUAL = "ANN"
|
ANNUAL = "ANN"
|
||||||
SEMESTER = "SEM"
|
SEMESTER = "SEM"
|
||||||
|
@ -67,24 +121,30 @@ class Club(models.Model):
|
||||||
(COURSE, _("Au cours"))
|
(COURSE, _("Au cours"))
|
||||||
]
|
]
|
||||||
|
|
||||||
associations = models.ManyToManyField(Group, related_name="clubs")
|
association = models.ForeignKey(
|
||||||
name = models.CharField(_("Nom"), max_length=200, unique=True)
|
Association,
|
||||||
description = models.TextField("Description", blank=True)
|
on_delete=models.PROTECT,
|
||||||
|
related_name="clubs",
|
||||||
|
verbose_name=_("association"),
|
||||||
|
)
|
||||||
|
name = models.CharField(_("nom"), max_length=200, unique=True)
|
||||||
|
description = models.TextField(_("description"), blank=True)
|
||||||
members = models.ManyToManyField(
|
members = models.ManyToManyField(
|
||||||
User,
|
User,
|
||||||
through="ClubUser",
|
through="ClubUser",
|
||||||
related_name="in_clubs",
|
related_name="in_clubs",
|
||||||
blank=True
|
blank=True,
|
||||||
|
verbose_name=_("membres du club"),
|
||||||
)
|
)
|
||||||
price = models.DecimalField(
|
price = models.DecimalField(
|
||||||
_("Cotisation (€)"),
|
_("cotisation (€)"),
|
||||||
decimal_places=2,
|
decimal_places=2,
|
||||||
max_digits=5,
|
max_digits=5,
|
||||||
blank=True,
|
blank=True,
|
||||||
default=0
|
default=0
|
||||||
)
|
)
|
||||||
cotisation_frequency = models.CharField(
|
cotisation_frequency = models.CharField(
|
||||||
_("Fréquence de la cotisation"),
|
_("fréquence de la cotisation"),
|
||||||
default=ANNUAL,
|
default=ANNUAL,
|
||||||
choices=COTISATION_FREQUENCY_CHOICES,
|
choices=COTISATION_FREQUENCY_CHOICES,
|
||||||
max_length=3,
|
max_length=3,
|
||||||
|
@ -94,10 +154,10 @@ class Club(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
template = (
|
template = (
|
||||||
self.needs_cotiz and
|
self.needs_cotiz and
|
||||||
"{name} ({price}€ / {cotisation_frequency})" or
|
"%(name)s (%(price).2f€ / %(cotisation_frequency)s)" or
|
||||||
"{name}"
|
"%(name)s"
|
||||||
)
|
)
|
||||||
return template.format(**vars(self))
|
return template % vars(self)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('gestion:club_detail', args=[str(self.pk)])
|
return reverse('gestion:club_detail', args=[str(self.pk)])
|
||||||
|
@ -113,5 +173,202 @@ class Club(models.Model):
|
||||||
class ClubUser(models.Model):
|
class ClubUser(models.Model):
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
club = models.ForeignKey(Club, on_delete=models.CASCADE)
|
club = models.ForeignKey(Club, on_delete=models.CASCADE)
|
||||||
is_respo = models.BooleanField(_("Est responsable du club"))
|
is_respo = models.BooleanField(_("est responsable du club"))
|
||||||
has_paid = models.BooleanField(_("A payé sa cotisation"))
|
has_paid = models.BooleanField(_("a payé sa cotisation"))
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Events
|
||||||
|
# ---
|
||||||
|
|
||||||
|
class Location(models.Model):
|
||||||
|
name = models.CharField(_("nom du lieu"), max_length=200)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("lieu")
|
||||||
|
verbose_name_plural = _("lieux")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Event(models.Model):
|
||||||
|
associations = models.ManyToManyField(
|
||||||
|
Association,
|
||||||
|
related_name="events",
|
||||||
|
verbose_name=_("associations"),
|
||||||
|
)
|
||||||
|
title = models.CharField(_("titre"), max_length=200)
|
||||||
|
location = models.ForeignKey(
|
||||||
|
Location,
|
||||||
|
blank=True, null=True,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("lieux"),
|
||||||
|
)
|
||||||
|
start_date = models.DateTimeField(
|
||||||
|
_("début de l'événement"),
|
||||||
|
blank=True, null=True,
|
||||||
|
)
|
||||||
|
end_date = models.DateTimeField(
|
||||||
|
_("fin de l'événement"),
|
||||||
|
blank=True, null=True,
|
||||||
|
)
|
||||||
|
description = models.TextField(_("description"), blank=True)
|
||||||
|
image = models.ImageField(
|
||||||
|
_("image"),
|
||||||
|
blank=True, null=True,
|
||||||
|
upload_to="public/imgs/events/",
|
||||||
|
)
|
||||||
|
registration_open = models.NullBooleanField(
|
||||||
|
_("les inscriptions sont ouvertes"),
|
||||||
|
help_text=_("Indéfini signifie « l'inscription n'est pas requise »"),
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
old = models.BooleanField(_("archiver (événement fini)"), default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("événement")
|
||||||
|
verbose_name_plural = _("événements")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
title, location = self.title, self.location
|
||||||
|
start = self.start_date.date()
|
||||||
|
end = self.end_date.date()
|
||||||
|
if not self.start_date.date():
|
||||||
|
return "{} @ {}".format(title, location)
|
||||||
|
elif start == end:
|
||||||
|
return "{} @ {} ({})".format(title, location, start)
|
||||||
|
else:
|
||||||
|
return "{} @ {} ({} → {})".format(title, location, start, end)
|
||||||
|
|
||||||
|
|
||||||
|
class EventCommentField(models.Model):
|
||||||
|
TEXT = "text"
|
||||||
|
CHAR = "char"
|
||||||
|
|
||||||
|
FIELD_TYPE = [
|
||||||
|
(TEXT, _("Texte long")),
|
||||||
|
(CHAR, _("Texte court")),
|
||||||
|
]
|
||||||
|
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="commentfields",
|
||||||
|
verbose_name=_("événement"),
|
||||||
|
)
|
||||||
|
name = models.CharField(_("nom du champ"), max_length=200)
|
||||||
|
fieldtype = models.CharField(
|
||||||
|
_("type de champ"),
|
||||||
|
max_length=10,
|
||||||
|
choices=FIELD_TYPE, default=TEXT,
|
||||||
|
)
|
||||||
|
default = models.TextField(_("valeur par défaut"), blank=True)
|
||||||
|
ordering = models.IntegerField(
|
||||||
|
_("ordre des champs"),
|
||||||
|
default=0,
|
||||||
|
help_text=_(
|
||||||
|
"plus petit en premier, ordre alphabétique sur le nom si "
|
||||||
|
"ambiguïté"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("champ")
|
||||||
|
verbose_name_plural = _("champs")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class EventCommentValue(models.Model):
|
||||||
|
commentfield = models.ForeignKey(
|
||||||
|
EventCommentField,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="values"
|
||||||
|
)
|
||||||
|
registration = models.ForeignKey(
|
||||||
|
"EventRegistration",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="comments"
|
||||||
|
)
|
||||||
|
content = models.TextField(_("contenu"), blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ("commentfield", "registration")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return (
|
||||||
|
_("Commentaire de %(field_name)s")
|
||||||
|
% {"field_name": self.commentfield}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EventOption(models.Model):
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="options",
|
||||||
|
verbose_name=_("événement"),
|
||||||
|
)
|
||||||
|
name = models.CharField(_("option"), max_length=200)
|
||||||
|
multi_choices = models.BooleanField(_("choix multiples"), default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("option des événements")
|
||||||
|
verbose_name_plural = _("options des événements")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class EventOptionChoice(models.Model):
|
||||||
|
event_option = models.ForeignKey(
|
||||||
|
EventOption,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="choices",
|
||||||
|
verbose_name=_("événement"),
|
||||||
|
)
|
||||||
|
value = models.CharField("Valeur", max_length=200)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("choix")
|
||||||
|
verbose_name_plural = _("choix")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class EventRegistration(models.Model):
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
verbose_name=_("utilisateur"),
|
||||||
|
)
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_("événement"),
|
||||||
|
)
|
||||||
|
options = models.ManyToManyField(
|
||||||
|
EventOptionChoice,
|
||||||
|
verbose_name=_("choix"),
|
||||||
|
)
|
||||||
|
filledcomments = models.ManyToManyField(
|
||||||
|
EventCommentField,
|
||||||
|
through=EventCommentValue,
|
||||||
|
verbose_name=_("commentaires"),
|
||||||
|
)
|
||||||
|
paid = models.BooleanField(_("a payé"), default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("inscription")
|
||||||
|
verbose_name_plural = _("inscriptions")
|
||||||
|
unique_together = ("user", "event")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return (
|
||||||
|
_("Inscription de %(user)s à %(event)s")
|
||||||
|
% {"user": self.user, "event": self.event}
|
||||||
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
source ~/venv/bin/activate
|
source ~/venv/bin/activate
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py loaddata gestion sites articles
|
python manage.py loaddata gestion events sites articles
|
||||||
python manage.py loaddevdata
|
python manage.py loaddevdata
|
||||||
python manage.py syncmails
|
python manage.py syncmails
|
||||||
python manage.py collectstatic --noinput
|
python manage.py collectstatic --noinput
|
||||||
|
|
|
@ -20,3 +20,4 @@ django-widget-tweaks==1.4.1
|
||||||
git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_custommail
|
git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_custommail
|
||||||
ldap3
|
ldap3
|
||||||
git+https://github.com/Aureplop/channels.git#egg=channels
|
git+https://github.com/Aureplop/channels.git#egg=channels
|
||||||
|
django-nested-admin==3.0.17
|
||||||
|
|
Loading…
Reference in a new issue