diff --git a/README.md b/README.md
index 15f0ec0d..db2cc93b 100644
--- a/README.md
+++ b/README.md
@@ -47,28 +47,49 @@ gérer la machine virtuelle :
- `vagrant ssh` vous connecte en SSH à la machine virtuelle, dans le dossier
où est installé GestioCOF. Vous pouvez utiliser les commandes Django
- habituelles (`manage.py runserver` etc.); toutefois pour lancer le serveur 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.
+ habituelles (`manage.py runserver` etc.) pour lancer
+ [le serveur en dev](#lancer-le-serveur-de-développement-standard) par
+ exemple
**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
coder depuis l'extérieur de la machine virtuelle, et les changements seront
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
Si vous optez pour une installation manuelle plutôt que d'utiliser Vagrant, il
est fortement conseillé d'utiliser un environnement virtuel pour Python.
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
+ redis-server
Si vous décidez d'utiliser un environnement virtuel Python (virtualenv;
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
-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
diff --git a/apache/__init__.py b/apache/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/apache/asgi.py b/apache/asgi.py
deleted file mode 100644
index eb18c7b2..00000000
--- a/apache/asgi.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import os
-from channels.asgi import get_channel_layer
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings")
-
-channel_layer = get_channel_layer()
diff --git a/apache/django.wsgi b/apache/django.wsgi
deleted file mode 100644
index 7b9c271d..00000000
--- a/apache/django.wsgi
+++ /dev/null
@@ -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()
diff --git a/apache/wsgi.py b/apache/wsgi.py
deleted file mode 100644
index 177542a8..00000000
--- a/apache/wsgi.py
+++ /dev/null
@@ -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()
diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py
index 9fea3f6a..f45357b1 100644
--- a/bda/management/commands/manage_reventes.py
+++ b/bda/management/commands/manage_reventes.py
@@ -14,6 +14,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
now = timezone.now()
+ self.stdout.write(now)
reventes = SpectacleRevente.objects.all()
for revente in reventes:
# Check si < 24h
@@ -22,11 +23,14 @@ class Command(BaseCommand):
now >= revente.date + timedelta(minutes=15) and \
not revente.notif_sent:
revente.mail_shotgun()
+ self.stdout.write("Mail de disponibilité immédiate envoyé")
# Check si délai de retrait dépassé
elif (now >= revente.date + timedelta(hours=1) and
not revente.notif_sent):
revente.send_notif()
+ self.stdout.write("Mail d'inscription à une revente envoyé")
# Check si tirage à faire
elif (now >= revente.expiration_time and
not revente.tirage_done):
revente.tirage()
+ self.stdout.write("Tirage effectué, mails envoyés")
diff --git a/bda/templates/descriptions.html b/bda/templates/descriptions.html
index dd186dac..26da76b6 100644
--- a/bda/templates/descriptions.html
+++ b/bda/templates/descriptions.html
@@ -3,6 +3,7 @@
+
@@ -50,11 +55,16 @@
{{ show.date|date:"l j F Y - H\hi" }} | {{ show.slots }} place{{ show.slots|pluralize}} {% if show.slots_description != "" %}({{ show.slots_description }}){% endif %} - {{ show.price }} euro{{ show.price|pluralize}} |
-
+ {% if show.vips %}
+
+ {{ show.vips }} |
+
+ {% endif %}
+
{{ show.description }}
{% for quote in show.quote_set.all %}
- «{{ quote.text }}»{% if show.quote.author %} - {{ quote.author }}{% endif %}
+ «{{ quote.text }}»{% if quote.author %} - {{ quote.author }}{% endif %}
{% endfor %}
|
@@ -69,7 +79,7 @@
diff --git a/bda/views.py b/bda/views.py
index bac7415d..79212710 100644
--- a/bda/views.py
+++ b/bda/views.py
@@ -71,7 +71,7 @@ def etat_places(request, tirage_id):
def _hash_queryset(queryset):
- data = serializers.serialize("json", queryset).encode()
+ data = serializers.serialize("json", queryset).encode('utf-8')
hasher = hashlib.sha256()
hasher.update(data)
return hasher.hexdigest()
@@ -406,7 +406,7 @@ def list_revente(request, tirage_id):
if qset.exists():
# On l'inscrit à l'un des tirages au sort
for revente in qset.all():
- if revente.shotgun:
+ if revente.shotgun and not revente.soldTo:
deja_revente = True
else:
revente.interested.add(participant)
@@ -435,12 +435,16 @@ def buy_revente(request, spectacle_id):
revente.delete()
return HttpResponseRedirect(reverse("bda-liste-revente",
args=[tirage.id]))
+ reventes_shotgun = []
+ for revente in reventes.all():
+ if revente.shotgun:
+ reventes_shotgun.append(revente)
- if not reventes.exists():
+ if reventes_shotgun.empty():
return render(request, "bda-no-revente.html", {})
if request.POST:
- revente = random.choice(reventes.all())
+ revente = random.choice(reventes_shotgun)
revente.soldTo = participant
revente.save()
mail = """Bonjour !
diff --git a/cof/asgi.py b/cof/asgi.py
new file mode 100644
index 00000000..a34621c7
--- /dev/null
+++ b/cof/asgi.py
@@ -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()
diff --git a/cof/settings_dev.py b/cof/settings_dev.py
index 45ea010b..7d270648 100644
--- a/cof/settings_dev.py
+++ b/cof/settings_dev.py
@@ -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!
DEBUG = True
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['127.0.0.1']
# Application definition
@@ -123,6 +123,7 @@ USE_TZ = True
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
+STATIC_ROOT = '/var/www/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static/'),
@@ -154,12 +155,12 @@ RAPPEL_REPLY_TO = RAPPEL_FROM
REVENTE_FROM = 'BDA-Revente '
REVENTE_REPLY_TO = REVENTE_FROM
-LOGIN_URL = "/login"
-LOGIN_REDIRECT_URL = "/"
+LOGIN_URL = "/gestion/login"
+LOGIN_REDIRECT_URL = "/gestion/"
CAS_SERVER_URL = 'https://cas.eleves.ens.fr/'
CAS_IGNORE_REFERER = True
-CAS_REDIRECT_URL = '/'
+CAS_REDIRECT_URL = '/gestion/'
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
@@ -178,7 +179,7 @@ CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"CONFIG": {
- "hosts": [("redis://:redis_password@127.0.0.1:6379/0")],
+ "hosts": [("localhost", 6379)],
},
"ROUTING": "cof.routing.channel_routing",
}
diff --git a/cof/urls.py b/cof/urls.py
index ca7ea247..263fc3a0 100644
--- a/cof/urls.py
+++ b/cof/urls.py
@@ -24,7 +24,7 @@ from gestioncof.autocomplete import autocomplete
autocomplete_light.autodiscover()
admin.autodiscover()
-urlpatterns = [
+my_urlpatterns = [
# Page d'accueil
url(r'^$', gestioncof_views.home, name='home'),
# Le BdA
@@ -88,3 +88,7 @@ urlpatterns = [
else [])
# 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.
+
+urlpatterns = [
+ url(r'^gestion/', include(my_urlpatterns))
+]
diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py
index 5b4616be..ed0a1e5a 100644
--- a/gestioncof/autocomplete.py
+++ b/gestioncof/autocomplete.py
@@ -10,8 +10,10 @@ from django.db.models import Q
from django.contrib.auth.models import User
from gestioncof.models import CofProfile, Clipper
+from gestioncof.decorators import buro_required
+@buro_required
def autocomplete(request):
if "q" not in request.GET:
raise Http404
diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py
index 7d54766e..1a31115d 100644
--- a/gestioncof/petits_cours_views.py
+++ b/gestioncof/petits_cours_views.py
@@ -135,7 +135,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
unsatisfied, attribdata, redo=False, errors=None):
proposals = proposals.items()
proposed_for = proposed_for.items()
- attribdata = attribdata.items()
+ attribdata = list(attribdata.items())
proposed_mails = _generate_eleve_email(demande, proposed_for)
mainmail = render_template("petits-cours-mail-demandeur.txt",
{"proposals": proposals,
@@ -153,7 +153,8 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
"proposed_mails": proposed_mails,
"mainmail": mainmail,
"attribdata":
- base64.b64encode(simplejson.dumps(attribdata)),
+ base64.b64encode(simplejson.dumps(attribdata)
+ .encode('utf_8')),
"redo": redo,
"errors": errors,
})
diff --git a/gestioncof/views.py b/gestioncof/views.py
index 3148308a..80f528f7 100644
--- a/gestioncof/views.py
+++ b/gestioncof/views.py
@@ -346,7 +346,7 @@ def registration_form2(request, login_clipper=None, username=None):
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()})
+ clubs_form = ClubsForm()
if username:
member = get_object_or_404(User, username=username)
(profile, _) = CofProfile.objects.get_or_create(user=member)
diff --git a/kfet/__init__.py b/kfet/__init__.py
index e69de29b..5d6c8f97 100644
--- a/kfet/__init__.py
+++ b/kfet/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'kfet.apps.KFetConfig'
diff --git a/kfet/apps.py b/kfet/apps.py
new file mode 100644
index 00000000..29f9f98e
--- /dev/null
+++ b/kfet/apps.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import (absolute_import, division,
+ print_function, unicode_literals)
+from builtins import *
+
+from django.apps import AppConfig
+
+class KFetConfig(AppConfig):
+ name = 'kfet'
+ verbose_name = "Application K-Fêt"
+
+ def ready(self):
+ import kfet.signals
diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py
index e4203bd1..2a24a51e 100644
--- a/kfet/autocomplete.py
+++ b/kfet/autocomplete.py
@@ -8,8 +8,10 @@ from django.shortcuts import render
from django.http import Http404
from django.db.models import Q
from gestioncof.models import User, Clipper
+from kfet.decorators import teamkfet_required
from kfet.models import Account
+@teamkfet_required
def account_create(request):
if "q" not in request.GET:
raise Http404
diff --git a/kfet/backends.py b/kfet/backends.py
index 62b2d820..3729f1bd 100644
--- a/kfet/backends.py
+++ b/kfet/backends.py
@@ -18,7 +18,7 @@ class KFetBackend(object):
return None
try:
- password_sha256 = hashlib.sha256(password.encode()).hexdigest()
+ password_sha256 = hashlib.sha256(password.encode('utf-8')).hexdigest()
account = Account.objects.get(password=password_sha256)
user = account.cofprofile.user
except Account.DoesNotExist:
diff --git a/kfet/routing.py b/kfet/routing.py
index e7bcca55..9c816c92 100644
--- a/kfet/routing.py
+++ b/kfet/routing.py
@@ -8,7 +8,7 @@ from channels.routing import route, route_class
from kfet import consumers
channel_routing = [
- route_class(consumers.KPsul, path=r"^/ws/k-fet/k-psul/$"),
+ route_class(consumers.KPsul, path=r"^/gestion/ws/k-fet/k-psul/$"),
#route("websocket.connect", ws_kpsul_history_connect),
#route('websocket.receive', ws_message)
]
diff --git a/kfet/signals.py b/kfet/signals.py
new file mode 100644
index 00000000..3dd4d677
--- /dev/null
+++ b/kfet/signals.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import (absolute_import, division,
+ print_function, unicode_literals)
+from builtins import *
+
+from django.contrib import messages
+from django.contrib.auth.signals import user_logged_in
+from django.core.urlresolvers import reverse
+from django.dispatch import receiver
+
+@receiver(user_logged_in)
+def messages_on_login(sender, request, user, **kwargs):
+ if (not user.username == 'kfet_genericteam'
+ and user.has_perm('kfet.is_team')):
+ messages.info(request, 'Connexion en utilisateur partagé ?' % reverse('kfet.login.genericteam'), extra_tags='safe')
diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css
index c6ee9ff6..f3e9bf8c 100644
--- a/kfet/static/kfet/css/index.css
+++ b/kfet/static/kfet/css/index.css
@@ -263,3 +263,81 @@ textarea {
display:block;
padding:5px 20px;
}
+
+/*
+ * Messages
+ */
+
+.messages .alert {
+ padding:10px 15px;
+ margin:0;
+ border:0;
+ border-radius:0;
+}
+
+.messages .alert-dismissible {
+ padding-right:35px;
+}
+
+.messages .alert .close {
+ top:0;
+ right:0;
+}
+
+.messages .alert-info {
+ color:inherit;
+ background-color:#ccc;
+}
+
+.messages .alert-error {
+ color:inherit;
+ background-color:rgba(200,16,46,0.2);
+}
+
+.messages .alert-success {
+ color:#333;
+}
+
+/*
+ * Help
+ */
+
+.help {
+ display:none;
+ position:fixed;
+ top:50px;
+ left:0;
+ right:0;
+ bottom:0;
+ overflow:auto;
+ background:rgba(51,51,51,0.3);
+ z-index:500;
+}
+
+.help-box {
+ margin-top:30px;
+ padding-top:1px;
+ padding-bottom:15px;
+ background:rgba(51,51,51,0.7);
+ color:#fff;
+}
+
+@media (max-width:768px) {
+ .help-box {
+ margin:20px 15px;
+ }
+}
+
+.help h2 {
+ padding:0 15px 20px;
+ border-bottom:1px solid #999;
+ text-align:center;
+}
+
+.help .row > div {
+ padding-right:0;
+}
+
+.help h4 {
+ margin:15px 0;
+}
diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css
index b15f6de8..9fd53604 100644
--- a/kfet/static/kfet/css/kpsul.css
+++ b/kfet/static/kfet/css/kpsul.css
@@ -319,6 +319,11 @@ input[type=number]::-webkit-outer-spin-button {
padding-left:20px;
}
+#articles_data .article:hover {
+ background:rgba(200,16,46,0.3);
+ cursor:pointer;
+}
+
/* Second part - Left - bottom */
.kpsul_middle_left_bottom {
diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js
index 7aa1d963..dbfba0b2 100644
--- a/kfet/static/kfet/js/kfet.js
+++ b/kfet/static/kfet/js/kfet.js
@@ -66,8 +66,11 @@ function getErrorsHtml(data) {
content += '';
}
if ('negative' in data['errors']) {
- var url_base = "{% url 'kfet.account.update' LIQ}";
- url_base = base_url(0, url_base.length-8);
+ if (window.location.pathname.startsWith('/gestion/')) {
+ var url_base = '/gestion/k-fet/accounts/';
+ } else {
+ var url_base = '/k-fet/accounts/';
+ }
for (var i=0; iAutorisation de négatif requise pour '+data['errors']['negative'][i]+'';
}
@@ -110,4 +113,3 @@ function requestAuth(data, callback, focus_next = null) {
}
});
}
-
diff --git a/kfet/templates/kfet/account_create_autocomplete.html b/kfet/templates/kfet/account_create_autocomplete.html
index b99abecf..1185c3a8 100644
--- a/kfet/templates/kfet/account_create_autocomplete.html
+++ b/kfet/templates/kfet/account_create_autocomplete.html
@@ -38,6 +38,7 @@
{{ clipper|highlight_clipper:q }}
+
{% endfor %}
{% endif %}
diff --git a/kfet/templates/kfet/account_negative.html b/kfet/templates/kfet/account_negative.html
index 77fdf118..5f77b8f0 100644
--- a/kfet/templates/kfet/account_negative.html
+++ b/kfet/templates/kfet/account_negative.html
@@ -59,7 +59,7 @@
{{ neg.account.name }} |
{{ neg.account.balance|floatformat:2 }}€ |
- {% if neg.account.balance_offset %}
+ {% if neg.balance_offset %}
{{ neg.account.real_balance|floatformat:2 }}€
{% endif %}
|
diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html
index c1db0c26..173a5fb7 100644
--- a/kfet/templates/kfet/base.html
+++ b/kfet/templates/kfet/base.html
@@ -40,5 +40,13 @@
{% block content %}{% endblock %}
{% include "kfet/base_footer.html" %}
+
+
+
+
Aide
+ {% block help %}{% endblock %}
+
+
+