Merge branch 'issue81' into 'k-fet'
Fix Issue81 Fix #81 Fix touche H sur K-Psul See merge request !85
This commit is contained in:
commit
6108d58594
25 changed files with 338 additions and 96 deletions
39
README.md
39
README.md
|
@ -47,28 +47,49 @@ gérer la machine virtuelle :
|
||||||
|
|
||||||
- `vagrant ssh` vous connecte en SSH à la machine virtuelle, dans le dossier
|
- `vagrant ssh` vous connecte en SSH à la machine virtuelle, dans le dossier
|
||||||
où est installé GestioCOF. Vous pouvez utiliser les commandes Django
|
où est installé GestioCOF. Vous pouvez utiliser les commandes Django
|
||||||
habituelles (`manage.py runserver` etc.); toutefois pour lancer le serveur il faut faire
|
habituelles (`manage.py runserver` etc.) pour lancer
|
||||||
|
[le serveur en dev](#lancer-le-serveur-de-développement-standard) par
|
||||||
python manage.py runserver 0.0.0.0:8000
|
exemple
|
||||||
|
|
||||||
car par défaut Django n'écoute que sur l'adresse locale de la machine
|
|
||||||
virtuelle - or vous voudrez accéder à GestioCOF depuis votre machine
|
|
||||||
physique.
|
|
||||||
|
|
||||||
**Le dossier avec le code de GestioCOF est partagé entre la machine virtuelle
|
**Le dossier avec le code de GestioCOF est partagé entre la machine virtuelle
|
||||||
et votre machine physique : vous pouvez donc utiliser votre éditeur favori pour
|
et votre machine physique : vous pouvez donc utiliser votre éditeur favori pour
|
||||||
coder depuis l'extérieur de la machine virtuelle, et les changements seront
|
coder depuis l'extérieur de la machine virtuelle, et les changements seront
|
||||||
répercutés dans la machine virtuelle.**
|
répercutés dans la machine virtuelle.**
|
||||||
|
|
||||||
|
#### Lancer le serveur de développement standard
|
||||||
|
|
||||||
|
Pour lancer le serveur de développement, il faut faire
|
||||||
|
|
||||||
|
python manage.py runserver 0.0.0.0:8000
|
||||||
|
|
||||||
|
car par défaut Django n'écoute que sur l'adresse locale de la machine virtuelle
|
||||||
|
or vous voudrez accéder à GestioCOF depuis votre machine physique. L'url à
|
||||||
|
entrer dans le navigateur est `localhost:8000`.
|
||||||
|
|
||||||
|
#### Serveur de développement type production
|
||||||
|
|
||||||
|
Sur la VM Vagrant, un serveur apache est configuré pour servir GestioCOF de
|
||||||
|
façon similaire à la version en production : on utilise
|
||||||
|
[Daphne](https://github.com/django/daphne/) et `python manage.py runworker`
|
||||||
|
derrière un reverse-proxy apache. Le tout est monitoré par
|
||||||
|
[supervisor](http://supervisord.org/).
|
||||||
|
|
||||||
|
Ce serveur se lance tout seul et est accessible en dehors de la VM à l'url
|
||||||
|
`localhost:8080`. Toutefois il ne se recharge pas tout seul lorsque le code
|
||||||
|
change, il faut relancer le worker avec `sudo supervisorctl restart worker` pour
|
||||||
|
visualiser la dernière version du code.
|
||||||
|
|
||||||
### Installation manuelle
|
### Installation manuelle
|
||||||
|
|
||||||
Si vous optez pour une installation manuelle plutôt que d'utiliser Vagrant, il
|
Si vous optez pour une installation manuelle plutôt que d'utiliser Vagrant, il
|
||||||
est fortement conseillé d'utiliser un environnement virtuel pour Python.
|
est fortement conseillé d'utiliser un environnement virtuel pour Python.
|
||||||
|
|
||||||
Il vous faudra installer mercurial, pip, les librairies de développement de
|
Il vous faudra installer mercurial, pip, les librairies de développement de
|
||||||
python, ainsi qu'un client et un serveur MySQL ; sous Debian et dérivées (Ubuntu, ...) :
|
python, un client et un serveur MySQL ainsi qu'un serveur redis ; sous Debian et
|
||||||
|
dérivées (Ubuntu, ...) :
|
||||||
|
|
||||||
sudo apt-get install mercurial python-pip python-dev libmysqlclient-dev
|
sudo apt-get install mercurial python-pip python-dev libmysqlclient-dev
|
||||||
|
redis-server
|
||||||
|
|
||||||
Si vous décidez d'utiliser un environnement virtuel Python (virtualenv;
|
Si vous décidez d'utiliser un environnement virtuel Python (virtualenv;
|
||||||
fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF
|
fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF
|
||||||
|
@ -87,7 +108,7 @@ Vous pouvez maintenant installer les dépendances Python depuis les fichiers
|
||||||
|
|
||||||
pip install -r requirements.txt -r requirements-devel.txt
|
pip install -r requirements.txt -r requirements-devel.txt
|
||||||
|
|
||||||
Enfin, copiez le fichier `cof/settings_dev.py` dans `cof/settings.py`.
|
Copiez le fichier `cof/settings_dev.py` dans `cof/settings.py`.
|
||||||
|
|
||||||
#### Installation avec MySQL
|
#### Installation avec MySQL
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import os, sys
|
|
||||||
sys.path.append (os.path.expanduser ('~gestion/www'))
|
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'cof.settings'
|
|
||||||
|
|
||||||
import django.core.handlers.wsgi
|
|
||||||
|
|
||||||
application = django.core.handlers.wsgi.WSGIHandler()
|
|
|
@ -1,18 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
WSGI config for myproject project.
|
|
||||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import os
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings")
|
|
||||||
application = get_wsgi_application()
|
|
|
@ -14,12 +14,21 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='choixspectacle',
|
model_name='choixspectacle',
|
||||||
name='double_choice',
|
name='double_choice',
|
||||||
field=models.CharField(verbose_name='Nombre de places', choices=[('1', '1 place'), ('autoquit', '2 places si possible, 1 sinon'), ('double', '2 places sinon rien')], default='1', max_length=10),
|
field=models.CharField(
|
||||||
|
verbose_name='Nombre de places',
|
||||||
|
choices=[('1', '1 place'),
|
||||||
|
('autoquit', '2 places si possible, 1 sinon'),
|
||||||
|
('double', '2 places sinon rien')],
|
||||||
|
max_length=10, default='1'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='participant',
|
model_name='participant',
|
||||||
name='paymenttype',
|
name='paymenttype',
|
||||||
field=models.CharField(verbose_name='Moyen de paiement', choices=[('cash', 'Cash'), ('cb', 'CB'), ('cheque', 'Chèque'), ('autre', 'Autre')], max_length=6, blank=True),
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[('cash', 'Cash'), ('cb', 'CB'),
|
||||||
|
('cheque', 'Chèque'), ('autre', 'Autre')],
|
||||||
|
max_length=6, verbose_name='Moyen de paiement'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='salle',
|
model_name='salle',
|
||||||
|
@ -44,7 +53,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='spectacle',
|
model_name='spectacle',
|
||||||
name='listing',
|
name='listing',
|
||||||
field=models.BooleanField(verbose_name='Les places sont sur listing'),
|
field=models.BooleanField(
|
||||||
|
verbose_name='Les places sont sur listing'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='spectacle',
|
model_name='spectacle',
|
||||||
|
@ -59,7 +69,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='spectacle',
|
model_name='spectacle',
|
||||||
name='slots_description',
|
name='slots_description',
|
||||||
field=models.TextField(verbose_name='Description des places', blank=True),
|
field=models.TextField(verbose_name='Description des places',
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='spectacle',
|
model_name='spectacle',
|
||||||
|
@ -69,17 +80,20 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='tirage',
|
model_name='tirage',
|
||||||
name='active',
|
name='active',
|
||||||
field=models.BooleanField(verbose_name='Tirage actif', default=False),
|
field=models.BooleanField(verbose_name='Tirage actif',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='tirage',
|
model_name='tirage',
|
||||||
name='fermeture',
|
name='fermeture',
|
||||||
field=models.DateTimeField(verbose_name='Date et heure de fermerture du tirage'),
|
field=models.DateTimeField(
|
||||||
|
verbose_name='Date et heure de fermerture du tirage'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='tirage',
|
model_name='tirage',
|
||||||
name='ouverture',
|
name='ouverture',
|
||||||
field=models.DateTimeField(verbose_name="Date et heure d'ouverture du tirage"),
|
field=models.DateTimeField(
|
||||||
|
verbose_name="Date et heure d'ouverture du tirage"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='tirage',
|
model_name='tirage',
|
||||||
|
|
|
@ -32,7 +32,8 @@ class Tirage(models.Model):
|
||||||
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.astimezone(timezone.get_current_timezone()) \
|
||||||
|
.strftime('%d %b %Y %H:%M')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s - %s" % (self.title, self.date_no_seconds())
|
return "%s - %s" % (self.title, self.date_no_seconds())
|
||||||
|
@ -89,7 +90,8 @@ class Spectacle(models.Model):
|
||||||
return "%d" % calendar.timegm(self.date.utctimetuple())
|
return "%d" % calendar.timegm(self.date.utctimetuple())
|
||||||
|
|
||||||
def date_no_seconds(self):
|
def date_no_seconds(self):
|
||||||
return self.date.strftime('%d %b %Y %H:%M')
|
return self.date.astimezone(timezone.get_current_timezone()) \
|
||||||
|
.strftime('%d %b %Y %H:%M')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(),
|
return "%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(),
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<base target="_parent"/>
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: josefinsans;
|
font-family: josefinsans;
|
||||||
|
@ -18,8 +19,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.descTable{
|
.descTable{
|
||||||
width: auto;
|
width: 100%;
|
||||||
margin: 0 auto 1em;
|
margin: 0 auto 1em;
|
||||||
|
border-bottom: 2px solid;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -30,9 +32,14 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #5a5a5a;
|
color: #5a5a5a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img{
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<meta charset="utf8" />
|
<meta charset="utf8" />
|
||||||
</head>
|
</head>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
|
||||||
<body>
|
<body>
|
||||||
{% for show in shows %}
|
{% for show in shows %}
|
||||||
<table class="descTable">
|
<table class="descTable">
|
||||||
|
@ -46,26 +53,61 @@
|
||||||
<td><p style="text-align: left;">{{ show.location }}</p></td><td class="column-2"><p style="text-align: right;">{{ show.category }}</p></td>
|
<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>
|
||||||
<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>
|
<td><p style="text-align: left;">{{ show.date|date:"l j F Y - H\hi" }}</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 }} euro{{ show.price|pluralize}}</p></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if show.vips %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><p style="text-align: justify;">{{ show.category }}</p></td>
|
<td colspan="2"><p style="text-align: justify;">{{ show.vips }}</p></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<p style="text-align: justify;">{{ show.description }}</p>
|
<p style="text-align: justify;">{{ show.description }}</p>
|
||||||
{% for quote in show.quote_set.all %}
|
{% 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>
|
<p style="text-align:center; font-style: italic;">«{{ quote.text }}»{% if quote.author %} - {{ quote.author }}{% endif %}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if show.image %}
|
{% if show.image %}
|
||||||
<tr>
|
<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>
|
<td colspan="2"><p style="text-align:center;"><a href="{{ show.ext_link }}"><img class="imgDesc" style="display: inline;" src="{{ MEDIA_URL }}{{ show.image }}" alt="{{ show.title }}"></a></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<script>
|
||||||
|
// Correction de la taille des images
|
||||||
|
|
||||||
|
/*$(document).ready(function() {
|
||||||
|
$(".descTable").each(function() {
|
||||||
|
$(this).width($("body").width());
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".imgDesc").on("load", function() {
|
||||||
|
|
||||||
|
// Dimensions
|
||||||
|
origHeight = 500; // Hauteur souhaitée
|
||||||
|
|
||||||
|
w = $(this).width();
|
||||||
|
h = $(this).height();
|
||||||
|
r = w/h; // Ratio de l'image
|
||||||
|
maxWidth = $("body").width();
|
||||||
|
|
||||||
|
if (r * origHeight > maxWidth)
|
||||||
|
{
|
||||||
|
$(this).width(maxWidth);
|
||||||
|
$(this).height(maxWidth/r);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$(this).width(r * origHeight);
|
||||||
|
$(this).height(origHeight);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});*/
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -66,7 +66,7 @@ def etat_places(request, tirage_id):
|
||||||
|
|
||||||
|
|
||||||
def _hash_queryset(queryset):
|
def _hash_queryset(queryset):
|
||||||
data = serializers.serialize("json", queryset).encode()
|
data = serializers.serialize("json", queryset).encode('utf-8')
|
||||||
hasher = hashlib.sha256()
|
hasher = hashlib.sha256()
|
||||||
hasher.update(data)
|
hasher.update(data)
|
||||||
return hasher.hexdigest()
|
return hasher.hexdigest()
|
||||||
|
|
7
cof/asgi.py
Normal file
7
cof/asgi.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import os
|
||||||
|
from channels.asgi import get_channel_layer
|
||||||
|
|
||||||
|
if "DJANGO_SETTINGS_MODULE" not in os.environ:
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings")
|
||||||
|
|
||||||
|
channel_layer = get_channel_layer()
|
|
@ -29,7 +29,7 @@ SECRET_KEY = 'q()(zn4m63i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah'
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = ['127.0.0.1']
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
@ -123,6 +123,7 @@ USE_TZ = True
|
||||||
# https://docs.djangoproject.com/en/1.8/howto/static-files/
|
# https://docs.djangoproject.com/en/1.8/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = '/var/www/static/'
|
||||||
|
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (
|
||||||
os.path.join(BASE_DIR, 'static/'),
|
os.path.join(BASE_DIR, 'static/'),
|
||||||
|
@ -151,12 +152,12 @@ PETITS_COURS_REPLYTO = "cof@ens.fr"
|
||||||
RAPPEL_FROM = 'Le BdA <bda@ens.fr>'
|
RAPPEL_FROM = 'Le BdA <bda@ens.fr>'
|
||||||
RAPPEL_REPLY_TO = RAPPEL_FROM
|
RAPPEL_REPLY_TO = RAPPEL_FROM
|
||||||
|
|
||||||
LOGIN_URL = "/login"
|
LOGIN_URL = "/gestion/login"
|
||||||
LOGIN_REDIRECT_URL = "/"
|
LOGIN_REDIRECT_URL = "/gestion/"
|
||||||
|
|
||||||
CAS_SERVER_URL = 'https://cas.eleves.ens.fr/'
|
CAS_SERVER_URL = 'https://cas.eleves.ens.fr/'
|
||||||
CAS_IGNORE_REFERER = True
|
CAS_IGNORE_REFERER = True
|
||||||
CAS_REDIRECT_URL = '/'
|
CAS_REDIRECT_URL = '/gestion/'
|
||||||
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
|
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
@ -175,12 +176,13 @@ CHANNEL_LAYERS = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "asgi_redis.RedisChannelLayer",
|
"BACKEND": "asgi_redis.RedisChannelLayer",
|
||||||
"CONFIG": {
|
"CONFIG": {
|
||||||
"hosts": [("redis://:password_redis@127.0.0.1:6379/0")],
|
"hosts": [("localhost", 6379)],
|
||||||
},
|
},
|
||||||
"ROUTING": "cof.routing.channel_routing",
|
"ROUTING": "cof.routing.channel_routing",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def show_toolbar(request):
|
def show_toolbar(request):
|
||||||
"""
|
"""
|
||||||
On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar
|
On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar
|
||||||
|
|
|
@ -24,7 +24,7 @@ from gestioncof.autocomplete import autocomplete
|
||||||
autocomplete_light.autodiscover()
|
autocomplete_light.autodiscover()
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = [
|
my_urlpatterns = [
|
||||||
# Page d'accueil
|
# Page d'accueil
|
||||||
url(r'^$', gestioncof_views.home, name='home'),
|
url(r'^$', gestioncof_views.home, name='home'),
|
||||||
# Le BdA
|
# Le BdA
|
||||||
|
@ -88,3 +88,7 @@ urlpatterns = [
|
||||||
else [])
|
else [])
|
||||||
# Si on est en production, MEDIA_ROOT est servi par Apache.
|
# Si on est en production, MEDIA_ROOT est servi par Apache.
|
||||||
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
|
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^gestion/', include(my_urlpatterns))
|
||||||
|
]
|
||||||
|
|
|
@ -6,16 +6,18 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
|
from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
|
||||||
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
|
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
|
||||||
Survey, EventCommentField, EventRegistration
|
Survey, EventCommentField, EventRegistration
|
||||||
from gestioncof.petits_cours_models import PetitCoursDemande, \
|
from gestioncof.petits_cours_models import PetitCoursDemande, \
|
||||||
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
||||||
PetitCoursAttributionCounter
|
PetitCoursAttributionCounter
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.db.models import Q
|
||||||
import django.utils.six as six
|
import django.utils.six as six
|
||||||
|
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
@ -163,6 +165,7 @@ class UserProfileAdmin(UserAdmin):
|
||||||
return False
|
return False
|
||||||
is_cof.short_description = 'Membre du COF'
|
is_cof.short_description = 'Membre du COF'
|
||||||
is_cof.boolean = True
|
is_cof.boolean = True
|
||||||
|
|
||||||
list_display = ('profile_num',) + UserAdmin.list_display \
|
list_display = ('profile_num',) + UserAdmin.list_display \
|
||||||
+ ('profile_login_clipper', 'profile_phone', 'profile_occupation',
|
+ ('profile_login_clipper', 'profile_phone', 'profile_occupation',
|
||||||
'profile_mailing_cof', 'profile_mailing_bda',
|
'profile_mailing_cof', 'profile_mailing_bda',
|
||||||
|
@ -176,6 +179,40 @@ class UserProfileAdmin(UserAdmin):
|
||||||
CofProfileInline,
|
CofProfileInline,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
staff_fieldsets = [
|
||||||
|
(None, {'fields': ['username', 'password']}),
|
||||||
|
(_('Personal info'), {'fields': ['first_name', 'last_name', 'email']}),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_fieldsets(self, request, user=None):
|
||||||
|
if not request.user.is_superuser:
|
||||||
|
return self.staff_fieldsets
|
||||||
|
return super(UserProfileAdmin, self).get_fieldsets(request, user)
|
||||||
|
|
||||||
|
def save_model(self, request, user, form, change):
|
||||||
|
cof_group, created = Group.objects.get_or_create(name='COF')
|
||||||
|
if created:
|
||||||
|
# Si le groupe COF n'était pas déjà dans la bdd
|
||||||
|
# On lui assigne les bonnes permissions
|
||||||
|
perms = Permission.objects.filter(
|
||||||
|
Q(content_type__app_label='gestioncof')
|
||||||
|
| Q(content_type__app_label='bda')
|
||||||
|
| (Q(content_type__app_label='auth')
|
||||||
|
& Q(content_type__model='user')))
|
||||||
|
cof_group.permissions = perms
|
||||||
|
# On y associe les membres du Burô
|
||||||
|
cof_group.user_set = User.objects.filter(profile__is_buro=True)
|
||||||
|
# Sauvegarde
|
||||||
|
cof_group.save()
|
||||||
|
# le Burô est staff et appartient au groupe COF
|
||||||
|
if user.profile.is_buro:
|
||||||
|
user.is_staff = True
|
||||||
|
user.groups.add(cof_group)
|
||||||
|
else:
|
||||||
|
user.is_staff = False
|
||||||
|
user.groups.remove(cof_group)
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
# FIXME: This is absolutely horrible.
|
# FIXME: This is absolutely horrible.
|
||||||
def user_unicode(self):
|
def user_unicode(self):
|
||||||
|
|
|
@ -10,8 +10,10 @@ from django.db.models import Q
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper
|
||||||
|
from gestioncof.decorators import buro_required
|
||||||
|
|
||||||
|
|
||||||
|
@buro_required
|
||||||
def autocomplete(request):
|
def autocomplete(request):
|
||||||
if "q" not in request.GET:
|
if "q" not in request.GET:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
|
@ -4,6 +4,11 @@ from __future__ import unicode_literals
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
def forwards(apps, schema_editor):
|
||||||
|
Profile = apps.get_model("gestioncof", "CofProfile")
|
||||||
|
Profile.objects.update(comments="")
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
@ -24,57 +29,85 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='comments',
|
name='comments',
|
||||||
field=models.TextField(verbose_name='Commentaires visibles uniquement par le Buro', blank=True),
|
field=models.TextField(
|
||||||
|
verbose_name="Commentaires visibles par l'utilisateur",
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='is_cof',
|
name='is_cof',
|
||||||
field=models.BooleanField(verbose_name='Membre du COF', default=False),
|
field=models.BooleanField(verbose_name='Membre du COF',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='login_clipper',
|
name='login_clipper',
|
||||||
field=models.CharField(verbose_name='Login clipper', max_length=8, blank=True),
|
field=models.CharField(verbose_name='Login clipper', max_length=8,
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='mailing_bda',
|
name='mailing_bda',
|
||||||
field=models.BooleanField(verbose_name='Recevoir les mails BdA', default=False),
|
field=models.BooleanField(verbose_name='Recevoir les mails BdA',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='mailing_bda_revente',
|
name='mailing_bda_revente',
|
||||||
field=models.BooleanField(verbose_name='Recevoir les mails de revente de places BdA', default=False),
|
field=models.BooleanField(
|
||||||
|
verbose_name='Recevoir les mails de revente de places BdA',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='mailing_cof',
|
name='mailing_cof',
|
||||||
field=models.BooleanField(verbose_name='Recevoir les mails COF', default=False),
|
field=models.BooleanField(verbose_name='Recevoir les mails COF',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='occupation',
|
name='occupation',
|
||||||
field=models.CharField(verbose_name='Occupation', choices=[('exterieur', 'Extérieur'), ('1A', '1A'), ('2A', '2A'), ('3A', '3A'), ('4A', '4A'), ('archicube', 'Archicube'), ('doctorant', 'Doctorant'), ('CST', 'CST')], default='1A', max_length=9),
|
field=models.CharField(verbose_name='Occupation',
|
||||||
|
choices=[('exterieur', 'Extérieur'),
|
||||||
|
('1A', '1A'),
|
||||||
|
('2A', '2A'),
|
||||||
|
('3A', '3A'),
|
||||||
|
('4A', '4A'),
|
||||||
|
('archicube', 'Archicube'),
|
||||||
|
('doctorant', 'Doctorant'),
|
||||||
|
('CST', 'CST')],
|
||||||
|
max_length=9, default='1A'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='petits_cours_accept',
|
name='petits_cours_accept',
|
||||||
field=models.BooleanField(verbose_name='Recevoir des petits cours', default=False),
|
field=models.BooleanField(verbose_name='Recevoir des petits cours',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='petits_cours_remarques',
|
name='petits_cours_remarques',
|
||||||
field=models.TextField(verbose_name='Remarques et précisions pour les petits cours', default='', blank=True),
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
verbose_name='Remarques et précisions pour les petits cours',
|
||||||
|
default=''),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='cofprofile',
|
model_name='cofprofile',
|
||||||
name='type_cotiz',
|
name='type_cotiz',
|
||||||
field=models.CharField(verbose_name='Type de cotisation', choices=[('etudiant', 'Normalien étudiant'), ('normalien', 'Normalien élève'), ('exterieur', 'Extérieur')], default='normalien', max_length=9),
|
field=models.CharField(
|
||||||
|
verbose_name='Type de cotisation',
|
||||||
|
choices=[('etudiant', 'Normalien étudiant'),
|
||||||
|
('normalien', 'Normalien élève'),
|
||||||
|
('exterieur', 'Extérieur')],
|
||||||
|
max_length=9, default='normalien'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='custommail',
|
model_name='custommail',
|
||||||
name='comments',
|
name='comments',
|
||||||
field=models.TextField(verbose_name='Informations contextuelles sur le mail', blank=True),
|
field=models.TextField(
|
||||||
|
verbose_name='Informations contextuelles sur le mail',
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='custommail',
|
model_name='custommail',
|
||||||
|
@ -94,12 +127,14 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='end_date',
|
name='end_date',
|
||||||
field=models.DateTimeField(verbose_name='Date de fin', null=True, blank=True),
|
field=models.DateTimeField(null=True, verbose_name='Date de fin',
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='image',
|
name='image',
|
||||||
field=models.ImageField(verbose_name='Image', upload_to='imgs/events/', null=True, blank=True),
|
field=models.ImageField(upload_to='imgs/events/', null=True,
|
||||||
|
verbose_name='Image', blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
|
@ -109,7 +144,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='registration_open',
|
name='registration_open',
|
||||||
field=models.BooleanField(verbose_name='Inscriptions ouvertes', default=True),
|
field=models.BooleanField(verbose_name='Inscriptions ouvertes',
|
||||||
|
default=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
|
@ -119,7 +155,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventcommentfield',
|
model_name='eventcommentfield',
|
||||||
name='fieldtype',
|
name='fieldtype',
|
||||||
field=models.CharField(verbose_name='Type', choices=[('text', 'Texte long'), ('char', 'Texte court')], default='text', max_length=10),
|
field=models.CharField(verbose_name='Type',
|
||||||
|
choices=[('text', 'Texte long'),
|
||||||
|
('char', 'Texte court')],
|
||||||
|
max_length=10, default='text'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventcommentfield',
|
model_name='eventcommentfield',
|
||||||
|
@ -129,12 +168,14 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventcommentvalue',
|
model_name='eventcommentvalue',
|
||||||
name='content',
|
name='content',
|
||||||
field=models.TextField(verbose_name='Contenu', null=True, blank=True),
|
field=models.TextField(null=True, verbose_name='Contenu',
|
||||||
|
blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventoption',
|
model_name='eventoption',
|
||||||
name='multi_choices',
|
name='multi_choices',
|
||||||
field=models.BooleanField(verbose_name='Choix multiples', default=False),
|
field=models.BooleanField(verbose_name='Choix multiples',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventoption',
|
model_name='eventoption',
|
||||||
|
@ -149,7 +190,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='petitcoursability',
|
model_name='petitcoursability',
|
||||||
name='niveau',
|
name='niveau',
|
||||||
field=models.CharField(verbose_name='Niveau', choices=[('college', 'Collège'), ('lycee', 'Lycée'), ('prepa1styear', 'Prépa 1ère année / L1'), ('prepa2ndyear', 'Prépa 2ème année / L2'), ('licence3', 'Licence 3'), ('other', 'Autre (préciser dans les commentaires)')], max_length=12),
|
field=models.CharField(
|
||||||
|
choices=[('college', 'Collège'), ('lycee', 'Lycée'),
|
||||||
|
('prepa1styear', 'Prépa 1ère année / L1'),
|
||||||
|
('prepa2ndyear', 'Prépa 2ème année / L2'),
|
||||||
|
('licence3', 'Licence 3'),
|
||||||
|
('other', 'Autre (préciser dans les commentaires)')],
|
||||||
|
max_length=12, verbose_name='Niveau'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='petitcoursattribution',
|
model_name='petitcoursattribution',
|
||||||
|
@ -159,22 +206,32 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='petitcoursattributioncounter',
|
model_name='petitcoursattributioncounter',
|
||||||
name='count',
|
name='count',
|
||||||
field=models.IntegerField(verbose_name="Nombre d'envois", default=0),
|
field=models.IntegerField(verbose_name="Nombre d'envois",
|
||||||
|
default=0),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='petitcoursdemande',
|
model_name='petitcoursdemande',
|
||||||
name='niveau',
|
name='niveau',
|
||||||
field=models.CharField(verbose_name='Niveau', choices=[('college', 'Collège'), ('lycee', 'Lycée'), ('prepa1styear', 'Prépa 1ère année / L1'), ('prepa2ndyear', 'Prépa 2ème année / L2'), ('licence3', 'Licence 3'), ('other', 'Autre (préciser dans les commentaires)')], default='', max_length=12),
|
field=models.CharField(
|
||||||
|
verbose_name='Niveau',
|
||||||
|
choices=[('college', 'Collège'), ('lycee', 'Lycée'),
|
||||||
|
('prepa1styear', 'Prépa 1ère année / L1'),
|
||||||
|
('prepa2ndyear', 'Prépa 2ème année / L2'),
|
||||||
|
('licence3', 'Licence 3'),
|
||||||
|
('other', 'Autre (préciser dans les commentaires)')],
|
||||||
|
max_length=12, default=''),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='survey',
|
model_name='survey',
|
||||||
name='old',
|
name='old',
|
||||||
field=models.BooleanField(verbose_name='Archiver (sondage fini)', default=False),
|
field=models.BooleanField(verbose_name='Archiver (sondage fini)',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='survey',
|
model_name='survey',
|
||||||
name='survey_open',
|
name='survey_open',
|
||||||
field=models.BooleanField(verbose_name='Sondage ouvert', default=True),
|
field=models.BooleanField(verbose_name='Sondage ouvert',
|
||||||
|
default=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='survey',
|
model_name='survey',
|
||||||
|
@ -184,11 +241,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='surveyquestion',
|
model_name='surveyquestion',
|
||||||
name='multi_answers',
|
name='multi_answers',
|
||||||
field=models.BooleanField(verbose_name='Choix multiples', default=False),
|
field=models.BooleanField(verbose_name='Choix multiples',
|
||||||
|
default=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='surveyquestion',
|
model_name='surveyquestion',
|
||||||
name='question',
|
name='question',
|
||||||
field=models.CharField(verbose_name='Question', max_length=200),
|
field=models.CharField(verbose_name='Question', max_length=200),
|
||||||
),
|
),
|
||||||
|
migrations.RunPython(forwards, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|
|
@ -62,7 +62,7 @@ class CofProfile(models.Model):
|
||||||
mailing_bda_revente = models.BooleanField(
|
mailing_bda_revente = models.BooleanField(
|
||||||
"Recevoir les mails de revente de places BdA", default=False)
|
"Recevoir les mails de revente de places BdA", default=False)
|
||||||
comments = models.TextField(
|
comments = models.TextField(
|
||||||
"Commentaires visibles uniquement par le Buro", blank=True)
|
"Commentaires visibles par l'utilisateur", blank=True)
|
||||||
is_buro = models.BooleanField("Membre du Burô", default=False)
|
is_buro = models.BooleanField("Membre du Burô", default=False)
|
||||||
petits_cours_accept = models.BooleanField(
|
petits_cours_accept = models.BooleanField(
|
||||||
"Recevoir des petits cours", default=False)
|
"Recevoir des petits cours", default=False)
|
||||||
|
|
|
@ -135,7 +135,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
unsatisfied, attribdata, redo=False, errors=None):
|
unsatisfied, attribdata, redo=False, errors=None):
|
||||||
proposals = proposals.items()
|
proposals = proposals.items()
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
attribdata = attribdata.items()
|
attribdata = list(attribdata.items())
|
||||||
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
||||||
mainmail = render_template("petits-cours-mail-demandeur.txt",
|
mainmail = render_template("petits-cours-mail-demandeur.txt",
|
||||||
{"proposals": proposals,
|
{"proposals": proposals,
|
||||||
|
@ -153,7 +153,8 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
"proposed_mails": proposed_mails,
|
"proposed_mails": proposed_mails,
|
||||||
"mainmail": mainmail,
|
"mainmail": mainmail,
|
||||||
"attribdata":
|
"attribdata":
|
||||||
base64.b64encode(simplejson.dumps(attribdata)),
|
base64.b64encode(simplejson.dumps(attribdata)
|
||||||
|
.encode('utf_8')),
|
||||||
"redo": redo,
|
"redo": redo,
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,8 +58,7 @@ class COFCASBackend(CASBackend):
|
||||||
if not user.email:
|
if not user.email:
|
||||||
user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper
|
user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper
|
||||||
user.save()
|
user.save()
|
||||||
if profile.is_buro and not user.is_superuser:
|
if profile.is_buro and not user.is_staff:
|
||||||
user.is_superuser = True
|
|
||||||
user.is_staff = True
|
user.is_staff = True
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
<link type="text/css" rel="stylesheet" href="{% static "css/cof.css" %}" />
|
<link type="text/css" rel="stylesheet" href="{% static "css/cof.css" %}" />
|
||||||
<link href="https://fonts.googleapis.com/css?family=Dosis|Dosis:700|Raleway|Roboto:300,300i,700" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Dosis|Dosis:700|Raleway|Roboto:300,300i,700" rel="stylesheet">
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
{% block extra_head %}{% endblock %}
|
{% block extra_head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -13,10 +13,18 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<fieldset"center-block">
|
<fieldset"center-block">
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
{{ field | bootstrap}}
|
{{ field | bootstrap }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
{% if user.profile.comments %}
|
||||||
|
<div class="row" style="margin: 0 15%;">
|
||||||
|
<h4>Commentaires</h4>
|
||||||
|
<p>
|
||||||
|
{{ user.profile.comments }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<input type="submit" class="btn btn-primary pull-right" value="Enregistrer" />
|
<input type="submit" class="btn btn-primary pull-right" value="Enregistrer" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -346,7 +346,7 @@ def registration_form2(request, login_clipper=None, username=None):
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
# events & clubs
|
# events & clubs
|
||||||
event_formset = EventFormset(events=events, prefix='events')
|
event_formset = EventFormset(events=events, prefix='events')
|
||||||
clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
|
clubs_form = ClubsForm()
|
||||||
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)
|
||||||
|
|
|
@ -1240,9 +1240,10 @@ $(document).ready(function() {
|
||||||
case 72:
|
case 72:
|
||||||
if (e.ctrlKey) {
|
if (e.ctrlKey) {
|
||||||
// Ctrl+H - Display help
|
// Ctrl+H - Display help
|
||||||
|
e.preventDefault();
|
||||||
$('.help').show('fast');
|
$('.help').show('fast');
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
case 112:
|
case 112:
|
||||||
// F1 - Cool reset
|
// F1 - Cool reset
|
||||||
coolReset();
|
coolReset();
|
||||||
|
|
29
provisioning/apache.conf
Normal file
29
provisioning/apache.conf
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName default
|
||||||
|
DocumentRoot /var/www/html
|
||||||
|
|
||||||
|
ProxyPreserveHost On
|
||||||
|
ProxyRequests Off
|
||||||
|
ProxyPass /static/ !
|
||||||
|
ProxyPass /media/ !
|
||||||
|
ProxyPass /ws/ ws://127.0.0.1:8001/ws/
|
||||||
|
ProxyPass / http://127.0.0.1:8001/
|
||||||
|
ProxyPassReverse / http://127.0.0.1:8001/
|
||||||
|
|
||||||
|
Alias /media /vagrant/media
|
||||||
|
Alias /static /var/www/static
|
||||||
|
<Directory /vagrant/media>
|
||||||
|
Order deny,allow
|
||||||
|
Allow from all
|
||||||
|
</Directory>
|
||||||
|
<Directory /var/www/static>
|
||||||
|
Order deny,allow
|
||||||
|
Allow from all
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||||
|
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||||
|
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
|
@ -9,7 +9,7 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4"
|
||||||
|
|
||||||
# Installation de paquets utiles
|
# Installation de paquets utiles
|
||||||
apt-get update && apt-get install -y mercurial python-pip python-dev \
|
apt-get update && apt-get install -y mercurial python-pip python-dev \
|
||||||
libmysqlclient-dev libjpeg-dev git
|
libmysqlclient-dev libjpeg-dev git redis-server
|
||||||
|
|
||||||
# Configuration et installation de mysql. Le mot de passe root est le même que
|
# Configuration et installation de mysql. Le mot de passe root est le même que
|
||||||
# le mot de passe pour l'utilisateur local - pour rappel, ceci est une instance
|
# le mot de passe pour l'utilisateur local - pour rappel, ceci est une instance
|
||||||
|
@ -21,8 +21,15 @@ apt-get install -y mysql-server
|
||||||
|
|
||||||
mysql -uroot -p$DBPASSWD -e "CREATE DATABASE $DBNAME; GRANT ALL PRIVILEGES ON $DBNAME.* TO '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASSWD'"
|
mysql -uroot -p$DBPASSWD -e "CREATE DATABASE $DBNAME; GRANT ALL PRIVILEGES ON $DBNAME.* TO '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASSWD'"
|
||||||
|
|
||||||
# Installation de redis-server. Todo: lui mettre un mot de passe
|
# Installation et configuration d'Apache
|
||||||
apt-get install -y redis-server
|
apt-get install -y apache2
|
||||||
|
a2enmod proxy proxy_http
|
||||||
|
cp /vagrant/provisioning/apache.conf /etc/apache2/sites-available/gestiocof.conf
|
||||||
|
a2ensite gestiocof
|
||||||
|
a2dissite 000-default
|
||||||
|
service apache2 restart
|
||||||
|
mkdir /var/www/static
|
||||||
|
chown -R vagrant:www-data /var/www/static
|
||||||
|
|
||||||
# Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh`
|
# Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh`
|
||||||
cat > ~vagrant/.bash_profile <<EOF
|
cat > ~vagrant/.bash_profile <<EOF
|
||||||
|
@ -53,3 +60,12 @@ sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNA
|
||||||
|
|
||||||
# Installation du cron pour les mails de rappels
|
# Installation du cron pour les mails de rappels
|
||||||
sudo -H -u vagrant crontab provisioning/cron.dev
|
sudo -H -u vagrant crontab provisioning/cron.dev
|
||||||
|
|
||||||
|
# On installe Daphne et on demande à supervisor de le lancer
|
||||||
|
pip install daphne
|
||||||
|
apt-get install -y supervisor
|
||||||
|
cp /vagrant/provisioning/supervisor.conf /etc/supervisor/conf.d/gestiocof.conf
|
||||||
|
sed "s/{DBUSER}/$DBUSER/" -i /etc/supervisor/conf.d/gestiocof.conf
|
||||||
|
sed "s/{DBNAME}/$DBNAME/" -i /etc/supervisor/conf.d/gestiocof.conf
|
||||||
|
sed "s/{DBPASSWD}/$DBPASSWD/" -i /etc/supervisor/conf.d/gestiocof.conf
|
||||||
|
service supervisor restart
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py loaddata users root bda gestion sites
|
python manage.py loaddata users root bda gestion sites
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
20
provisioning/supervisor.conf
Normal file
20
provisioning/supervisor.conf
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[program:worker]
|
||||||
|
command=/usr/bin/python /vagrant/manage.py runworker
|
||||||
|
directory=/vagrant/
|
||||||
|
user=vagrant
|
||||||
|
environment=DBUSER={DBUSER},DBNAME={DBNAME},DBPASSWD={DBPASSWD},DJANGO_SETTINGS_MODULE="cof.settings_dev"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
redirect_stderr=true
|
||||||
|
stopasgroup=true
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:interface]
|
||||||
|
command=/usr/local/bin/daphne -b 127.0.0.1 -p 8001 cof.asgi:channel_layer
|
||||||
|
environment=DBUSER={DBUSER},DBNAME={DBNAME},DBPASSWD={DBPASSWD},DJANGO_SETTINGS_MODULE="cof.settings_dev"
|
||||||
|
directory=/vagrant/
|
||||||
|
redirect_stderr=true
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stopasgroup=true
|
||||||
|
user=vagrant
|
|
@ -2,7 +2,7 @@ configparser==3.5.0
|
||||||
Django==1.8
|
Django==1.8
|
||||||
django-autocomplete-light==2.3.3
|
django-autocomplete-light==2.3.3
|
||||||
django-autoslug==1.9.3
|
django-autoslug==1.9.3
|
||||||
django-cas-ng==3.5.4
|
git+https://github.com/xapantu/django-cas-ng.git#egg=django-cas-ng
|
||||||
django-grappelli==2.8.1
|
django-grappelli==2.8.1
|
||||||
django-recaptcha==1.0.5
|
django-recaptcha==1.0.5
|
||||||
mysqlclient==1.3.7
|
mysqlclient==1.3.7
|
||||||
|
|
Loading…
Reference in a new issue