forked from DGNum/gestioCOF
Merge branch 'master' into k-fet
This commit is contained in:
commit
3d25d1ab77
25 changed files with 650 additions and 199 deletions
|
@ -152,7 +152,7 @@ Il ne vous reste plus qu'à initialiser les modèles de Django avec la commande
|
||||||
|
|
||||||
Une base de donnée pré-remplie est disponible en lançant la commande :
|
Une base de donnée pré-remplie est disponible en lançant la commande :
|
||||||
|
|
||||||
python manage.py loaddata users bda gestion
|
python manage.py loaddata users root bda gestion sites
|
||||||
|
|
||||||
Vous êtes prêts à développer ! Lancer GestioCOF en faisant
|
Vous êtes prêts à développer ! Lancer GestioCOF en faisant
|
||||||
|
|
||||||
|
@ -171,6 +171,6 @@ Pour mettre à jour les modèles après une migration, il faut ensuite faire :
|
||||||
|
|
||||||
## Documentation utilisateur
|
## Documentation utilisateur
|
||||||
|
|
||||||
Une brève documentation utilisateur pour se faliliariser plus vite avec l'outil
|
Une brève documentation utilisateur pour se familiariser plus vite avec l'outil
|
||||||
est accessible sur le
|
est accessible sur le
|
||||||
[wiki](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/home).
|
[wiki](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/home).
|
||||||
|
|
10
bda/admin.py
10
bda/admin.py
|
@ -9,7 +9,7 @@ from django.core.mail import send_mail
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.db.models import Sum, Count
|
from django.db.models import Sum, Count
|
||||||
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
|
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
|
||||||
Attribution, Tirage
|
Attribution, Tirage, Quote, CategorieSpectacle
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
@ -182,7 +182,12 @@ class ChoixSpectacleAdmin(admin.ModelAdmin):
|
||||||
'spectacle__title')
|
'spectacle__title')
|
||||||
|
|
||||||
|
|
||||||
|
class QuoteInline(admin.TabularInline):
|
||||||
|
model = Quote
|
||||||
|
|
||||||
|
|
||||||
class SpectacleAdmin(admin.ModelAdmin):
|
class SpectacleAdmin(admin.ModelAdmin):
|
||||||
|
inlines = [QuoteInline]
|
||||||
model = Spectacle
|
model = Spectacle
|
||||||
list_display = ("title", "date", "tirage", "location", "slots", "price",
|
list_display = ("title", "date", "tirage", "location", "slots", "price",
|
||||||
"listing")
|
"listing")
|
||||||
|
@ -194,7 +199,7 @@ class SpectacleAdmin(admin.ModelAdmin):
|
||||||
class TirageAdmin(admin.ModelAdmin):
|
class TirageAdmin(admin.ModelAdmin):
|
||||||
model = Tirage
|
model = Tirage
|
||||||
list_display = ("title", "ouverture", "fermeture", "active",
|
list_display = ("title", "ouverture", "fermeture", "active",
|
||||||
"enable_do_tirage")
|
"enable_do_tirage")
|
||||||
readonly_fields = ("tokens", )
|
readonly_fields = ("tokens", )
|
||||||
list_filter = ("active", )
|
list_filter = ("active", )
|
||||||
search_fields = ("title", )
|
search_fields = ("title", )
|
||||||
|
@ -205,6 +210,7 @@ class SalleAdmin(admin.ModelAdmin):
|
||||||
search_fields = ('name', 'address')
|
search_fields = ('name', 'address')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(CategorieSpectacle)
|
||||||
admin.site.register(Spectacle, SpectacleAdmin)
|
admin.site.register(Spectacle, SpectacleAdmin)
|
||||||
admin.site.register(Salle, SalleAdmin)
|
admin.site.register(Salle, SalleAdmin)
|
||||||
admin.site.register(Participant, ParticipantAdmin)
|
admin.site.register(Participant, ParticipantAdmin)
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
"description": "Jazz / Funk",
|
"description": "Jazz / Funk",
|
||||||
"title": "Un super concert",
|
"title": "Un super concert",
|
||||||
"price": 10.0,
|
"price": 10.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 2,
|
"location": 2,
|
||||||
"date": "2016-09-30T18:00:00Z",
|
"date": "2016-09-30T18:00:00Z",
|
||||||
|
@ -91,7 +90,6 @@
|
||||||
"description": "Homemade",
|
"description": "Homemade",
|
||||||
"title": "Une super pi\u00e8ce",
|
"title": "Une super pi\u00e8ce",
|
||||||
"price": 10.0,
|
"price": 10.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 3,
|
"location": 3,
|
||||||
"date": "2016-09-29T14:00:00Z",
|
"date": "2016-09-29T14:00:00Z",
|
||||||
|
@ -108,7 +106,6 @@
|
||||||
"description": "Plein air, soleil, bonne musique",
|
"description": "Plein air, soleil, bonne musique",
|
||||||
"title": "Concert pour la f\u00eate de la musique",
|
"title": "Concert pour la f\u00eate de la musique",
|
||||||
"price": 5.0,
|
"price": 5.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 1,
|
"location": 1,
|
||||||
"date": "2016-09-21T15:00:00Z",
|
"date": "2016-09-21T15:00:00Z",
|
||||||
|
@ -125,7 +122,6 @@
|
||||||
"description": "Sous le regard s\u00e9v\u00e8re de Louis Pasteur",
|
"description": "Sous le regard s\u00e9v\u00e8re de Louis Pasteur",
|
||||||
"title": "Op\u00e9ra sans d\u00e9cors",
|
"title": "Op\u00e9ra sans d\u00e9cors",
|
||||||
"price": 5.0,
|
"price": 5.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 4,
|
"location": 4,
|
||||||
"date": "2016-10-06T19:00:00Z",
|
"date": "2016-10-06T19:00:00Z",
|
||||||
|
@ -142,7 +138,6 @@
|
||||||
"description": "Buffet \u00e0 la fin",
|
"description": "Buffet \u00e0 la fin",
|
||||||
"title": "Concert Trouv\u00e8re",
|
"title": "Concert Trouv\u00e8re",
|
||||||
"price": 20.0,
|
"price": 20.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 5,
|
"location": 5,
|
||||||
"date": "2016-11-30T12:00:00Z",
|
"date": "2016-11-30T12:00:00Z",
|
||||||
|
@ -159,7 +154,6 @@
|
||||||
"description": "Vive les maths",
|
"description": "Vive les maths",
|
||||||
"title": "Dessin \u00e0 la craie sur tableau noir",
|
"title": "Dessin \u00e0 la craie sur tableau noir",
|
||||||
"price": 10.0,
|
"price": 10.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 6,
|
"location": 6,
|
||||||
"date": "2016-12-15T07:00:00Z",
|
"date": "2016-12-15T07:00:00Z",
|
||||||
|
@ -176,7 +170,6 @@
|
||||||
"description": "Une pi\u00e8ce \u00e0 un personnage",
|
"description": "Une pi\u00e8ce \u00e0 un personnage",
|
||||||
"title": "D\u00e9cors, d\u00e9montage en musique",
|
"title": "D\u00e9cors, d\u00e9montage en musique",
|
||||||
"price": 0.0,
|
"price": 0.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 3,
|
"location": 3,
|
||||||
"date": "2016-12-26T07:00:00Z",
|
"date": "2016-12-26T07:00:00Z",
|
||||||
|
@ -193,7 +186,6 @@
|
||||||
"description": "Annulera, annulera pas\u00a0?",
|
"description": "Annulera, annulera pas\u00a0?",
|
||||||
"title": "La Nuit",
|
"title": "La Nuit",
|
||||||
"price": 27.0,
|
"price": 27.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 1,
|
"location": 1,
|
||||||
"date": "2016-11-14T23:00:00Z",
|
"date": "2016-11-14T23:00:00Z",
|
||||||
|
@ -210,7 +202,6 @@
|
||||||
"description": "Le boum fait sa carte blanche",
|
"description": "Le boum fait sa carte blanche",
|
||||||
"title": "Turbomix",
|
"title": "Turbomix",
|
||||||
"price": 10.0,
|
"price": 10.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 2,
|
"location": 2,
|
||||||
"date": "2017-01-10T20:00:00Z",
|
"date": "2017-01-10T20:00:00Z",
|
||||||
|
@ -227,7 +218,6 @@
|
||||||
"description": "Unique repr\u00e9sentation",
|
"description": "Unique repr\u00e9sentation",
|
||||||
"title": "Carinettes et trombone",
|
"title": "Carinettes et trombone",
|
||||||
"price": 15.0,
|
"price": 15.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 5,
|
"location": 5,
|
||||||
"date": "2017-01-02T14:00:00Z",
|
"date": "2017-01-02T14:00:00Z",
|
||||||
|
@ -244,7 +234,6 @@
|
||||||
"description": "Suivi d'une jam session",
|
"description": "Suivi d'une jam session",
|
||||||
"title": "Percussion sur rondins",
|
"title": "Percussion sur rondins",
|
||||||
"price": 5.0,
|
"price": 5.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 4,
|
"location": 4,
|
||||||
"date": "2017-01-13T14:00:00Z",
|
"date": "2017-01-13T14:00:00Z",
|
||||||
|
@ -261,7 +250,6 @@
|
||||||
"description": "\u00c9preuve sportive et artistique",
|
"description": "\u00c9preuve sportive et artistique",
|
||||||
"title": "Bassin aux ernests, nage libre",
|
"title": "Bassin aux ernests, nage libre",
|
||||||
"price": 5.0,
|
"price": 5.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 1,
|
"location": 1,
|
||||||
"date": "2016-11-17T09:00:00Z",
|
"date": "2016-11-17T09:00:00Z",
|
||||||
|
@ -278,7 +266,6 @@
|
||||||
"description": "Sonore",
|
"description": "Sonore",
|
||||||
"title": "Chant du barde",
|
"title": "Chant du barde",
|
||||||
"price": 13.0,
|
"price": 13.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 2,
|
"location": 2,
|
||||||
"date": "2017-02-26T07:00:00Z",
|
"date": "2017-02-26T07:00:00Z",
|
||||||
|
@ -295,7 +282,6 @@
|
||||||
"description": "Cocorico",
|
"description": "Cocorico",
|
||||||
"title": "Chant du coq",
|
"title": "Chant du coq",
|
||||||
"price": 4.0,
|
"price": 4.0,
|
||||||
"priority": 1000,
|
|
||||||
"rappel_sent": null,
|
"rappel_sent": null,
|
||||||
"location": 1,
|
"location": 1,
|
||||||
"date": "2016-12-17T04:00:00Z",
|
"date": "2016-12-17T04:00:00Z",
|
||||||
|
|
89
bda/migrations/0007_extends_spectacle.py
Normal file
89
bda/migrations/0007_extends_spectacle.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bda', '0006_add_tirage_switch'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CategorieSpectacle',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False,
|
||||||
|
auto_created=True, primary_key=True)),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Nom',
|
||||||
|
unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Cat\xe9gorie',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Quote',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False,
|
||||||
|
auto_created=True, primary_key=True)),
|
||||||
|
('text', models.TextField(verbose_name='Citation')),
|
||||||
|
('author', models.CharField(max_length=200,
|
||||||
|
verbose_name='Auteur')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='spectacle',
|
||||||
|
options={'ordering': ('date', 'title'),
|
||||||
|
'verbose_name': 'Spectacle'},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='spectacle',
|
||||||
|
name='priority',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='spectacle',
|
||||||
|
name='ext_link',
|
||||||
|
field=models.CharField(
|
||||||
|
max_length=500,
|
||||||
|
verbose_name='Lien vers le site du spectacle',
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='spectacle',
|
||||||
|
name='image',
|
||||||
|
field=models.ImageField(upload_to='imgs/shows/', null=True,
|
||||||
|
verbose_name='Image', blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='tirage',
|
||||||
|
name='enable_do_tirage',
|
||||||
|
field=models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name='Le tirage peut \xeatre lanc\xe9'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='tirage',
|
||||||
|
name='tokens',
|
||||||
|
field=models.TextField(verbose_name='Graine(s) du tirage',
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='spectacle',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle',
|
||||||
|
null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='spectacle',
|
||||||
|
name='vips',
|
||||||
|
field=models.TextField(verbose_name='Personnalit\xe9s',
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='quote',
|
||||||
|
name='spectacle',
|
||||||
|
field=models.ForeignKey(to='bda.Spectacle'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -29,7 +29,7 @@ class Tirage(models.Model):
|
||||||
tokens = models.TextField("Graine(s) du tirage", blank=True)
|
tokens = models.TextField("Graine(s) du tirage", blank=True)
|
||||||
active = models.BooleanField("Tirage actif", default=False)
|
active = models.BooleanField("Tirage actif", default=False)
|
||||||
enable_do_tirage = models.BooleanField("Le tirage peut être lancé",
|
enable_do_tirage = models.BooleanField("Le tirage peut être lancé",
|
||||||
default=False)
|
default=False)
|
||||||
|
|
||||||
def date_no_seconds(self):
|
def date_no_seconds(self):
|
||||||
return self.fermeture.strftime('%d %b %Y %H:%M')
|
return self.fermeture.strftime('%d %b %Y %H:%M')
|
||||||
|
@ -47,16 +47,32 @@ class Salle(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class CategorieSpectacle(models.Model):
|
||||||
|
name = models.CharField('Nom', max_length=100, unique=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Catégorie"
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Spectacle(models.Model):
|
class Spectacle(models.Model):
|
||||||
title = models.CharField("Titre", max_length=300)
|
title = models.CharField("Titre", max_length=300)
|
||||||
|
category = models.ForeignKey(CategorieSpectacle, blank=True, null=True)
|
||||||
date = models.DateTimeField("Date & heure")
|
date = models.DateTimeField("Date & heure")
|
||||||
location = models.ForeignKey(Salle)
|
location = models.ForeignKey(Salle)
|
||||||
|
vips = models.TextField('Personnalités', blank=True)
|
||||||
description = models.TextField("Description", blank=True)
|
description = models.TextField("Description", blank=True)
|
||||||
slots_description = models.TextField("Description des places", blank=True)
|
slots_description = models.TextField("Description des places", blank=True)
|
||||||
|
image = models.ImageField('Image', blank=True, null=True,
|
||||||
|
upload_to='imgs/shows/')
|
||||||
|
ext_link = models.CharField('Lien vers le site du spectacle', blank=True,
|
||||||
|
max_length=500)
|
||||||
price = models.FloatField("Prix d'une place")
|
price = models.FloatField("Prix d'une place")
|
||||||
slots = models.IntegerField("Places")
|
slots = models.IntegerField("Places")
|
||||||
priority = models.IntegerField("Priorité", default=1000)
|
|
||||||
tirage = models.ForeignKey(Tirage)
|
tirage = models.ForeignKey(Tirage)
|
||||||
listing = models.BooleanField("Les places sont sur listing")
|
listing = models.BooleanField("Les places sont sur listing")
|
||||||
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
|
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
|
||||||
|
@ -64,7 +80,7 @@ class Spectacle(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Spectacle"
|
verbose_name = "Spectacle"
|
||||||
ordering = ("priority", "date", "title",)
|
ordering = ("date", "title",)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "[%s]" % self
|
return "[%s]" % self
|
||||||
|
@ -111,6 +127,13 @@ class Spectacle(models.Model):
|
||||||
# On renvoie la liste des destinataires
|
# On renvoie la liste des destinataires
|
||||||
return members.values()
|
return members.values()
|
||||||
|
|
||||||
|
|
||||||
|
class Quote(models.Model):
|
||||||
|
spectacle = models.ForeignKey(Spectacle)
|
||||||
|
text = models.TextField('Citation')
|
||||||
|
author = models.CharField('Auteur', max_length=200)
|
||||||
|
|
||||||
|
|
||||||
PAYMENT_TYPES = (
|
PAYMENT_TYPES = (
|
||||||
("cash", "Cash"),
|
("cash", "Cash"),
|
||||||
("cb", "CB"),
|
("cb", "CB"),
|
||||||
|
|
BIN
bda/static/fonts/josefinsans.ttf
Normal file
BIN
bda/static/fonts/josefinsans.ttf
Normal file
Binary file not shown.
71
bda/templates/descriptions.html
Normal file
71
bda/templates/descriptions.html
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
{% load staticfiles %}
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: josefinsans;
|
||||||
|
src: url({% static "fonts/josefinsans.ttf" %});
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-moz-selection {
|
||||||
|
background: #B0B0B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::selection {
|
||||||
|
background: #B0B0B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.descTable{
|
||||||
|
width: auto;
|
||||||
|
margin: 0 auto 1em;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 2;
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
font-family: 'josefinsans', 'Arial';
|
||||||
|
font-weight: 700;
|
||||||
|
color: #5a5a5a;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% for show in shows %}
|
||||||
|
<table class="descTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2"><p style="text-align:center;font-size:22px;">{{ show.title }}</p></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><p style="text-align: left;">{{ show.location }}</p></td><td class="column-2"><p style="text-align: right;">{{ show.category }}</p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><p style="text-align: left;">{{ show.date }}</p></td><td class="column-2"><p style="text-align: right;">{{ show.slots }} place{{ show.slots|pluralize}} {% if show.slots_description != "" %}({{ show.slots_description }}){% endif %}- {{ show.price }}</p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><p style="text-align: justify;">{{ show.category }}</p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<p style="text-align: justify;">{{ show.description }}</p>
|
||||||
|
{% for quote in show.quote_set.all %}
|
||||||
|
<p style="text-align:center; font-style: italic;">«{{ quote.text }}»{% if show.quote.author %} - {{ quote.author }}{% endif %}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if show.image %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><p style="text-align:center;"><a href="{{ show.ext_link }}"><img style="display: inline;" src="{{ MEDIA_URL }}{{ show.image }}" alt="{{ show.title }}" width="200px"></a></p></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -39,14 +39,15 @@
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
jQuery(document).ready(function($) {
|
jQuery(document).ready(function($) {
|
||||||
$(".clickable-row").click(function() {
|
$(".clickable-row").click(function() {
|
||||||
window.document.location = $(this).data("href");
|
window.document.location = $(this).data("href");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h3> Exports </h3>
|
<h3> Exports </h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
|
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
|
||||||
|
<li><a href="{% url 'bda-descriptions' tirage_id %}">Lien vers les descriptions des spectacles, à utiliser dans une page wordpress</a>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
from gestioncof.decorators import buro_required
|
||||||
from bda.views import SpectacleListView
|
from bda.views import SpectacleListView
|
||||||
from bda import views
|
from bda import views
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ urlpatterns = [
|
||||||
name='bda-etat-places'),
|
name='bda-etat-places'),
|
||||||
url(r'^tirage/(?P<tirage_id>\d+)$', views.tirage),
|
url(r'^tirage/(?P<tirage_id>\d+)$', views.tirage),
|
||||||
url(r'^spectacles/(?P<tirage_id>\d+)$',
|
url(r'^spectacles/(?P<tirage_id>\d+)$',
|
||||||
SpectacleListView.as_view(),
|
buro_required(SpectacleListView.as_view()),
|
||||||
name="bda-liste-spectacles"),
|
name="bda-liste-spectacles"),
|
||||||
url(r'^spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
url(r'^spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
||||||
views.spectacle,
|
views.spectacle,
|
||||||
|
@ -32,4 +33,6 @@ urlpatterns = [
|
||||||
views.unpaid,
|
views.unpaid,
|
||||||
name="bda-unpaid"),
|
name="bda-unpaid"),
|
||||||
url(r'^mails-rappel/(?P<spectacle_id>\d+)$', views.send_rappel),
|
url(r'^mails-rappel/(?P<spectacle_id>\d+)$', views.send_rappel),
|
||||||
|
url(r'^descriptions/(?P<tirage_id>\d+)$', views.descriptions_spectacles,
|
||||||
|
name='bda-descriptions'),
|
||||||
]
|
]
|
||||||
|
|
21
bda/views.py
21
bda/views.py
|
@ -10,13 +10,13 @@ from django.db import models
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
from django.forms.models import inlineformset_factory
|
from django.forms.models import inlineformset_factory
|
||||||
|
from django.http import HttpResponseBadRequest
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from gestioncof.decorators import cof_required, buro_required
|
from gestioncof.decorators import cof_required, buro_required
|
||||||
|
@ -110,8 +110,7 @@ def places(request, tirage_id):
|
||||||
def inscription(request, tirage_id):
|
def inscription(request, tirage_id):
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
if timezone.now() < tirage.ouverture:
|
if timezone.now() < tirage.ouverture:
|
||||||
error_desc = "Ouverture le %s" % (
|
error_desc = tirage.ouverture.strftime('Ouverture le %d %b %Y à %H:%M')
|
||||||
tirage.ouverture.strftime('%d %b %Y à %H:%M'))
|
|
||||||
return render(request, 'resume_inscription.html',
|
return render(request, 'resume_inscription.html',
|
||||||
{"error_title": "Le tirage n'est pas encore ouvert !",
|
{"error_title": "Le tirage n'est pas encore ouvert !",
|
||||||
"error_description": error_desc})
|
"error_description": error_desc})
|
||||||
|
@ -366,3 +365,19 @@ def send_rappel(request, spectacle_id):
|
||||||
else:
|
else:
|
||||||
ctxt['sent'] = False
|
ctxt['sent'] = False
|
||||||
return render(request, "mails-rappel.html", ctxt)
|
return render(request, "mails-rappel.html", ctxt)
|
||||||
|
|
||||||
|
|
||||||
|
def descriptions_spectacles(request, tirage_id):
|
||||||
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
|
shows_qs = tirage.spectacle_set
|
||||||
|
category_name = request.GET.get('category', '')
|
||||||
|
location_id = request.GET.get('location', '')
|
||||||
|
if category_name:
|
||||||
|
shows_qs = shows_qs.filter(category__name=category_name)
|
||||||
|
if location_id:
|
||||||
|
try:
|
||||||
|
shows_qs = shows_qs.filter(location__id=int(location_id))
|
||||||
|
except ValueError:
|
||||||
|
return HttpResponseBadRequest(
|
||||||
|
"La variable GET 'location' doit contenir un entier")
|
||||||
|
return render(request, 'descriptions.html', {'shows': shows_qs.all()})
|
||||||
|
|
|
@ -16,7 +16,8 @@ from django.contrib.auth import views as django_views
|
||||||
from django_cas_ng import views as django_cas_views
|
from django_cas_ng import views as django_cas_views
|
||||||
from gestioncof import views as gestioncof_views, csv_views
|
from gestioncof import views as gestioncof_views, csv_views
|
||||||
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
||||||
surveys_patterns, events_patterns, calendar_patterns
|
surveys_patterns, events_patterns, calendar_patterns, \
|
||||||
|
clubs_patterns
|
||||||
|
|
||||||
from gestioncof.autocomplete import autocomplete
|
from gestioncof.autocomplete import autocomplete
|
||||||
|
|
||||||
|
@ -38,6 +39,8 @@ urlpatterns = [
|
||||||
url(r'^event/', include(events_patterns)),
|
url(r'^event/', include(events_patterns)),
|
||||||
# Calendrier
|
# Calendrier
|
||||||
url(r'^calendar/', include(calendar_patterns)),
|
url(r'^calendar/', include(calendar_patterns)),
|
||||||
|
# Clubs
|
||||||
|
url(r'^clubs/', include(clubs_patterns)),
|
||||||
# Authentification
|
# Authentification
|
||||||
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
|
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
|
||||||
name="cof-denied"),
|
name="cof-denied"),
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
|
from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
|
||||||
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
|
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
|
||||||
|
@ -232,6 +233,25 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin):
|
||||||
class CustomMailAdmin(admin.ModelAdmin):
|
class CustomMailAdmin(admin.ModelAdmin):
|
||||||
search_fields = ('shortname', 'title')
|
search_fields = ('shortname', 'title')
|
||||||
|
|
||||||
|
|
||||||
|
class ClubAdminForm(forms.ModelForm):
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super(ClubAdminForm, self).clean()
|
||||||
|
respos = cleaned_data.get('respos')
|
||||||
|
members = cleaned_data.get('membres')
|
||||||
|
for respo in respos.all():
|
||||||
|
if respo not in members:
|
||||||
|
raise forms.ValidationError(
|
||||||
|
"Erreur : le respo %s n'est pas membre du club."
|
||||||
|
% respo.get_full_name())
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class ClubAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['name']
|
||||||
|
form = ClubAdminForm
|
||||||
|
|
||||||
|
|
||||||
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(Event, EventAdmin)
|
||||||
|
@ -239,7 +259,7 @@ admin.site.register(EventOption, EventOptionAdmin)
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User, UserProfileAdmin)
|
admin.site.register(User, UserProfileAdmin)
|
||||||
admin.site.register(CofProfile)
|
admin.site.register(CofProfile)
|
||||||
admin.site.register(Club)
|
admin.site.register(Club, ClubAdmin)
|
||||||
admin.site.register(CustomMail)
|
admin.site.register(CustomMail)
|
||||||
admin.site.register(PetitCoursSubject)
|
admin.site.register(PetitCoursSubject)
|
||||||
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
||||||
|
|
10
gestioncof/fixtures/sites.json
Normal file
10
gestioncof/fixtures/sites.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"domain": "localhost",
|
||||||
|
"name": "GestioCOF - dev - local"
|
||||||
|
},
|
||||||
|
"model": "sites.site",
|
||||||
|
"pk": 1
|
||||||
|
}
|
||||||
|
]
|
|
@ -8,10 +8,12 @@ from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
|
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
|
||||||
|
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 gestioncof.models import CofProfile, EventCommentValue, \
|
from gestioncof.models import CofProfile, EventCommentValue, \
|
||||||
CalendarSubscription
|
CalendarSubscription, Club
|
||||||
from gestioncof.widgets import TriStateCheckbox
|
from gestioncof.widgets import TriStateCheckbox
|
||||||
from gestioncof.shared import lock_table, unlock_table
|
from gestioncof.shared import lock_table, unlock_table
|
||||||
|
|
||||||
|
@ -183,14 +185,6 @@ class UserProfileForm(forms.ModelForm):
|
||||||
super(UserProfileForm, self).__init__(*args, **kw)
|
super(UserProfileForm, self).__init__(*args, **kw)
|
||||||
self.fields['first_name'].initial = self.instance.user.first_name
|
self.fields['first_name'].initial = self.instance.user.first_name
|
||||||
self.fields['last_name'].initial = self.instance.user.last_name
|
self.fields['last_name'].initial = self.instance.user.last_name
|
||||||
self.fields.keyOrder = [
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'phone',
|
|
||||||
'mailing_cof',
|
|
||||||
'mailing_bda',
|
|
||||||
'mailing_bda_revente',
|
|
||||||
]
|
|
||||||
|
|
||||||
def save(self, *args, **kw):
|
def save(self, *args, **kw):
|
||||||
super(UserProfileForm, self).save(*args, **kw)
|
super(UserProfileForm, self).save(*args, **kw)
|
||||||
|
@ -200,8 +194,8 @@ class UserProfileForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CofProfile
|
model = CofProfile
|
||||||
fields = ("phone", "mailing_cof", "mailing_bda",
|
fields = ["first_name", "last_name", "phone", "mailing_cof",
|
||||||
"mailing_bda_revente", )
|
"mailing_bda", "mailing_bda_revente"]
|
||||||
|
|
||||||
|
|
||||||
class RegistrationUserForm(forms.ModelForm):
|
class RegistrationUserForm(forms.ModelForm):
|
||||||
|
@ -209,11 +203,40 @@ class RegistrationUserForm(forms.ModelForm):
|
||||||
super(RegistrationUserForm, self).__init__(*args, **kw)
|
super(RegistrationUserForm, self).__init__(*args, **kw)
|
||||||
self.fields['username'].help_text = ""
|
self.fields['username'].help_text = ""
|
||||||
|
|
||||||
|
def force_long_username(self):
|
||||||
|
self.fields['username'].validators = [MinLengthValidator(9)]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ("username", "first_name", "last_name", "email")
|
fields = ("username", "first_name", "last_name", "email")
|
||||||
|
|
||||||
|
|
||||||
|
class RegistrationPassUserForm(RegistrationUserForm):
|
||||||
|
"""
|
||||||
|
Formulaire pour changer le mot de passe d'un utilisateur.
|
||||||
|
"""
|
||||||
|
password1 = forms.CharField(label=_('Mot de passe'),
|
||||||
|
widget=forms.PasswordInput)
|
||||||
|
password2 = forms.CharField(label=_('Confirmation du mot de passe'),
|
||||||
|
widget=forms.PasswordInput)
|
||||||
|
|
||||||
|
def clean_password2(self):
|
||||||
|
pass1 = self.cleaned_data['password1']
|
||||||
|
pass2 = self.cleaned_data['password2']
|
||||||
|
if pass1 and pass2:
|
||||||
|
if pass1 != pass2:
|
||||||
|
raise forms.ValidationError(_('Mots de passe non identiques.'))
|
||||||
|
return pass2
|
||||||
|
|
||||||
|
def save(self, commit=True, *args, **kwargs):
|
||||||
|
user = super(RegistrationPassUserForm, self).save(commit, *args,
|
||||||
|
**kwargs)
|
||||||
|
user.set_password(self.cleaned_data['password2'])
|
||||||
|
if commit:
|
||||||
|
user.save()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
class RegistrationProfileForm(forms.ModelForm):
|
class RegistrationProfileForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
super(RegistrationProfileForm, self).__init__(*args, **kw)
|
super(RegistrationProfileForm, self).__init__(*args, **kw)
|
||||||
|
@ -263,17 +286,15 @@ STATUS_CHOICES = (('no', 'Non'),
|
||||||
|
|
||||||
|
|
||||||
class AdminEventForm(forms.Form):
|
class AdminEventForm(forms.Form):
|
||||||
status = forms.ChoiceField(label="Inscription",
|
status = forms.ChoiceField(label="Inscription", initial="no",
|
||||||
choices=STATUS_CHOICES, widget=RadioSelect)
|
choices=STATUS_CHOICES, widget=RadioSelect)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
event = kwargs.pop("event")
|
self.event = kwargs.pop("event")
|
||||||
self.event = event
|
|
||||||
registration = kwargs.pop("current_registration", None)
|
registration = kwargs.pop("current_registration", None)
|
||||||
current_choices = \
|
current_choices, paid = \
|
||||||
registration.options.all() if registration is not None\
|
(registration.options.all(), registration.paid) \
|
||||||
else []
|
if registration is not None else ([], None)
|
||||||
paid = kwargs.pop("paid", None)
|
|
||||||
if paid is True:
|
if paid is True:
|
||||||
kwargs["initial"] = {"status": "paid"}
|
kwargs["initial"] = {"status": "paid"}
|
||||||
elif paid is False:
|
elif paid is False:
|
||||||
|
@ -288,7 +309,7 @@ class AdminEventForm(forms.Form):
|
||||||
else:
|
else:
|
||||||
choices[choice.event_option.id].append(choice.id)
|
choices[choice.event_option.id].append(choice.id)
|
||||||
all_choices = choices
|
all_choices = choices
|
||||||
for option in event.options.all():
|
for option in self.event.options.all():
|
||||||
choices = [(choice.id, choice.value)
|
choices = [(choice.id, choice.value)
|
||||||
for choice in option.choices.all()]
|
for choice in option.choices.all()]
|
||||||
if option.multi_choices:
|
if option.multi_choices:
|
||||||
|
@ -310,7 +331,7 @@ class AdminEventForm(forms.Form):
|
||||||
initial=initial)
|
initial=initial)
|
||||||
field.option_id = option.id
|
field.option_id = option.id
|
||||||
self.fields["option_%d" % option.id] = field
|
self.fields["option_%d" % option.id] = field
|
||||||
for commentfield in event.commentfields.all():
|
for commentfield in self.event.commentfields.all():
|
||||||
initial = commentfield.default
|
initial = commentfield.default
|
||||||
if registration is not None:
|
if registration is not None:
|
||||||
try:
|
try:
|
||||||
|
@ -338,6 +359,22 @@ class AdminEventForm(forms.Form):
|
||||||
yield (self.fields[name].comment_id, value)
|
yield (self.fields[name].comment_id, value)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseEventRegistrationFormset(BaseFormSet):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.events = kwargs.pop('events')
|
||||||
|
self.current_registrations = kwargs.pop('current_registrations', None)
|
||||||
|
self.extra = len(self.events)
|
||||||
|
super(BaseEventRegistrationFormset, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _construct_form(self, index, **kwargs):
|
||||||
|
kwargs['event'] = self.events[index]
|
||||||
|
if self.current_registrations is not None:
|
||||||
|
kwargs['current_registration'] = self.current_registrations[index]
|
||||||
|
return super(BaseEventRegistrationFormset, self)._construct_form(
|
||||||
|
index, **kwargs)
|
||||||
|
EventFormset = formset_factory(AdminEventForm, BaseEventRegistrationFormset)
|
||||||
|
|
||||||
|
|
||||||
class CalendarForm(forms.ModelForm):
|
class CalendarForm(forms.ModelForm):
|
||||||
subscribe_to_events = forms.BooleanField(
|
subscribe_to_events = forms.BooleanField(
|
||||||
initial=True,
|
initial=True,
|
||||||
|
@ -348,9 +385,21 @@ class CalendarForm(forms.ModelForm):
|
||||||
other_shows = forms.ModelMultipleChoiceField(
|
other_shows = forms.ModelMultipleChoiceField(
|
||||||
label="Spectacles supplémentaires.",
|
label="Spectacles supplémentaires.",
|
||||||
queryset=Spectacle.objects.filter(tirage__active=True),
|
queryset=Spectacle.objects.filter(tirage__active=True),
|
||||||
widget=forms.CheckboxSelectMultiple)
|
widget=forms.CheckboxSelectMultiple,
|
||||||
|
required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CalendarSubscription
|
model = CalendarSubscription
|
||||||
fields = ['subscribe_to_events', 'subscribe_to_my_shows',
|
fields = ['subscribe_to_events', 'subscribe_to_my_shows',
|
||||||
'other_shows']
|
'other_shows']
|
||||||
|
|
||||||
|
|
||||||
|
class ClubsForm(forms.Form):
|
||||||
|
"""
|
||||||
|
Formulaire d'inscription d'un membre à plusieurs clubs du COF.
|
||||||
|
"""
|
||||||
|
clubs = forms.ModelMultipleChoiceField(
|
||||||
|
label="Inscriptions aux clubs du COF",
|
||||||
|
queryset=Club.objects.all(),
|
||||||
|
widget=forms.CheckboxSelectMultiple,
|
||||||
|
required=False)
|
||||||
|
|
47
gestioncof/migrations/0007_alter_club.py
Normal file
47
gestioncof/migrations/0007_alter_club.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gestioncof', '0006_add_calendar'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(unique=True, max_length=200,
|
||||||
|
verbose_name='Nom')
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(verbose_name='Description', blank=True)
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='membres',
|
||||||
|
field=models.ManyToManyField(related_name='clubs',
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='club',
|
||||||
|
name='respos',
|
||||||
|
field=models.ManyToManyField(related_name='clubs_geres',
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='start_date',
|
||||||
|
field=models.DateTimeField(null=True,
|
||||||
|
verbose_name='Date de d\xe9but',
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -86,10 +86,11 @@ post_save.connect(create_user_profile, sender=User)
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Club(models.Model):
|
class Club(models.Model):
|
||||||
name = models.CharField("Nom", max_length=200)
|
name = models.CharField("Nom", max_length=200, unique=True)
|
||||||
description = models.TextField("Description")
|
description = models.TextField("Description", blank=True)
|
||||||
respos = models.ManyToManyField(User, related_name="clubs_geres")
|
respos = models.ManyToManyField(User, related_name="clubs_geres",
|
||||||
membres = models.ManyToManyField(User, related_name="clubs")
|
blank=True)
|
||||||
|
membres = models.ManyToManyField(User, related_name="clubs", blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
|
@ -825,6 +825,16 @@ input#search_autocomplete:focus {
|
||||||
color: #343a4a;
|
color: #343a4a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=number][readonly] {
|
||||||
|
-moz-appearance:textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=number][readonly]::-webkit-inner-spin-button,
|
||||||
|
input[type=number][readonly]::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.autocomplete {
|
.autocomplete {
|
||||||
margin-bottom:5px;
|
margin-bottom:5px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ souscrire aux événements du COF et/ou aux spectacles BdA.
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
<input type="submit" value="Enregistrer" />
|
<input type="submit" value="Enregistrer" class="btn btn-primary" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -37,26 +37,29 @@
|
||||||
{% for tirage in open_tirages %}
|
{% for tirage in open_tirages %}
|
||||||
<ul>
|
<ul>
|
||||||
<h4>{{ tirage.title }}</h4>
|
<h4>{{ tirage.title }}</h4>
|
||||||
<li><a href="{% url "bda-tirage-inscription" tirage.id %}">Inscription</a></li>
|
{% if tirage.fermeture > now %}
|
||||||
<li><a href="{% url "bda-etat-places" tirage.id %}">État des demandes</a>
|
<li><a href="{% url "bda-tirage-inscription" tirage.id %}">Inscription</a></li>
|
||||||
<li><a href="{% url "bda-places-attribuees" tirage.id %}">Mes places</a></li>
|
<li><a href="{% url "bda-etat-places" tirage.id %}">État des demandes</a></li>
|
||||||
<li><a href="{% url "bda-revente" tirage.id %}">Revendre une place</a></li>
|
{% else %}
|
||||||
|
<li><a href="{% url "bda-places-attribuees" tirage.id %}">Mes places</a></li>
|
||||||
|
<li><a href="{% url "bda-revente" tirage.id %}">Revendre une place</a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3>
|
<h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3>
|
||||||
<div class="hm-block">
|
<div class="hm-block">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url "gestioncof.views.calendar" %}">Calendrier dynamique</a></li>
|
<li><a href="{% url "gestioncof.views.calendar" %}">Calendrier dynamique</a></li>
|
||||||
{% if user.profile.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %}
|
{% if user.profile.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %}
|
||||||
|
|
||||||
<li><a href="{% url "gestioncof.views.profile" %}">Éditer mon profil</a></li>
|
<li><a href="{% url "gestioncof.views.profile" %}">Éditer mon profil</a></li>
|
||||||
{% if not user.profile.login_clipper %}<li><a href="{% url "django.contrib.auth.views.password_change" %}">Changer mon mot de passe</a></li>{% endif %}
|
{% if not user.profile.login_clipper %}<li><a href="{% url "django.contrib.auth.views.password_change" %}">Changer mon mot de passe</a></li>{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if user.profile.is_buro %}
|
{% if user.profile.is_buro %}
|
||||||
<div class="col-sm-6 buro-user-hm">
|
<div class="col-sm-6 buro-user-hm">
|
||||||
|
@ -67,6 +70,7 @@
|
||||||
<li><a href="{% url "admin:index" %}">Administration générale</a></li>
|
<li><a href="{% url "admin:index" %}">Administration générale</a></li>
|
||||||
<li><a href="{% url "petits-cours-demandes-list" %}">Demandes de petits cours</a></li>
|
<li><a href="{% url "petits-cours-demandes-list" %}">Demandes de petits cours</a></li>
|
||||||
<li><a href="{% url "gestioncof.views.registration" %}">Inscription d'un nouveau membre</a></li>
|
<li><a href="{% url "gestioncof.views.registration" %}">Inscription d'un nouveau membre</a></li>
|
||||||
|
<li><a href="{% url "liste-clubs" %}">Gestion des clubs</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<h4>Évènements & Sondages</h4>
|
<h4>Évènements & Sondages</h4>
|
||||||
|
@ -80,12 +84,15 @@
|
||||||
</div>
|
</div>
|
||||||
<h3 class="block-title">Gestion tirages BDA<span class="pull-right glyphicon glyphicon-list"></span></h3>
|
<h3 class="block-title">Gestion tirages BDA<span class="pull-right glyphicon glyphicon-list"></span></h3>
|
||||||
<div class="hm-block">
|
<div class="hm-block">
|
||||||
{% if open_tirages %}
|
{% if active_tirages %}
|
||||||
{% for tirage in open_tirages %}
|
{% for tirage in active_tirages %}
|
||||||
<ul>
|
<ul>
|
||||||
<h4>{{ tirage.title }}</h4>
|
<h4>{{ tirage.title }}</h4>
|
||||||
<li><a href="{% url "bda-liste-spectacles" tirage.id %}">Spectacles</a></li>
|
<li><a href="{% url "bda-liste-spectacles" tirage.id %}">Spectacles</a></li>
|
||||||
<li><a href="{% url "admin:bda_participant_changelist" %}?tirage__id__exact={{ tirage.id }}">Participants</a></li>
|
<li><a href="{% url "admin:bda_participant_changelist" %}?tirage__id__exact={{ tirage.id }}">Participants</a></li>
|
||||||
|
{% if tirage.fermeture < now %}
|
||||||
|
<li><a href="{% url "bda-etat-places" tirage.id %}">Ratios</a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
25
gestioncof/templates/liste_clubs.html
Normal file
25
gestioncof/templates/liste_clubs.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
|
{% block page_size %}col-sm-8{% endblock %}
|
||||||
|
|
||||||
|
{% block realcontent %}
|
||||||
|
<h2>Clubs enregistrés sur GestioCOF</h2>
|
||||||
|
<ul>
|
||||||
|
{% for club in owned_clubs %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "membres-club" club.name %}">
|
||||||
|
{{ club }} ({% for respo in club.respos.all %}{{ respo.get_full_name }}, {% empty %}pas de respo{% endfor %})
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% if other_clubs %}
|
||||||
|
{% for club in other_clubs %}
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
{{ club }} ({% for respo in club.respos.all %}{{ respo.get_full_name }}, {% empty %}pas de respo{% endfor %})
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
41
gestioncof/templates/membres_clubs.html
Normal file
41
gestioncof/templates/membres_clubs.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block realcontent %}
|
||||||
|
<h2>{{ club }}</h2>
|
||||||
|
|
||||||
|
|
||||||
|
{% if club.respos.exists %}
|
||||||
|
<h3>Respo{{ club.respos.all|pluralize }}</h3>
|
||||||
|
<table class="table table-striped">
|
||||||
|
{% for member in club.respos.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ member }}</td>
|
||||||
|
<td>{{ member.email }}</td>
|
||||||
|
<td><a class="glyphicon glyphicon-arrow-down"
|
||||||
|
href="{% url "change-respo" club.name member.id %}"></a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<h3>Pas de respo</h3>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if club.membres.exists %}
|
||||||
|
<h3>Liste des membres</h3>
|
||||||
|
<table class="table table-striped">
|
||||||
|
{% for member in members_no_respo %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ member }}</td>
|
||||||
|
<td>{{ member.email }}</td>
|
||||||
|
<td><a class="glyphicon glyphicon-arrow-up"
|
||||||
|
href="{% url "change-respo" club.name member.id %}"></a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
Ce club ne comporte actuellement aucun membre.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -12,16 +12,19 @@
|
||||||
<table>
|
<table>
|
||||||
{{ user_form | bootstrap }}
|
{{ user_form | bootstrap }}
|
||||||
{{ profile_form | bootstrap }}
|
{{ profile_form | bootstrap }}
|
||||||
{% if event_forms %}
|
|
||||||
</table>
|
</table>
|
||||||
{% for event_form in event_forms %}
|
<hr />
|
||||||
|
<table>
|
||||||
|
{{ clubs_form | bootstrap }}
|
||||||
|
</table>
|
||||||
|
{{ event_formset.management_form }}
|
||||||
|
{% for event_form in event_formset %}
|
||||||
<hr />
|
<hr />
|
||||||
<h3>Inscription {{ event_form.event.title }} :</h2>
|
<h3>Inscription {{ event_form.event.title }} :</h3>
|
||||||
<table>
|
<table>
|
||||||
{{ event_form | bootstrap }}
|
{{ event_form | bootstrap }}
|
||||||
</table>
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
{% if login_clipper or member %}
|
{% if login_clipper or member %}
|
||||||
<input type="hidden" name="user_exists" value="1" />
|
<input type="hidden" name="user_exists" value="1" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -52,3 +52,10 @@ calendar_patterns = [
|
||||||
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$',
|
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$',
|
||||||
'gestioncof.views.calendar_ics')
|
'gestioncof.views.calendar_ics')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
clubs_patterns = [
|
||||||
|
url(r'^membres/(?P<name>\w+)', views.membres_club, name='membres-club'),
|
||||||
|
url(r'^liste', views.liste_clubs, name='liste-clubs'),
|
||||||
|
url(r'^change_respo/(?P<club_name>\w+)/(?P<user_id>\d+)',
|
||||||
|
views.change_respo, name='change-respo'),
|
||||||
|
]
|
||||||
|
|
|
@ -10,10 +10,11 @@ from datetime import timedelta
|
||||||
from icalendar import Calendar, Event as Vevent
|
from icalendar import Calendar, Event as Vevent
|
||||||
|
|
||||||
from django.shortcuts import redirect, get_object_or_404, render
|
from django.shortcuts import redirect, get_object_or_404, render
|
||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404, HttpResponse, HttpResponseForbidden
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.views import login as django_login_view
|
from django.contrib.auth.views import login as django_login_view
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import timezone
|
||||||
import django.utils.six as six
|
import django.utils.six as six
|
||||||
|
|
||||||
from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
|
from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
|
||||||
|
@ -23,11 +24,12 @@ from gestioncof.models import Event, EventRegistration, EventOption, \
|
||||||
from gestioncof.models import EventCommentField, EventCommentValue, \
|
from gestioncof.models import EventCommentField, EventCommentValue, \
|
||||||
CalendarSubscription
|
CalendarSubscription
|
||||||
from gestioncof.shared import send_custom_mail
|
from gestioncof.shared import send_custom_mail
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper, Club
|
||||||
from gestioncof.decorators import buro_required, cof_required
|
from gestioncof.decorators import buro_required, cof_required
|
||||||
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
|
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
|
||||||
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
|
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
|
||||||
RegistrationProfileForm, AdminEventForm, EventForm, CalendarForm
|
RegistrationProfileForm, EventForm, CalendarForm, EventFormset, \
|
||||||
|
RegistrationPassUserForm, ClubsForm
|
||||||
|
|
||||||
from bda.models import Tirage, Spectacle
|
from bda.models import Tirage, Spectacle
|
||||||
|
|
||||||
|
@ -40,7 +42,11 @@ def home(request):
|
||||||
Survey.objects.filter(survey_open=True, old=False).all(),
|
Survey.objects.filter(survey_open=True, old=False).all(),
|
||||||
"open_events":
|
"open_events":
|
||||||
Event.objects.filter(registration_open=True, old=False).all(),
|
Event.objects.filter(registration_open=True, old=False).all(),
|
||||||
"open_tirages": Tirage.objects.filter(active=True).all()}
|
"active_tirages": Tirage.objects.filter(active=True).all(),
|
||||||
|
"open_tirages":
|
||||||
|
Tirage.objects.filter(active=True,
|
||||||
|
ouverture__lte=timezone.now()).all(),
|
||||||
|
"now": timezone.now()}
|
||||||
return render(request, "home.html", data)
|
return render(request, "home.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +97,7 @@ def logout(request):
|
||||||
@login_required
|
@login_required
|
||||||
def survey(request, survey_id):
|
def survey(request, survey_id):
|
||||||
survey = get_object_or_404(Survey, id=survey_id)
|
survey = get_object_or_404(Survey, id=survey_id)
|
||||||
if not survey.survey_open:
|
if not survey.survey_open or survey.old:
|
||||||
raise Http404
|
raise Http404
|
||||||
success = False
|
success = False
|
||||||
deleted = False
|
deleted = False
|
||||||
|
@ -188,7 +194,7 @@ def update_event_form_comments(event, form, registration):
|
||||||
@login_required
|
@login_required
|
||||||
def event(request, event_id):
|
def event(request, event_id):
|
||||||
event = get_object_or_404(Event, id=event_id)
|
event = get_object_or_404(Event, id=event_id)
|
||||||
if not event.registration_open:
|
if (not event.registration_open) or event.old:
|
||||||
raise Http404
|
raise Http404
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -295,7 +301,7 @@ def survey_status(request, survey_id):
|
||||||
"form": form})
|
"form": form})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@cof_required
|
||||||
def profile(request):
|
def profile(request):
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -313,45 +319,6 @@ def registration_set_ro_fields(user_form, profile_form):
|
||||||
profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def registration_form(request, login_clipper=None, username=None):
|
|
||||||
member = None
|
|
||||||
if login_clipper:
|
|
||||||
clipper = get_object_or_404(Clipper, username=login_clipper)
|
|
||||||
try: # check if the given user is already registered
|
|
||||||
member = User.objects.filter(username=login_clipper).get()
|
|
||||||
username = member.username
|
|
||||||
login_clipper = None
|
|
||||||
except User.DoesNotExist:
|
|
||||||
# new user, but prefill
|
|
||||||
user_form = RegistrationUserForm()
|
|
||||||
profile_form = RegistrationProfileForm()
|
|
||||||
user_form.fields['username'].initial = login_clipper
|
|
||||||
user_form.fields['email'].initial = \
|
|
||||||
login_clipper + "@clipper.ens.fr"
|
|
||||||
profile_form.fields['login_clipper'].initial = login_clipper
|
|
||||||
if clipper.fullname:
|
|
||||||
bits = clipper.fullname.split(" ")
|
|
||||||
user_form.fields['first_name'].initial = bits[0]
|
|
||||||
if len(bits) > 1:
|
|
||||||
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
|
||||||
if username:
|
|
||||||
member = get_object_or_404(User, username=username)
|
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
|
||||||
# already existing, prefill
|
|
||||||
user_form = RegistrationUserForm(instance=member)
|
|
||||||
profile_form = RegistrationProfileForm(instance=profile)
|
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
|
||||||
elif not login_clipper:
|
|
||||||
# new user
|
|
||||||
user_form = RegistrationUserForm()
|
|
||||||
profile_form = RegistrationProfileForm()
|
|
||||||
return render(request, "registration_form.html",
|
|
||||||
{"user_form": user_form, "profile_form": profile_form,
|
|
||||||
"member": member, "login_clipper": login_clipper})
|
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration_form2(request, login_clipper=None, username=None):
|
def registration_form2(request, login_clipper=None, username=None):
|
||||||
events = Event.objects.filter(old=False).all()
|
events = Event.objects.filter(old=False).all()
|
||||||
|
@ -359,24 +326,27 @@ def registration_form2(request, login_clipper=None, username=None):
|
||||||
if login_clipper:
|
if login_clipper:
|
||||||
clipper = get_object_or_404(Clipper, username=login_clipper)
|
clipper = get_object_or_404(Clipper, username=login_clipper)
|
||||||
try: # check if the given user is already registered
|
try: # check if the given user is already registered
|
||||||
member = User.objects.filter(username=login_clipper).get()
|
member = User.objects.get(username=login_clipper)
|
||||||
username = member.username
|
username = member.username
|
||||||
login_clipper = None
|
login_clipper = None
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
# new user, but prefill
|
# new user, but prefill
|
||||||
user_form = RegistrationUserForm()
|
# user
|
||||||
profile_form = RegistrationProfileForm()
|
user_form = RegistrationUserForm(initial={
|
||||||
event_forms = [AdminEventForm(event=event) for event in events]
|
'username': login_clipper,
|
||||||
user_form.fields['username'].initial = login_clipper
|
'email': "%s@clipper.ens.fr" % login_clipper})
|
||||||
user_form.fields['email'].initial = \
|
|
||||||
login_clipper + "@clipper.ens.fr"
|
|
||||||
profile_form.fields['login_clipper'].initial = login_clipper
|
|
||||||
if clipper.fullname:
|
if clipper.fullname:
|
||||||
bits = clipper.fullname.split(" ")
|
bits = clipper.fullname.split(" ")
|
||||||
user_form.fields['first_name'].initial = bits[0]
|
user_form.fields['first_name'].initial = bits[0]
|
||||||
if len(bits) > 1:
|
if len(bits) > 1:
|
||||||
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
||||||
|
# profile
|
||||||
|
profile_form = RegistrationProfileForm(initial={
|
||||||
|
'login_clipper': login_clipper})
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
|
# events & clubs
|
||||||
|
event_formset = EventFormset(events=events, prefix='events')
|
||||||
|
clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
|
||||||
if username:
|
if username:
|
||||||
member = get_object_or_404(User, username=username)
|
member = get_object_or_404(User, username=username)
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
||||||
|
@ -384,121 +354,185 @@ def registration_form2(request, login_clipper=None, username=None):
|
||||||
user_form = RegistrationUserForm(instance=member)
|
user_form = RegistrationUserForm(instance=member)
|
||||||
profile_form = RegistrationProfileForm(instance=profile)
|
profile_form = RegistrationProfileForm(instance=profile)
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
event_forms = []
|
# events
|
||||||
|
current_registrations = []
|
||||||
for event in events:
|
for event in events:
|
||||||
try:
|
try:
|
||||||
current_registration = EventRegistration.objects.get(
|
current_registrations.append(
|
||||||
user=member, event=event)
|
EventRegistration.objects.get(user=member, event=event))
|
||||||
form = AdminEventForm(
|
|
||||||
event=event,
|
|
||||||
current_registration=current_registration,
|
|
||||||
paid=current_registration.paid)
|
|
||||||
except EventRegistration.DoesNotExist:
|
except EventRegistration.DoesNotExist:
|
||||||
form = AdminEventForm(event=event)
|
current_registrations.append(None)
|
||||||
event_forms.append(form)
|
event_formset = EventFormset(
|
||||||
|
events=events, prefix='events',
|
||||||
|
current_registrations=current_registrations)
|
||||||
|
# Clubs
|
||||||
|
clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
|
||||||
elif not login_clipper:
|
elif not login_clipper:
|
||||||
# new user
|
# new user
|
||||||
user_form = RegistrationUserForm()
|
user_form = RegistrationPassUserForm()
|
||||||
|
user_form.force_long_username()
|
||||||
profile_form = RegistrationProfileForm()
|
profile_form = RegistrationProfileForm()
|
||||||
event_forms = [AdminEventForm(event=event) for event in events]
|
event_formset = EventFormset(events=events, prefix='events')
|
||||||
|
clubs_form = ClubsForm()
|
||||||
return render(request, "registration_form.html",
|
return render(request, "registration_form.html",
|
||||||
{"user_form": user_form, "profile_form": profile_form,
|
{"member": member, "login_clipper": login_clipper,
|
||||||
"member": member, "login_clipper": login_clipper,
|
"user_form": user_form,
|
||||||
"event_forms": event_forms})
|
"profile_form": profile_form,
|
||||||
|
"event_formset": event_formset,
|
||||||
|
"clubs_form": clubs_form})
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration(request):
|
def registration(request):
|
||||||
if request.POST:
|
if request.POST:
|
||||||
request_dict = request.POST.copy()
|
request_dict = request.POST.copy()
|
||||||
|
# num ne peut pas être défini manuellement
|
||||||
if "num" in request_dict:
|
if "num" in request_dict:
|
||||||
del request_dict["num"]
|
del request_dict["num"]
|
||||||
success = False
|
|
||||||
user_form = RegistrationUserForm(request_dict)
|
|
||||||
profile_form = RegistrationProfileForm(request_dict)
|
|
||||||
events = Event.objects.filter(old=False).all()
|
|
||||||
event_forms = \
|
|
||||||
[AdminEventForm(request_dict, event=event) for event in events]
|
|
||||||
user_form.is_valid()
|
|
||||||
profile_form.is_valid()
|
|
||||||
for event_form in event_forms:
|
|
||||||
event_form.is_valid()
|
|
||||||
member = None
|
member = None
|
||||||
login_clipper = None
|
login_clipper = None
|
||||||
|
success = False
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Remplissage des formulaires
|
||||||
|
# -----
|
||||||
|
|
||||||
|
if 'password1' in request_dict or 'password2' in request_dict:
|
||||||
|
user_form = RegistrationPassUserForm(request_dict)
|
||||||
|
else:
|
||||||
|
user_form = RegistrationUserForm(request_dict)
|
||||||
|
profile_form = RegistrationProfileForm(request_dict)
|
||||||
|
clubs_form = ClubsForm(request_dict)
|
||||||
|
events = Event.objects.filter(old=False).all()
|
||||||
|
event_formset = EventFormset(events=events, data=request_dict,
|
||||||
|
prefix='events')
|
||||||
if "user_exists" in request_dict and request_dict["user_exists"]:
|
if "user_exists" in request_dict and request_dict["user_exists"]:
|
||||||
username = request_dict["username"]
|
username = request_dict["username"]
|
||||||
try:
|
try:
|
||||||
member = User.objects.filter(username=username).get()
|
member = User.objects.get(username=username)
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
|
||||||
user_form = RegistrationUserForm(request_dict, instance=member)
|
user_form = RegistrationUserForm(request_dict, instance=member)
|
||||||
profile_form = RegistrationProfileForm(request_dict,
|
|
||||||
instance=profile)
|
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
try:
|
try:
|
||||||
clipper = Clipper.objects.filter(username=username).get()
|
clipper = Clipper.objects.get(username=username)
|
||||||
login_clipper = clipper.username
|
login_clipper = clipper.username
|
||||||
except Clipper.DoesNotExist:
|
except Clipper.DoesNotExist:
|
||||||
pass
|
user_form.force_long_username()
|
||||||
for form in event_forms:
|
else:
|
||||||
if not form.is_valid():
|
user_form.force_long_username()
|
||||||
break
|
|
||||||
if form.cleaned_data['status'] == 'no':
|
# -----
|
||||||
continue
|
# Validation des formulaires
|
||||||
all_choices = get_event_form_choices(form.event, form)
|
# -----
|
||||||
if user_form.is_valid() and profile_form.is_valid() \
|
|
||||||
and not any([not form.is_valid() for form in event_forms]):
|
if user_form.is_valid():
|
||||||
member = user_form.save()
|
member = user_form.save()
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
profile, _ = CofProfile.objects.get_or_create(user=member)
|
||||||
was_cof = profile.is_cof
|
was_cof = profile.is_cof
|
||||||
request_dict["num"] = profile.num
|
request_dict["num"] = profile.num
|
||||||
|
# Maintenant on remplit le formulaire de profil
|
||||||
profile_form = RegistrationProfileForm(request_dict,
|
profile_form = RegistrationProfileForm(request_dict,
|
||||||
instance=profile)
|
instance=profile)
|
||||||
profile_form.is_valid()
|
if (profile_form.is_valid() and event_formset.is_valid()
|
||||||
profile_form.save()
|
and clubs_form.is_valid()):
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
# Enregistrement du profil
|
||||||
if profile.is_cof and not was_cof:
|
profile = profile_form.save()
|
||||||
send_custom_mail(member, "bienvenue")
|
if profile.is_cof and not was_cof:
|
||||||
for form in event_forms:
|
send_custom_mail(member, "bienvenue")
|
||||||
if form.cleaned_data['status'] == 'no':
|
# Enregistrement des inscriptions aux événements
|
||||||
try:
|
for form in event_formset:
|
||||||
current_registration = EventRegistration.objects.get(
|
if 'status' not in form.cleaned_data:
|
||||||
|
form.cleaned_data['status'] = 'no'
|
||||||
|
if form.cleaned_data['status'] == 'no':
|
||||||
|
try:
|
||||||
|
current_registration = EventRegistration.objects \
|
||||||
|
.get(user=member, event=form.event)
|
||||||
|
current_registration.delete()
|
||||||
|
except EventRegistration.DoesNotExist:
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
all_choices = get_event_form_choices(form.event, form)
|
||||||
|
(current_registration, created_reg) = \
|
||||||
|
EventRegistration.objects.get_or_create(
|
||||||
user=member, event=form.event)
|
user=member, event=form.event)
|
||||||
current_registration.delete()
|
update_event_form_comments(form.event, form,
|
||||||
except EventRegistration.DoesNotExist:
|
current_registration)
|
||||||
pass
|
current_registration.options = all_choices
|
||||||
continue
|
current_registration.paid = \
|
||||||
all_choices = get_event_form_choices(form.event, form)
|
(form.cleaned_data['status'] == 'paid')
|
||||||
(current_registration, created_reg) = \
|
current_registration.save()
|
||||||
EventRegistration.objects.get_or_create(user=member,
|
if form.event.title == "Mega 15" and created_reg:
|
||||||
event=form.event)
|
field = EventCommentField.objects.get(
|
||||||
update_event_form_comments(form.event, form,
|
event=form.event, name="Commentaires")
|
||||||
current_registration)
|
try:
|
||||||
current_registration.options = all_choices
|
comments = EventCommentValue.objects.get(
|
||||||
current_registration.paid = \
|
commentfield=field,
|
||||||
(form.cleaned_data['status'] == 'paid')
|
registration=current_registration).content
|
||||||
current_registration.save()
|
except EventCommentValue.DoesNotExist:
|
||||||
if form.event.title == "Mega 15" and created_reg:
|
comments = field.default
|
||||||
field = EventCommentField.objects.get(event=form.event,
|
send_custom_mail(member, "mega",
|
||||||
name="Commentaires")
|
{"remarques": comments})
|
||||||
try:
|
# Enregistrement des inscriptions aux clubs
|
||||||
comments = EventCommentValue.objects.get(
|
member.clubs.clear()
|
||||||
commentfield=field,
|
for club in clubs_form.cleaned_data['clubs']:
|
||||||
registration=current_registration).content
|
club.membres.add(member)
|
||||||
except EventCommentValue.DoesNotExist:
|
club.save()
|
||||||
comments = field.default
|
success = True
|
||||||
send_custom_mail(member, "mega", {"remarques": comments})
|
|
||||||
success = True
|
|
||||||
return render(request, "registration_post.html",
|
return render(request, "registration_post.html",
|
||||||
{"success": success,
|
{"success": success,
|
||||||
"user_form": user_form,
|
"user_form": user_form,
|
||||||
"profile_form": profile_form,
|
"profile_form": profile_form,
|
||||||
"member": member,
|
"member": member,
|
||||||
"login_clipper": login_clipper,
|
"login_clipper": login_clipper,
|
||||||
"event_forms": event_forms})
|
"event_formset": event_formset,
|
||||||
|
"clubs_form": clubs_form})
|
||||||
else:
|
else:
|
||||||
return render(request, "registration.html")
|
return render(request, "registration.html")
|
||||||
|
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Clubs
|
||||||
|
# -----
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def membres_club(request, name):
|
||||||
|
# Vérification des permissions : l'utilisateur doit être membre du burô
|
||||||
|
# ou respo du club.
|
||||||
|
user = request.user
|
||||||
|
club = get_object_or_404(Club, name=name)
|
||||||
|
if not request.user.profile.is_buro \
|
||||||
|
and club not in user.clubs_geres.all():
|
||||||
|
return HttpResponseForbidden('<h1>Permission denied</h1>')
|
||||||
|
members_no_respo = club.membres.exclude(clubs_geres=club).all()
|
||||||
|
return render(request, 'membres_clubs.html',
|
||||||
|
{'club': club,
|
||||||
|
'members_no_respo': members_no_respo})
|
||||||
|
|
||||||
|
|
||||||
|
@buro_required
|
||||||
|
def change_respo(request, club_name, user_id):
|
||||||
|
club = get_object_or_404(Club, name=club_name)
|
||||||
|
user = get_object_or_404(User, id=user_id)
|
||||||
|
if user in club.respos.all():
|
||||||
|
club.respos.remove(user)
|
||||||
|
elif user in club.membres.all():
|
||||||
|
club.respos.add(user)
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
|
return redirect('membres-club', name=club_name)
|
||||||
|
|
||||||
|
|
||||||
|
@cof_required
|
||||||
|
def liste_clubs(request):
|
||||||
|
clubs = Club.objects
|
||||||
|
if request.user.profile.is_buro:
|
||||||
|
data = {'owned_clubs': clubs.all()}
|
||||||
|
else:
|
||||||
|
data = {'owned_clubs': request.user.clubs_geres,
|
||||||
|
'other_clubs': clubs.exclude(respos=request.user)}
|
||||||
|
return render(request, 'liste_clubs.html', data)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_members(request):
|
def export_members(request):
|
||||||
response = HttpResponse(content_type='text/csv')
|
response = HttpResponse(content_type='text/csv')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Doit être lancé par bootstrap.sh
|
# Doit être lancé par bootstrap.sh
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py loaddata users root bda gestion
|
python manage.py loaddata users root bda gestion sites
|
||||||
|
|
Loading…
Reference in a new issue