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

This commit is contained in:
Ludovic Stephan 2016-11-12 21:48:03 -02:00
commit 13f282a289
12 changed files with 177 additions and 45 deletions

View file

@ -5,12 +5,13 @@ from __future__ import print_function
from __future__ import unicode_literals
from django.core.mail import send_mail
from django.contrib import admin
from django.db.models import Sum, Count
from django.template.defaultfilters import pluralize
from django.utils import timezone
from django import forms
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente
from django import forms
from datetime import timedelta
@ -211,9 +212,15 @@ class SalleAdmin(admin.ModelAdmin):
class SpectacleReventeAdmin(admin.ModelAdmin):
"""
Administration des reventes de spectacles
"""
model = SpectacleRevente
def spectacle(self, obj):
"""
Raccourci vers le spectacle associé à la revente.
"""
return obj.attribution.spectacle
list_display = ("spectacle", "seller", "date", "soldTo")
@ -224,6 +231,48 @@ class SpectacleReventeAdmin(admin.ModelAdmin):
'seller__user__first_name',
'seller__user__last_name']
actions = ['transfer', 'reinit']
actions_on_bottom = True
def transfer(self, request, queryset):
"""
Effectue le transfert des reventes pour lesquels on connaît l'acheteur.
"""
reventes = queryset.exclude(soldTo__isnull=True).all()
count = reventes.count()
for revente in reventes:
attrib = revente.attribution
attrib.participant = revente.soldTo
attrib.save()
self.message_user(
request,
"%d attribution%s %s été transférée%s avec succès." % (
count, pluralize(count),
pluralize(count, "a,ont"), pluralize(count))
)
transfer.short_description = "Transférer les reventes sélectionnées"
def reinit(self, request, queryset):
"""
Réinitialise les reventes.
"""
count = queryset.count()
for revente in queryset.all():
revente.date = timezone.now() - timedelta(hours=1)
revente.soldTo = None
revente.notif_sent = False
revente.tirage_done = False
if revente.answered_mail:
revente.answered_mail.clear()
revente.save()
self.message_user(
request,
"%d attribution%s %s été réinitialisée%s avec succès." % (
count, pluralize(count),
pluralize(count, "a,ont"), pluralize(count))
)
reinit.short_description = "Réinitialiser les reventes sélectionnées"
admin.site.register(CategorieSpectacle)
admin.site.register(Spectacle, SpectacleAdmin)

View file

@ -315,36 +315,55 @@ class SpectacleRevente(models.Model):
self.save()
def tirage(self):
inscrits = self.answered_mail
inscrits = list(self.answered_mail.all())
spectacle = self.attribution.spectacle
seller = self.seller
if inscrits.exists():
winner = random.choice(inscrits.all())
if inscrits:
mails = []
mail_subject = "BdA-Revente : {:s}".format(spectacle.title)
# Envoie un mail au gagnant et au vendeur
winner = random.choice(inscrits)
self.soldTo = winner
mail_buyer = """Bonjour,
context = {
'acheteur': winner.user,
'vendeur': seller.user,
'spectacle': spectacle,
}
mails.append(mail.EmailMessage(
mail_subject, loader.render_to_string('mail-revente-winner.txt', context),
from_email=settings.MAIL_DATA['revente']['FROM'],
to=[winner.user.email],
reply_to=[seller.user.email],
))
mails.append(mail.EmailMessage(
mail_subject, loader.render_to_string('mail-revente-seller.txt', context),
from_email=settings.MAIL_DATA['revente']['FROM'],
to=[seller.user.email],
reply_to=[winner.user.email],
))
Tu as été tiré-e au sort pour racheter une place pour %s le %s (%s) à %0.02f.
Tu peux contacter le/la vendeur-se à l'adresse %s.
# Envoie un mail aux perdants
for inscrit in inscrits:
if inscrit == winner:
continue
Chaleureusement,
Le BdA""" % (spectacle.title, spectacle.date_no_seconds(),
spectacle.location, spectacle.price, seller.user.email)
mail_body = loader.render_to_string('mail-revente-loser.txt', {
'acheteur': inscrit.user,
'vendeur': seller.user,
'spectacle': spectacle,
})
mails.append(mail.EmailMessage(
mail_subject, mail_body,
from_email=settings.MAIL_DATA['revente']['FROM'],
to=[inscrit.user.email],
reply_to=[settings.MAIL_DATA['revente']['REPLYTO']],
))
mail.get_connection().send_messages(mails)
mail.send_mail("BdA-Revente : %s" % spectacle.title,
mail_buyer, "bda@ens.fr", [winner.user.email],
fail_silently=False)
mail_seller = """Bonjour,
La personne tirée au sort pour racheter ta place pour %s est %s.
Tu peux le/la contacter à l'adresse %s.
Chaleureusement,
Le BdA""" % (spectacle.title, winner.user.get_full_name(), winner.user.email)
mail.send_mail("BdA-Revente : %s" % spectacle.title,
mail_seller, "bda@ens.fr", [seller.user.email],
fail_silently=False)
else: # Si personne ne veut la place, elle part au shotgun
# Si personne ne veut de la place, elle part au shotgun
else:
self.shotgun = True
self.tirage_done = True

View file

@ -62,9 +62,9 @@
<td>{{attrib.spectacle}}</td>
<td>{{attrib.revente.soldTo.user.get_full_name}}</td>
<td><button type="submit" class="btn btn-primary" name="transfer"
value={{attrib.revente.id}}>Transférer</button></td>
value="{{attrib.revente.id}}">Transférer</button></td>
<td><button type="submit" class="btn btn-primary" name="reinit"
value={{attrib.revente.id}}>Réinitialiser</button></td>
value="{{attrib.revente.id}}">Réinitialiser</button></td>
</form>
</tr>
{% endfor %}

View file

@ -0,0 +1,9 @@
Bonjour {{ acheteur.first_name }},
Tu t'étais inscrit-e pour la revente de la place de {{ vendeur.get_full_name }}
pour {{ spectacle.title }}.
Malheureusement, une autre personne a été tirée au sort pour racheter la place.
Tu pourras certainement retenter ta chance pour une autre revente !
À très bientôt,
Le Bureau des Arts

View file

@ -0,0 +1,13 @@
Bonjour {{ vendeur.first_name }},
Tu tes bien inscrit-e pour la revente de {{ spectacle.title }}.
{% with revente.expiration_time as time %}
Le tirage au sort entre tout-e-s les racheteuse-eur-s potentiel-le-s aura lieu
le {{ time|date:"DATE_FORMAT" }} à {{ time|time:"TIME_FORMAT" }} (dans {{time|timeuntil }}).
Si personne ne sest inscrit pour racheter la place, celle-ci apparaitra parmi
les « Places disponibles immédiatement à la revente » sur GestioCOF.
{% endwith %}
Bonne revente !
Le Bureau des Arts

View file

@ -0,0 +1,7 @@
Bonjour {{ vendeur.first_name }},
La personne tirée au sort pour racheter ta place pour {{ spectacle.title }} est {{ acheteur.get_full_name }}.
Tu peux le/la contacter à l'adresse {{ acheteur.email }}, ou en répondant à ce mail.
Chaleureusement,
Le BdA

View file

@ -0,0 +1,7 @@
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 peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail.
Chaleureusement,
Le BdA

View file

@ -8,15 +8,17 @@ import random
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.db import models
from django.db import models, transaction
from django.db.models import Count, Q
from django.core import serializers
from django.core import serializers, mail
from django.forms.models import inlineformset_factory
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.conf import settings
import hashlib
from django.core.mail import send_mail
from django.template import loader
from django.utils import timezone
from django.views.generic.list import ListView
@ -273,15 +275,30 @@ def revente(request, tirage_id):
resellform = ResellForm(participant, request.POST, prefix='resell')
annulform = AnnulForm(participant, prefix='annul')
if resellform.is_valid():
mails = []
attributions = resellform.cleaned_data["attributions"]
for attribution in attributions:
revente, created = SpectacleRevente.objects.get_or_create(
attribution=attribution,
defaults={'seller': participant})
if not created:
revente.seller = participant
revente.date = timezone.now()
revente.save()
with transaction.atomic():
for attribution in attributions:
revente, created = SpectacleRevente.objects.get_or_create(
attribution=attribution,
defaults={'seller': participant})
if not created:
revente.seller = participant
revente.date = timezone.now()
mail_subject = "BdA-Revente : {:s}".format(attribution.spectacle.title)
mail_body = loader.render_to_string('mail-revente-new.txt', {
'vendeur': participant.user,
'spectacle': attribution.spectacle,
'revente': revente,
})
mails.append(mail.EmailMessage(
mail_subject, mail_body,
from_email=settings.MAIL_DATA['revente']['FROM'],
to=[participant.user.email],
reply_to=[settings.MAIL_DATA['revente']['REPLYTO']],
))
revente.save()
mail.get_connection().send_messages(mails)
elif 'annul' in request.POST:
annulform = AnnulForm(participant, request.POST, prefix='annul')
@ -314,6 +331,8 @@ def revente(request, tirage_id):
revente = rev.get()
revente.date = timezone.now() - timedelta(hours=1)
revente.soldTo = None
revente.notif_sent = False
revente.tirage_done = False
if revente.answered_mail:
revente.answered_mail.clear()
revente.save()

View file

@ -29,9 +29,6 @@ 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 = ['127.0.0.1']
# Application definition
INSTALLED_APPS = (
'gestioncof',
@ -126,7 +123,7 @@ STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static/'),
os.path.join(BASE_DIR, 'static/'),
)
# Media upload (through ImageField, SiteField)

View file

@ -29,6 +29,12 @@ class COFCASBackend(CASBackend):
request.session['attributes'] = attributes
if not username:
return None
# Le CAS de l'ENS accepte les logins avec des espaces au début
# et à la fin, ainsi quavec une casse variable. On normalise pour
# éviter les doublons.
username = username.strip().lower()
profiles = CofProfile.objects.filter(login_clipper=username)
if len(profiles) > 0:
profile = profiles.order_by('-is_cof')[0]

View file

@ -14,6 +14,7 @@ from django.http import Http404, HttpResponse, HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as django_login_view
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.utils import timezone
import django.utils.six as six
@ -710,12 +711,15 @@ def calendar_ics(request, token):
tirage__active=True)
shows = shows.distinct()
vcal = Calendar()
site = Site.objects.get_current()
for show in shows:
vevent = Vevent()
vevent.add('dtstart', show.date)
vevent.add('dtend', show.date + timedelta(seconds=7200))
vevent.add('summary', show.title)
vevent.add('location', show.location.name)
vevent.add('uid', 'show-{:d}-{:d}@{:s}'.format(
show.pk, show.tirage_id, site.domain))
vcal.add_component(vevent)
if subscription.subscribe_to_events:
for event in Event.objects.filter(old=False).all():
@ -725,6 +729,8 @@ def calendar_ics(request, token):
vevent.add('summary', event.title)
vevent.add('location', event.location)
vevent.add('description', event.description)
vevent.add('uid', 'event-{:d}@{:s}'.format(
event.pk, site.domain))
vcal.add_component(vevent)
response = HttpResponse(content=vcal.to_ical())
response['Content-Type'] = "text/calendar"

View file

@ -1,8 +1,8 @@
configparser==3.5.0
Django==1.8
Django==1.8.*
django-autocomplete-light==2.3.3
django-autoslug==1.9.3
git+https://github.com/xapantu/django-cas-ng.git#egg=django-cas-ng
django-cas-ng==3.5.5
django-grappelli==2.8.1
django-recaptcha==1.0.5
mysqlclient==1.3.7
@ -15,7 +15,7 @@ django-bootstrap-form==3.2.1
asgiref==0.14.0
daphne==0.14.3
asgi-redis==0.14.0
-e git+https://github.com/Aureplop/channels.git#egg=channel
git+https://github.com/Aureplop/channels.git#egg=channel
statistics==1.0.3.5
future==0.15.2
django-widget-tweaks==1.4.1