diff --git a/README.md b/README.md index 01f4ead2..b9d736ae 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # GestioCOF +![build_status](https://git.eleves.ens.fr/cof-geek/gestioCOF/badges/master/build.svg) + ## Installation ### Vagrant diff --git a/bda/admin.py b/bda/admin.py index 60d3c1ba..6638ad45 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -import autocomplete_light from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail @@ -9,6 +8,9 @@ from django.db.models import Sum, Count from django.template.defaultfilters import pluralize from django.utils import timezone from django import forms + +from dal.autocomplete import ModelSelect2 + from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente @@ -24,8 +26,17 @@ class ReadOnlyMixin(object): return readonly_fields + self.readonly_fields_update +class ChoixSpectacleAdminForm(forms.ModelForm): + class Meta: + widgets = { + 'participant': ModelSelect2(url='bda-participant-autocomplete'), + 'spectacle': ModelSelect2(url='bda-spectacle-autocomplete'), + } + + class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle + form = ChoixSpectacleAdminForm sortable_field_name = "priority" @@ -180,7 +191,7 @@ class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin): class ChoixSpectacleAdmin(admin.ModelAdmin): - form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) + form = ChoixSpectacleAdminForm def tirage(self, obj): return obj.participant.tirage diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py deleted file mode 100644 index 6c2f3ea6..00000000 --- a/bda/autocomplete_light_registry.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import autocomplete_light - -from bda.models import Participant, Spectacle - -autocomplete_light.register( - Participant, search_fields=('user__username', 'user__first_name', - 'user__last_name'), - autocomplete_js_attributes={'placeholder': 'participant...'}) - -autocomplete_light.register( - Spectacle, search_fields=('title', ), - autocomplete_js_attributes={'placeholder': 'spectacle...'}) diff --git a/bda/migrations/0001_initial.py b/bda/migrations/0001_initial.py index aa2cb252..c4494413 100644 --- a/bda/migrations/0001_initial.py +++ b/bda/migrations/0001_initial.py @@ -59,7 +59,7 @@ class Migration(migrations.Migration): ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)), ('slots', models.IntegerField(verbose_name=b'Places')), ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')), - ('location', models.ForeignKey(to='bda.Salle')), + ('location', models.ForeignKey(to='bda.Salle', on_delete=models.CASCADE)), ], options={ 'ordering': ('priority', 'date', 'title'), @@ -79,27 +79,27 @@ class Migration(migrations.Migration): migrations.AddField( model_name='participant', name='user', - field=models.OneToOneField(to=settings.AUTH_USER_MODEL), + field=models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), ), migrations.AddField( model_name='choixspectacle', name='participant', - field=models.ForeignKey(to='bda.Participant'), + field=models.ForeignKey(to='bda.Participant', on_delete=models.CASCADE), ), migrations.AddField( model_name='choixspectacle', name='spectacle', - field=models.ForeignKey(related_name='participants', to='bda.Spectacle'), + field=models.ForeignKey(related_name='participants', to='bda.Spectacle', on_delete=models.CASCADE), ), migrations.AddField( model_name='attribution', name='participant', - field=models.ForeignKey(to='bda.Participant'), + field=models.ForeignKey(to='bda.Participant', on_delete=models.CASCADE), ), migrations.AddField( model_name='attribution', name='spectacle', - field=models.ForeignKey(related_name='attribues', to='bda.Spectacle'), + field=models.ForeignKey(related_name='attribues', to='bda.Spectacle', on_delete=models.CASCADE), ), migrations.AlterUniqueTogether( name='choixspectacle', diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py index 22c387a0..79f79a57 100644 --- a/bda/migrations/0002_add_tirage.py +++ b/bda/migrations/0002_add_tirage.py @@ -55,7 +55,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='participant', name='user', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL), + field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), ), # Create fields `spectacle` for `Participant` and `Spectacle` models. # These fields are not nullable, but we first create them as nullable @@ -63,22 +63,22 @@ class Migration(migrations.Migration): migrations.AddField( model_name='participant', name='tirage', - field=models.ForeignKey(to='bda.Tirage', null=True), + field=models.ForeignKey(to='bda.Tirage', null=True, on_delete=models.CASCADE), ), migrations.AddField( model_name='spectacle', name='tirage', - field=models.ForeignKey(to='bda.Tirage', null=True), + field=models.ForeignKey(to='bda.Tirage', null=True, on_delete=models.CASCADE), ), migrations.RunPython(fill_tirage_fields, migrations.RunPython.noop), migrations.AlterField( model_name='participant', name='tirage', - field=models.ForeignKey(to='bda.Tirage'), + field=models.ForeignKey(to='bda.Tirage', on_delete=models.CASCADE), ), migrations.AlterField( model_name='spectacle', name='tirage', - field=models.ForeignKey(to='bda.Tirage'), + field=models.ForeignKey(to='bda.Tirage', on_delete=models.CASCADE), ), ] diff --git a/bda/migrations/0007_extends_spectacle.py b/bda/migrations/0007_extends_spectacle.py index b95c18de..6ea11dc0 100644 --- a/bda/migrations/0007_extends_spectacle.py +++ b/bda/migrations/0007_extends_spectacle.py @@ -73,6 +73,7 @@ class Migration(migrations.Migration): model_name='spectacle', name='category', field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle', + on_delete=models.CASCADE, null=True), ), migrations.AddField( @@ -84,6 +85,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='quote', name='spectacle', - field=models.ForeignKey(to='bda.Spectacle'), + field=models.ForeignKey(to='bda.Spectacle', + on_delete=models.CASCADE), ), ] diff --git a/bda/migrations/0009_revente.py b/bda/migrations/0009_revente.py index 1cca4e86..70d6f338 100644 --- a/bda/migrations/0009_revente.py +++ b/bda/migrations/0009_revente.py @@ -47,12 +47,14 @@ class Migration(migrations.Migration): model_name='spectaclerevente', name='attribution', field=models.OneToOneField(to='bda.Attribution', + on_delete=models.CASCADE, related_name='revente'), ), migrations.AddField( model_name='spectaclerevente', name='seller', field=models.ForeignKey(to='bda.Participant', + on_delete=models.CASCADE, verbose_name='Vendeur', related_name='original_shows'), ), @@ -60,6 +62,7 @@ class Migration(migrations.Migration): model_name='spectaclerevente', name='soldTo', field=models.ForeignKey(to='bda.Participant', + on_delete=models.CASCADE, verbose_name='Vendue à', null=True, blank=True), ), diff --git a/bda/models.py b/bda/models.py index 41462d70..73356038 100644 --- a/bda/models.py +++ b/bda/models.py @@ -6,12 +6,15 @@ from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail from django.contrib.sites.models import Site +from django.core import mail from django.db import models from django.db.models import Count from django.contrib.auth.models import User from django.conf import settings from django.utils import timezone, formats +from custommail.models import CustomMail + def get_generic_user(): generic, _ = User.objects.get_or_create( @@ -59,9 +62,12 @@ class CategorieSpectacle(models.Model): class Spectacle(models.Model): title = models.CharField("Titre", max_length=300) - category = models.ForeignKey(CategorieSpectacle, blank=True, null=True) + category = models.ForeignKey( + CategorieSpectacle, on_delete=models.CASCADE, + blank=True, null=True, + ) date = models.DateTimeField("Date & heure") - location = models.ForeignKey(Salle) + location = models.ForeignKey(Salle, on_delete=models.CASCADE) vips = models.TextField('Personnalités', blank=True) description = models.TextField("Description", blank=True) slots_description = models.TextField("Description des places", blank=True) @@ -71,7 +77,7 @@ class Spectacle(models.Model): max_length=500) price = models.FloatField("Prix d'une place") slots = models.IntegerField("Places") - tirage = models.ForeignKey(Tirage) + tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE) listing = models.BooleanField("Les places sont sur listing") rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True, null=True) @@ -135,7 +141,7 @@ class Spectacle(models.Model): class Quote(models.Model): - spectacle = models.ForeignKey(Spectacle) + spectacle = models.ForeignKey(Spectacle, on_delete=models.CASCADE) text = models.TextField('Citation') author = models.CharField('Auteur', max_length=200) @@ -149,7 +155,7 @@ PAYMENT_TYPES = ( class Participant(models.Model): - user = models.ForeignKey(User) + user = models.ForeignKey(User, on_delete=models.CASCADE) choices = models.ManyToManyField(Spectacle, through="ChoixSpectacle", related_name="chosen_by") @@ -160,7 +166,7 @@ class Participant(models.Model): paymenttype = models.CharField("Moyen de paiement", max_length=6, choices=PAYMENT_TYPES, blank=True) - tirage = models.ForeignKey(Tirage) + tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE) choicesrevente = models.ManyToManyField(Spectacle, related_name="subscribed", blank=True) @@ -176,8 +182,11 @@ DOUBLE_CHOICES = ( class ChoixSpectacle(models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name="participants") + participant = models.ForeignKey(Participant, on_delete=models.CASCADE) + spectacle = models.ForeignKey( + Spectacle, on_delete=models.CASCADE, + related_name="participants", + ) priority = models.PositiveIntegerField("Priorité") double_choice = models.CharField("Nombre de places", default="1", choices=DOUBLE_CHOICES, @@ -204,8 +213,11 @@ class ChoixSpectacle(models.Model): class Attribution(models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name="attribues") + participant = models.ForeignKey(Participant, on_delete=models.CASCADE) + spectacle = models.ForeignKey( + Spectacle, on_delete=models.CASCADE, + related_name="attribues", + ) given = models.BooleanField("Donnée", default=False) def __str__(self): @@ -214,18 +226,25 @@ class Attribution(models.Model): class SpectacleRevente(models.Model): - attribution = models.OneToOneField(Attribution, - related_name="revente") + attribution = models.OneToOneField( + Attribution, on_delete=models.CASCADE, + related_name="revente", + ) date = models.DateTimeField("Date de mise en vente", default=timezone.now) answered_mail = models.ManyToManyField(Participant, related_name="wanted", blank=True) - seller = models.ForeignKey(Participant, - related_name="original_shows", - verbose_name="Vendeur") - soldTo = models.ForeignKey(Participant, blank=True, null=True, - verbose_name="Vendue à") + seller = models.ForeignKey( + Participant, on_delete=models.CASCADE, + verbose_name="Vendeur", + related_name="original_shows", + ) + soldTo = models.ForeignKey( + Participant, on_delete=models.CASCADE, + verbose_name="Vendue à", + blank=True, null=True, + ) notif_sent = models.BooleanField("Notification envoyée", default=False) @@ -312,37 +331,55 @@ class SpectacleRevente(models.Model): # Envoie un mail au gagnant et au vendeur winner = random.choice(inscrits) self.soldTo = winner - datatuple = [] + + mails = [] + context = { 'acheteur': winner.user, 'vendeur': seller.user, 'show': spectacle, } - datatuple.append(( - 'bda-revente-winner', - context, - settings.MAIL_DATA['revente']['FROM'], - [winner.user.email], - )) - datatuple.append(( + + c_mails_qs = CustomMail.objects.filter(shortname__in=[ + 'bda-revente-winner', 'bda-revente-loser', 'bda-revente-seller', - context, - settings.MAIL_DATA['revente']['FROM'], - [seller.user.email] - )) + ]) + + c_mails = {cm.shortname: cm for cm in c_mails_qs} + + mails.append( + c_mails['bda-revente-winner'].get_message( + context, + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[winner.user.email], + ) + ) + + mails.append( + c_mails['bda-revente-seller'].get_message( + context, + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[seller.user.email], + reply_to=[winner.user.email], + ) + ) # Envoie un mail aux perdants for inscrit in inscrits: if inscrit != winner: new_context = dict(context) new_context['acheteur'] = inscrit.user - datatuple.append(( - 'bda-revente-loser', - new_context, - settings.MAIL_DATA['revente']['FROM'], - [inscrit.user.email] - )) - send_mass_custom_mail(datatuple) + + mails.append( + c_mails['bda-revente-loser'].get_message( + new_context, + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[inscrit.user.email], + ) + ) + + mail_conn = mail.get_connection() + mail_conn.send_messages(mails) # Si personne ne veut de la place, elle part au shotgun else: self.shotgun = True diff --git a/bda/templates/bda/inscription-formset.html b/bda/templates/bda/inscription-formset.html index 65ef389b..88b65600 100644 --- a/bda/templates/bda/inscription-formset.html +++ b/bda/templates/bda/inscription-formset.html @@ -14,7 +14,7 @@
{% endif %} -Identifiants incorrects.
{% endif %}