{{ actu|dates|capfirst }}
{{ actu.chapo }}
-
- {% for p in object_list %}
-
- {{ p.user.first_name }} {{ p.user.last_name }} ({{ p.user.username }}), {{ p.get_cotisation_period_display }} - {% endfor %} -
diff --git a/.credentials/HCAPTCHA_SECRET b/.credentials/HCAPTCHA_SECRET deleted file mode 100644 index 7daa69d3..00000000 --- a/.credentials/HCAPTCHA_SECRET +++ /dev/null @@ -1 +0,0 @@ -0x0000000000000000000000000000000000000000 diff --git a/.credentials/HCAPTCHA_SITEKEY b/.credentials/HCAPTCHA_SITEKEY deleted file mode 100644 index f5093057..00000000 --- a/.credentials/HCAPTCHA_SITEKEY +++ /dev/null @@ -1 +0,0 @@ -10000000-ffff-ffff-ffff-000000000001 diff --git a/.credentials/KFETOPEN_TOKEN b/.credentials/KFETOPEN_TOKEN deleted file mode 100644 index 4cbb2bf5..00000000 --- a/.credentials/KFETOPEN_TOKEN +++ /dev/null @@ -1 +0,0 @@ -k-feste_token diff --git a/.credentials/SECRET_KEY b/.credentials/SECRET_KEY deleted file mode 100644 index de873cc2..00000000 --- a/.credentials/SECRET_KEY +++ /dev/null @@ -1 +0,0 @@ -insecure-key diff --git a/.credentials/SYMPA_PASSWORD b/.credentials/SYMPA_PASSWORD deleted file mode 100644 index fbcf12d5..00000000 --- a/.credentials/SYMPA_PASSWORD +++ /dev/null @@ -1 +0,0 @@ -toto diff --git a/.credentials/SYMPA_USERNAME b/.credentials/SYMPA_USERNAME deleted file mode 100644 index d525803f..00000000 --- a/.credentials/SYMPA_USERNAME +++ /dev/null @@ -1 +0,0 @@ -sympa diff --git a/.envrc b/.envrc deleted file mode 100644 index 1d953f4b..00000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use nix diff --git a/.gitignore b/.gitignore index 9122298b..347d4b78 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ cof/settings.py settings.py *~ venv/ -.venv/ .vagrant /src media/ @@ -19,6 +18,4 @@ media/ .cache # VSCode -.vscode/ -.direnv -.static +.vscode/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ce3bd041..a8bece7d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,8 @@ -image: "python:3.7" +image: "python:3.5" variables: # GestioCOF settings + DJANGO_SETTINGS_MODULE: "cof.settings.prod" DBHOST: "postgres" REDIS_HOST: "redis" REDIS_PASSWD: "dummy" @@ -17,23 +18,22 @@ variables: # psql password authentication PGPASSWORD: $POSTGRES_PASSWORD - # apps to check migrations for - MIGRATION_APPS: "bda bds cofcms clubs events gestioncof kfet kfetauth kfetcms open petitscours shared" - .test_template: before_script: - mkdir -p vendor/{pip,apt} - - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client libldap2-dev libsasl2-dev - - sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' gestioasso/settings/secret_example.py > gestioasso/settings/secret.py - - sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' gestioasso/settings/secret.py + - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client + - sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py + - sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py # Remove the old test database if it has not been done yet - psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB" - pip install --upgrade -r requirements-prod.txt coverage tblib - python --version + script: + - coverage run manage.py test --parallel after_script: - coverage report services: - - postgres:11.7 + - postgres:9.6 - redis:latest cache: key: test @@ -43,40 +43,27 @@ variables: # Keep this disabled for now, as it may kill GitLab... # coverage: '/TOTAL.*\s(\d+\.\d+)\%$/' -kfettest: - stage: test - extends: .test_template - variables: - DJANGO_SETTINGS_MODULE: "gestioasso.settings.cof_prod" - script: - - coverage run manage.py test kfet +test35: + extends: ".test_template" + image: "python:3.5" + stage: test -coftest: - stage: test - extends: .test_template - variables: - DJANGO_SETTINGS_MODULE: "gestioasso.settings.cof_prod" - script: - - coverage run manage.py test gestioncof bda petitscours shared --parallel - -bdstest: - stage: test - extends: .test_template - variables: - DJANGO_SETTINGS_MODULE: "gestioasso.settings.bds_prod" - script: - - coverage run manage.py test bds clubs events --parallel +test37: + extends: ".test_template" + image: "python:3.7" + stage: test linters: + image: python:3.6 stage: test before_script: - mkdir -p vendor/pip - pip install --upgrade black isort flake8 script: - black --check . - - isort --check --diff . + - isort --recursive --check-only --diff bda bds clubs cof events gestioncof kfet petitscours provisioning shared utils # Print errors only - - flake8 --exit-zero bda bds clubs gestioasso events gestioncof kfet petitscours provisioning shared + - flake8 --exit-zero bda bds clubs cof events gestioncof kfet petitscours provisioning shared utils cache: key: linters paths: @@ -85,18 +72,16 @@ linters: # Check whether there are some missing migrations. migration_checks: stage: test - variables: - DJANGO_SETTINGS_MODULE: "gestioasso.settings.local" before_script: - mkdir -p vendor/{pip,apt} - - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client libldap2-dev libsasl2-dev - - cp gestioasso/settings/secret_example.py gestioasso/settings/secret.py - - pip install --upgrade -r requirements-devel.txt + - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client + - cp cof/settings/secret_example.py cof/settings/secret.py + - pip install --upgrade -r requirements-prod.txt - python --version - script: python manage.py makemigrations --dry-run --check $MIGRATION_APPS + script: python manage.py makemigrations --dry-run --check services: # this should not be necessary… - - postgres:11.7 + - postgres:9.6 cache: key: migration_checks paths: diff --git a/.pre-commit.sh b/.pre-commit.sh deleted file mode 100755 index abf1fe7d..00000000 --- a/.pre-commit.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash -# pre-commit hook for gestioCOF project. -# -# Run formatters first, then checkers. -# Formatters which changed a file must set the flag 'formatter_updated'. - -exit_code=0 -formatter_updated=0 -checker_dirty=0 - -# TODO(AD): We should check only staged changes. -# Working? -> Stash unstaged changes, run it, pop stash -STAGED_PYTHON_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".py$") - - -# Formatter: black - -printf "> black ... " - -if type black &>/dev/null; then - if [ -z "$STAGED_PYTHON_FILES" ]; then - printf "OK\n" - else - BLACK_OUTPUT="/tmp/gc-black-output.log" - touch $BLACK_OUTPUT - - if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' black --check &>$BLACK_OUTPUT; then - echo "$STAGED_PYTHON_FILES" | xargs -d'\n' black &>$BLACK_OUTPUT - tail -1 $BLACK_OUTPUT - formatter_updated=1 - else - printf "OK\n" - fi - fi -else - printf "SKIP: program not found\n" - printf "HINT: Install black with 'pip3 install black' (black requires Python>=3.6)\n" -fi - -# Formatter: isort - -printf "> isort ... " - -if type isort &>/dev/null; then - if [ -z "$STAGED_PYTHON_FILES" ]; then - printf "OK\n" - else - ISORT_OUTPUT="/tmp/gc-isort-output.log" - touch $ISORT_OUTPUT - - if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' isort --check &>$ISORT_OUTPUT; then - echo "$STAGED_PYTHON_FILES" | xargs -d'\n' isort &>$ISORT_OUTPUT - printf "Reformatted.\n" - formatter_updated=1 - else - printf "OK\n" - fi - fi -else - printf "SKIP: program not found\n" - printf "HINT: Install isort with 'pip install isort'\n" -fi - -# Checker: flake8 - -printf "> flake8 ... " - -if type flake8 &>/dev/null; then - if [ -z "$STAGED_PYTHON_FILES" ]; then - printf "OK\n" - else - FLAKE8_OUTPUT="/tmp/gc-flake8-output.log" - touch $FLAKE8_OUTPUT - - if ! echo "$STAGED_PYTHON_FILES" | xargs -d'\n' flake8 &>$FLAKE8_OUTPUT; then - printf "FAIL\n" - cat $FLAKE8_OUTPUT - checker_dirty=1 - else - printf "OK\n" - fi - fi -else - printf "SKIP: program not found\n" - printf "HINT: Install flake8 with 'pip install flake8'\n" -fi - -# End - -if [ $checker_dirty -ne 0 ] -then - printf ">>> Checker(s) detect(s) issue(s)\n" - printf " You can still commit and push :)\n" - printf " Be warned that our CI may cause you more trouble.\n" -fi - -if [ $formatter_updated -ne 0 ] -then - printf ">>> Working tree updated by formatter(s)\n" - printf " Add changes to staging area and retry.\n" - exit_code=1 -fi - -printf "\n" - -exit $exit_code diff --git a/CHANGELOG.md b/CHANGELOG.md index b68fb40c..269e5194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,234 +5,20 @@ Liste des changements notables dans GestioCOF depuis la version 0.1 (septembre ## Le FUTUR ! (pas prêt pour la prod) -### Nouveau module de gestion des événements +- Nouveau module de gestion des événements +- Nouveau module BDS +- Nouveau module clubs -- Désormais complet niveau modèles -- Export des participants implémenté - -#### TODO - -- Vue de création d'événements ergonomique -- Vue d'inscription à un événement **ou** intégration propre dans la vue - "inscription d'un nouveau membre" - -### Nouveau module de gestion des clubs - -Uniquement un modèle simple de clubs avec des respos. Aucune gestion des -adhérents ni des cotisations. - -## TODO Prod - -- Lancer `python manage.py update_translation_fields` après la migration -- Mettre à jour les units systemd `daphne.service` et `worker.service` - -- Créer un compte hCaptcha (https://www.hcaptcha.com/), au COF, et remplacer les secrets associés - -## Version ??? - ??/??/???? - -## Version 0.15.1 - 15/06/2023 - -### K-Fêt - -- Rattrape les erreurs d'envoi de mail de négatif -- Utilise l'adresse chefs pour les envois de négatifs - -## Version 0.15 - 22/05/2023 - -### K-Fêt - -- Rajoute un formulaire de contact -- Rajoute un formulaire de demande de soirée -- Désactive les mails d'envoi de négatifs sur les comptes gelés - -## Version 0.14 - 19/05/2023 - -- Répare les dépendances en spécifiant toutes les versions - -### K-Fêt - -- Répare la gestion des changement d'heure via moment.js - -## Version 0.13 - 19/02/2023 - -### K-Fêt - -- Rajoute la valeur des inventaires -- Résout les problèmes de négatif ne disparaissant pas -- Affiche son surnom s'il y en a un -- Bugfixes - -## Version 0.12.1 - 03/10/2022 - -### K-Fêt - -- Fixe un problème de rendu causé par l'agrandissement du menu - -- Mise à jour vers Channels 3.x et Django 3.2 - -## Version 0.12 - 17/06/2022 - -### K-Fêt - -- Ajoute une exception à la limite d'historique pour les comptes `LIQ` et `#13` -- Répare le problème des étiquettes LIQ/Comptes K-Fêt inversées dans les stats des articles K-Fêt - -## Version 0.11 - 26/10/2021 - -### COF - -- Répare un problème de rendu sur le wagtail du COF - -### K-Fêt - -- Ajoute de mails de rappels pour les comptes en négatif -- La recherche de comptes sur K-Psul remarche normalement -- Le pointeur de la souris change de forme quand on survole un item d'autocomplétion -- Modification du gel de compte: - - on ne peut plus geler/dégeler son compte soi-même (il faut la permission "Gérer les permissions K-Fêt") - - on ne peut rien compter sur un compte gelé (aucune override possible), et les K-Fêteux·ses dont le compte est gelé perdent tout accès à K-Psul - - les comptes actuellement gelés (sur l'ancien système) sont dégelés automatiquement -- Modification du fonctionnement des négatifs - - impossible d'avoir des négatifs inférieurs à `kfet_config.overdraft_amount` - - il n'y a plus de limite de temps sur les négatifs - - supression des autorisations de négatif - - il n'est plus possible de réinitialiser la durée d'un négatif en faisant puis en annulant une charge -- La gestion des erreurs passe du client au serveur, ce qui permet d'avoir des messages plus explicites -- La supression d'opérations anciennes est réparée - -## Version 0.10 - 18/04/2021 - -### K-Fêt - -- On fait sauter la limite qui empêchait de vendre plus de 24 unités d'un item à - la fois. -- L'interface indique plus clairement quand on fait une erreur en modifiant un - compte. -- On supprime la fonction "décalage de balance". -- L'accès à l'historique est maintenant limité à 7 jours pour raison de - confidentialité. Les chefs/trez peuvent disposer d'une permission - supplémentaire pour accéder à jusqu'à 30 jours en cas de problème de compta. - L'accès à son historique personnel n'est pas limité. Les durées sont - configurables dans `settings/cof_prod.py`. - -### COF - -- Le Captcha sur la page de demande de petits cours utilise maintenant hCaptcha - au lieu de ReCaptcha, pour mieux respecter la vie privée des utilisateur·ices - -## Version 0.9 - 06/02/2020 - -### COF / BdA - -- Le COF peut remettre à zéro la liste de ses adhérents en août (sans passer par - KDE). -- La page d'accueil affiche la date de fermeture des tirages BdA. -- On peut revendre une place dès qu'on l'a payée, plus besoin de payer toutes - ses places pour pouvoir revendre. -- On s'assure que l'email fourni lors d'une demande de petit cours est valide. - -### BDS - -- Le burô peut maintenant accorder ou révoquer le statut de membre du Burô - en modifiant le profil d'un membre du BDS. -- Le burô peut exporter la liste de ses membres avec email au format CSV depuis - la page d'accueil. - -### K-Fêt - -- On affiche les articles actuellement en vente en premier lors des inventaires - et des commandes. -- On peut supprimer un inventaire. Seuls les articles dont c'est le dernier - inventaire sont affectés. - -## Version 0.8 - 03/12/2020 - -### COF - -- La page "Mes places" dans la section BdA indique quelles places sont sur - listing. -- ergonomie de l'interface admin du BdA : moins d'options inutiles lors de - la sélection de participants. -- les tirages sont maintenant archivables pour éviter d'avoir encore d'autres - options inutiles. -- l'autocomplétion dans l'admin BdA est réparée. -- Les icones de la page de gestion des petits cours sont (à nouveau) réparées. -- On a supprimé la possibilité de modifier les mails automatiques depuis - l'interface admin car trop problématique. Faute de mieux, envoyer un mail à - KDE pour modifier ces mails. -- corrige un crash sporadique sur la page d'inscription au système de petits - cours - -### K-Fêt - -- (fix partiel) Empêche la K-Fêt de modifier des données COF (e.g. nom, prénom, - username) lors de la création d'un nouveau compte. -- Les statistiques de conso globales montrent deux courbes COF / non-COF au - lieu de LIQ / sur compte. -- Un bug empêchait de fermer manuellement la K-Fêt depuis un compte non - privilégié en tapant un mot de passe. C'est corrigé. - -## Version 0.7.2 - 08/09/2020 - -- Nouvelle page 404 -- Correction de bug en K-Fêt : le lien pour créer un nouveau compte exté apparaît - à nouveau dans l'autocomplétion - -## Version 0.7.1 - 05/09/2020 - -Petits ajustements sur le site du COF : - -- Possibilité d'ajouter des champs d'infos supplémentaires en plus de l'email et - de la page web dans les annuaires (clubs et partenaires). -- Corrige un bug d'affichage des adresses emails de clubs - -## Version 0.7 - 29/08/2020 - -### GestioBDS - -- Ajout d'un bouton pour supprimer un compte -- Le nombre d'adhérent⋅es est affiché sur la page d'accueil -- le groupe BDS a les bonnes permissions - -### Site du COF - -- Captcha fonctionnel pour les mailing-listes - -### K-Fêt - -- L'autocomplétion pour la création de compte K-Fêt se lance à 3 caractères seulement, -donc est plus rapide. - -## Version 0.6 - 27/07/2020 - -Arrivée du BDS ! -GestioCOF et GestioBDS ont du code en commun mais tournent de façon séparée, les -deux bases de données sont distinctes. - -## Version 0.5 - 11/07/2020 +## Upcoming ### Problèmes corrigés -- La recherche d'utilisateurices (COF + K-Fêt) fonctionne de nouveau -- Bug d'affichage quand on a beaucoup de clubs dans le cadre "Accès rapide" sur - la page des clubs (nouveau site du COF) -- Version mobile plus ergonimique sur le nouveau site du COF - Cliquer sur "visualiser" sur les pages de clubs dans wagtail ne provoque plus - d'erreurs 500 (nouveau site du COF) -- L'historique des ventes des articles K-Fêt fonctionne à nouveau + d'erreurs 500. +- L'historique des ventes des articles fonctionne à nouveau - Les montants en K-Fêt sont à nouveau affichés en UKF (et non en €). - Les boutons "afficher/cacher" des mails et noms des participant⋅e⋅s à un spectacle BdA fonctionnent à nouveau. -- on ne peut plus compter de consos sur ☠☠☠, ni éditer les comptes spéciaux -(LIQ, GNR, ☠☠☠, #13). - -### Nouvelles fonctionnalités - -- On n'affiche que 4 articles sur la pages "nouveautés" (nouveau site du COF) -- Plus de traductions sur le nouveau site du COF -- Les transferts apparaissent maintenant dans l'historique K-Fêt et l'historique - personnel. -- les statistiques K-Fêt remontent à plus d'un an (et le code est simplifié) ## Version 0.4.1 - 17/01/2020 diff --git a/README.md b/README.md index 5708277c..ffe680db 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GestioCOF / GestioBDS +# GestioCOF [](https://git.eleves.ens.fr/cof-geek/gestioCOF/commits/master) [](https://git.eleves.ens.fr/cof-geek/gestioCOF/commits/master) @@ -18,7 +18,7 @@ Il vous faudra installer pip, les librairies de développement de python ainsi que sqlite3, un moteur de base de données léger et simple d'utilisation. Sous Debian et dérivées (Ubuntu, ...) : - sudo apt-get install python3-pip python3-dev python3-venv sqlite3 libsasl2-dev python-dev-is-python3 libldap2-dev libssl-dev + sudo apt-get install python3-pip python3-dev python3-venv sqlite3 Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF @@ -30,15 +30,7 @@ Pour l'activer, il faut taper . venv/bin/activate -depuis le même dossier. Pour préparer l'environnement à l'utilisation de `./manage.py` -(qui permet de faire des tests en local), il faut également taper - - export CREDENTIALS_DIRECTORY=$(realpath .credentials) - export DJANGO_SETTINGS_MODULE=gestioasso.settings.local - export GESTIOCOF_DEBUG=true - export GESTIOCOF_STATIC_ROOT=$(realpath .static) - export GESTIOBDS_DEBUG=true - export GESTIOBDS_STATIC_ROOT=$(realpath .static) +depuis le même dossier. Vous pouvez maintenant installer les dépendances Python depuis le fichier `requirements-devel.txt` : @@ -46,11 +38,11 @@ Vous pouvez maintenant installer les dépendances Python depuis le fichier pip install -U pip # parfois nécessaire la première fois pip install -r requirements-devel.txt -Pour terminer, copier le fichier `gestioasso/settings/secret_example.py` vers -`gestioasso/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique +Pour terminer, copier le fichier `cof/settings/secret_example.py` vers +`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique pour profiter de façon transparente des mises à jour du fichier: - ln -s secret_example.py gestioasso/settings/secret.py + ln -s secret_example.py cof/settings/secret.py Nous avons un git hook de pre-commit pour formatter et vérifier que votre code vérifie nos conventions. Pour bénéficier des mises à jour du hook, préférez diff --git a/Vagrantfile b/Vagrantfile index f34653a5..e12a45ed 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,19 +1,47 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -# Configuration de base pour GestioCOF. -# Voir https://docs.vagrantup.com pour plus d'informations. +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. Vagrant.configure(2) do |config| - # On se base sur Debian 10 (Buster) pour avoir le même environnement qu'en - # production. - config.vm.box = "debian/contrib-buster64" + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + config.vm.box = "ubuntu/xenial64" # On associe le port 80 dans la machine virtuelle avec le port 8080 de notre # ordinateur, et le port 8000 avec le port 8000. config.vm.network :forwarded_port, guest: 80, host: 8080 config.vm.network :forwarded_port, guest: 8000, host: 8000 - # Le restes de la configuration (installation de paquets, etc) est géré un - # script shell. + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider "virtualbox" do |vb| + # # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # + # # Customize the amount of memory on the VM: + # vb.memory = "1024" + # end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + # config.vm.provision "shell", inline: <<-SHELL + # sudo apt-get update + # sudo apt-get install -y apache2 + # SHELL config.vm.provision :shell, path: "provisioning/bootstrap.sh" end diff --git a/bda/admin.py b/bda/admin.py index f52f721d..7f626c7a 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,11 +1,10 @@ from datetime import timedelta +from custommail.shortcuts import send_mass_custom_mail from dal.autocomplete import ModelSelect2 from django import forms from django.contrib import admin -from django.core.mail import send_mass_mail from django.db.models import Count, Q, Sum -from django.template import loader from django.template.defaultfilters import pluralize from django.utils import timezone @@ -33,6 +32,20 @@ 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" + + class AttributionTabularAdminForm(forms.ModelForm): listing = None @@ -80,17 +93,14 @@ class WithoutListingAttributionInline(AttributionInline): class ParticipantAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - queryset = Spectacle.objects.select_related("location") - - if self.instance.pk is not None: - queryset = queryset.filter(tirage=self.instance.tirage) - - self.fields["choicesrevente"].queryset = queryset + self.fields["choicesrevente"].queryset = Spectacle.objects.select_related( + "location" + ) class ParticipantPaidFilter(admin.SimpleListFilter): """ - Permet de filtrer les participants sur s'ils ont payé leurs places ou pas + Permet de filtrer les participants sur s'ils ont payé leurs places ou pas """ title = "A payé" @@ -159,23 +169,19 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin): form = ParticipantAdminForm def send_attribs(self, request, queryset): - emails = [] + datatuple = [] for member in queryset.all(): - subject = "Résultats du tirage au sort" attribs = member.attributions.all() context = {"member": member.user} - - template_name = "" + shortname = "" if len(attribs) == 0: - template_name = "bda/mails/attributions-decus.txt" + shortname = "bda-attributions-decus" else: - template_name = "bda/mails/attributions.txt" + shortname = "bda-attributions" context["places"] = attribs - - message = loader.render_to_string(template_name, context) - emails.append((subject, message, "bda@ens.fr", [member.user.email])) - - send_mass_mail(emails) + print(context) + datatuple.append((shortname, context, "bda@ens.fr", [member.user.email])) + send_mass_custom_mail(datatuple) count = len(queryset.all()) if count == 1: message_bit = "1 membre a" @@ -191,6 +197,17 @@ class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin): class AttributionAdminForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if "spectacle" in self.fields: + self.fields["spectacle"].queryset = Spectacle.objects.select_related( + "location" + ) + if "participant" in self.fields: + self.fields["participant"].queryset = Participant.objects.select_related( + "user", "tirage" + ) + def clean(self): cleaned_data = super().clean() participant = cleaned_data.get("participant") @@ -203,14 +220,9 @@ class AttributionAdminForm(forms.ModelForm): ) return cleaned_data - class Meta: - widgets = { - "participant": ModelSelect2(url="bda-participant-autocomplete"), - "spectacle": ModelSelect2(url="bda-spectacle-autocomplete"), - } - class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin): + list_display = ("id", "spectacle", "participant", "given", "paid") search_fields = ( "spectacle__title", @@ -223,7 +235,7 @@ class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin): class ChoixSpectacleAdmin(admin.ModelAdmin): - autocomplete_fields = ["participant", "spectacle"] + form = ChoixSpectacleAdminForm def tirage(self, obj): return obj.participant.tirage @@ -267,14 +279,15 @@ class SalleAdmin(admin.ModelAdmin): class SpectacleReventeAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - qset = Participant.objects.select_related("user", "tirage") - - if self.instance.pk is not None: - qset = qset.filter(tirage=self.instance.seller.tirage) - - self.fields["confirmed_entry"].queryset = qset - self.fields["seller"].queryset = qset - self.fields["soldTo"].queryset = qset + self.fields["confirmed_entry"].queryset = Participant.objects.select_related( + "user", "tirage" + ) + self.fields["seller"].queryset = Participant.objects.select_related( + "user", "tirage" + ) + self.fields["soldTo"].queryset = Participant.objects.select_related( + "user", "tirage" + ) class SpectacleReventeAdmin(admin.ModelAdmin): diff --git a/bda/algorithm.py b/bda/algorithm.py index 078f2be8..add09335 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -2,6 +2,7 @@ import random class Algorithm(object): + shows = None ranks = None origranks = None @@ -9,10 +10,10 @@ class Algorithm(object): def __init__(self, shows, members, choices): """Initialisation : - - on aggrège toutes les demandes pour chaque spectacle dans - show.requests - - on crée des tables de demandes pour chaque personne, afin de - pouvoir modifier les rankings""" + - on aggrège toutes les demandes pour chaque spectacle dans + show.requests + - on crée des tables de demandes pour chaque personne, afin de + pouvoir modifier les rankings""" self.max_group = 2 * max(choice.priority for choice in choices) self.shows = [] showdict = {} diff --git a/bda/forms.py b/bda/forms.py index d1d0f74f..bb79932e 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -3,7 +3,7 @@ from django.forms.models import BaseInlineFormSet from django.template import loader from django.utils import timezone -from bda.models import SpectacleRevente +from bda.models import Attribution, Spectacle, SpectacleRevente class InscriptionInlineFormSet(BaseInlineFormSet): @@ -77,7 +77,7 @@ class ResellForm(forms.Form): super().__init__(*args, **kwargs) self.fields["attributions"] = TemplateLabelField( queryset=participant.attribution_set.filter( - spectacle__date__gte=timezone.now(), paid=True + spectacle__date__gte=timezone.now() ) .exclude(revente__seller=participant) .select_related("spectacle", "spectacle__location", "participant__user"), diff --git a/bda/management/commands/loadbdadevdata.py b/bda/management/commands/loadbdadevdata.py index 186e1da7..a608db6a 100644 --- a/bda/management/commands/loadbdadevdata.py +++ b/bda/management/commands/loadbdadevdata.py @@ -81,7 +81,7 @@ class Command(MyBaseCommand): shows = random.sample( list(tirage.spectacle_set.all()), tirage.spectacle_set.count() // 2 ) - for rank, show in enumerate(shows): + for (rank, show) in enumerate(shows): choices.append( ChoixSpectacle( participant=part, diff --git a/bda/migrations/0001_initial.py b/bda/migrations/0001_initial.py index 5bc848c8..077ddd4e 100644 --- a/bda/migrations/0001_initial.py +++ b/bda/migrations/0001_initial.py @@ -6,6 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py index c2c6bd3c..f4b01ed2 100644 --- a/bda/migrations/0002_add_tirage.py +++ b/bda/migrations/0002_add_tirage.py @@ -35,6 +35,7 @@ def fill_tirage_fields(apps, schema_editor): class Migration(migrations.Migration): + dependencies = [("bda", "0001_initial")] operations = [ diff --git a/bda/migrations/0003_update_tirage_and_spectacle.py b/bda/migrations/0003_update_tirage_and_spectacle.py index 07f3742e..3548eb88 100644 --- a/bda/migrations/0003_update_tirage_and_spectacle.py +++ b/bda/migrations/0003_update_tirage_and_spectacle.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0002_add_tirage")] operations = [ diff --git a/bda/migrations/0004_mails-rappel.py b/bda/migrations/0004_mails-rappel.py index 407353a4..d331568a 100644 --- a/bda/migrations/0004_mails-rappel.py +++ b/bda/migrations/0004_mails-rappel.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0003_update_tirage_and_spectacle")] operations = [ diff --git a/bda/migrations/0005_encoding.py b/bda/migrations/0005_encoding.py index 29ee0027..eedfcee4 100644 --- a/bda/migrations/0005_encoding.py +++ b/bda/migrations/0005_encoding.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0004_mails-rappel")] operations = [ diff --git a/bda/migrations/0006_add_tirage_switch.py b/bda/migrations/0006_add_tirage_switch.py index 1535a5fe..ccfe7505 100644 --- a/bda/migrations/0006_add_tirage_switch.py +++ b/bda/migrations/0006_add_tirage_switch.py @@ -18,6 +18,7 @@ def forwards_func(apps, schema_editor): class Migration(migrations.Migration): + dependencies = [("bda", "0005_encoding")] operations = [ diff --git a/bda/migrations/0007_extends_spectacle.py b/bda/migrations/0007_extends_spectacle.py index 48865acb..87182ff7 100644 --- a/bda/migrations/0007_extends_spectacle.py +++ b/bda/migrations/0007_extends_spectacle.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0006_add_tirage_switch")] operations = [ diff --git a/bda/migrations/0008_py3.py b/bda/migrations/0008_py3.py index 3a7dfeb1..6aa69abd 100644 --- a/bda/migrations/0008_py3.py +++ b/bda/migrations/0008_py3.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0007_extends_spectacle")] operations = [ diff --git a/bda/migrations/0009_revente.py b/bda/migrations/0009_revente.py index 7a547f85..d888140f 100644 --- a/bda/migrations/0009_revente.py +++ b/bda/migrations/0009_revente.py @@ -6,6 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0008_py3")] operations = [ diff --git a/bda/migrations/0010_spectaclerevente_shotgun.py b/bda/migrations/0010_spectaclerevente_shotgun.py index ae0fdff1..da5c014c 100644 --- a/bda/migrations/0010_spectaclerevente_shotgun.py +++ b/bda/migrations/0010_spectaclerevente_shotgun.py @@ -12,15 +12,15 @@ def forwards_func(apps, schema_editor): for revente in SpectacleRevente.objects.all(): is_expired = timezone.now() > revente.date_tirage() - is_direct = ( - revente.attribution.spectacle.date >= revente.date - and timezone.now() > revente.date + timedelta(minutes=15) + is_direct = revente.attribution.spectacle.date >= revente.date and timezone.now() > revente.date + timedelta( + minutes=15 ) revente.shotgun = is_expired or is_direct revente.save() class Migration(migrations.Migration): + dependencies = [("bda", "0009_revente")] operations = [ diff --git a/bda/migrations/0011_tirage_appear_catalogue.py b/bda/migrations/0011_tirage_appear_catalogue.py index a8c49e2d..446be392 100644 --- a/bda/migrations/0011_tirage_appear_catalogue.py +++ b/bda/migrations/0011_tirage_appear_catalogue.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0010_spectaclerevente_shotgun")] operations = [ diff --git a/bda/migrations/0012_notif_time.py b/bda/migrations/0012_notif_time.py index 78ef8dce..96853a24 100644 --- a/bda/migrations/0012_notif_time.py +++ b/bda/migrations/0012_notif_time.py @@ -5,6 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0011_tirage_appear_catalogue")] operations = [ diff --git a/bda/migrations/0012_swap_double_choice.py b/bda/migrations/0012_swap_double_choice.py index dcb8056d..e712f2ff 100644 --- a/bda/migrations/0012_swap_double_choice.py +++ b/bda/migrations/0012_swap_double_choice.py @@ -13,6 +13,7 @@ def swap_double_choice(apps, schema_editor): class Migration(migrations.Migration): + dependencies = [("bda", "0011_tirage_appear_catalogue")] operations = [ diff --git a/bda/migrations/0013_merge_20180524_2123.py b/bda/migrations/0013_merge_20180524_2123.py index b974abf2..8f78b6a9 100644 --- a/bda/migrations/0013_merge_20180524_2123.py +++ b/bda/migrations/0013_merge_20180524_2123.py @@ -6,6 +6,7 @@ from django.db import migrations class Migration(migrations.Migration): + dependencies = [("bda", "0012_notif_time"), ("bda", "0012_swap_double_choice")] operations = [] diff --git a/bda/migrations/0014_attribution_paid_field.py b/bda/migrations/0014_attribution_paid_field.py index e5ef2b2d..b5bb6208 100644 --- a/bda/migrations/0014_attribution_paid_field.py +++ b/bda/migrations/0014_attribution_paid_field.py @@ -4,6 +4,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0013_merge_20180524_2123")] operations = [ diff --git a/bda/migrations/0015_move_bda_payment.py b/bda/migrations/0015_move_bda_payment.py index a39a159c..93f121a1 100644 --- a/bda/migrations/0015_move_bda_payment.py +++ b/bda/migrations/0015_move_bda_payment.py @@ -29,6 +29,7 @@ def set_participant_payment(apps, schema_editor): class Migration(migrations.Migration): + dependencies = [("bda", "0014_attribution_paid_field")] operations = [ diff --git a/bda/migrations/0016_delete_participant_paid.py b/bda/migrations/0016_delete_participant_paid.py index 86a17b24..f59d1eb9 100644 --- a/bda/migrations/0016_delete_participant_paid.py +++ b/bda/migrations/0016_delete_participant_paid.py @@ -4,6 +4,7 @@ from django.db import migrations class Migration(migrations.Migration): + dependencies = [("bda", "0015_move_bda_payment")] operations = [ diff --git a/bda/migrations/0017_participant_accepte_charte.py b/bda/migrations/0017_participant_accepte_charte.py index 3157654b..6bd32d8f 100644 --- a/bda/migrations/0017_participant_accepte_charte.py +++ b/bda/migrations/0017_participant_accepte_charte.py @@ -4,6 +4,7 @@ from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [("bda", "0016_delete_participant_paid")] operations = [ diff --git a/bda/migrations/0018_auto_20201021_1818.py b/bda/migrations/0018_auto_20201021_1818.py deleted file mode 100644 index 444f32d8..00000000 --- a/bda/migrations/0018_auto_20201021_1818.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 2.2.12 on 2020-10-21 16:18 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("bda", "0017_participant_accepte_charte"), - ] - - operations = [ - migrations.AlterModelOptions( - name="participant", - options={"ordering": ("-tirage", "user__last_name", "user__first_name")}, - ), - migrations.AddField( - model_name="tirage", - name="archived", - field=models.BooleanField(default=False, verbose_name="Archivé"), - ), - migrations.AlterField( - model_name="participant", - name="tirage", - field=models.ForeignKey( - limit_choices_to={"archived": False}, - on_delete=django.db.models.deletion.CASCADE, - to="bda.Tirage", - ), - ), - migrations.AddConstraint( - model_name="participant", - constraint=models.UniqueConstraint( - fields=("tirage", "user"), name="unique_tirage" - ), - ), - ] diff --git a/bda/migrations/0019_auto_20220630_1245.py b/bda/migrations/0019_auto_20220630_1245.py deleted file mode 100644 index 12b7149d..00000000 --- a/bda/migrations/0019_auto_20220630_1245.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2.13 on 2022-06-30 10:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("bda", "0018_auto_20201021_1818"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="choixspectacle", - unique_together=set(), - ), - migrations.AddConstraint( - model_name="choixspectacle", - constraint=models.UniqueConstraint( - fields=("participant", "spectacle"), name="unique_participation" - ), - ), - ] diff --git a/bda/migrations/0019_auto_20240707_1359.py b/bda/migrations/0019_auto_20240707_1359.py deleted file mode 100644 index ad25e0d6..00000000 --- a/bda/migrations/0019_auto_20240707_1359.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.28 on 2024-07-07 11:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('bda', '0018_auto_20201021_1818'), - ] - - operations = [ - migrations.AlterField( - model_name='attribution', - name='paymenttype', - field=models.CharField(blank=True, choices=[('cash', 'Cash'), ('cb', 'CB'), ('cheque', 'Chèque'), ('virement', 'Virement'), ('autre', 'Autre')], max_length=8, verbose_name='Moyen de paiement'), - ), - ] diff --git a/bda/migrations/0020_merge_0019_auto_20220630_1245_0019_auto_20240707_1359.py b/bda/migrations/0020_merge_0019_auto_20220630_1245_0019_auto_20240707_1359.py deleted file mode 100644 index a8c7a72e..00000000 --- a/bda/migrations/0020_merge_0019_auto_20220630_1245_0019_auto_20240707_1359.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 4.2.16 on 2025-02-26 08:23 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("bda", "0019_auto_20220630_1245"), - ("bda", "0019_auto_20240707_1359"), - ] - - operations = [] diff --git a/bda/models.py b/bda/models.py index af0d49fb..f4a0fac6 100644 --- a/bda/models.py +++ b/bda/models.py @@ -2,14 +2,14 @@ import calendar import random from datetime import timedelta +from custommail.models import CustomMail +from custommail.shortcuts import send_mass_custom_mail from django.conf import settings from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core import mail -from django.core.mail import EmailMessage, send_mass_mail from django.db import models from django.db.models import Count, Exists -from django.template import loader from django.utils import formats, timezone @@ -31,7 +31,6 @@ class Tirage(models.Model): "Tirage à afficher dans le catalogue", default=False ) enable_do_tirage = models.BooleanField("Le tirage peut être lancé", default=False) - archived = models.BooleanField("Archivé", default=False) def __str__(self): return "%s - %s" % ( @@ -117,19 +116,16 @@ class Spectacle(models.Model): bda_generic.nb_attr = 1 members.append(bda_generic) # On écrit un mail personnalisé à chaque participant - mails = [ + datatuple = [ ( - str(self), - loader.render_to_string( - "bda/mails/rappel.txt", - context={"member": member, "nb_attr": member.nb_attr, "show": self}, - ), + "bda-rappel", + {"member": member, "nb_attr": member.nb_attr, "show": self}, settings.MAIL_DATA["rappels"]["FROM"], [member.email], ) for member in members ] - send_mass_mail(mails) + send_mass_custom_mail(datatuple) # On enregistre le fait que l'envoi a bien eu lieu self.rappel_sent = timezone.now() self.save() @@ -151,7 +147,6 @@ PAYMENT_TYPES = ( ("cash", "Cash"), ("cb", "CB"), ("cheque", "Chèque"), - ("virement", "Virement"), ("autre", "Autre"), ) @@ -164,7 +159,7 @@ class Attribution(models.Model): given = models.BooleanField("Donnée", default=False) paid = models.BooleanField("Payée", default=False) paymenttype = models.CharField( - "Moyen de paiement", max_length=8, choices=PAYMENT_TYPES, blank=True + "Moyen de paiement", max_length=6, choices=PAYMENT_TYPES, blank=True ) def __str__(self): @@ -177,8 +172,8 @@ class Attribution(models.Model): class ParticipantPaidQueryset(models.QuerySet): """ - Un manager qui annote le queryset avec un champ `paid`, - indiquant si un participant a payé toutes ses attributions. + Un manager qui annote le queryset avec un champ `paid`, + indiquant si un participant a payé toutes ses attributions. """ def annotate_paid(self): @@ -199,9 +194,7 @@ class Participant(models.Model): attributions = models.ManyToManyField( Spectacle, through="Attribution", related_name="attributed_to" ) - tirage = models.ForeignKey( - Tirage, on_delete=models.CASCADE, limit_choices_to={"archived": False} - ) + tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE) accepte_charte = models.BooleanField("A accepté la charte BdA", default=False) choicesrevente = models.ManyToManyField( Spectacle, related_name="subscribed", blank=True @@ -212,12 +205,6 @@ class Participant(models.Model): def __str__(self): return "%s - %s" % (self.user, self.tirage.title) - class Meta: - ordering = ("-tirage", "user__last_name", "user__first_name") - constraints = [ - models.UniqueConstraint(fields=("tirage", "user"), name="unique_tirage"), - ] - DOUBLE_CHOICES = ( ("1", "1 place"), @@ -254,11 +241,7 @@ class ChoixSpectacle(models.Model): class Meta: ordering = ("priority",) - constraints = [ - models.UniqueConstraint( - fields=["participant", "spectacle"], name="unique_participation" - ) - ] + unique_together = (("participant", "spectacle"),) verbose_name = "voeu" verbose_name_plural = "voeux" @@ -365,24 +348,21 @@ class SpectacleRevente(models.Model): BdA-Revente à tous les intéressés. """ inscrits = self.attribution.spectacle.subscribed.select_related("user") - mails = [ + datatuple = [ ( - "BdA-Revente : {}".format(self.attribution.spectacle.title), - loader.render_to_string( - "bda/mails/revente-new.txt", - context={ - "member": participant.user, - "show": self.attribution.spectacle, - "revente": self, - "site": Site.objects.get_current(), - }, - ), + "bda-revente", + { + "member": participant.user, + "show": self.attribution.spectacle, + "revente": self, + "site": Site.objects.get_current(), + }, settings.MAIL_DATA["revente"]["FROM"], [participant.user.email], ) for participant in inscrits ] - send_mass_mail(mails) + send_mass_custom_mail(datatuple) self.notif_sent = True self.notif_time = timezone.now() self.save() @@ -393,23 +373,20 @@ class SpectacleRevente(models.Model): leur indiquer qu'il est désormais disponible au shotgun. """ inscrits = self.attribution.spectacle.subscribed.select_related("user") - mails = [ + datatuple = [ ( - "BdA-Revente : {}".format(self.attribution.spectacle.title), - loader.render_to_string( - "bda/mails/revente-shotgun.txt", - context={ - "member": participant.user, - "show": self.attribution.spectacle, - "site": Site.objects.get_current(), - }, - ), + "bda-shotgun", + { + "member": participant.user, + "show": self.attribution.spectacle, + "site": Site.objects.get_current(), + }, settings.MAIL_DATA["revente"]["FROM"], [participant.user.email], ) for participant in inscrits ] - send_mass_mail(mails) + send_mass_custom_mail(datatuple) self.notif_sent = True self.notif_time = timezone.now() # Flag inutile, sauf si l'horloge interne merde @@ -441,30 +418,31 @@ class SpectacleRevente(models.Model): "show": spectacle, } - subject = "BdA-Revente : {}".format(spectacle.title) + c_mails_qs = CustomMail.objects.filter( + shortname__in=[ + "bda-revente-winner", + "bda-revente-loser", + "bda-revente-seller", + ] + ) + + c_mails = {cm.shortname: cm for cm in c_mails_qs} mails.append( - EmailMessage( - subject=subject, - body=loader.render_to_string( - "bda/mails/revente-tirage-winner.txt", - context=context, - ), + c_mails["bda-revente-winner"].get_message( + context, from_email=settings.MAIL_DATA["revente"]["FROM"], to=[winner.user.email], ) ) + mails.append( - EmailMessage( - subject=subject, - body=loader.render_to_string( - "bda/mails/revente-tirage-seller.txt", - context=context, - ), + 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 @@ -474,15 +452,11 @@ class SpectacleRevente(models.Model): new_context["acheteur"] = inscrit.user mails.append( - EmailMessage( - subject=subject, - body=loader.render_to_string( - "bda/mails/revente-tirage-loser.txt", - context=new_context, - ), + 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() diff --git a/bda/templates/bda-attrib.html b/bda/templates/bda-attrib.html index 057cacb4..fac0de67 100644 --- a/bda/templates/bda-attrib.html +++ b/bda/templates/bda-attrib.html @@ -1,5 +1,5 @@ {% extends "base_title.html" %} -{% load static %} +{% load staticfiles %} {% block extra_head %} diff --git a/bda/templates/bda/etat-places.html b/bda/templates/bda/etat-places.html index d1af0667..401cc856 100644 --- a/bda/templates/bda/etat-places.html +++ b/bda/templates/bda/etat-places.html @@ -1,5 +1,5 @@ {% extends "base_title.html" %} -{% load static %} +{% load staticfiles %} {% block realcontent %}
+ Note : le template de ce mail peut être modifié à + cette adresse +
+ +Ne manque pas un spectacle avec le diff --git a/bda/templates/bda/revente/confirm-shotgun.html b/bda/templates/bda/revente/confirm-shotgun.html index bf8dccba..d7614c25 100644 --- a/bda/templates/bda/revente/confirm-shotgun.html +++ b/bda/templates/bda/revente/confirm-shotgun.html @@ -1,5 +1,5 @@ {% extends "base_title.html" %} -{% load static %} +{% load staticfiles %} {%block realcontent %} diff --git a/bda/templates/bda/revente/confirmed.html b/bda/templates/bda/revente/confirmed.html index 6f8ee583..780330bd 100644 --- a/bda/templates/bda/revente/confirmed.html +++ b/bda/templates/bda/revente/confirmed.html @@ -1,5 +1,5 @@ {% extends "base_title.html" %} -{% load static %} +{% load staticfiles %} {% block realcontent %}
Avant de revendre des places, il faut aller les payer !
+{% endblock %} diff --git a/bda/templates/bda/revente/subscribe.html b/bda/templates/bda/revente/subscribe.html index c91fff15..e0a7176c 100644 --- a/bda/templates/bda/revente/subscribe.html +++ b/bda/templates/bda/revente/subscribe.html @@ -1,5 +1,5 @@ {% extends "base_title.html" %} -{% load static %} +{% load staticfiles%} {% block realcontent %}- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -- {{ field.help_text|safe }} -
- {% endif %} -Confirmer la suppression
- -Bienvenue sur le site du COF !
", - "introduction_fr": "Bienvenue sur le site du COF !
", - "introduction_en": "" - } -}, -{ - "model": "cofcms.cofpage", - "pk": 28, - "fields": { - "body": "[{\"value\": \"On est le COF on est tout gentil
\", \"type\": \"paragraph\", \"id\": \"0b3a92bd-1e27-433b-842c-ab4f0a2750ad\"}]", - "body_fr": "[{\"value\": \"On est le COF on est tout gentil
\", \"type\": \"paragraph\", \"id\": \"0b3a92bd-1e27-433b-842c-ab4f0a2750ad\"}]", - "body_en": "[]" - } -}, -{ - "model": "cofcms.cofactuindexpage", - "pk": 29, - "fields": {} -}, -{ - "model": "cofcms.cofactupage", - "pk": 30, - "fields": { - "chapo": "Grosse teuf en K-F\u00eat", - "chapo_fr": "Grosse teuf en K-F\u00eat", - "chapo_en": "Big typar in K-F\u00eat", - "body": "Viens boire en K-F\u00eat
", - "body_fr": "Viens boire en K-F\u00eat
", - "body_en": "", - "image": 34, - "is_event": true, - "date_start": "2019-02-07T21:00:00Z", - "date_end": "2019-02-08T03:00:00Z", - "all_day": false - } -}, -{ - "model": "cofcms.cofactupage", - "pk": 31, - "fields": { - "chapo": "", - "chapo_fr": "", - "chapo_en": "", - "body": "C'est l'art
", - "body_fr": "C'est l'art
", - "body_en": "", - "image": 37, - "is_event": true, - "date_start": "2019-03-16T21:05:00Z", - "date_end": "2019-03-24T21:05:00Z", - "all_day": true - } -}, -{ - "model": "cofcms.cofdirectorypage", - "pk": 32, - "fields": { - "introduction": "Ce sont les clubs
", - "introduction_fr": "Ce sont les clubs
", - "introduction_en": "", - "alphabetique": true - } -}, -{ - "model": "cofcms.cofdirectoryentrypage", - "pk": 33, - "fields": { - "body": "Club Arts Plastiques
", - "body_fr": "Club Arts Plastiques
", - "body_en": "", - "links": "[{\"value\": {\"texte\": \"Liste Mails\", \"email\": \"artsplastiques@ens.fr\"}, \"type\": \"contact\", \"id\": \"cf198b98-0b84-4f38-ac00-6d883cfd60a4\"}]", - "links_fr": "[{\"value\": {\"texte\": \"Liste Mails\", \"email\": \"artsplastiques@ens.fr\"}, \"type\": \"contact\", \"id\": \"cf198b98-0b84-4f38-ac00-6d883cfd60a4\"}]", - "links_en": "[]", - "image": 37 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 7, - "fields": { - "sort_order": 0, - "link_page": null, - "link_url": "https://www.cof.ens.fr/bda/", - "url_append": "", - "handle": "", - "link_text": "BdA", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 8, - "fields": { - "sort_order": 1, - "link_page": null, - "link_url": "https://www.cof.ens.fr/bds/", - "url_append": "", - "handle": "", - "link_text": "BdS", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 9, - "fields": { - "sort_order": 2, - "link_page": null, - "link_url": "https://www.cof.ens.fr/gestion", - "url_append": "", - "handle": "", - "link_text": "GestioCOF", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 10, - "fields": { - "sort_order": 3, - "link_page": null, - "link_url": "https://www.cof.ens.fr/bocal", - "url_append": "", - "handle": "", - "link_text": "Le BOcal", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 11, - "fields": { - "sort_order": 4, - "link_page": null, - "link_url": "https://photos.cof.ens.fr/", - "url_append": "", - "handle": "", - "link_text": "Serveur photos", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 12, - "fields": { - "sort_order": 5, - "link_page": null, - "link_url": "https://www.eleves.ens.fr", - "url_append": "", - "handle": "", - "link_text": "Services \u00e9l\u00e8ves ENS", - "allow_subnav": false, - "menu": 2 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 20, - "fields": { - "sort_order": 0, - "link_page": 28, - "link_url": null, - "url_append": "", - "handle": "", - "link_text": "", - "allow_subnav": false, - "menu": 4 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 21, - "fields": { - "sort_order": 1, - "link_page": 29, - "link_url": null, - "url_append": "", - "handle": "", - "link_text": "", - "allow_subnav": false, - "menu": 4 - } -}, -{ - "model": "wagtailmenus.flatmenuitem", - "pk": 22, - "fields": { - "sort_order": 2, - "link_page": 32, - "link_url": null, - "url_append": "", - "handle": "", - "link_text": "", - "allow_subnav": false, - "menu": 4 - } -}, -{ - "model": "wagtailmenus.flatmenu", - "pk": 2, - "fields": { - "site": 2, - "title": "COF - liens externes", - "handle": "cof-nav-ext", - "heading": "", - "max_levels": 1, - "use_specific": 1 - } -}, -{ - "model": "wagtailmenus.flatmenu", - "pk": 4, - "fields": { - "site": 2, - "title": "COF - liens internes", - "handle": "cof-nav-int", - "heading": "", - "max_levels": 1, - "use_specific": 1 - } -} -] diff --git a/gestioncof/cms/forms.py b/gestioncof/cms/forms.py deleted file mode 100644 index d2766bf0..00000000 --- a/gestioncof/cms/forms.py +++ /dev/null @@ -1,15 +0,0 @@ -import re - -from django import forms -from django.utils.translation import gettext as _ - - -class CaptchaForm(forms.Form): - answer = forms.CharField(label="Réponse", max_length=32) - - def clean_answer(self): - value = self.cleaned_data["answer"] - if not re.match(r"(les|the)? *ernests?", value.strip().lower()): - raise forms.ValidationError(_("Réponse incorrecte")) - - return value diff --git a/gestioncof/cms/locale/en/LC_MESSAGES/django.mo b/gestioncof/cms/locale/en/LC_MESSAGES/django.mo deleted file mode 100644 index 40b2f45f..00000000 Binary files a/gestioncof/cms/locale/en/LC_MESSAGES/django.mo and /dev/null differ diff --git a/gestioncof/cms/locale/en/LC_MESSAGES/django.po b/gestioncof/cms/locale/en/LC_MESSAGES/django.po deleted file mode 100644 index d586f73e..00000000 --- a/gestioncof/cms/locale/en/LC_MESSAGES/django.po +++ /dev/null @@ -1,118 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR< | {{ this_month|date:"F Y" }} | > | diff --git a/gestioncof/cms/templates/cofcms/cof_actu_index_page.html b/gestioncof/cms/templates/cofcms/cof_actu_index_page.html index a1ea29ed..a6a909db 100644 --- a/gestioncof/cms/templates/cofcms/cof_actu_index_page.html +++ b/gestioncof/cms/templates/cofcms/cof_actu_index_page.html @@ -3,11 +3,11 @@ {% block extra_head %} {{ block.super }} - + {% endblock %} -{% block aside_title %}{% trans "Calendrier" %}{% endblock %} +{% block aside_title %}Calendrier{% endblock %} {% block aside %}
---|