Merge branch 'master' of git.eleves.ens.fr:cof-geek/gestioCOF into Aufinal/clean_code

This commit is contained in:
Ludovic Stephan 2016-11-23 01:49:54 -02:00
commit a9f25374ff
26 changed files with 162 additions and 123 deletions

2
Vagrantfile vendored
View file

@ -10,7 +10,7 @@ Vagrant.configure(2) do |config|
# For a complete reference, please see the online documentation at # For a complete reference, please see the online documentation at
# https://docs.vagrantup.com. # https://docs.vagrantup.com.
config.vm.box = "ubuntu/trusty64" config.vm.box = "ubuntu/xenial64"
# On associe le port 80 dans la machine virtuelle avec le port 8080 de notre # On associe le port 80 dans la machine virtuelle avec le port 8080 de notre
# ordinateur, et le port 8000 avec le port 8000. # ordinateur, et le port 8000 avec le port 8000.

View file

@ -1,16 +1,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Gestion en ligne de commande des reventes.
"""
from __future__ import unicode_literals from __future__ import unicode_literals
from datetime import timedelta
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone from django.utils import timezone
from datetime import timedelta
from bda.models import SpectacleRevente from bda.models import SpectacleRevente
class Command(BaseCommand): class Command(BaseCommand):
help = "Envoie les mails de notification et effectue " \ help = "Envoie les mails de notification et effectue " \
"les tirages au sort des reventes" "les tirages au sort des reventes"
leave_locale_alone = True
def handle(self, *args, **options): def handle(self, *args, **options):
now = timezone.now() now = timezone.now()
@ -18,21 +23,21 @@ class Command(BaseCommand):
for revente in reventes: for revente in reventes:
# Check si < 24h # Check si < 24h
if (revente.attribution.spectacle.date <= if (revente.attribution.spectacle.date <=
revente.date + timedelta(days=1)) and \ revente.date + timedelta(days=1)) and \
now >= revente.date + timedelta(minutes=15) and \ now >= revente.date + timedelta(minutes=15) and \
not revente.notif_sent: not revente.notif_sent:
self.stdout.write(str(now)) self.stdout.write(str(now))
revente.mail_shotgun() revente.mail_shotgun()
self.stdout.write("Mail de disponibilité immédiate envoyé") self.stdout.write("Mail de disponibilité immédiate envoyé")
# Check si délai de retrait dépassé # Check si délai de retrait dépassé
elif (now >= revente.date + timedelta(hours=1) and elif (now >= revente.date + timedelta(hours=1) and
not revente.notif_sent): not revente.notif_sent):
self.stdout.write(str(now)) self.stdout.write(str(now))
revente.send_notif() revente.send_notif()
self.stdout.write("Mail d'inscription à une revente envoyé") self.stdout.write("Mail d'inscription à une revente envoyé")
# Check si tirage à faire # Check si tirage à faire
elif (now >= revente.date_tirage and elif (now >= revente.date_tirage and
not revente.tirage_done): not revente.tirage_done):
self.stdout.write(str(now)) self.stdout.write(str(now))
revente.tirage() revente.tirage()
self.stdout.write("Tirage effectué, mails envoyés") self.stdout.write("Tirage effectué, mails envoyés")

View file

@ -1,16 +1,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Gestion en ligne de commande des mails de rappel.
"""
from __future__ import unicode_literals from __future__ import unicode_literals
from datetime import timedelta
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils import timezone from django.utils import timezone
from datetime import timedelta
from bda.models import Spectacle from bda.models import Spectacle
class Command(BaseCommand): class Command(BaseCommand):
help = 'Envoie les mails de rappel des spectacles dont la date ' \ help = 'Envoie les mails de rappel des spectacles dont la date ' \
'approche.\nNe renvoie pas les mails déjà envoyés.' 'approche.\nNe renvoie pas les mails déjà envoyés.'
leave_locale_alone = True
def handle(self, *args, **options): def handle(self, *args, **options):
now = timezone.now() now = timezone.now()

View file

@ -11,19 +11,13 @@ from datetime import timedelta
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.template import loader, Context from django.template import loader
from django.core import mail from django.core import mail
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone, formats
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
def render_template(template_name, data):
tmpl = loader.get_template(template_name)
ctxt = Context(data)
return tmpl.render(ctxt)
@python_2_unicode_compatible @python_2_unicode_compatible
class Tirage(models.Model): class Tirage(models.Model):
title = models.CharField("Titre", max_length=300) title = models.CharField("Titre", max_length=300)
@ -34,12 +28,9 @@ class Tirage(models.Model):
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):
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, formats.localize(
timezone.template_localtime(self.fermeture)))
@python_2_unicode_compatible @python_2_unicode_compatible
@ -89,15 +80,19 @@ class Spectacle(models.Model):
def timestamp(self): def timestamp(self):
return "%d" % calendar.timegm(self.date.utctimetuple()) return "%d" % calendar.timegm(self.date.utctimetuple())
def date_no_seconds(self):
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.location, self.price) self.title,
formats.localize(timezone.template_localtime(self.date)),
self.location,
self.price
)
def send_rappel(self): def send_rappel(self):
"""
Envoie un mail de rappel à toutes les personnes qui ont une place pour
ce spectacle.
"""
# On récupère la liste des participants # On récupère la liste des participants
members = {} members = {}
for attr in Attribution.objects.filter(spectacle=self).all(): for attr in Attribution.objects.filter(spectacle=self).all():
@ -111,18 +106,17 @@ class Spectacle(models.Model):
members[-1] = ['BdA', 2, 'bda@ens.fr'] members[-1] = ['BdA', 2, 'bda@ens.fr']
# On écrit un mail personnalisé à chaque participant # On écrit un mail personnalisé à chaque participant
mails_to_send = [] mails_to_send = []
mail_object = "%s - %s - %s" % (self.title, self.date_no_seconds(), mail_object = str(self)
self.location)
for member in members.values(): for member in members.values():
mail_body = render_template('mail-rappel.txt', { mail_body = loader.render_to_string('bda/mails/rappel.txt', {
'name': member[0], 'name': member[0],
'nb_attr': member[1], 'nb_attr': member[1],
'show': self}) 'show': self})
mail_tot = mail.EmailMessage( mail_tot = mail.EmailMessage(
mail_object, mail_body, mail_object, mail_body,
settings.MAIL_DATA['rappels']['FROM'], [member[2]], settings.MAIL_DATA['rappels']['FROM'], [member[2]],
[], headers={ [], headers={
'Reply-To': settings.MAIL_DATA['rappels']['REPLYTO']}) 'Reply-To': settings.MAIL_DATA['rappels']['REPLYTO']})
mails_to_send.append(mail_tot) mails_to_send.append(mail_tot)
# On envoie les mails # On envoie les mails
connection = mail.get_connection() connection = mail.get_connection()
@ -262,17 +256,17 @@ class SpectacleRevente(models.Model):
mails_to_send = [] mails_to_send = []
mail_object = "%s" % (self.attribution.spectacle) mail_object = "%s" % (self.attribution.spectacle)
for participant in inscrits: for participant in inscrits:
mail_body = render_template('mail-revente.txt', { mail_body = loader.render_to_string('bda/mails/revente.txt', {
'user': participant.user, 'user': participant.user,
'spectacle': self.attribution.spectacle, 'spectacle': self.attribution.spectacle,
'revente': self, 'revente': self,
'domain': Site.objects.get_current().domain}) 'domain': Site.objects.get_current().domain})
mail_tot = mail.EmailMessage( mail_tot = mail.EmailMessage(
mail_object, mail_body, mail_object, mail_body,
settings.MAIL_DATA['revente']['FROM'], settings.MAIL_DATA['revente']['FROM'],
[participant.user.email], [participant.user.email],
[], headers={ [], headers={
'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']})
mails_to_send.append(mail_tot) mails_to_send.append(mail_tot)
connection = mail.get_connection() connection = mail.get_connection()
@ -281,22 +275,26 @@ class SpectacleRevente(models.Model):
self.save() self.save()
def mail_shotgun(self): def mail_shotgun(self):
"""
Envoie un mail à toutes les personnes intéréssées par le spectacle pour
leur indiquer qu'il est désormais disponible au shotgun.
"""
inscrits = self.attribution.spectacle.subscribed.select_related('user') inscrits = self.attribution.spectacle.subscribed.select_related('user')
mails_to_send = [] mails_to_send = []
mail_object = "%s" % (self.attribution.spectacle) mail_object = "%s" % (self.attribution.spectacle)
for participant in inscrits: for participant in inscrits:
mail_body = render_template('mail-shotgun.txt', { mail_body = loader.render_to_string('bda/mails/shotgun.txt', {
'user': participant.user, 'user': participant.user,
'spectacle': self.attribution.spectacle, 'spectacle': self.attribution.spectacle,
'domain': Site.objects.get_current(), 'domain': Site.objects.get_current(),
'mail': self.attribution.participant.user.email}) 'mail': self.attribution.participant.user.email})
mail_tot = mail.EmailMessage( mail_tot = mail.EmailMessage(
mail_object, mail_body, mail_object, mail_body,
settings.MAIL_DATA['revente']['FROM'], settings.MAIL_DATA['revente']['FROM'],
[participant.user.email], [participant.user.email],
[], headers={ [], headers={
'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']})
mails_to_send.append(mail_tot) mails_to_send.append(mail_tot)
connection = mail.get_connection() connection = mail.get_connection()
@ -308,6 +306,11 @@ class SpectacleRevente(models.Model):
self.save() self.save()
def tirage(self): def tirage(self):
"""
Lance le tirage au sort associé à la revente. Un gagnant est choisi
parmis les personnes intéressées par le spectacle. Les personnes sont
ensuites prévenues par mail du résultat du tirage.
"""
inscrits = list(self.answered_mail.all()) inscrits = list(self.answered_mail.all())
spectacle = self.attribution.spectacle spectacle = self.attribution.spectacle
seller = self.seller seller = self.seller
@ -325,13 +328,17 @@ class SpectacleRevente(models.Model):
'spectacle': spectacle, 'spectacle': spectacle,
} }
mails.append(mail.EmailMessage( mails.append(mail.EmailMessage(
mail_subject, loader.render_to_string('mail-revente-winner.txt', context), mail_subject,
loader.render_to_string('bda/mails/revente-winner.txt',
context),
from_email=settings.MAIL_DATA['revente']['FROM'], from_email=settings.MAIL_DATA['revente']['FROM'],
to=[winner.user.email], to=[winner.user.email],
reply_to=[seller.user.email], reply_to=[seller.user.email],
)) ))
mails.append(mail.EmailMessage( mails.append(mail.EmailMessage(
mail_subject, loader.render_to_string('mail-revente-seller.txt', context), mail_subject,
loader.render_to_string('bda/mails/revente-seller.txt',
context),
from_email=settings.MAIL_DATA['revente']['FROM'], from_email=settings.MAIL_DATA['revente']['FROM'],
to=[seller.user.email], to=[seller.user.email],
reply_to=[winner.user.email], reply_to=[winner.user.email],
@ -342,11 +349,12 @@ class SpectacleRevente(models.Model):
if inscrit == winner: if inscrit == winner:
continue continue
mail_body = loader.render_to_string('mail-revente-loser.txt', { mail_body = loader.render_to_string(
'acheteur': inscrit.user, 'bda/mails/revente-loser.txt',
'vendeur': seller.user, {'acheteur': inscrit.user,
'spectacle': spectacle, 'vendeur': seller.user,
}) 'spectacle': spectacle}
)
mails.append(mail.EmailMessage( mails.append(mail.EmailMessage(
mail_subject, mail_body, mail_subject, mail_body,
from_email=settings.MAIL_DATA['revente']['FROM'], from_email=settings.MAIL_DATA['revente']['FROM'],

View file

@ -22,7 +22,7 @@
{% for show, members, losers in results %} {% for show, members, losers in results %}
<div class="attribresult"> <div class="attribresult">
<h3 class="horizontal-title">{{ show.title }} - {{ show.date_no_seconds }} @ {{ show.location }}</h3> <h3 class="horizontal-title">{{ show.title }} - {{ show.date }} @ {{ show.location }}</h3>
<p> <p>
<strong>{{ show.nrequests }} demandes pour {{ show.slots }} places</strong> <strong>{{ show.nrequests }} demandes pour {{ show.slots }} places</strong>
{{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }} de déficit{% endif %} {{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }} de déficit{% endif %}

View file

@ -0,0 +1,6 @@
Bonjour {{ vendeur.first_name }} !
Je souhaiterais racheter ta place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€.
Contacte-moi si tu es toujours intéressé·e !
{{ acheteur.get_full_name }} ({{ acheteur.email }})

View file

@ -1,7 +1,7 @@
Bonjour {{ name }}, Bonjour {{ name }},
Nous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:"une place,deux places" }} Nous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:"une place,deux places" }}
pour {{ show.title }}, le {{ show.date_no_seconds }} au {{ show.location }}. N'oublie pas de t'y rendre ! pour {{ show.title }}, le {{ show.date }} au {{ show.location }}. N'oublie pas de t'y rendre !
{% if nb_attr == 2 %} {% if nb_attr == 2 %}
Tu as obtenu deux places pour ce spectacle. Nous te rappelons que Tu as obtenu deux places pour ce spectacle. Nous te rappelons que
ces places sont strictement réservées aux personnes de moins de 28 ans. ces places sont strictement réservées aux personnes de moins de 28 ans.

View file

@ -1,6 +1,6 @@
Bonjour {{ acheteur.first_name }}, Bonjour {{ acheteur.first_name }},
Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date_no_seconds }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€.
Tu peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail. Tu peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail.
Chaleureusement, Chaleureusement,

View file

@ -1,6 +1,6 @@
Bonjour {{ user.first_name }} Bonjour {{ user.first_name }}
Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date_no_seconds }}) Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }})
a été postée sur BdA-Revente. a été postée sur BdA-Revente.
{% with revente.date_tirage as time %} {% with revente.date_tirage as time %}

View file

@ -1,10 +1,10 @@
Bonjour {{ user.first_name }} Bonjour {{ user.first_name }}
Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date_no_seconds }}) Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }})
a été postée sur BdA-Revente. a été postée sur BdA-Revente.
Puisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour Puisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour
cette place : elle est disponible immédiatement à l'addresse cette place : elle est disponible immédiatement à l'adresse
http://{{ domain }}{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous. http://{{ domain }}{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous.
Chaleureusement, Chaleureusement,

View file

@ -18,7 +18,7 @@
{% for spectacle in spectacles %} {% for spectacle in spectacles %}
<tr> <tr>
<td>{{ spectacle.title }}</td> <td>{{ spectacle.title }}</td>
<td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date_no_seconds }}</td> <td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date }}</td>
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td> <td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
<td data-sort-value="{{ spectacle.slots }}">{{ spectacle.slots }} places</td> <td data-sort-value="{{ spectacle.slots }}">{{ spectacle.slots }} places</td>
<td data-sort-value="{{ spectacle.total }}">{{ spectacle.total }} demandes</td> <td data-sort-value="{{ spectacle.total }}">{{ spectacle.total }} demandes</td>

View file

@ -11,7 +11,7 @@
<tr> <tr>
<td>{{place.spectacle.title}}</td> <td>{{place.spectacle.title}}</td>
<td>{{place.spectacle.location}}</td> <td>{{place.spectacle.location}}</td>
<td>{{place.spectacle.date_no_seconds}}</td> <td>{{place.spectacle.date}}</td>
<td>{% if place.double %}deux places{%else%}une place{% endif %}</td> <td>{% if place.double %}deux places{%else%}une place{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -19,7 +19,7 @@
{% for spectacle in object_list %} {% for spectacle in object_list %}
<tr class="clickable-row" data-href="{% url 'bda-spectacle' tirage_id spectacle.id %}"> <tr class="clickable-row" data-href="{% url 'bda-spectacle' tirage_id spectacle.id %}">
<td><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle.title }} <span style="font-size:small;" class="glyphicon glyphicon-link" aria-hidden="true"></span></a></td> <td><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle.title }} <span style="font-size:small;" class="glyphicon glyphicon-link" aria-hidden="true"></span></a></td>
<td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date_no_seconds }}</td> <td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date }}</td>
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td> <td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
<td data-sort-value="{{ spectacle.price |stringformat:".3f" }}"> <td data-sort-value="{{ spectacle.price |stringformat:".3f" }}">
{{ spectacle.price |floatformat }}€ {{ spectacle.price |floatformat }}€

View file

@ -27,7 +27,7 @@ from datetime import timedelta
from gestioncof.decorators import cof_required, buro_required from gestioncof.decorators import cof_required, buro_required
from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\ from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\
Tirage, render_template, SpectacleRevente Tirage, SpectacleRevente
from bda.algorithm import Algorithm from bda.algorithm import Algorithm
from bda.forms import BaseBdaFormSet, TokenForm, ResellForm, AnnulForm,\ from bda.forms import BaseBdaFormSet, TokenForm, ResellForm, AnnulForm,\
@ -289,7 +289,7 @@ def revente(request, tirage_id):
revente.tirage_done = False revente.tirage_done = False
revente.shotgun = False revente.shotgun = False
mail_subject = "BdA-Revente : {:s}".format(attribution.spectacle.title) mail_subject = "BdA-Revente : {:s}".format(attribution.spectacle.title)
mail_body = loader.render_to_string('mail-revente-new.txt', { mail_body = loader.render_to_string('bda/mails/revente-new.txt', {
'vendeur': participant.user, 'vendeur': participant.user,
'spectacle': attribution.spectacle, 'spectacle': attribution.spectacle,
'revente': revente, 'revente': revente,
@ -443,14 +443,11 @@ def buy_revente(request, spectacle_id):
revente = random.choice(reventes_shotgun) revente = random.choice(reventes_shotgun)
revente.soldTo = participant revente.soldTo = participant
revente.save() revente.save()
mail = """Bonjour ! mail = loader.render_to_string('bda/mails/buy-shotgun.txt', {
'spectacle': spectacle,
Je souhaiterais racheter ta place pour %s le %s (%s) à %.02f. 'acheteur': request.user,
Contacte-moi si tu es toujours intéressé·e ! 'vendeur': revente.seller.user,
})
%s (%s)""" % (spectacle.title, spectacle.date_no_seconds(),
spectacle.location, spectacle.price,
request.user.get_full_name(), request.user.email)
send_mail("BdA-Revente : %s" % spectacle.title, mail, send_mail("BdA-Revente : %s" % spectacle.title, mail,
request.user.email, request.user.email,
[revente.seller.user.email], [revente.seller.user.email],
@ -543,11 +540,11 @@ def send_rappel(request, spectacle_id):
# Mails d'exemples # Mails d'exemples
fake_member = request.user fake_member = request.user
fake_member.nb_attr = 1 fake_member.nb_attr = 1
exemple_mail_1place = render_template('mail-rappel.txt', { exemple_mail_1place = loader.render_to_string('bda/mails/rappel.txt', {
'member': fake_member, 'member': fake_member,
'show': show}) 'show': show})
fake_member.nb_attr = 2 fake_member.nb_attr = 2
exemple_mail_2places = render_template('mail-rappel.txt', { exemple_mail_2places = loader.render_to_string('bda/mails/rappel.txt', {
'member': fake_member, 'member': fake_member,
'show': show}) 'show': show})
# Contexte # Contexte

0
cof/locale/__init__.py Normal file
View file

View file

9
cof/locale/fr/formats.py Normal file
View file

@ -0,0 +1,9 @@
# -*- encoding: utf-8 -*-
"""
Formats français.
"""
from __future__ import unicode_literals
DATETIME_FORMAT = r'l j F Y \à H:i'

View file

@ -200,3 +200,5 @@ def show_toolbar(request):
DEBUG_TOOLBAR_CONFIG = { DEBUG_TOOLBAR_CONFIG = {
'SHOW_TOOLBAR_CALLBACK': show_toolbar, 'SHOW_TOOLBAR_CALLBACK': show_toolbar,
} }
FORMAT_MODULE_PATH = 'cof.locale'

View file

@ -1,24 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Fichier principal de configuration des urls du projet GestioCOF
"""
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
import autocomplete_light
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
import autocomplete_light
from django.contrib.auth import views as django_views 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 clubs_patterns
from gestioncof.autocomplete import autocomplete from gestioncof.autocomplete import autocomplete
autocomplete_light.autodiscover() autocomplete_light.autodiscover()
@ -92,4 +95,5 @@ if settings.DEBUG:
# 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 += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)

View file

@ -14,7 +14,7 @@ from django.contrib.auth.models import User
from django.views.generic import ListView from django.views.generic import ListView
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.template import loader, Context from django.template import loader
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Min from django.db.models import Min
@ -33,12 +33,6 @@ import base64
import json import json
def render_template(template_path, data):
tmpl = loader.get_template(template_path)
context = Context(data)
return tmpl.render(context)
class DemandeListView(ListView): class DemandeListView(ListView):
model = PetitCoursDemande model = PetitCoursDemande
template_name = "petits_cours_demandes_list.html" template_name = "petits_cours_demandes_list.html"
@ -137,14 +131,14 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
proposed_for = proposed_for.items() proposed_for = proposed_for.items()
attribdata = list(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 = loader.render_to_string("petits-cours-mail-demandeur.txt", {
{"proposals": proposals, "proposals": proposals,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"extra": "extra":
'<textarea name="extra" ' '<textarea name="extra" '
'style="width:99%; height: 90px;">' 'style="width:99%; height: 90px;">'
'</textarea>' '</textarea>'
}) })
return render(request, "traitement_demande_petit_cours.html", return render(request, "traitement_demande_petit_cours.html",
{"demande": demande, {"demande": demande,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
@ -163,8 +157,10 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
def _generate_eleve_email(demande, proposed_for): def _generate_eleve_email(demande, proposed_for):
proposed_mails = [] proposed_mails = []
for user, matieres in proposed_for: for user, matieres in proposed_for:
msg = render_template("petits-cours-mail-eleve.txt", msg = loader.render_to_string("petits-cours-mail-eleve.txt", {
{"demande": demande, "matieres": matieres}) "demande": demande,
"matieres": matieres
})
proposed_mails.append((user, msg)) proposed_mails.append((user, msg))
return proposed_mails return proposed_mails
@ -278,10 +274,11 @@ def _traitement_post(request, demande):
proposals_list = proposals.items() proposals_list = proposals.items()
proposed_for = proposed_for.items() proposed_for = proposed_for.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 = loader.render_to_string("petits-cours-mail-demandeur.txt", {
{"proposals": proposals_list, "proposals": proposals_list,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"extra": extra}) "extra": extra,
})
frommail = settings.MAIL_DATA['petits_cours']['FROM'] frommail = settings.MAIL_DATA['petits_cours']['FROM']
bccaddress = settings.MAIL_DATA['petits_cours']['BCC'] bccaddress = settings.MAIL_DATA['petits_cours']['BCC']
replyto = settings.MAIL_DATA['petits_cours']['REPLYTO'] replyto = settings.MAIL_DATA['petits_cours']['REPLYTO']

View file

@ -8,7 +8,7 @@ DBNAME="cof_gestion"
DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" 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 python3-pip python3-dev python3-venv \
libmysqlclient-dev libjpeg-dev git redis-server libmysqlclient-dev libjpeg-dev git redis-server
pip install -U pip pip install -U pip
@ -30,10 +30,10 @@ a2ensite gestiocof
a2dissite 000-default a2dissite 000-default
service apache2 restart service apache2 restart
mkdir /var/www/static mkdir /var/www/static
chown -R vagrant:www-data /var/www/static chown -R ubuntu: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 >> ~ubuntu/.bashrc <<EOF
# On utilise la version de développement de GestioCOF # On utilise la version de développement de GestioCOF
export DJANGO_SETTINGS_MODULE='cof.settings_dev' export DJANGO_SETTINGS_MODULE='cof.settings_dev'
@ -45,25 +45,29 @@ export DBPASSWD="$DBPASSWD"
# Permet d'utiliser les utilitaires pythons locaux # Permet d'utiliser les utilitaires pythons locaux
export PATH="\$PATH:\$HOME/.local/bin" export PATH="\$PATH:\$HOME/.local/bin"
# Charge le virtualenv
source ~/venv/bin/activate
# On va dans /vagrant où se trouve le code de gestioCOF # On va dans /vagrant où se trouve le code de gestioCOF
cd /vagrant cd /vagrant
EOF EOF
chown vagrant: ~vagrant/.bash_profile
# On va dans /vagrant où se trouve gestioCOF # On va dans /vagrant où se trouve gestioCOF
cd /vagrant cd /vagrant
# Installation des dépendances python # Installation du virtualenv, on utilise désormais python3
sudo -H -u vagrant pip install --user -r requirements.txt -r requirements-devel.txt sudo -H -u ubuntu python3 -m venv ~ubuntu/venv
sudo -H -u ubuntu ~ubuntu/venv/bin/pip install -U pip
sudo -H -u ubuntu ~ubuntu/venv/bin/pip install -r requirements.txt -r requirements-devel.txt
# Préparation de Django # Préparation de Django
sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD sh provisioning/prepare_django.sh sudo -H -u ubuntu DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD bash provisioning/prepare_django.sh
# 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 ubuntu crontab provisioning/cron.dev
# On installe Daphne et on demande à supervisor de le lancer # On installe Daphne et on demande à supervisor de le lancer
pip install daphne sudo -H -u ubuntu ~ubuntu/venv/bin/pip install daphne
apt-get install -y supervisor apt-get install -y supervisor
cp /vagrant/provisioning/supervisor.conf /etc/supervisor/conf.d/gestiocof.conf cp /vagrant/provisioning/supervisor.conf /etc/supervisor/conf.d/gestiocof.conf
sed "s/{DBUSER}/$DBUSER/" -i /etc/supervisor/conf.d/gestiocof.conf sed "s/{DBUSER}/$DBUSER/" -i /etc/supervisor/conf.d/gestiocof.conf

View file

@ -1,5 +1,7 @@
#!/bin/bash
# Doit être lancé par bootstrap.sh # Doit être lancé par bootstrap.sh
source ~/venv/bin/activate
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 python manage.py collectstatic --noinput

View file

@ -1,7 +1,7 @@
[program:worker] [program:worker]
command=/usr/bin/python /vagrant/manage.py runworker command=/home/ubuntu/venv/bin/python /vagrant/manage.py runworker
directory=/vagrant/ directory=/vagrant/
user=vagrant user=ubuntu
environment=DBUSER={DBUSER},DBNAME={DBNAME},DBPASSWD={DBPASSWD},DJANGO_SETTINGS_MODULE="cof.settings_dev" environment=DBUSER={DBUSER},DBNAME={DBNAME},DBPASSWD={DBPASSWD},DJANGO_SETTINGS_MODULE="cof.settings_dev"
autostart=true autostart=true
autorestart=true autorestart=true
@ -10,11 +10,11 @@ stopasgroup=true
redirect_stderr=true redirect_stderr=true
[program:interface] [program:interface]
command=/usr/local/bin/daphne -b 127.0.0.1 -p 8001 cof.asgi:channel_layer command=/home/ubuntu/venv/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" environment=DBUSER={DBUSER},DBNAME={DBNAME},DBPASSWD={DBPASSWD},DJANGO_SETTINGS_MODULE="cof.settings_dev"
directory=/vagrant/ directory=/vagrant/
redirect_stderr=true redirect_stderr=true
autostart=true autostart=true
autorestart=true autorestart=true
stopasgroup=true stopasgroup=true
user=vagrant user=ubuntu