From fc4e5f0ea94ffdc8ec1ea1e7658cff3e4383426c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 4 Jan 2018 20:17:23 +0100 Subject: [PATCH 1/5] Gitignore venv --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3f4eebc..8489a96 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ media/ db.sqlite3 Ernestophone/settings/secret.py __pycache__ +venv From 4591fface7cf5eb5684fa9dbad03542a1fba5941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 4 Jan 2018 20:20:30 +0100 Subject: [PATCH 2/5] Categories can be created dynamically --- partitions/admin.py | 9 +++ partitions/migrations/0002_category.py | 80 +++++++++++++++++++ partitions/models.py | 26 +++--- partitions/templates/partitions/liste.html | 56 ++++++------- .../templates/partitions/liste_item.html | 11 --- partitions/views.py | 13 +-- 6 files changed, 132 insertions(+), 63 deletions(-) create mode 100644 partitions/admin.py create mode 100644 partitions/migrations/0002_category.py delete mode 100644 partitions/templates/partitions/liste_item.html diff --git a/partitions/admin.py b/partitions/admin.py new file mode 100644 index 0000000..0a0538f --- /dev/null +++ b/partitions/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from .models import Category + + +@admin.register(Category) +class CategoryAdmin(admin.ModelAdmin): + list_display = ["name", "order"] + list_editable = ["order"] + ordering = ["order"] diff --git a/partitions/migrations/0002_category.py b/partitions/migrations/0002_category.py new file mode 100644 index 0000000..37f55c0 --- /dev/null +++ b/partitions/migrations/0002_category.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +def create_categories(apps, schema_editor): + # Insert the previously hardcoded categories in the database + Category = apps.get_model("partitions", "Category") + Category.objects.bulk_create([ + Category(name="Partitions actives", order=1), + Category(name="Partitions optionnelles", order=2), + Category(name="Partitions à venir", order=3), + Category(name="Archives", order=4) + ]) + + +def set_new_categories(apps, schema_editor): + Category = apps.get_model("partitions", "Category") + PartitionSet = apps.get_model("partitions", "PartitionSet") + assoc_list = Category.objects.order_by("order") + mapping = { + "active": assoc_list[0], + "incoming": assoc_list[2], + "old": assoc_list[3], + "optional": assoc_list[1] + } + for par_set in PartitionSet.objects.all(): + par_set.category = mapping[par_set.category_old] + par_set.save() + + +def reset_old_categories(apps, schema_editor): + Category = apps.get_model("partitions", "Category") + PartitionSet = apps.get_model("partition", "PartitionSet") + assoc_list = Category.values_list("order", "id").order_by("order") + mapping = { + assoc_list[0][1]: "active", + assoc_list[2][1]: "incoming", + assoc_list[3][1]: "old", + assoc_list[1][1]: "optional" + } + for par_set in PartitionSet.objects.all(): + par_set.category_old = mapping[par_set.category] + par_set.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('partitions', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), + ('name', models.CharField(max_length=127)), + ('order', models.IntegerField(verbose_name='order')), + ], + options={'verbose_name': 'catégorie', 'verbose_name_plural': 'catégories'}, + ), + migrations.RunPython(create_categories, migrations.RunPython.noop), + migrations.RenameField(model_name="partitionset", old_name="category", new_name="category_old"), + migrations.AddField( + model_name='partitionset', + name='category', + field=models.ForeignKey( + verbose_name='Type de partition', + to='partitions.Category', + on_delete=django.db.models.deletion.PROTECT, + default=1 # Dummy, will be set by the RunPython operation + ), + preserve_default=False, + ), + migrations.RunPython(set_new_categories, migrations.RunPython.noop), + migrations.RemoveField(model_name="partitionset", name="category_old"), + ] diff --git a/partitions/models.py b/partitions/models.py index ec823d2..103b672 100644 --- a/partitions/models.py +++ b/partitions/models.py @@ -4,12 +4,16 @@ from django.conf import settings from django.db import models -PARTITION_TYPES = ( - ("active", "Actif"), - ("incoming", "À venir"), - ("old", "Archive"), - ("optional", "Optionnel"), -) +class Category(models.Model): + name = models.CharField(max_length=127) + order = models.IntegerField(verbose_name="order") + + def __str__(self): + return self.name + + class Meta: + verbose_name = "catégorie" + verbose_name_plural = "catégories" class Partition(models.Model): @@ -28,10 +32,12 @@ class Partition(models.Model): class PartitionSet(models.Model): nom = models.CharField(max_length=100) auteur = models.CharField(max_length=100) - category = models.CharField('Types de partitions', max_length=8, - choices=PARTITION_TYPES, default="incoming") + category = models.ForeignKey( + Category, + on_delete=models.PROTECT, + verbose_name="Type de partition" + ) infos = models.TextField("Infos utiles", null=True, blank=True) def __str__(self): - return("%s - %s [%s]" % (self.nom, self.auteur, - self.get_category_display())) + return("%s - %s [%s]" % (self.nom, self.auteur, self.category)) diff --git a/partitions/templates/partitions/liste.html b/partitions/templates/partitions/liste.html index fc66abf..8f0d31b 100644 --- a/partitions/templates/partitions/liste.html +++ b/partitions/templates/partitions/liste.html @@ -2,41 +2,33 @@ {% block titre %}Liste des partitions{% endblock %} -{% block content %}

Liste des partitions

- {% if suppression %} -

{{ suppression }}

- {% endif %} +{% block content %} +

Liste des partitions

+ {% if suppression %} +

{{ suppression }}

+ {% endif %} - {% if user.is_authenticated %} -

Ajouter un morceau

- {% endif %} + {% if user.is_authenticated %} +

Ajouter un morceau

+ {% endif %} - -

Partitions actives

+ {% for category in categories %} +

{{ category }}

- -

Partitions optionnelles

- - -

Partitions à venir

- - -

Archives

- + {% endfor %} {% endblock %} diff --git a/partitions/templates/partitions/liste_item.html b/partitions/templates/partitions/liste_item.html deleted file mode 100644 index 5c79f2f..0000000 --- a/partitions/templates/partitions/liste_item.html +++ /dev/null @@ -1,11 +0,0 @@ -
  • - {% if not user.is_authenticated %} - {{ part.nom }} - {{ part.auteur }} - {% endif %} - {% if user.is_authenticated %} - {{ part.nom }} - {{ part.auteur }} - {% endif %} - {% if user.profile.is_chef %} - Supprimer - {% endif %} -
  • diff --git a/partitions/views.py b/partitions/views.py index 3dfdbc8..cbdbc0f 100644 --- a/partitions/views.py +++ b/partitions/views.py @@ -9,20 +9,13 @@ from django.http import Http404 import os from partitions.forms import UploadFileForm, UploadMorceauForm -from partitions.models import Partition, PartitionSet +from partitions.models import Partition, PartitionSet, Category from partitions.decorators import chef_required def liste(request): - partitions = PartitionSet.objects.order_by("nom") - context = { - "request": request, - "active_partitions": partitions.filter(category="active").all(), - "optional_partitions": partitions.filter(category="optional").all(), - "incoming_partitions": partitions.filter(category="incoming").all(), - "old_partitions": partitions.filter(category="old").all() - } - return render(request, 'partitions/liste.html', context) + categories = Category.objects.prefetch_related("partitionset_set") + return render(request, 'partitions/liste.html', {"categories": categories}) @login_required From 663f202149e5e1f8189dcd70b7f8ed5f236cc33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 4 Jan 2018 22:11:27 +0100 Subject: [PATCH 3/5] hack: fake default category in the view --- partitions/views.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/partitions/views.py b/partitions/views.py index cbdbc0f..760a0d9 100644 --- a/partitions/views.py +++ b/partitions/views.py @@ -99,6 +99,13 @@ def ajouter_morceau(request): auteur=partitionset.auteur) error = "Un morceau du même nom existe déjà" except PartitionSet.DoesNotExist: + # XXX. Hideous + cat = Category.objects.first() + try: + cat = Category.objects.get(name="Partitions à venir") + except Category.DoesNotExist: + pass + partitionset.category = cat partitionset.save() sauvegarde = True else: From cd149f1052b0f9d126a02e1d1ab4797f8f8cf9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 5 Jan 2018 15:13:13 +0100 Subject: [PATCH 4/5] Fix typo in "previous year" on the calendar --- calendrier/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calendrier/views.py b/calendrier/views.py index a5da1ae..ad124ac 100644 --- a/calendrier/views.py +++ b/calendrier/views.py @@ -45,7 +45,7 @@ def calendar(request, pYear, pMonth): lPreviousMonth = lMonth - 1 if lPreviousMonth == 0: lPreviousMonth = 12 - lPreviousYear - 1 + lPreviousYear -= 1 lNextYear = lYear lNextMonth = lMonth + 1 if lNextMonth == 13: From 0b7464e16dbd5a92464134cb7446aab7a839b38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 6 Jan 2018 19:02:48 +0100 Subject: [PATCH 5/5] Hotfix: event emails are broken --- calendrier/views.py | 115 ++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/calendrier/views.py b/calendrier/views.py index ad124ac..5515a7f 100644 --- a/calendrier/views.py +++ b/calendrier/views.py @@ -105,6 +105,7 @@ def view_eventbis(request, id): return render(request, 'calendrier/view_event.html', locals()) +# XXX: Horrible nasty code duplication. Go to hell RikM @chef_required def resend(request, id): if request.method == "POST": @@ -113,42 +114,35 @@ def resend(request, id): ev = get_object_or_404(Event, id=id) users = ErnestoUser.objects.filter(is_ernesto=True) message = form.cleaned_data["message"] - try: - for user in users: - if user.mails: - Subject = "[Pouet-Pouet] %s, le %s" % ( - ev.nom, ev.date.strftime('%d/%m/%Y')) - sender = 'fanfare@ens.fr' - receivers = [user.user.email] - if message != '': - text = "%s\n\n" % message - else: - text = "Bonjour, un évémenent a été créé.\n" - domain = get_current_site(request).domain - text += ( - 'Pour voir l\'événement, allez sur %s%s\n' - 'Pour répondre oui allez sur %s%s\n' - 'Pour répondre non, allez sur %s%s\n' - 'Pour répondre peut-être, allez sur %s%s\n') \ - % (domain, - reverse_lazy('view-event', args=[obj.id]), - domain, - reverse_lazy( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "oui"]), - domain, - reverse_lazy( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "non"]), - domain, - reverse_lazy( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "pe"])) + for user in users: + if user.mails: + Subject = "[Pouet-Pouet] %s, le %s" % ( + ev.nom, ev.date.strftime('%d/%m/%Y')) + sender = 'fanfare@ens.fr' + receivers = [user.user.email] + if message != '': + text = "%s\n\n" % message + else: + text = "Bonjour, un évémenent a été créé.\n" + domain = get_current_site(request).domain + text += ( + 'Pour voir l\'événement, allez sur %s%s\n' + 'Pour répondre oui allez sur %s%s\n' + 'Pour répondre non, allez sur %s%s\n' + 'Pour répondre peut-être, allez sur %s%s\n') \ + % (domain, + reverse_lazy('view-event', args=[ev.id]), + domain, + reverse_lazy('calendrier.reponse_event', args=[user.slug, ev.slug, "oui"]), + domain, + reverse_lazy('calendrier.reponse_event', args=[user.slug, ev.slug, "non"]), + domain, + reverse_lazy('calendrier.reponse_event', args=[user.slug, ev.slug, "pe"])) + try: send_mail(Subject, text, sender, receivers) - return redirect("calendrier.views.view_eventbis", id) - except: - erreur = "Une erreur est survenue, le mail n'a pas pu être " \ - + "envoyé." + except: + erreur = "Une erreur est survenue, le mail n'a pas pu être envoyé." + return redirect("calendrier.views.view_eventbis", id) else: form = SendMail() return render(request, "calendrier/resend.html", locals()) @@ -194,38 +188,31 @@ def create_event(request): users = ErnestoUser.objects.filter(is_ernesto=True) for user in users: if user.mails: + Subject = "[Pouet-Pouet] %s, le %s" % (nom, date) + sender = 'fanfare@ens.fr' + receivers = [user.user.email] + if message != '': + text = "%s\n\n" % message + else: + text = "Bonjour, un évémenent a été créé.\n" + domain = get_current_site(request).domain + text += ( + "Pour voir l'événement, allez sur %s%s" + '\nPour répondre oui allez sur %s%s\n' + 'Pour répondre non, allez sur %s%s\n' + 'Pour répondre peut-être, allez sur %s%s\n') \ + % (domain, + reverse('view-event', args=[obj.id]), + domain, + reverse('calendrier.reponse_event', args=[user.slug, obj.slug, "oui"]), + domain, + reverse('calendrier.reponse_event', args=[user.slug, obj.slug, "non"]), + domain, + reverse('calendrier.reponse_event', args=[user.slug, obj.slug, "pe"])) try: - Subject = "[Pouet-Pouet] %s, le %s" % (nom, date) - sender = 'fanfare@ens.fr' - receivers = [user.user.email] - if message != '': - text = "%s\n\n" % message - else: - text = "Bonjour, un évémenent a été créé.\n" - domain = get_current_site(request).domain - text += ( - "Pour voir l'événement, allez sur %s%s" - '\nPour répondre oui allez sur %s%s\n' - 'Pour répondre non, allez sur %s%s\n' - 'Pour répondre peut-être, allez sur %s%s\n') \ - % (domain, - reverse('view-event', args=[obj.id]), - domain, - reverse( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "oui"]), - domain, - reverse( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "non"]), - domain, - reverse( - 'calendrier.reponse_event', - args=[user.slug, obj.slug, "pe"])) send_mail(Subject, text, sender, receivers) except: - erreur = "Une erreur est survenue, le mail n'a " \ - + "pas pu être envoyé." + erreur = "Une erreur est survenue, le mail n'a pas pu être envoyé." else: form = EventForm()