Compare commits
39 commits
master
...
thubrecht/
Author | SHA1 | Date | |
---|---|---|---|
2e5ecdf636 | |||
8c3914694c | |||
533d4fdb2c | |||
50e59167ae | |||
0568daca8d | |||
1fea8ed462 | |||
59683ec59c | |||
b37c9daecb | |||
68065c94ef | |||
42bd1cde39 | |||
e8143856f5 | |||
ce2182d99e | |||
373aa32e43 | |||
e6ea8f5675 | |||
031717b28b | |||
0aaa41a8f9 | |||
745360ec76 | |||
112332ea42 | |||
260a819eb3 | |||
0e2a0fbc95 | |||
8c0f2a43bf | |||
224eccc6f0 | |||
8f223f6e83 | |||
b8aa30a2e9 | |||
9dc049d04f | |||
461ab6c7a1 | |||
8318af1fd3 | |||
279a3c1828 | |||
9c06d46d58 | |||
a334241c4f | |||
9ab5d95c30 | |||
c927085a7e | |||
40475a47c4 | |||
a2ef251252 | |||
89b01884d0 | |||
9cc32f642a | |||
6a6d14fe6f | |||
0cc035d903 | |||
0065269af5 |
108 changed files with 480 additions and 2874 deletions
|
@ -1 +0,0 @@
|
||||||
0x0000000000000000000000000000000000000000
|
|
|
@ -1 +0,0 @@
|
||||||
10000000-ffff-ffff-ffff-000000000001
|
|
|
@ -1 +0,0 @@
|
||||||
k-feste_token
|
|
|
@ -1 +0,0 @@
|
||||||
insecure-key
|
|
|
@ -1 +0,0 @@
|
||||||
toto
|
|
|
@ -1 +0,0 @@
|
||||||
sympa
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -21,4 +21,3 @@ media/
|
||||||
# VSCode
|
# VSCode
|
||||||
.vscode/
|
.vscode/
|
||||||
.direnv
|
.direnv
|
||||||
.static
|
|
||||||
|
|
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -30,29 +30,6 @@ adhérents ni des cotisations.
|
||||||
|
|
||||||
## Version ??? - ??/??/????
|
## 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
|
## Version 0.13 - 19/02/2023
|
||||||
|
|
||||||
### K-Fêt
|
### K-Fêt
|
||||||
|
|
12
README.md
12
README.md
|
@ -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
|
que sqlite3, un moteur de base de données léger et simple d'utilisation. Sous
|
||||||
Debian et dérivées (Ubuntu, ...) :
|
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;
|
Si vous décidez d'utiliser un environnement virtuel Python (virtualenv;
|
||||||
fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF
|
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
|
. venv/bin/activate
|
||||||
|
|
||||||
depuis le même dossier. Pour préparer l'environnement à l'utilisation de `./manage.py`
|
depuis le même dossier.
|
||||||
(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)
|
|
||||||
|
|
||||||
Vous pouvez maintenant installer les dépendances Python depuis le fichier
|
Vous pouvez maintenant installer les dépendances Python depuis le fichier
|
||||||
`requirements-devel.txt` :
|
`requirements-devel.txt` :
|
||||||
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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 = []
|
|
|
@ -151,7 +151,6 @@ PAYMENT_TYPES = (
|
||||||
("cash", "Cash"),
|
("cash", "Cash"),
|
||||||
("cb", "CB"),
|
("cb", "CB"),
|
||||||
("cheque", "Chèque"),
|
("cheque", "Chèque"),
|
||||||
("virement", "Virement"),
|
|
||||||
("autre", "Autre"),
|
("autre", "Autre"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -164,7 +163,7 @@ class Attribution(models.Model):
|
||||||
given = models.BooleanField("Donnée", default=False)
|
given = models.BooleanField("Donnée", default=False)
|
||||||
paid = models.BooleanField("Payée", default=False)
|
paid = models.BooleanField("Payée", default=False)
|
||||||
paymenttype = models.CharField(
|
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):
|
def __str__(self):
|
||||||
|
|
|
@ -6,23 +6,25 @@ pour les spectacles suivants :
|
||||||
- 1 place pour {{ place }}{% endfor %}
|
- 1 place pour {{ place }}{% endfor %}
|
||||||
|
|
||||||
*Paiement*
|
*Paiement*
|
||||||
Au burô :
|
L'intégralité de ces places de spectacles est à régler dès maintenant et AVANT
|
||||||
L'intégralité de ces places de spectacles est à régler dès maintenant, au bureau du COF pendant les heures de permanences (lundi, mardi, jeudi entre 12h et 14h et entre 18h30 et 19h30, mercredi entre 18h30 et 19h30, vendredi entre 12h et 14h). Les places sont à régler AVANT les représentations. Si vous êtes en vacances, vous pourrez venir les régler dès votre retour. Il est demandé à chacun·e de prendre garde à honorer l’ensemble des places qui lui sont attribuées et de s'engager de fait à payer la ou les place(s) qui lui sont attribuées.
|
vendredi prochain, au bureau du COF pendant les heures de permanences (du lundi au vendredi
|
||||||
|
entre 12h et 14h, et entre 18h et 20h). Des facilités de paiement sont bien
|
||||||
Par virements :
|
évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement,
|
||||||
L'intégralité de ces places de spectacles est à régler dès maintenant par virements. Il vous sera demandé d'envoyer une confirmation de l'envoi de virement à bda@ens.fr.
|
ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas
|
||||||
IBAN AEENS : FR76 4255 9100 0008 0263 8331 927
|
venir payer au bureau, merci de nous contacter par mail.
|
||||||
Motif de virements : AVR25(ou MAI25)-tirageprintemps-NOM-prénom
|
|
||||||
|
|
||||||
Les places sont à régler AVANT les représentations. Il est demandé à chacun·e de prendre garde à honorer l’ensemble des places qui lui sont attribuées et de s'engager de fait à payer la ou les place(s) qui lui sont attribuées.
|
|
||||||
Des facilités de paiement sont bien évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas venir payer au bureau, merci de nous contacter par mail.
|
|
||||||
|
|
||||||
*Mode de retrait des places*
|
*Mode de retrait des places*
|
||||||
Au moment du paiement, certaines places vous seront remises directement, d'autres seront à récupérer au cours de l'année, d'autres encore seront nominatives et à retirer le soir même dans les théâtres correspondants. Pour chaque spectacle, vous recevrez un mail quelques jours avant la représentation vous indiquant le mode de retrait.
|
Au moment du paiement, certaines places vous seront remises directement,
|
||||||
Nous vous rappelons que l'obtention de places du BdA vous engage à respecter les règles de fonctionnement :
|
d'autres seront à récupérer au cours de l'année, d'autres encore seront
|
||||||
https://bda.ens.fr/lequipe/charte-bda/
|
nominatives et à retirer le soir même dans les théâtres correspondants.
|
||||||
|
Pour chaque spectacle, vous recevrez un mail quelques jours avant la
|
||||||
|
représentation vous indiquant le mode de retrait.
|
||||||
|
|
||||||
Un système de revente des places via les mails BdA-revente est disponible directement sur votre compte GestioCOF. Pour pouvoir l'utiliser, il faut que vous ayez payé vos places en amont.
|
Nous vous rappelons que l'obtention de places du BdA vous engage à
|
||||||
|
respecter les règles de fonctionnement :
|
||||||
|
https://bda.ens.fr/lequipe/charte-bda/
|
||||||
|
Un système de revente des places via les mails BdA-revente est disponible
|
||||||
|
directement sur votre compte GestioCOF.
|
||||||
|
|
||||||
En vous souhaitant de très beaux spectacles tout au long de l'année,
|
En vous souhaitant de très beaux spectacles tout au long de l'année,
|
||||||
--
|
--
|
||||||
|
|
|
@ -11,19 +11,9 @@
|
||||||
<td>{{place.spectacle.date}}</td>
|
<td>{{place.spectacle.date}}</td>
|
||||||
<td>{% if place.double %}deux places{%else%}une place{% endif %}</td>
|
<td>{% if place.double %}deux places{%else%}une place{% endif %}</td>
|
||||||
<td>{% if place.spectacle.listing %}sur listing{% else %}place physique{% endif %}</td>
|
<td>{% if place.spectacle.listing %}sur listing{% else %}place physique{% endif %}</td>
|
||||||
<td>
|
|
||||||
{% if place.unpaid == 0 %}
|
|
||||||
Payé
|
|
||||||
{% elif place.unpaid == 1 %}
|
|
||||||
Une place à payer ({{place.unpaid_price|floatformat}}€)
|
|
||||||
{% else %}
|
|
||||||
Deux places à payer ({{place.unpaid_price|floatformat}}€)
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
<h4 class="bda-prix">Reste à payer : {{ unpaid|floatformat }}€</h4>
|
|
||||||
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
|
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
|
||||||
<br/>
|
<br/>
|
||||||
<p>Ne manque pas un spectacle avec le
|
<p>Ne manque pas un spectacle avec le
|
||||||
|
|
10
bda/views.py
10
bda/views.py
|
@ -114,7 +114,6 @@ def places(request, tirage_id):
|
||||||
"spectacle__date", "spectacle"
|
"spectacle__date", "spectacle"
|
||||||
).select_related("spectacle", "spectacle__location")
|
).select_related("spectacle", "spectacle__location")
|
||||||
total = sum(place.spectacle.price for place in places)
|
total = sum(place.spectacle.price for place in places)
|
||||||
unpaid = 0
|
|
||||||
filtered_places = []
|
filtered_places = []
|
||||||
places_dict = {}
|
places_dict = {}
|
||||||
spectacles = []
|
spectacles = []
|
||||||
|
@ -125,8 +124,6 @@ def places(request, tirage_id):
|
||||||
places_dict[place.spectacle].double = True
|
places_dict[place.spectacle].double = True
|
||||||
else:
|
else:
|
||||||
place.double = False
|
place.double = False
|
||||||
place.unpaid = 0
|
|
||||||
place.unpaid_price = 0
|
|
||||||
places_dict[place.spectacle] = place
|
places_dict[place.spectacle] = place
|
||||||
spectacles.append(place.spectacle)
|
spectacles.append(place.spectacle)
|
||||||
filtered_places.append(place)
|
filtered_places.append(place)
|
||||||
|
@ -135,12 +132,6 @@ def places(request, tirage_id):
|
||||||
warning = True
|
warning = True
|
||||||
else:
|
else:
|
||||||
dates.append(date)
|
dates.append(date)
|
||||||
|
|
||||||
if not place.paid:
|
|
||||||
unpaid += place.spectacle.price
|
|
||||||
places_dict[place.spectacle].unpaid += 1
|
|
||||||
places_dict[place.spectacle].unpaid_price += place.spectacle.price
|
|
||||||
|
|
||||||
# On prévient l'utilisateur s'il a deux places à la même date
|
# On prévient l'utilisateur s'il a deux places à la même date
|
||||||
if warning:
|
if warning:
|
||||||
messages.warning(
|
messages.warning(
|
||||||
|
@ -156,7 +147,6 @@ def places(request, tirage_id):
|
||||||
"places": filtered_places,
|
"places": filtered_places,
|
||||||
"tirage": tirage,
|
"tirage": tirage,
|
||||||
"total": total,
|
"total": total,
|
||||||
"unpaid": unpaid,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from bds import views
|
from bds import views
|
||||||
from shared.views import SympaListView
|
|
||||||
|
|
||||||
app_name = "bds"
|
app_name = "bds"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -22,10 +21,4 @@ urlpatterns = [
|
||||||
name="members.expired",
|
name="members.expired",
|
||||||
),
|
),
|
||||||
path("members/reset", views.ResetMembershipView.as_view(), name="members.reset"),
|
path("members/reset", views.ResetMembershipView.as_view(), name="members.reset"),
|
||||||
# Sympa export view
|
|
||||||
path(
|
|
||||||
"sympa/members/",
|
|
||||||
SympaListView.as_view(filters={"bds__is_member": True}),
|
|
||||||
name="export.sympa",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -67,8 +67,8 @@ INSTALLED_APPS = (
|
||||||
"wagtail.images",
|
"wagtail.images",
|
||||||
"wagtail.search",
|
"wagtail.search",
|
||||||
"wagtail.admin",
|
"wagtail.admin",
|
||||||
"wagtail",
|
"wagtail.core",
|
||||||
# "wagtail.contrib.modeladmin",
|
"wagtail.contrib.modeladmin",
|
||||||
"wagtail.contrib.routable_page",
|
"wagtail.contrib.routable_page",
|
||||||
"wagtailmenus",
|
"wagtailmenus",
|
||||||
"modelcluster",
|
"modelcluster",
|
||||||
|
@ -205,9 +205,8 @@ MAIL_DATA = {
|
||||||
"REPLYTO": "cof@ens.fr",
|
"REPLYTO": "cof@ens.fr",
|
||||||
},
|
},
|
||||||
"rappels": {"FROM": "Le BdA <bda@ens.fr>", "REPLYTO": "Le BdA <bda@ens.fr>"},
|
"rappels": {"FROM": "Le BdA <bda@ens.fr>", "REPLYTO": "Le BdA <bda@ens.fr>"},
|
||||||
"kfet": {
|
"rappel_negatif": {
|
||||||
"FROM": "La K-Fêt <chefs-k-fet@ens.fr>",
|
"FROM": "La K-Fêt <k-fet@ens.fr>",
|
||||||
"REPLYTO": "La K-Fêt <chefs-k-fet@ens.fr>",
|
|
||||||
},
|
},
|
||||||
"revente": {
|
"revente": {
|
||||||
"FROM": "BdA-Revente <bda-revente@ens.fr>",
|
"FROM": "BdA-Revente <bda-revente@ens.fr>",
|
||||||
|
|
|
@ -27,9 +27,6 @@ ALLOWED_HOSTS = []
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
SYMPA_PASSWORD = b"sympa"
|
|
||||||
SYMPA_USERNAME = b"sympa"
|
|
||||||
|
|
||||||
if TESTING:
|
if TESTING:
|
||||||
PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||||
|
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
"""
|
|
||||||
Django settings for the gestioBDS project.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from loadcredential import Credentials
|
|
||||||
|
|
||||||
credentials = Credentials(env_prefix="GESTIOBDS_")
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
|
||||||
# WARNING: keep the secret key used in production secret!
|
|
||||||
SECRET_KEY = credentials["SECRET_KEY"]
|
|
||||||
|
|
||||||
# WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = credentials.get_json("DEBUG", False)
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", [])
|
|
||||||
ADMINS = credentials.get_json("ADMINS", [])
|
|
||||||
|
|
||||||
SERVER_EMAIL = credentials.get("SERVER_EMAIL")
|
|
||||||
EMAIL_HOST = credentials.get("EMAIL_HOST")
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
|
||||||
|
|
||||||
SYMPA_PASSWORD = credentials["SYMPA_PASSWORD"].encode()
|
|
||||||
SYMPA_USERNAME = credentials["SYMPA_USERNAME"].encode()
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Installed Apps configuration
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
"shared",
|
|
||||||
# Must be before 'django.contrib.admin'.
|
|
||||||
# https://django-autocomplete-light.readthedocs.io/en/master/install.html
|
|
||||||
"dal",
|
|
||||||
"dal_select2",
|
|
||||||
"django.contrib.auth",
|
|
||||||
"django.contrib.contenttypes",
|
|
||||||
"django.contrib.sessions",
|
|
||||||
"django.contrib.sites",
|
|
||||||
"django.contrib.messages",
|
|
||||||
"django.contrib.admin",
|
|
||||||
"django.contrib.admindocs",
|
|
||||||
"gestioasso.apps.IgnoreSrcStaticFilesConfig",
|
|
||||||
"django_cas_ng",
|
|
||||||
"bootstrapform",
|
|
||||||
"widget_tweaks",
|
|
||||||
"bds",
|
|
||||||
"events",
|
|
||||||
"clubs",
|
|
||||||
"authens",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Middleware configuration
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
|
||||||
"django.middleware.common.CommonMiddleware",
|
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
||||||
"django.middleware.security.SecurityMiddleware",
|
|
||||||
"django.middleware.locale.LocaleMiddleware",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# URL configuration
|
|
||||||
|
|
||||||
ROOT_URLCONF = "gestioasso.urls"
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Templates configuration
|
|
||||||
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
||||||
"APP_DIRS": True,
|
|
||||||
"OPTIONS": {
|
|
||||||
"context_processors": [
|
|
||||||
"django.template.context_processors.debug",
|
|
||||||
"django.template.context_processors.request",
|
|
||||||
"django.contrib.auth.context_processors.auth",
|
|
||||||
"django.contrib.messages.context_processors.messages",
|
|
||||||
"django.template.context_processors.i18n",
|
|
||||||
"django.template.context_processors.media",
|
|
||||||
"django.template.context_processors.static",
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Database configuration
|
|
||||||
|
|
||||||
DATABASES = credentials.get_json(
|
|
||||||
"DATABASES",
|
|
||||||
default={
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
|
||||||
"NAME": (BASE_DIR / "db.sqlite3"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
CACHES = credentials.get_json(
|
|
||||||
"CACHES",
|
|
||||||
default={
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
CORS_ORIGIN_WHITELIST = credentials.get("CORS_ORIGIN_WHITELIST", [])
|
|
||||||
|
|
||||||
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Staticfiles configuration
|
|
||||||
|
|
||||||
STATIC_ROOT = credentials["STATIC_ROOT"]
|
|
||||||
STATIC_URL = "/static/"
|
|
||||||
|
|
||||||
MEDIA_ROOT = credentials.get("MEDIA_ROOT", (BASE_DIR / "media"))
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Authens and Authentication configuration
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
|
||||||
"authens.backends.ENSCASBackend",
|
|
||||||
"authens.backends.OldCASBackend",
|
|
||||||
]
|
|
||||||
|
|
||||||
AUTHENS_USE_OLDCAS = False
|
|
||||||
|
|
||||||
LOGIN_URL = "authens:login"
|
|
||||||
LOGIN_REDIRECT_URL = "bds:home"
|
|
||||||
LOGOUT_REDIRECT_URL = "bds:home"
|
|
||||||
|
|
||||||
|
|
||||||
# ---
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
|
||||||
# ---
|
|
||||||
|
|
||||||
LANGUAGE_CODE = "fr-fr"
|
|
||||||
TIME_ZONE = "Europe/Paris"
|
|
||||||
USE_I18N = True
|
|
||||||
USE_L10N = True
|
|
||||||
USE_TZ = True
|
|
||||||
LANGUAGES = (("fr", "Français"), ("en", "English"))
|
|
||||||
FORMAT_MODULE_PATH = "gestioasso.locale"
|
|
||||||
|
|
||||||
##
|
|
||||||
# Development configuration
|
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
|
||||||
|
|
||||||
def show_toolbar(request):
|
|
||||||
"""
|
|
||||||
On active la debug-toolbar en mode développement local sauf :
|
|
||||||
- dans l'admin où ça ne sert pas à grand chose;
|
|
||||||
- si la variable d'environnement DJANGO_NO_DDT est à 1 → ça permet de la désactiver
|
|
||||||
sans modifier ce fichier en exécutant `export DJANGO_NO_DDT=1` dans le terminal
|
|
||||||
qui lance `./manage.py runserver`.
|
|
||||||
|
|
||||||
Autre side effect de cette fonction : on ne fait pas la vérification de INTERNAL_IPS
|
|
||||||
que ferait la debug-toolbar par défaut, ce qui la fait fonctionner aussi à
|
|
||||||
l'intérieur de Vagrant (comportement non testé depuis un moment…)
|
|
||||||
"""
|
|
||||||
|
|
||||||
env_no_ddt = bool(os.environ.get("DJANGO_NO_DDT", None))
|
|
||||||
return not (env_no_ddt or request.path.startswith("/admin/"))
|
|
||||||
|
|
||||||
##
|
|
||||||
# Django Debug Toolbar configuration
|
|
||||||
|
|
||||||
DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar}
|
|
||||||
INSTALLED_APPS += ["debug_toolbar"]
|
|
||||||
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
|
|
|
@ -1,324 +0,0 @@
|
||||||
"""
|
|
||||||
Django settings for the gestioCOF project.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from loadcredential import Credentials
|
|
||||||
|
|
||||||
credentials = Credentials(env_prefix="GESTIOCOF_")
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
|
||||||
# WARNING: keep the secret key used in production secret!
|
|
||||||
SECRET_KEY = credentials["SECRET_KEY"]
|
|
||||||
|
|
||||||
# WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = credentials.get_json("DEBUG", False)
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", [])
|
|
||||||
ADMINS = credentials.get_json("ADMINS", [])
|
|
||||||
|
|
||||||
SERVER_EMAIL = credentials.get("SERVER_EMAIL")
|
|
||||||
EMAIL_HOST = credentials.get("EMAIL_HOST")
|
|
||||||
|
|
||||||
LDAP_SERVER_URL = credentials.get("LDAP_SERVER_URL")
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
|
||||||
|
|
||||||
SYMPA_PASSWORD = credentials["SYMPA_PASSWORD"].encode()
|
|
||||||
SYMPA_USERNAME = credentials["SYMPA_USERNAME"].encode()
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Installed Apps configuration
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
"gestioncof",
|
|
||||||
# Must be before django admin
|
|
||||||
# https://github.com/infoportugal/wagtail-modeltranslation/issues/193
|
|
||||||
"wagtail_modeltranslation",
|
|
||||||
"wagtail_modeltranslation.makemigrations",
|
|
||||||
"wagtail_modeltranslation.migrate",
|
|
||||||
"modeltranslation",
|
|
||||||
"shared",
|
|
||||||
# Must be before 'django.contrib.admin'.
|
|
||||||
# https://django-autocomplete-light.readthedocs.io/en/master/install.html
|
|
||||||
"dal",
|
|
||||||
"dal_select2",
|
|
||||||
"django.contrib.auth",
|
|
||||||
"django.contrib.contenttypes",
|
|
||||||
"django.contrib.sessions",
|
|
||||||
"django.contrib.sites",
|
|
||||||
"django.contrib.messages",
|
|
||||||
"django.contrib.admin",
|
|
||||||
"django.contrib.admindocs",
|
|
||||||
"gestioasso.apps.IgnoreSrcStaticFilesConfig",
|
|
||||||
"django_cas_ng",
|
|
||||||
"bootstrapform",
|
|
||||||
"widget_tweaks",
|
|
||||||
"bda",
|
|
||||||
"petitscours",
|
|
||||||
"hcaptcha",
|
|
||||||
"kfet",
|
|
||||||
"kfet.open",
|
|
||||||
"channels",
|
|
||||||
"djconfig",
|
|
||||||
"wagtail.contrib.forms",
|
|
||||||
"wagtail.contrib.redirects",
|
|
||||||
"wagtail.embeds",
|
|
||||||
"wagtail.sites",
|
|
||||||
"wagtail.users",
|
|
||||||
"wagtail.snippets",
|
|
||||||
"wagtail.documents",
|
|
||||||
"wagtail.images",
|
|
||||||
"wagtail.search",
|
|
||||||
"wagtail.admin",
|
|
||||||
"wagtail",
|
|
||||||
# "wagtail.contrib.modeladmin",
|
|
||||||
"wagtail.contrib.routable_page",
|
|
||||||
"wagtailmenus",
|
|
||||||
"modelcluster",
|
|
||||||
"taggit",
|
|
||||||
"kfet.auth",
|
|
||||||
"kfet.cms",
|
|
||||||
"gestioncof.cms",
|
|
||||||
"django_js_reverse",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Middleware configuration
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
|
||||||
"corsheaders.middleware.CorsMiddleware",
|
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
|
||||||
"django.middleware.common.CommonMiddleware",
|
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
||||||
"django.middleware.security.SecurityMiddleware",
|
|
||||||
"django.middleware.locale.LocaleMiddleware",
|
|
||||||
"djconfig.middleware.DjConfigMiddleware",
|
|
||||||
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# URL configuration
|
|
||||||
|
|
||||||
ROOT_URLCONF = "gestioasso.urls"
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Templates configuration
|
|
||||||
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
||||||
"APP_DIRS": True,
|
|
||||||
"OPTIONS": {
|
|
||||||
"context_processors": [
|
|
||||||
"wagtailmenus.context_processors.wagtailmenus",
|
|
||||||
"djconfig.context_processors.config",
|
|
||||||
"gestioncof.shared.context_processor",
|
|
||||||
"kfet.auth.context_processors.temporary_auth",
|
|
||||||
"kfet.context_processors.config",
|
|
||||||
"django.template.context_processors.debug",
|
|
||||||
"django.template.context_processors.request",
|
|
||||||
"django.contrib.auth.context_processors.auth",
|
|
||||||
"django.contrib.messages.context_processors.messages",
|
|
||||||
"django.template.context_processors.i18n",
|
|
||||||
"django.template.context_processors.media",
|
|
||||||
"django.template.context_processors.static",
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Wagtail configuration
|
|
||||||
|
|
||||||
WAGTAIL_SITE_NAME = "GestioCOF"
|
|
||||||
WAGTAIL_ENABLE_UPDATE_CHECK = False
|
|
||||||
TAGGIT_CASE_INSENSITIVE = True
|
|
||||||
|
|
||||||
##
|
|
||||||
# Django-js-reverse settings
|
|
||||||
|
|
||||||
JS_REVERSE_JS_VAR_NAME = "django_urls"
|
|
||||||
# Quand on aura namespace les urls...
|
|
||||||
# JS_REVERSE_INCLUDE_ONLY_NAMESPACES = ['k-fet']
|
|
||||||
|
|
||||||
##
|
|
||||||
# K-Fêt history configuration
|
|
||||||
|
|
||||||
# L'historique n'est accesible que d'aujourd'hui
|
|
||||||
# à aujourd'hui - KFET_HISTORY_DATE_LIMIT
|
|
||||||
KFET_HISTORY_DATE_LIMIT = timedelta(days=7)
|
|
||||||
|
|
||||||
# Limite plus longue pour les chefs/trez
|
|
||||||
# (qui ont la permission kfet.access_old_history)
|
|
||||||
KFET_HISTORY_LONG_DATE_LIMIT = timedelta(days=30)
|
|
||||||
|
|
||||||
# These accounts don't represent actual people and can be freely accessed
|
|
||||||
# Identification based on trigrammes
|
|
||||||
KFET_HISTORY_NO_DATE_LIMIT_TRIGRAMMES = ["LIQ", "#13"]
|
|
||||||
KFET_HISTORY_NO_DATE_LIMIT = datetime(1794, 10, 30) # AKA the distant past
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Database configuration
|
|
||||||
|
|
||||||
DATABASES = credentials.get_json(
|
|
||||||
"DATABASES",
|
|
||||||
default={
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
|
||||||
"NAME": (BASE_DIR / "db.sqlite3"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
CACHES = credentials.get_json(
|
|
||||||
"CACHES",
|
|
||||||
default={
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
CHANNEL_LAYERS = credentials.get_json(
|
|
||||||
"CHANNEL_LAYERS",
|
|
||||||
default={
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "channels.layers.InMemoryChannelLayer",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
ASGI_APPLICATION = "gestioasso.routing.application"
|
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS = credentials.get("CORS_ALLOWED_ORIGINS", [])
|
|
||||||
CSRF_TRUSTED_ORIGINS = [f"https://{host}" for host in ALLOWED_HOSTS]
|
|
||||||
|
|
||||||
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Staticfiles configuration
|
|
||||||
|
|
||||||
STATIC_ROOT = credentials["STATIC_ROOT"]
|
|
||||||
STATIC_URL = "/static/"
|
|
||||||
|
|
||||||
MEDIA_ROOT = credentials.get("MEDIA_ROOT", (BASE_DIR / "media"))
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Authentication configuration
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
"kfet.auth.backends.BlockFrozenAccountBackend", # Must be in first
|
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
|
||||||
"gestioncof.shared.COFCASBackend",
|
|
||||||
"kfet.auth.backends.GenericBackend",
|
|
||||||
]
|
|
||||||
|
|
||||||
LOGIN_URL = "cof-login"
|
|
||||||
LOGIN_REDIRECT_URL = reverse_lazy("home")
|
|
||||||
|
|
||||||
# FIXME: Switch to authens
|
|
||||||
CAS_SERVER_URL = "https://cas.eleves.ens.fr/"
|
|
||||||
CAS_VERSION = "2"
|
|
||||||
CAS_LOGIN_MSG = None
|
|
||||||
CAS_IGNORE_REFERER = True
|
|
||||||
CAS_REDIRECT_URL = "/"
|
|
||||||
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# h-captcha configuration
|
|
||||||
|
|
||||||
HCAPTCHA_SITEKEY = credentials["HCAPTCHA_SITEKEY"]
|
|
||||||
HCAPTCHA_SECRET = credentials["HCAPTCHA_SECRET"]
|
|
||||||
|
|
||||||
##
|
|
||||||
# K-Fêt token for the openness indicator
|
|
||||||
|
|
||||||
KFETOPEN_TOKEN = credentials["KFETOPEN_TOKEN"]
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Mail configuration
|
|
||||||
|
|
||||||
MAIL_DATA = {
|
|
||||||
"petits_cours": {
|
|
||||||
"FROM": "Le COF <cof@ens.fr>",
|
|
||||||
"BCC": "archivescof@gmail.com",
|
|
||||||
"REPLYTO": "cof@ens.fr",
|
|
||||||
},
|
|
||||||
"rappels": {
|
|
||||||
"FROM": "Le BdA <bda@ens.fr>",
|
|
||||||
"REPLYTO": "Le BdA <bda@ens.fr>",
|
|
||||||
},
|
|
||||||
"kfet": {
|
|
||||||
"FROM": "La K-Fêt <chefs-k-fet@ens.fr>",
|
|
||||||
"REPLYTO": "La K-Fêt <chefs-k-fet@ens.fr>",
|
|
||||||
},
|
|
||||||
"revente": {
|
|
||||||
"FROM": "BdA-Revente <bda-revente@ens.fr>",
|
|
||||||
"REPLYTO": "BdA-Revente <bda-revente@ens.fr>",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# ---
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
|
||||||
# ---
|
|
||||||
|
|
||||||
LANGUAGE_CODE = "fr-fr"
|
|
||||||
TIME_ZONE = "Europe/Paris"
|
|
||||||
USE_I18N = True
|
|
||||||
USE_L10N = True
|
|
||||||
USE_TZ = True
|
|
||||||
LANGUAGES = (("fr", "Français"), ("en", "English"))
|
|
||||||
FORMAT_MODULE_PATH = "gestioasso.locale"
|
|
||||||
|
|
||||||
##
|
|
||||||
# Development configuration
|
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
|
||||||
|
|
||||||
def show_toolbar(request):
|
|
||||||
"""
|
|
||||||
On active la debug-toolbar en mode développement local sauf :
|
|
||||||
- dans l'admin où ça ne sert pas à grand chose;
|
|
||||||
- si la variable d'environnement DJANGO_NO_DDT est à 1 → ça permet de la désactiver
|
|
||||||
sans modifier ce fichier en exécutant `export DJANGO_NO_DDT=1` dans le terminal
|
|
||||||
qui lance `./manage.py runserver`.
|
|
||||||
|
|
||||||
Autre side effect de cette fonction : on ne fait pas la vérification de INTERNAL_IPS
|
|
||||||
que ferait la debug-toolbar par défaut, ce qui la fait fonctionner aussi à
|
|
||||||
l'intérieur de Vagrant (comportement non testé depuis un moment…)
|
|
||||||
"""
|
|
||||||
|
|
||||||
env_no_ddt = bool(os.environ.get("DJANGO_NO_DDT", None))
|
|
||||||
return not (env_no_ddt or request.path.startswith("/admin/"))
|
|
||||||
|
|
||||||
##
|
|
||||||
# Django Debug Toolbar configuration
|
|
||||||
|
|
||||||
DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar}
|
|
||||||
INSTALLED_APPS += ["debug_toolbar"]
|
|
||||||
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""
|
"""
|
||||||
Fichier principal de configuration des urls du projet GestioCOF
|
Fichier principal de configuration des urls du projet GestioCOF
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.i18n import i18n_patterns
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
@ -57,13 +56,12 @@ if settings.DEBUG:
|
||||||
# Si on est en production, MEDIA_ROOT est servi par Apache.
|
# Si on est en production, MEDIA_ROOT est servi par Apache.
|
||||||
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
|
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
|
||||||
|
|
||||||
|
|
||||||
# Wagtail URLs (wagtail urls must be last, as catch-all)
|
# Wagtail URLs (wagtail.core urls must be last, as catch-all)
|
||||||
if "wagtail" in settings.INSTALLED_APPS:
|
if "wagtail.core" in settings.INSTALLED_APPS:
|
||||||
from wagtail import urls as wagtail_urls
|
|
||||||
from wagtail.admin import urls as wagtailadmin_urls
|
from wagtail.admin import urls as wagtailadmin_urls
|
||||||
|
from wagtail.core import urls as wagtail_urls
|
||||||
from wagtail.documents import urls as wagtaildocs_urls
|
from wagtail.documents import urls as wagtaildocs_urls
|
||||||
|
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
|
|
|
@ -130,33 +130,15 @@ class UserProfileAdmin(UserAdmin):
|
||||||
is_buro.short_description = "Membre du Buro"
|
is_buro.short_description = "Membre du Buro"
|
||||||
is_buro.boolean = True
|
is_buro.boolean = True
|
||||||
|
|
||||||
def is_chef(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.profile.is_chef
|
|
||||||
except CofProfile.DoesNotExist:
|
|
||||||
return False
|
|
||||||
|
|
||||||
is_chef.short_description = "Chef K-Fêt"
|
|
||||||
is_chef.boolean = True
|
|
||||||
|
|
||||||
def is_cof(self, obj):
|
def is_cof(self, obj):
|
||||||
try:
|
try:
|
||||||
return obj.profile.is_cof
|
return obj.profile.is_cof
|
||||||
except CofProfile.DoesNotExist:
|
except CofProfile.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
is_cof.short_description = "Membre COF"
|
is_cof.short_description = "Membre du COF"
|
||||||
is_cof.boolean = True
|
is_cof.boolean = True
|
||||||
|
|
||||||
def is_kfet(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.profile.is_kfet
|
|
||||||
except CofProfile.DoesNotExist:
|
|
||||||
return False
|
|
||||||
|
|
||||||
is_kfet.short_description = "Membre K-Fêt"
|
|
||||||
is_kfet.boolean = True
|
|
||||||
|
|
||||||
list_display = UserAdmin.list_display + (
|
list_display = UserAdmin.list_display + (
|
||||||
"profile_phone",
|
"profile_phone",
|
||||||
"profile_occupation",
|
"profile_occupation",
|
||||||
|
@ -164,9 +146,7 @@ class UserProfileAdmin(UserAdmin):
|
||||||
"profile_mailing_bda",
|
"profile_mailing_bda",
|
||||||
"profile_mailing_bda_revente",
|
"profile_mailing_bda_revente",
|
||||||
"is_cof",
|
"is_cof",
|
||||||
"is_kfet",
|
|
||||||
"is_buro",
|
"is_buro",
|
||||||
"is_chef",
|
|
||||||
)
|
)
|
||||||
list_display_links = ("username", "email", "first_name", "last_name")
|
list_display_links = ("username", "email", "first_name", "last_name")
|
||||||
list_filter = UserAdmin.list_filter + (
|
list_filter = UserAdmin.list_filter + (
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import wagtail.blocks
|
|
||||||
import wagtail.contrib.routable_page.models
|
import wagtail.contrib.routable_page.models
|
||||||
import wagtail.fields
|
import wagtail.core.blocks
|
||||||
|
import wagtail.core.fields
|
||||||
import wagtail.images.blocks
|
import wagtail.images.blocks
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
@ -72,14 +72,18 @@ class Migration(migrations.Migration):
|
||||||
blank=True, null=True, verbose_name="Description rapide"
|
blank=True, null=True, verbose_name="Description rapide"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("body", wagtail.fields.RichTextField(verbose_name="Contenu")),
|
("body", wagtail.core.fields.RichTextField(verbose_name="Contenu")),
|
||||||
(
|
(
|
||||||
"body_fr",
|
"body_fr",
|
||||||
wagtail.fields.RichTextField(null=True, verbose_name="Contenu"),
|
wagtail.core.fields.RichTextField(
|
||||||
|
null=True, verbose_name="Contenu"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"body_en",
|
"body_en",
|
||||||
wagtail.fields.RichTextField(null=True, verbose_name="Contenu"),
|
wagtail.core.fields.RichTextField(
|
||||||
|
null=True, verbose_name="Contenu"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"is_event",
|
"is_event",
|
||||||
|
@ -134,40 +138,46 @@ class Migration(migrations.Migration):
|
||||||
to="wagtailcore.Page",
|
to="wagtailcore.Page",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("body", wagtail.fields.RichTextField(verbose_name="Description")),
|
("body", wagtail.core.fields.RichTextField(verbose_name="Description")),
|
||||||
(
|
(
|
||||||
"body_fr",
|
"body_fr",
|
||||||
wagtail.fields.RichTextField(null=True, verbose_name="Description"),
|
wagtail.core.fields.RichTextField(
|
||||||
|
null=True, verbose_name="Description"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"body_en",
|
"body_en",
|
||||||
wagtail.fields.RichTextField(null=True, verbose_name="Description"),
|
wagtail.core.fields.RichTextField(
|
||||||
|
null=True, verbose_name="Description"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"links",
|
"links",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(required=True),
|
wagtail.core.blocks.URLBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(
|
||||||
|
required=True
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
),
|
||||||
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -176,29 +186,31 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"links_fr",
|
"links_fr",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(required=True),
|
wagtail.core.blocks.URLBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(
|
||||||
|
required=True
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
),
|
||||||
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -208,29 +220,31 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"links_en",
|
"links_en",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(required=True),
|
wagtail.core.blocks.URLBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(
|
||||||
|
required=True
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
),
|
||||||
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -272,17 +286,17 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction",
|
"introduction",
|
||||||
wagtail.fields.RichTextField(verbose_name="Introduction"),
|
wagtail.core.fields.RichTextField(verbose_name="Introduction"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction_fr",
|
"introduction_fr",
|
||||||
wagtail.fields.RichTextField(
|
wagtail.core.fields.RichTextField(
|
||||||
null=True, verbose_name="Introduction"
|
null=True, verbose_name="Introduction"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction_en",
|
"introduction_en",
|
||||||
wagtail.fields.RichTextField(
|
wagtail.core.fields.RichTextField(
|
||||||
null=True, verbose_name="Introduction"
|
null=True, verbose_name="Introduction"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -315,27 +329,27 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"body",
|
"body",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"heading",
|
"heading",
|
||||||
wagtail.blocks.CharBlock(classname="full title"),
|
wagtail.core.blocks.CharBlock(classname="full title"),
|
||||||
),
|
),
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
("paragraph", wagtail.core.blocks.RichTextBlock()),
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
("image", wagtail.images.blocks.ImageChooserBlock()),
|
||||||
(
|
(
|
||||||
"iframe",
|
"iframe",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(
|
wagtail.core.blocks.URLBlock(
|
||||||
"Adresse de la page"
|
"Adresse de la page"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"height",
|
"height",
|
||||||
wagtail.blocks.CharBlock(
|
wagtail.core.blocks.CharBlock(
|
||||||
"Hauteur (en pixels)"
|
"Hauteur (en pixels)"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -347,27 +361,27 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"body_fr",
|
"body_fr",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"heading",
|
"heading",
|
||||||
wagtail.blocks.CharBlock(classname="full title"),
|
wagtail.core.blocks.CharBlock(classname="full title"),
|
||||||
),
|
),
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
("paragraph", wagtail.core.blocks.RichTextBlock()),
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
("image", wagtail.images.blocks.ImageChooserBlock()),
|
||||||
(
|
(
|
||||||
"iframe",
|
"iframe",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(
|
wagtail.core.blocks.URLBlock(
|
||||||
"Adresse de la page"
|
"Adresse de la page"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"height",
|
"height",
|
||||||
wagtail.blocks.CharBlock(
|
wagtail.core.blocks.CharBlock(
|
||||||
"Hauteur (en pixels)"
|
"Hauteur (en pixels)"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -380,27 +394,27 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"body_en",
|
"body_en",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"heading",
|
"heading",
|
||||||
wagtail.blocks.CharBlock(classname="full title"),
|
wagtail.core.blocks.CharBlock(classname="full title"),
|
||||||
),
|
),
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
("paragraph", wagtail.core.blocks.RichTextBlock()),
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
("image", wagtail.images.blocks.ImageChooserBlock()),
|
||||||
(
|
(
|
||||||
"iframe",
|
"iframe",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"url",
|
"url",
|
||||||
wagtail.blocks.URLBlock(
|
wagtail.core.blocks.URLBlock(
|
||||||
"Adresse de la page"
|
"Adresse de la page"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"height",
|
"height",
|
||||||
wagtail.blocks.CharBlock(
|
wagtail.core.blocks.CharBlock(
|
||||||
"Hauteur (en pixels)"
|
"Hauteur (en pixels)"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -434,17 +448,17 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction",
|
"introduction",
|
||||||
wagtail.fields.RichTextField(verbose_name="Introduction"),
|
wagtail.core.fields.RichTextField(verbose_name="Introduction"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction_fr",
|
"introduction_fr",
|
||||||
wagtail.fields.RichTextField(
|
wagtail.core.fields.RichTextField(
|
||||||
null=True, verbose_name="Introduction"
|
null=True, verbose_name="Introduction"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"introduction_en",
|
"introduction_en",
|
||||||
wagtail.fields.RichTextField(
|
wagtail.core.fields.RichTextField(
|
||||||
null=True, verbose_name="Introduction"
|
null=True, verbose_name="Introduction"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 2.2.8 on 2019-12-20 16:22
|
# Generated by Django 2.2.8 on 2019-12-20 16:22
|
||||||
|
|
||||||
import wagtail.blocks
|
import wagtail.core.blocks
|
||||||
import wagtail.fields
|
import wagtail.core.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,26 +14,26 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links",
|
name="links",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -44,26 +44,26 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links_en",
|
name="links_en",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -75,26 +75,26 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links_fr",
|
name="links_fr",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 2.2.15 on 2020-08-29 21:14
|
# Generated by Django 2.2.15 on 2020-08-29 21:14
|
||||||
|
|
||||||
import wagtail.blocks
|
import wagtail.core.blocks
|
||||||
import wagtail.fields
|
import wagtail.core.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,35 +14,35 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links",
|
name="links",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"info",
|
"info",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
("nom", wagtail.core.blocks.CharBlock(required=False)),
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
("texte", wagtail.core.blocks.CharBlock(required=True)),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -53,35 +53,35 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links_en",
|
name="links_en",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"info",
|
"info",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
("nom", wagtail.core.blocks.CharBlock(required=False)),
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
("texte", wagtail.core.blocks.CharBlock(required=True)),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -93,35 +93,35 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="cofdirectoryentrypage",
|
model_name="cofdirectoryentrypage",
|
||||||
name="links_fr",
|
name="links_fr",
|
||||||
field=wagtail.fields.StreamField(
|
field=wagtail.core.fields.StreamField(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"lien",
|
"lien",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
("url", wagtail.core.blocks.URLBlock(required=True)),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"contact",
|
"contact",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"email",
|
"email",
|
||||||
wagtail.blocks.EmailBlock(required=True),
|
wagtail.core.blocks.EmailBlock(required=True),
|
||||||
),
|
),
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
("texte", wagtail.core.blocks.CharBlock()),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"info",
|
"info",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
("nom", wagtail.core.blocks.CharBlock(required=False)),
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
("texte", wagtail.core.blocks.CharBlock(required=True)),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
# Generated by Django 4.2.17 on 2024-12-19 12:27
|
|
||||||
|
|
||||||
import wagtail.blocks
|
|
||||||
import wagtail.fields
|
|
||||||
import wagtail.images.blocks
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("cofcms", "0004_auto_20200829_2314"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofdirectoryentrypage",
|
|
||||||
name="links",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"lien",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"contact",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("email", wagtail.blocks.EmailBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"info",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
blank=True,
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofdirectoryentrypage",
|
|
||||||
name="links_en",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"lien",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"contact",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("email", wagtail.blocks.EmailBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"info",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofdirectoryentrypage",
|
|
||||||
name="links_fr",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"lien",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"contact",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("email", wagtail.blocks.EmailBlock(required=True)),
|
|
||||||
("texte", wagtail.blocks.CharBlock()),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"info",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("nom", wagtail.blocks.CharBlock(required=False)),
|
|
||||||
("texte", wagtail.blocks.CharBlock(required=True)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofpage",
|
|
||||||
name="body",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
("heading", wagtail.blocks.CharBlock(form_classname="full title")),
|
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
|
||||||
(
|
|
||||||
"iframe",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock("Adresse de la page")),
|
|
||||||
(
|
|
||||||
"height",
|
|
||||||
wagtail.blocks.CharBlock("Hauteur (en pixels)"),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofpage",
|
|
||||||
name="body_en",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
("heading", wagtail.blocks.CharBlock(form_classname="full title")),
|
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
|
||||||
(
|
|
||||||
"iframe",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock("Adresse de la page")),
|
|
||||||
(
|
|
||||||
"height",
|
|
||||||
wagtail.blocks.CharBlock("Hauteur (en pixels)"),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
null=True,
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofpage",
|
|
||||||
name="body_fr",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
("heading", wagtail.blocks.CharBlock(form_classname="full title")),
|
|
||||||
("paragraph", wagtail.blocks.RichTextBlock()),
|
|
||||||
("image", wagtail.images.blocks.ImageChooserBlock()),
|
|
||||||
(
|
|
||||||
"iframe",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
("url", wagtail.blocks.URLBlock("Adresse de la page")),
|
|
||||||
(
|
|
||||||
"height",
|
|
||||||
wagtail.blocks.CharBlock("Hauteur (en pixels)"),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
null=True,
|
|
||||||
use_json_field=True,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,11 +1,12 @@
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from wagtail import blocks
|
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
|
||||||
from wagtail.admin.panels import FieldPanel
|
|
||||||
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
||||||
from wagtail.fields import RichTextField, StreamField
|
from wagtail.core import blocks
|
||||||
|
from wagtail.core.fields import RichTextField, StreamField
|
||||||
|
from wagtail.core.models import Page
|
||||||
from wagtail.images.blocks import ImageChooserBlock
|
from wagtail.images.blocks import ImageChooserBlock
|
||||||
from wagtail.models import Page
|
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||||
|
|
||||||
|
|
||||||
# Page pouvant afficher des actualités
|
# Page pouvant afficher des actualités
|
||||||
|
@ -68,11 +69,10 @@ class COFPage(Page):
|
||||||
("paragraph", blocks.RichTextBlock()),
|
("paragraph", blocks.RichTextBlock()),
|
||||||
("image", ImageChooserBlock()),
|
("image", ImageChooserBlock()),
|
||||||
("iframe", IFrameBlock()),
|
("iframe", IFrameBlock()),
|
||||||
],
|
]
|
||||||
use_json_field=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
content_panels = Page.content_panels + [FieldPanel("body")]
|
content_panels = Page.content_panels + [StreamFieldPanel("body")]
|
||||||
|
|
||||||
subpage_types = ["COFDirectoryPage", "COFPage"]
|
subpage_types = ["COFDirectoryPage", "COFPage"]
|
||||||
parent_page_types = ["COFPage", "COFRootPage"]
|
parent_page_types = ["COFPage", "COFRootPage"]
|
||||||
|
@ -127,7 +127,7 @@ class COFActuPage(RoutablePageMixin, Page):
|
||||||
all_day = models.BooleanField("Toute la journée", default=False, blank=True)
|
all_day = models.BooleanField("Toute la journée", default=False, blank=True)
|
||||||
|
|
||||||
content_panels = Page.content_panels + [
|
content_panels = Page.content_panels + [
|
||||||
FieldPanel("image"),
|
ImageChooserPanel("image"),
|
||||||
FieldPanel("chapo"),
|
FieldPanel("chapo"),
|
||||||
FieldPanel("body", classname="full"),
|
FieldPanel("body", classname="full"),
|
||||||
FieldPanel("is_event"),
|
FieldPanel("is_event"),
|
||||||
|
@ -204,7 +204,6 @@ class COFDirectoryEntryPage(Page):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
blank=True,
|
blank=True,
|
||||||
use_json_field=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
image = models.ForeignKey(
|
image = models.ForeignKey(
|
||||||
|
@ -217,9 +216,9 @@ class COFDirectoryEntryPage(Page):
|
||||||
)
|
)
|
||||||
|
|
||||||
content_panels = Page.content_panels + [
|
content_panels = Page.content_panels + [
|
||||||
FieldPanel("image"),
|
ImageChooserPanel("image"),
|
||||||
FieldPanel("body", classname="full"),
|
FieldPanel("body", classname="full"),
|
||||||
FieldPanel("links"),
|
StreamFieldPanel("links"),
|
||||||
]
|
]
|
||||||
|
|
||||||
subpage_types = []
|
subpage_types = []
|
||||||
|
|
|
@ -22,10 +22,10 @@
|
||||||
|
|
||||||
<section class="actulist">
|
<section class="actulist">
|
||||||
{% if actus.has_previous %}
|
{% if actus.has_previous %}
|
||||||
<a class="block prev-actus" href="?page={{ actus.previous_page_number }}{% for key,value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Actualités plus récentes" %}</a>
|
<a class="block prev-actus" href="?page={{ actus.previous_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">{% trans "Actualités plus récentes" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if actus.has_next %}
|
{% if actus.has_next %}
|
||||||
<a class="block next-actus" href="?page={{ actus.next_page_number }}{% for key,value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Actualités plus anciennes" %}</a>
|
<a class="block next-actus" href="?page={{ actus.next_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">{% trans "Actualités plus anciennes" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for actu in page.actus %}
|
{% for actu in page.actus %}
|
||||||
|
@ -44,10 +44,10 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if actus.has_previous %}
|
{% if actus.has_previous %}
|
||||||
<a class="block prev-actus" href="?page={{ actus.previous_page_number }}{% for key,value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Actualités plus récentes" %}</a>
|
<a class="block prev-actus" href="?page={{ actus.previous_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">{% trans "Actualités plus récentes" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if actus.has_next %}
|
{% if actus.has_next %}
|
||||||
<a class="block next-actus" href="?page={{ actus.next_page_number }}{% for key,value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Actualités plus anciennes" %}</a>
|
<a class="block next-actus" href="?page={{ actus.next_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">{% trans "Actualités plus anciennes" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
|
||||||
|
|
||||||
from gestioncof.cms.forms import CaptchaForm
|
from gestioncof.cms.forms import CaptchaForm
|
||||||
|
|
||||||
|
|
||||||
@xframe_options_sameorigin
|
|
||||||
def raw_calendar_view(request, year, month):
|
def raw_calendar_view(request, year, month):
|
||||||
return render(request, "cofcms/calendar_raw.html", {"month": month, "year": year})
|
return render(request, "cofcms/calendar_raw.html", {"month": month, "year": year})
|
||||||
|
|
||||||
|
|
||||||
@xframe_options_sameorigin
|
|
||||||
def sympa_captcha_form_view(request):
|
def sympa_captcha_form_view(request):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = CaptchaForm(request.POST)
|
form = CaptchaForm(request.POST)
|
||||||
|
|
|
@ -9,7 +9,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def cof_required(view_func):
|
def cof_required(view_func):
|
||||||
"""Décorateur qui vérifie que l'utilisateur est connecté et membre COF.
|
"""Décorateur qui vérifie que l'utilisateur est connecté et membre du COF.
|
||||||
|
|
||||||
- Si l'utilisteur n'est pas connecté, il est redirigé vers la page de
|
- Si l'utilisteur n'est pas connecté, il est redirigé vers la page de
|
||||||
connexion
|
connexion
|
||||||
|
@ -33,31 +33,6 @@ def cof_required(view_func):
|
||||||
return login_required(_wrapped_view)
|
return login_required(_wrapped_view)
|
||||||
|
|
||||||
|
|
||||||
def kfet_required(view_func):
|
|
||||||
"""Décorateur qui vérifie que l'utilisateur est connecté et membre K-Fêt.
|
|
||||||
|
|
||||||
- Si l'utilisteur n'est pas connecté, il est redirigé vers la page de
|
|
||||||
connexion
|
|
||||||
- Si l'utilisateur est connecté mais pas membre K-Fêt, il obtient une
|
|
||||||
page d'erreur lui demandant de s'inscrire à la K-Fêt
|
|
||||||
"""
|
|
||||||
|
|
||||||
def is_kfet(user):
|
|
||||||
try:
|
|
||||||
return user.profile.is_cof or user.profile.is_kfet
|
|
||||||
except AttributeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@wraps(view_func)
|
|
||||||
def _wrapped_view(request, *args, **kwargs):
|
|
||||||
if is_kfet(request.user):
|
|
||||||
return view_func(request, *args, **kwargs)
|
|
||||||
|
|
||||||
return render(request, "kfet-denied.html", status=403)
|
|
||||||
|
|
||||||
return login_required(_wrapped_view)
|
|
||||||
|
|
||||||
|
|
||||||
def buro_required(view_func):
|
def buro_required(view_func):
|
||||||
"""Décorateur qui vérifie que l'utilisateur est connecté et membre du burô.
|
"""Décorateur qui vérifie que l'utilisateur est connecté et membre du burô.
|
||||||
|
|
||||||
|
@ -83,33 +58,6 @@ def buro_required(view_func):
|
||||||
return login_required(_wrapped_view)
|
return login_required(_wrapped_view)
|
||||||
|
|
||||||
|
|
||||||
def chef_required(view_func):
|
|
||||||
"""Décorateur qui vérifie que l'utilisateur est connecté et membre du burô ou chef K-fêt.
|
|
||||||
|
|
||||||
- Si l'utilisateur n'est pas connecté, il est redirigé vers la page de
|
|
||||||
connexion
|
|
||||||
- Si l'utilisateur est connecté mais pas membre du burô ou chef, il obtient une
|
|
||||||
page d'erreur 403 Forbidden
|
|
||||||
"""
|
|
||||||
|
|
||||||
def is_chef(user):
|
|
||||||
try:
|
|
||||||
return user.profile.is_chef or user.profile.is_buro
|
|
||||||
except AttributeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@wraps(view_func)
|
|
||||||
def _wrapped_view(request, *args, **kwargs):
|
|
||||||
if is_chef(request.user):
|
|
||||||
return view_func(request, *args, **kwargs)
|
|
||||||
|
|
||||||
return render(
|
|
||||||
request, "buro-denied.html", status=403
|
|
||||||
) # TODO: reservé au burô ou au chef
|
|
||||||
|
|
||||||
return login_required(_wrapped_view)
|
|
||||||
|
|
||||||
|
|
||||||
class CofRequiredMixin(PermissionRequiredMixin):
|
class CofRequiredMixin(PermissionRequiredMixin):
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
if not self.request.user.is_authenticated:
|
if not self.request.user.is_authenticated:
|
||||||
|
@ -131,18 +79,3 @@ class BuroRequiredMixin(PermissionRequiredMixin):
|
||||||
"L'utilisateur %s n'a pas de profil !", self.request.user.username
|
"L'utilisateur %s n'a pas de profil !", self.request.user.username
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ChefRequiredMixin(PermissionRequiredMixin):
|
|
||||||
def has_permission(self):
|
|
||||||
if not self.request.user.is_authenticated:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
return (
|
|
||||||
self.request.user.profile.is_chef or self.request.user.profile.is_buro
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
logger.error(
|
|
||||||
"L'utilisateur %s n'a pas de profil !", self.request.user.username
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
|
@ -284,7 +284,6 @@ class RegistrationProfileForm(forms.ModelForm):
|
||||||
"occupation",
|
"occupation",
|
||||||
"departement",
|
"departement",
|
||||||
"is_cof",
|
"is_cof",
|
||||||
"is_kfet",
|
|
||||||
"type_cotiz",
|
"type_cotiz",
|
||||||
"mailing_cof",
|
"mailing_cof",
|
||||||
"mailing_bda",
|
"mailing_bda",
|
||||||
|
@ -294,19 +293,6 @@ class RegistrationProfileForm(forms.ModelForm):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RegistrationKFProfileForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = CofProfile
|
|
||||||
fields = [
|
|
||||||
"login_clipper",
|
|
||||||
"phone",
|
|
||||||
"occupation",
|
|
||||||
"departement",
|
|
||||||
"is_kfet",
|
|
||||||
"comments",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
("no", "Non"),
|
("no", "Non"),
|
||||||
("wait", "Oui mais attente paiement"),
|
("wait", "Oui mais attente paiement"),
|
||||||
|
@ -458,20 +444,3 @@ class GestioncofConfigForm(ConfigForm):
|
||||||
max_length=2048,
|
max_length=2048,
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ----
|
|
||||||
# Formulaire pour les adhésions self-service
|
|
||||||
# ----
|
|
||||||
|
|
||||||
|
|
||||||
class SubscribForm(forms.Form):
|
|
||||||
accept_ri = forms.BooleanField(
|
|
||||||
label="Lu et accepte le réglement intérieur de l'AEENS (COF).", required=True
|
|
||||||
)
|
|
||||||
accept_status = forms.BooleanField(
|
|
||||||
label="Lu et accepte les status de l'AEENS (COF).", required=True
|
|
||||||
)
|
|
||||||
accept_charte_kf = forms.BooleanField(
|
|
||||||
label="Lu et accepte la charte de la K-Fêt.", required=True
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Generated by Django 2.2.28 on 2023-05-22 09:01
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
("gestioncof", "0018_petitscours_email"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="date_adhesion",
|
|
||||||
field=models.DateField(
|
|
||||||
blank=True, null=True, verbose_name="Date d'adhésion"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,13 +0,0 @@
|
||||||
# Generated by Django 3.2.25 on 2024-12-18 21:40
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("gestioncof", "0019_auto_20220630_1241"),
|
|
||||||
("gestioncof", "0019_cofprofile_date_adhesion"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = []
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2024-12-24 10:09
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("gestioncof", "0020_merge_20241218_2240"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="is_kfet",
|
|
||||||
field=models.BooleanField(default=False, verbose_name="Membre K-Fêt"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="is_cof",
|
|
||||||
field=models.BooleanField(default=False, verbose_name="Membre COF"),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,32 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2024-12-30 14:19
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("gestioncof", "0021_cofprofile_is_kfet_alter_cofprofile_is_cof"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="date_adhesion",
|
|
||||||
field=models.DateField(
|
|
||||||
blank=True, null=True, verbose_name="Date d'adhésion COF"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
old_name="date_adhesion",
|
|
||||||
new_name="date_adhesion_cof",
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="date_adhesion_kfet",
|
|
||||||
field=models.DateField(
|
|
||||||
blank=True, null=True, verbose_name="Date d'adhésion K-Fêt"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-01-21 10:06
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("gestioncof", "0022_rename_cofprofile_date_adhesion_and_more"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="cofprofile",
|
|
||||||
name="is_chef",
|
|
||||||
field=models.BooleanField(default=False, verbose_name="Chef K-Fêt"),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,13 +1,7 @@
|
||||||
from datetime import date
|
|
||||||
from smtplib import SMTPRecipientsRefused
|
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.signals import post_delete, post_save
|
from django.db.models.signals import post_delete, post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.template import loader
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from bda.models import Spectacle
|
from bda.models import Spectacle
|
||||||
|
@ -55,12 +49,7 @@ class CofProfile(models.Model):
|
||||||
login_clipper = models.CharField(
|
login_clipper = models.CharField(
|
||||||
"Login clipper", max_length=32, blank=True, unique=True, null=True
|
"Login clipper", max_length=32, blank=True, unique=True, null=True
|
||||||
)
|
)
|
||||||
is_cof = models.BooleanField("Membre COF", default=False)
|
is_cof = models.BooleanField("Membre du COF", default=False)
|
||||||
is_kfet = models.BooleanField("Membre K-Fêt", default=False)
|
|
||||||
date_adhesion_cof = models.DateField("Date d'adhésion COF", blank=True, null=True)
|
|
||||||
date_adhesion_kfet = models.DateField(
|
|
||||||
"Date d'adhésion K-Fêt", blank=True, null=True
|
|
||||||
)
|
|
||||||
phone = models.CharField("Téléphone", max_length=20, blank=True)
|
phone = models.CharField("Téléphone", max_length=20, blank=True)
|
||||||
occupation = models.CharField(
|
occupation = models.CharField(
|
||||||
_("Occupation"),
|
_("Occupation"),
|
||||||
|
@ -85,7 +74,6 @@ class CofProfile(models.Model):
|
||||||
)
|
)
|
||||||
comments = models.TextField("Commentaires visibles par l'utilisateur", blank=True)
|
comments = models.TextField("Commentaires visibles par l'utilisateur", blank=True)
|
||||||
is_buro = models.BooleanField("Membre du Burô", default=False)
|
is_buro = models.BooleanField("Membre du Burô", default=False)
|
||||||
is_chef = models.BooleanField("Chef K-Fêt", default=False)
|
|
||||||
petits_cours_accept = models.BooleanField(
|
petits_cours_accept = models.BooleanField(
|
||||||
"Recevoir des petits cours", default=False
|
"Recevoir des petits cours", default=False
|
||||||
)
|
)
|
||||||
|
@ -100,46 +88,6 @@ class CofProfile(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
|
|
||||||
def make_adh_cof(self, request, was_cof):
|
|
||||||
if self.is_cof and not was_cof:
|
|
||||||
notify_new_member(request, self.user)
|
|
||||||
self.date_adhesion_cof = date.today()
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def make_adh_kfet(self, request, was_kfet):
|
|
||||||
if self.is_kfet and not was_kfet:
|
|
||||||
notify_new_member(request, self.user)
|
|
||||||
self.date_adhesion_kfet = date.today()
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
|
|
||||||
def notify_new_member(request, member: User):
|
|
||||||
if not member.email:
|
|
||||||
messages.warning(
|
|
||||||
request,
|
|
||||||
"GestioCOF n'a pas d'adresse mail pour {}, ".format(member)
|
|
||||||
+ "aucun email de bienvenue n'a été envoyé",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Try to send a welcome email and report SMTP errors
|
|
||||||
try:
|
|
||||||
send_mail(
|
|
||||||
"Bienvenue au COF",
|
|
||||||
loader.render_to_string(
|
|
||||||
"gestioncof/mails/welcome.txt", context={"member": member}
|
|
||||||
),
|
|
||||||
"cof@ens.fr",
|
|
||||||
[member.email],
|
|
||||||
)
|
|
||||||
except SMTPRecipientsRefused:
|
|
||||||
messages.error(
|
|
||||||
request,
|
|
||||||
"Error lors de l'envoi de l'email de bienvenue à {} ({})".format(
|
|
||||||
member, member.email
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
@receiver(post_save, sender=User)
|
||||||
def create_user_profile(sender, instance, created, **kwargs):
|
def create_user_profile(sender, instance, created, **kwargs):
|
||||||
|
|
|
@ -701,9 +701,6 @@ header a:active {
|
||||||
.user-is-cof {
|
.user-is-cof {
|
||||||
color : #ADE297;
|
color : #ADE297;
|
||||||
}
|
}
|
||||||
.user-is-kfet {
|
|
||||||
color : #FF8C00;
|
|
||||||
}
|
|
||||||
.user-is-not-cof {
|
.user-is-not-cof {
|
||||||
color: #EE8585;
|
color: #EE8585;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "base_title.html" %}
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
{% block realcontent %}
|
{% block realcontent %}
|
||||||
<h2>Section réservée aux membres COF -- merci de vous inscrire au COF ou de passer au COF/nous envoyer un mail si vous êtes déjà membre :)</h2>
|
<h2>Section réservée aux membres du COF -- merci de vous inscrire au COF ou de passer au COF/nous envoyer un mail si vous êtes déjà membre :)</h2>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -10,12 +10,10 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</a>
|
</a>
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<span class="hidden-xxs"> | </span>
|
<span class="hidden-xxs"> | </span>
|
||||||
<span><a href="{% url "cof-logout" %}">Se déconnecter <span class="glyphicon glyphicon-log-out"></span></a></span>
|
<span><a href="{% url "cof-logout" %}">Se déconnecter <span class="glyphicon glyphicon-log-out"></span></a></span>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<h2 class="member-status">{%if user.is_authenticated %}{% if user.first_name %}{{ user.first_name }}{% else %}<tt>{{ user.username }}</tt>{% endif %}, {% endif %}{% if user.profile.is_cof %}<tt class="user-is-cof">au COF{% elif user.profile.is_kfet %}<tt class="user-is-kfet">membre K-Fêt{% else %}<tt class="user-is-not-cof">non-COF{% endif %}</tt></h2>
|
<h2 class="member-status">{% if user.first_name %}{{ user.first_name }}{% else %}<tt>{{ user.username }}</tt>{% endif %}, {% if user.profile.is_cof %}<tt class="user-is-cof">au COF{% else %}<tt class="user-is-not-cof">non-COF{% endif %}</tt></h2>
|
||||||
</div><!-- /.container -->
|
</div><!-- /.container -->
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
{% extends "base_title.html" %}
|
|
||||||
{% load bootstrap %}
|
|
||||||
|
|
||||||
{% block page_size %}col-sm-8{%endblock%}
|
|
||||||
|
|
||||||
{% block realcontent %}
|
|
||||||
<h2>Pass K-Fêt</h2>
|
|
||||||
|
|
||||||
<center style="font-size: 20pt;">
|
|
||||||
<p>Profil de {{ user.first_name }} {{ user.last_name }}</p>
|
|
||||||
|
|
||||||
{% if user.profile.is_cof %}
|
|
||||||
<p>Membre COF depuis le {{ user.profile.date_adhesion_cof }}</p>
|
|
||||||
{% else %}
|
|
||||||
<p>Membre K-Fêt depuis le {{ user.profile.date_adhesion_kfet }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</center>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -8,7 +8,7 @@
|
||||||
<div class="container hidden-xs espace"></div>
|
<div class="container hidden-xs espace"></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="home-menu row">
|
<div class="home-menu row">
|
||||||
<div class="{% if user.profile.is_buro or user.profile.is_chef %}col-sm-6 {% else %}col-sm-8 col-sm-offset-2 col-xs-12 {%endif%}normal-user-hm">
|
<div class="{% if user.profile.is_buro %}col-sm-6 {% else %}col-sm-8 col-sm-offset-2 col-xs-12 {%endif%}normal-user-hm">
|
||||||
{% if open_surveys %}
|
{% if open_surveys %}
|
||||||
<h3 class="block-title">Sondages en cours<span class="pull-right glyphicon glyphicon-stats"></span></h3>
|
<h3 class="block-title">Sondages en cours<span class="pull-right glyphicon glyphicon-stats"></span></h3>
|
||||||
<div class="hm-block">
|
<div class="hm-block">
|
||||||
|
@ -50,10 +50,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
{# TODO: Since Django 1.9, we can store result with "as", allowing proper value management (if None) #}
|
{# TODO: Since Django 1.9, we can store result with "as", allowing proper value management (if None) #}
|
||||||
<li><a href="{% slugurl "k-fet" %}">Page d'accueil</a></li>
|
<li><a href="{% slugurl "k-fet" %}">Page d'accueil</a></li>
|
||||||
{% if user.profile.is_cof or user.profile.is_kfet %}
|
<li><a href="https://cof.ens.fr/gestion/k-fet/le-calendrier/">Calendrier</a></li>
|
||||||
<li><a href="{% url "profile.carte" %}">Carte K-Fêt</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li><a href="https://cof.ens.fr/k-fet/le-calendrier/">Calendrier</a></li>
|
|
||||||
{% if perms.kfet.is_team %}
|
{% if perms.kfet.is_team %}
|
||||||
<li><a href="{% url 'kfet.kpsul' %}">K-Psul</a></li>
|
<li><a href="{% url 'kfet.kpsul' %}">K-Psul</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -71,23 +68,9 @@
|
||||||
{% if not user.profile.login_clipper %}
|
{% if not user.profile.login_clipper %}
|
||||||
<li><a href="{% url "password_change" %}">Changer mon mot de passe</a></li>
|
<li><a href="{% url "password_change" %}">Changer mon mot de passe</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not user.profile.is_cof and not user.profile.is_kfet %}
|
|
||||||
<li><a href="{% url "self.kf_registration" %}">Adhérer à la K-Fêt</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if user.profile.is_chef and not user.profile.is_buro %}
|
|
||||||
<div class="col-sm-6 buro-user-hm">
|
|
||||||
<h3 class="block-title">Administration<span class="pull-right glyphicon glyphicon-cog"></span></h3>
|
|
||||||
<div class="hm-block">
|
|
||||||
<ul>
|
|
||||||
<h4>Général</h4>
|
|
||||||
<li><a href="{% url "registration" %}">Inscription d'un nouveau membre</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.profile.is_buro %}
|
{% if user.profile.is_buro %}
|
||||||
<div class="col-sm-6 buro-user-hm">
|
<div class="col-sm-6 buro-user-hm">
|
||||||
<h3 class="block-title">Administration<span class="pull-right glyphicon glyphicon-cog"></span></h3>
|
<h3 class="block-title">Administration<span class="pull-right glyphicon glyphicon-cog"></span></h3>
|
||||||
|
@ -132,7 +115,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url "utile_cof" %}">Liens utiles du COF</a></li>
|
<li><a href="{% url "utile_cof" %}">Liens utiles du COF</a></li>
|
||||||
<li><a href="{% url "utile_bda" %}">Liens utiles BdA</a></li>
|
<li><a href="{% url "utile_bda" %}">Liens utiles BdA</a></li>
|
||||||
<li><a href="{% url "reset_comptes" %}">Remise à zéro adhérent⋅e⋅s COF</a></li>
|
<li><a href="{% url "reset_comptes" %}">Remise à zéro adhérents COF</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
Bonjour {{ member.first_name }} et bienvenue au COF !
|
Bonjour {{ member.first_name }} et bienvenue au COF !
|
||||||
|
|
||||||
Tu trouveras plein de trucs cool sur le site du COF : https://cof.ens.fr/ et notre compte instagram : https://www.instagram.com/cof_ulm
|
Tu trouveras plein de trucs cool sur le site du COF : https://cof.ens.fr/ et notre page Facebook : https://www.facebook.com/cof.ulm
|
||||||
Et n'oublie pas d'aller découvrir GestioCOF, la plateforme de gestion du COF !
|
Et n'oublie pas d'aller découvrir GestioCOF, la plateforme de gestion du COF !
|
||||||
Si tu as des questions, tu peux nous envoyer un mail à cof@ens.fr (on aime le spam), ou passer nous voir au Burô près de la Courô les lundi, mardi, jeudi et vendredi de 12h à 14h et du lundi au jeudi de 18h30 à 19h30.
|
Si tu as des questions, tu peux nous envoyer un mail à cof@ens.fr (on aime le spam), ou passer nous voir au Burô près de la Courô du lundi au vendredi de 12h à 14h et de 18h à 20h.
|
||||||
|
|
||||||
Retrouvez tout les évènements organisés par le COF et ses clubs ici : https://calendrier.dgnum.eu/.
|
Retrouvez les évènements de rentrée pour les conscrit.e.s et les vieux/vieilles organisés par le COF et ses clubs ici : https://cof.ens.fr/planningrentree.
|
||||||
|
|
||||||
Amicalement,
|
Amicalement,
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
{% load bootstrap %}
|
|
||||||
|
|
||||||
{% if login_clipper %}
|
|
||||||
<h3>Inscription associée au compte clipper <tt>{{ login_clipper }}</tt></h3>
|
|
||||||
{% elif member %}
|
|
||||||
<h3>Inscription du compte GestioCOF existant <tt>{{ member.username }}</tt></h3>
|
|
||||||
{% else %}
|
|
||||||
<h3>Inscription d'un nouveau compte (extérieur ?)</h3>
|
|
||||||
{% endif %}
|
|
||||||
<form role="form" id="profile" method="post" action="{% url 'registration' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<table>
|
|
||||||
{{ user_form | bootstrap }}
|
|
||||||
{{ profile_form | bootstrap }}
|
|
||||||
</table>
|
|
||||||
<hr />
|
|
||||||
{% if login_clipper or member %}
|
|
||||||
<input type="hidden" name="user_exists" value="1" />
|
|
||||||
{% endif %}
|
|
||||||
<input type="submit" class="btn btn-primary pull-right" value="Enregistrer l'inscription" />
|
|
||||||
</form>
|
|
|
@ -1,8 +0,0 @@
|
||||||
{% extends "base_title.html" %}
|
|
||||||
|
|
||||||
{% block realcontent %}
|
|
||||||
<h2>Inscription d'un nouveau membre</h2>
|
|
||||||
<div id="form-placeholder">
|
|
||||||
{% include "gestioncof/registration_kf_form.html" %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,28 +0,0 @@
|
||||||
{% extends "base_title.html" %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block page_size %}col-sm-8{% endblock %}
|
|
||||||
|
|
||||||
{% load bootstrap %}
|
|
||||||
|
|
||||||
{% block realcontent %}
|
|
||||||
|
|
||||||
{% if member %}
|
|
||||||
<h3>Inscription K-Fêt du compte GestioCOF existant <tt>{{ member.username }}</tt></h3>
|
|
||||||
{% else %}
|
|
||||||
<h3>Inscription K-Fêt d'un nouveau compte (extérieur ?)</h3>
|
|
||||||
{% endif %}
|
|
||||||
<form role="form" id="profile" method="post" action="{% url 'self.kf_registration' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<table>
|
|
||||||
{{ user_form | bootstrap }}
|
|
||||||
{{ profile_form | bootstrap }}
|
|
||||||
{{ agreement_form | bootstrap }}
|
|
||||||
</table>
|
|
||||||
<hr />
|
|
||||||
{% if login_clipper or member %}
|
|
||||||
<input type="hidden" name="user_exists" value="1" />
|
|
||||||
{% endif %}
|
|
||||||
<input type="submit" class="btn btn-primary pull-right" value="Adhérer" />
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
|
@ -1,5 +0,0 @@
|
||||||
{% extends "base_title.html" %}
|
|
||||||
|
|
||||||
{% block realcontent %}
|
|
||||||
<h2>Section réservée aux membres K-Fêt -- merci de vous inscrire au COF ou de passer au COF/nous envoyer un mail si vous êtes déjà membre :)</h2>
|
|
||||||
{% endblock %}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import date, timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
@ -486,7 +486,6 @@ class ExportMembersViewTests(CSVResponseMixin, ViewTestCaseMixin, TestCase):
|
||||||
u1.last_name = "last"
|
u1.last_name = "last"
|
||||||
u1.email = "user@mail.net"
|
u1.email = "user@mail.net"
|
||||||
u1.save()
|
u1.save()
|
||||||
u1.profile.date_adhesion_cof = date(2023, 5, 22)
|
|
||||||
u1.profile.phone = "0123456789"
|
u1.profile.phone = "0123456789"
|
||||||
u1.profile.departement = "Dept"
|
u1.profile.departement = "Dept"
|
||||||
u1.profile.save()
|
u1.profile.save()
|
||||||
|
@ -508,9 +507,8 @@ class ExportMembersViewTests(CSVResponseMixin, ViewTestCaseMixin, TestCase):
|
||||||
"1A",
|
"1A",
|
||||||
"Dept",
|
"Dept",
|
||||||
"normalien",
|
"normalien",
|
||||||
"2023-05-22",
|
|
||||||
],
|
],
|
||||||
[str(u2.pk), "staff", "", "", "", "", "1A", "", "normalien", "None"],
|
[str(u2.pk), "staff", "", "", "", "", "1A", "", "normalien"],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,6 @@ from django.views.generic.base import TemplateView
|
||||||
from django_cas_ng import views as django_cas_views
|
from django_cas_ng import views as django_cas_views
|
||||||
|
|
||||||
from gestioncof import csv_views, views
|
from gestioncof import csv_views, views
|
||||||
from shared.views import SympaListView
|
|
||||||
|
|
||||||
sympa_patterns = [
|
|
||||||
path(
|
|
||||||
f"{mailing}/",
|
|
||||||
SympaListView.as_view(filters={f"profile__mailing_{mailing}": True}),
|
|
||||||
name=f"sympa.{mailing}",
|
|
||||||
)
|
|
||||||
for mailing in ["bda", "bda_revente", "cof", "unernestaparis"]
|
|
||||||
]
|
|
||||||
|
|
||||||
export_patterns = [
|
export_patterns = [
|
||||||
path("members", views.export_members, name="export.members"),
|
path("members", views.export_members, name="export.members"),
|
||||||
|
@ -80,7 +70,6 @@ registration_patterns = [
|
||||||
views.RegistrationAutocompleteView.as_view(),
|
views.RegistrationAutocompleteView.as_view(),
|
||||||
name="cof.registration.autocomplete",
|
name="cof.registration.autocomplete",
|
||||||
),
|
),
|
||||||
path("self_kf", views.self_kf_registration, name="self.kf_registration"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -100,7 +89,6 @@ urlpatterns = [
|
||||||
name="cof-user-autocomplete",
|
name="cof-user-autocomplete",
|
||||||
),
|
),
|
||||||
path("config", views.ConfigUpdate.as_view(), name="config.edit"),
|
path("config", views.ConfigUpdate.as_view(), name="config.edit"),
|
||||||
path("carte", views.carte_kf, name="profile.carte"),
|
|
||||||
# -----
|
# -----
|
||||||
# Authentification
|
# Authentification
|
||||||
# -----
|
# -----
|
||||||
|
@ -174,8 +162,4 @@ urlpatterns = [
|
||||||
# Clubs
|
# Clubs
|
||||||
# -----
|
# -----
|
||||||
path("clubs/", include(clubs_patterns)),
|
path("clubs/", include(clubs_patterns)),
|
||||||
# -----
|
|
||||||
# Sympa export
|
|
||||||
# -----
|
|
||||||
path("sympa/", include(sympa_patterns)),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import csv
|
import csv
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from smtplib import SMTPRecipientsRefused
|
||||||
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
|
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
@ -13,10 +14,11 @@ from django.contrib.auth.views import (
|
||||||
redirect_to_login,
|
redirect_to_login,
|
||||||
)
|
)
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.db.models import Q
|
from django.core.mail import send_mail
|
||||||
from django.http import Http404, HttpResponse, HttpResponseForbidden
|
from django.http import Http404, HttpResponse, HttpResponseForbidden
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.template import loader
|
||||||
|
from django.urls import reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import FormView, TemplateView
|
from django.views.generic import FormView, TemplateView
|
||||||
|
@ -25,14 +27,7 @@ from icalendar import Calendar, Event as Vevent
|
||||||
|
|
||||||
from bda.models import Spectacle, Tirage
|
from bda.models import Spectacle, Tirage
|
||||||
from gestioncof.autocomplete import cof_autocomplete
|
from gestioncof.autocomplete import cof_autocomplete
|
||||||
from gestioncof.decorators import (
|
from gestioncof.decorators import BuroRequiredMixin, buro_required, cof_required
|
||||||
BuroRequiredMixin,
|
|
||||||
ChefRequiredMixin,
|
|
||||||
buro_required,
|
|
||||||
chef_required,
|
|
||||||
cof_required,
|
|
||||||
kfet_required,
|
|
||||||
)
|
|
||||||
from gestioncof.forms import (
|
from gestioncof.forms import (
|
||||||
CalendarForm,
|
CalendarForm,
|
||||||
ClubsForm,
|
ClubsForm,
|
||||||
|
@ -43,11 +38,9 @@ from gestioncof.forms import (
|
||||||
GestioncofConfigForm,
|
GestioncofConfigForm,
|
||||||
PhoneForm,
|
PhoneForm,
|
||||||
ProfileForm,
|
ProfileForm,
|
||||||
RegistrationKFProfileForm,
|
|
||||||
RegistrationPassUserForm,
|
RegistrationPassUserForm,
|
||||||
RegistrationProfileForm,
|
RegistrationProfileForm,
|
||||||
RegistrationUserForm,
|
RegistrationUserForm,
|
||||||
SubscribForm,
|
|
||||||
SurveyForm,
|
SurveyForm,
|
||||||
SurveyStatusFilterForm,
|
SurveyStatusFilterForm,
|
||||||
UserForm,
|
UserForm,
|
||||||
|
@ -93,9 +86,6 @@ class ResetComptes(BuroRequiredMixin, TemplateView):
|
||||||
nb_adherents = CofProfile.objects.filter(is_cof=True).count()
|
nb_adherents = CofProfile.objects.filter(is_cof=True).count()
|
||||||
CofProfile.objects.update(
|
CofProfile.objects.update(
|
||||||
is_cof=False,
|
is_cof=False,
|
||||||
is_kfet=False,
|
|
||||||
date_adhesion_cof=None,
|
|
||||||
date_adhesion_kfet=None,
|
|
||||||
mailing_cof=False,
|
mailing_cof=False,
|
||||||
mailing_bda=False,
|
mailing_bda=False,
|
||||||
mailing_bda_revente=False,
|
mailing_bda_revente=False,
|
||||||
|
@ -430,20 +420,13 @@ def profile(request):
|
||||||
return render(request, "gestioncof/profile.html", context)
|
return render(request, "gestioncof/profile.html", context)
|
||||||
|
|
||||||
|
|
||||||
@kfet_required
|
|
||||||
def carte_kf(request):
|
|
||||||
user = request.user
|
|
||||||
return render(request, "gestioncof/carte_kf.html", {"user": user})
|
|
||||||
|
|
||||||
|
|
||||||
def registration_set_ro_fields(user_form, profile_form):
|
def registration_set_ro_fields(user_form, profile_form):
|
||||||
user_form.fields["username"].widget.attrs["readonly"] = True
|
user_form.fields["username"].widget.attrs["readonly"] = True
|
||||||
profile_form.fields["login_clipper"].widget.attrs["readonly"] = True
|
profile_form.fields["login_clipper"].widget.attrs["readonly"] = True
|
||||||
|
|
||||||
|
|
||||||
@chef_required
|
@buro_required
|
||||||
def registration_form2(request, login_clipper=None, username=None, fullname=None):
|
def registration_form2(request, login_clipper=None, username=None, fullname=None):
|
||||||
is_buro = request.user.profile.is_buro
|
|
||||||
events = Event.objects.filter(old=False).all()
|
events = Event.objects.filter(old=False).all()
|
||||||
member = None
|
member = None
|
||||||
if login_clipper:
|
if login_clipper:
|
||||||
|
@ -465,27 +448,21 @@ def registration_form2(request, login_clipper=None, username=None, fullname=None
|
||||||
user_form.fields["first_name"].initial = bits[0]
|
user_form.fields["first_name"].initial = bits[0]
|
||||||
if len(bits) > 1:
|
if len(bits) > 1:
|
||||||
user_form.fields["last_name"].initial = " ".join(bits[1:])
|
user_form.fields["last_name"].initial = " ".join(bits[1:])
|
||||||
if is_buro:
|
|
||||||
# profile
|
# profile
|
||||||
profile_form = RegistrationProfileForm(
|
profile_form = RegistrationProfileForm(
|
||||||
initial={"login_clipper": login_clipper}
|
initial={"login_clipper": login_clipper}
|
||||||
)
|
)
|
||||||
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
# events & clubs
|
# events & clubs
|
||||||
event_formset = EventFormset(events=events, prefix="events")
|
event_formset = EventFormset(events=events, prefix="events")
|
||||||
clubs_form = ClubsForm()
|
clubs_form = ClubsForm()
|
||||||
else:
|
|
||||||
profile_form = RegistrationKFProfileForm(
|
|
||||||
initial={"login_clipper": login_clipper}
|
|
||||||
)
|
|
||||||
|
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
|
||||||
if username:
|
if username:
|
||||||
member = get_object_or_404(User, username=username)
|
member = get_object_or_404(User, username=username)
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
||||||
# already existing, prefill
|
# already existing, prefill
|
||||||
user_form = RegistrationUserForm(instance=member)
|
user_form = RegistrationUserForm(instance=member)
|
||||||
if is_buro:
|
|
||||||
profile_form = RegistrationProfileForm(instance=profile)
|
profile_form = RegistrationProfileForm(instance=profile)
|
||||||
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
# events
|
# events
|
||||||
current_registrations = []
|
current_registrations = []
|
||||||
for event in events:
|
for event in events:
|
||||||
|
@ -496,25 +473,16 @@ def registration_form2(request, login_clipper=None, username=None, fullname=None
|
||||||
except EventRegistration.DoesNotExist:
|
except EventRegistration.DoesNotExist:
|
||||||
current_registrations.append(None)
|
current_registrations.append(None)
|
||||||
event_formset = EventFormset(
|
event_formset = EventFormset(
|
||||||
events=events,
|
events=events, prefix="events", current_registrations=current_registrations
|
||||||
prefix="events",
|
|
||||||
current_registrations=current_registrations,
|
|
||||||
)
|
)
|
||||||
# Clubs
|
# Clubs
|
||||||
clubs_form = ClubsForm(initial={"clubs": member.clubs.all()})
|
clubs_form = ClubsForm(initial={"clubs": member.clubs.all()})
|
||||||
else:
|
|
||||||
profile_form = RegistrationKFProfileForm(instance=profile)
|
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
|
||||||
elif not login_clipper:
|
elif not login_clipper:
|
||||||
# new user
|
# new user
|
||||||
user_form = RegistrationPassUserForm()
|
user_form = RegistrationPassUserForm()
|
||||||
if is_buro:
|
|
||||||
profile_form = RegistrationProfileForm()
|
profile_form = RegistrationProfileForm()
|
||||||
event_formset = EventFormset(events=events, prefix="events")
|
event_formset = EventFormset(events=events, prefix="events")
|
||||||
clubs_form = ClubsForm()
|
clubs_form = ClubsForm()
|
||||||
else:
|
|
||||||
profile_form = RegistrationKFProfileForm()
|
|
||||||
if is_buro:
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"gestioncof/registration_form.html",
|
"gestioncof/registration_form.html",
|
||||||
|
@ -527,22 +495,38 @@ def registration_form2(request, login_clipper=None, username=None, fullname=None
|
||||||
"clubs_form": clubs_form,
|
"clubs_form": clubs_form,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
return render(
|
|
||||||
|
def notify_new_member(request, member: User):
|
||||||
|
if not member.email:
|
||||||
|
messages.warning(
|
||||||
request,
|
request,
|
||||||
"gestioncof/registration_kf_form.html",
|
"GestioCOF n'a pas d'adresse mail pour {}, ".format(member)
|
||||||
{
|
+ "aucun email de bienvenue n'a été envoyé",
|
||||||
"member": member,
|
)
|
||||||
"login_clipper": login_clipper,
|
return
|
||||||
"user_form": user_form,
|
|
||||||
"profile_form": profile_form,
|
# Try to send a welcome email and report SMTP errors
|
||||||
},
|
try:
|
||||||
|
send_mail(
|
||||||
|
"Bienvenue au COF",
|
||||||
|
loader.render_to_string(
|
||||||
|
"gestioncof/mails/welcome.txt", context={"member": member}
|
||||||
|
),
|
||||||
|
"cof@ens.fr",
|
||||||
|
[member.email],
|
||||||
|
)
|
||||||
|
except SMTPRecipientsRefused:
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
"Error lors de l'envoi de l'email de bienvenue à {} ({})".format(
|
||||||
|
member, member.email
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@chef_required
|
@buro_required
|
||||||
def registration(request):
|
def registration(request):
|
||||||
is_buro = request.user.profile.is_buro
|
|
||||||
if request.POST:
|
if request.POST:
|
||||||
request_dict = request.POST.copy()
|
request_dict = request.POST.copy()
|
||||||
member = None
|
member = None
|
||||||
|
@ -556,15 +540,10 @@ def registration(request):
|
||||||
user_form = RegistrationPassUserForm(request_dict)
|
user_form = RegistrationPassUserForm(request_dict)
|
||||||
else:
|
else:
|
||||||
user_form = RegistrationUserForm(request_dict)
|
user_form = RegistrationUserForm(request_dict)
|
||||||
if is_buro:
|
|
||||||
profile_form = RegistrationProfileForm(request_dict)
|
profile_form = RegistrationProfileForm(request_dict)
|
||||||
clubs_form = ClubsForm(request_dict)
|
clubs_form = ClubsForm(request_dict)
|
||||||
events = Event.objects.filter(old=False).all()
|
events = Event.objects.filter(old=False).all()
|
||||||
event_formset = EventFormset(
|
event_formset = EventFormset(events=events, data=request_dict, prefix="events")
|
||||||
events=events, data=request_dict, prefix="events"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
profile_form = RegistrationKFProfileForm(request_dict)
|
|
||||||
if "user_exists" in request_dict and request_dict["user_exists"]:
|
if "user_exists" in request_dict and request_dict["user_exists"]:
|
||||||
username = request_dict["username"]
|
username = request_dict["username"]
|
||||||
try:
|
try:
|
||||||
|
@ -585,25 +564,17 @@ def registration(request):
|
||||||
member = user_form.save()
|
member = user_form.save()
|
||||||
profile, _ = CofProfile.objects.get_or_create(user=member)
|
profile, _ = CofProfile.objects.get_or_create(user=member)
|
||||||
was_cof = profile.is_cof
|
was_cof = profile.is_cof
|
||||||
was_kfet = profile.is_kfet
|
|
||||||
# Maintenant on remplit le formulaire de profil
|
# Maintenant on remplit le formulaire de profil
|
||||||
if is_buro:
|
|
||||||
profile_form = RegistrationProfileForm(request_dict, instance=profile)
|
profile_form = RegistrationProfileForm(request_dict, instance=profile)
|
||||||
else:
|
if (
|
||||||
profile_form = RegistrationKFProfileForm(request_dict, instance=profile)
|
profile_form.is_valid()
|
||||||
if profile_form.is_valid() and (
|
and event_formset.is_valid()
|
||||||
not is_buro or (event_formset.is_valid() and clubs_form.is_valid())
|
and clubs_form.is_valid()
|
||||||
):
|
):
|
||||||
# Enregistrement du profil
|
# Enregistrement du profil
|
||||||
profile = profile_form.save()
|
profile = profile_form.save()
|
||||||
if is_buro:
|
if profile.is_cof and not was_cof:
|
||||||
if profile.is_cof:
|
notify_new_member(request, member)
|
||||||
profile.make_adh_cof(request, was_cof)
|
|
||||||
|
|
||||||
if profile.is_kfet:
|
|
||||||
profile.make_adh_kfet(request, was_kfet)
|
|
||||||
|
|
||||||
if is_buro:
|
|
||||||
# Enregistrement des inscriptions aux événements
|
# Enregistrement des inscriptions aux événements
|
||||||
for form in event_formset:
|
for form in event_formset:
|
||||||
if "status" not in form.cleaned_data:
|
if "status" not in form.cleaned_data:
|
||||||
|
@ -624,13 +595,9 @@ def registration(request):
|
||||||
) = EventRegistration.objects.get_or_create(
|
) = EventRegistration.objects.get_or_create(
|
||||||
user=member, event=form.event
|
user=member, event=form.event
|
||||||
)
|
)
|
||||||
update_event_form_comments(
|
update_event_form_comments(form.event, form, current_registration)
|
||||||
form.event, form, current_registration
|
|
||||||
)
|
|
||||||
current_registration.options.set(all_choices)
|
current_registration.options.set(all_choices)
|
||||||
current_registration.paid = (
|
current_registration.paid = form.cleaned_data["status"] == "paid"
|
||||||
form.cleaned_data["status"] == "paid"
|
|
||||||
)
|
|
||||||
current_registration.save()
|
current_registration.save()
|
||||||
# if form.event.title == "Mega 15" and created_reg:
|
# if form.event.title == "Mega 15" and created_reg:
|
||||||
# field = EventCommentField.objects.get(
|
# field = EventCommentField.objects.get(
|
||||||
|
@ -662,12 +629,11 @@ def registration(request):
|
||||||
member.get_full_name(), member.email
|
member.get_full_name(), member.email
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if is_buro and profile.is_cof:
|
if profile.is_cof:
|
||||||
msg += "\nIl est désormais membre du COF n°{:d} !".format(
|
msg += "\nIl est désormais membre du COF n°{:d} !".format(
|
||||||
member.profile.id
|
member.profile.id
|
||||||
)
|
)
|
||||||
messages.success(request, msg, extra_tags="safe")
|
messages.success(request, msg, extra_tags="safe")
|
||||||
if is_buro:
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"gestioncof/registration_post.html",
|
"gestioncof/registration_post.html",
|
||||||
|
@ -680,73 +646,10 @@ def registration(request):
|
||||||
"clubs_form": clubs_form,
|
"clubs_form": clubs_form,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"gestioncof/registration_kf_post.html",
|
|
||||||
{
|
|
||||||
"user_form": user_form,
|
|
||||||
"profile_form": profile_form,
|
|
||||||
"member": member,
|
|
||||||
"login_clipper": login_clipper,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return render(request, "registration.html")
|
return render(request, "registration.html")
|
||||||
|
|
||||||
|
|
||||||
# TODO: without login
|
|
||||||
@login_required
|
|
||||||
def self_kf_registration(request):
|
|
||||||
member = request.user
|
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
|
||||||
|
|
||||||
if profile.is_kfet or profile.is_cof:
|
|
||||||
msg = "Vous êtes déjà adhérent du COF !"
|
|
||||||
messages.success(request, msg)
|
|
||||||
response = HttpResponse(content="", status=303)
|
|
||||||
response["Location"] = reverse("profile")
|
|
||||||
return response
|
|
||||||
|
|
||||||
was_kfet = profile.is_kfet
|
|
||||||
if request.POST:
|
|
||||||
user_form = RegistrationUserForm(request.POST, instance=member)
|
|
||||||
profile_form = PhoneForm(request.POST, instance=profile)
|
|
||||||
agreement_form = SubscribForm(request.POST)
|
|
||||||
if (
|
|
||||||
user_form.is_valid()
|
|
||||||
and profile_form.is_valid()
|
|
||||||
and agreement_form.is_valid()
|
|
||||||
):
|
|
||||||
member = user_form.save()
|
|
||||||
profile = profile_form.save()
|
|
||||||
profile.is_kfet = True
|
|
||||||
profile.save()
|
|
||||||
profile.make_adh_kfet(request, was_kfet)
|
|
||||||
|
|
||||||
msg = "Votre adhésion a été enregistrée avec succès."
|
|
||||||
messages.success(request, msg, extra_tags="safe")
|
|
||||||
response = HttpResponse(content="", status=303)
|
|
||||||
response["Location"] = reverse("profile")
|
|
||||||
return response
|
|
||||||
else:
|
|
||||||
user_form = RegistrationUserForm(instance=member)
|
|
||||||
profile_form = PhoneForm(instance=profile)
|
|
||||||
agreement_form = SubscribForm()
|
|
||||||
|
|
||||||
user_form.fields["username"].widget.attrs["readonly"] = True
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"gestioncof/self_registration.html",
|
|
||||||
{
|
|
||||||
"user_form": user_form,
|
|
||||||
"profile_form": profile_form,
|
|
||||||
"agreement_form": agreement_form,
|
|
||||||
"member": member,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Clubs
|
# Clubs
|
||||||
# -----
|
# -----
|
||||||
|
@ -800,7 +703,7 @@ def export_members(request):
|
||||||
response["Content-Disposition"] = "attachment; filename=membres_cof.csv"
|
response["Content-Disposition"] = "attachment; filename=membres_cof.csv"
|
||||||
|
|
||||||
writer = csv.writer(response)
|
writer = csv.writer(response)
|
||||||
for profile in CofProfile.objects.filter(Q(is_cof=True) | Q(is_kfet=True)).all():
|
for profile in CofProfile.objects.filter(is_cof=True).all():
|
||||||
user = profile.user
|
user = profile.user
|
||||||
bits = [
|
bits = [
|
||||||
user.id,
|
user.id,
|
||||||
|
@ -811,10 +714,7 @@ def export_members(request):
|
||||||
profile.phone,
|
profile.phone,
|
||||||
profile.occupation,
|
profile.occupation,
|
||||||
profile.departement,
|
profile.departement,
|
||||||
"COF" if profile.is_cof else "K-Fêt",
|
|
||||||
profile.type_cotiz,
|
profile.type_cotiz,
|
||||||
profile.date_adhesion_cof,
|
|
||||||
profile.date_adhesion_kfet,
|
|
||||||
]
|
]
|
||||||
writer.writerow([str(bit) for bit in bits])
|
writer.writerow([str(bit) for bit in bits])
|
||||||
|
|
||||||
|
@ -1070,6 +970,6 @@ class UserAutocompleteView(BuroRequiredMixin, Select2QuerySetView):
|
||||||
search_fields = ("username", "first_name", "last_name")
|
search_fields = ("username", "first_name", "last_name")
|
||||||
|
|
||||||
|
|
||||||
class RegistrationAutocompleteView(ChefRequiredMixin, AutocompleteView):
|
class RegistrationAutocompleteView(BuroRequiredMixin, AutocompleteView):
|
||||||
template_name = "gestioncof/search_results.html"
|
template_name = "gestioncof/search_results.html"
|
||||||
search_composer = cof_autocomplete
|
search_composer = cof_autocomplete
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from wagtail import hooks
|
from wagtail.core import hooks
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("insert_editor_css")
|
@hooks.register("insert_editor_css")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from wagtail.models import Page, Site
|
from wagtail.core.models import Page, Site
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import wagtail.blocks
|
import wagtail.core.blocks
|
||||||
import wagtail.fields
|
import wagtail.core.fields
|
||||||
import wagtail.snippets.blocks
|
import wagtail.snippets.blocks
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
@ -41,20 +41,20 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"content",
|
"content",
|
||||||
wagtail.fields.StreamField(
|
wagtail.core.fields.StreamField(
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
"rich",
|
"rich",
|
||||||
wagtail.blocks.RichTextBlock(label="Éditeur"),
|
wagtail.core.blocks.RichTextBlock(label="Éditeur"),
|
||||||
),
|
),
|
||||||
("carte", kfet.cms.models.MenuBlock()),
|
("carte", kfet.cms.models.MenuBlock()),
|
||||||
(
|
(
|
||||||
"group_team",
|
"group_team",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
"show_only",
|
"show_only",
|
||||||
wagtail.blocks.IntegerBlock(
|
wagtail.core.blocks.IntegerBlock(
|
||||||
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.", # noqa
|
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.", # noqa
|
||||||
required=False,
|
required=False,
|
||||||
label="Montrer seulement",
|
label="Montrer seulement",
|
||||||
|
@ -62,7 +62,7 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"members",
|
"members",
|
||||||
wagtail.blocks.ListBlock(
|
wagtail.core.blocks.ListBlock(
|
||||||
wagtail.snippets.blocks.SnippetChooserBlock( # noqa
|
wagtail.snippets.blocks.SnippetChooserBlock( # noqa
|
||||||
kfet.cms.models.MemberTeam
|
kfet.cms.models.MemberTeam
|
||||||
),
|
),
|
||||||
|
@ -75,22 +75,22 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"group",
|
"group",
|
||||||
wagtail.blocks.StreamBlock(
|
wagtail.core.blocks.StreamBlock(
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
"rich",
|
"rich",
|
||||||
wagtail.blocks.RichTextBlock(
|
wagtail.core.blocks.RichTextBlock(
|
||||||
label="Éditeur"
|
label="Éditeur"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("carte", kfet.cms.models.MenuBlock()),
|
("carte", kfet.cms.models.MenuBlock()),
|
||||||
(
|
(
|
||||||
"group_team",
|
"group_team",
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.core.blocks.StructBlock(
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
"show_only",
|
"show_only",
|
||||||
wagtail.blocks.IntegerBlock( # noqa
|
wagtail.core.blocks.IntegerBlock( # noqa
|
||||||
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.", # noqa
|
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.", # noqa
|
||||||
required=False,
|
required=False,
|
||||||
label="Montrer seulement",
|
label="Montrer seulement",
|
||||||
|
@ -98,7 +98,7 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"members",
|
"members",
|
||||||
wagtail.blocks.ListBlock(
|
wagtail.core.blocks.ListBlock(
|
||||||
wagtail.snippets.blocks.SnippetChooserBlock( # noqa
|
wagtail.snippets.blocks.SnippetChooserBlock( # noqa
|
||||||
kfet.cms.models.MemberTeam # noqa
|
kfet.cms.models.MemberTeam # noqa
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
# Generated by Django 4.2.17 on 2024-12-19 12:27
|
|
||||||
|
|
||||||
import wagtail.blocks
|
|
||||||
import wagtail.fields
|
|
||||||
import wagtail.snippets.blocks
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
import kfet.cms.models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfetcms", "0002_alter_kfetpage_colcount"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="kfetpage",
|
|
||||||
name="content",
|
|
||||||
field=wagtail.fields.StreamField(
|
|
||||||
[
|
|
||||||
("rich", wagtail.blocks.RichTextBlock(label="Éditeur")),
|
|
||||||
("carte", kfet.cms.models.MenuBlock()),
|
|
||||||
(
|
|
||||||
"group_team",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"show_only",
|
|
||||||
wagtail.blocks.IntegerBlock(
|
|
||||||
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
|
|
||||||
label="Montrer seulement",
|
|
||||||
required=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"members",
|
|
||||||
wagtail.blocks.ListBlock(
|
|
||||||
wagtail.snippets.blocks.SnippetChooserBlock(
|
|
||||||
kfet.cms.models.MemberTeam
|
|
||||||
),
|
|
||||||
form_classname="team-group",
|
|
||||||
label="K-Fêt-eux-ses",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"group",
|
|
||||||
wagtail.blocks.StreamBlock(
|
|
||||||
[
|
|
||||||
("rich", wagtail.blocks.RichTextBlock(label="Éditeur")),
|
|
||||||
("carte", kfet.cms.models.MenuBlock()),
|
|
||||||
(
|
|
||||||
"group_team",
|
|
||||||
wagtail.blocks.StructBlock(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"show_only",
|
|
||||||
wagtail.blocks.IntegerBlock(
|
|
||||||
help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
|
|
||||||
label="Montrer seulement",
|
|
||||||
required=False,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"members",
|
|
||||||
wagtail.blocks.ListBlock(
|
|
||||||
wagtail.snippets.blocks.SnippetChooserBlock(
|
|
||||||
kfet.cms.models.MemberTeam
|
|
||||||
),
|
|
||||||
form_classname="team-group",
|
|
||||||
label="K-Fêt-eux-ses",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
label="Contenu groupé",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
use_json_field=True,
|
|
||||||
verbose_name="Contenu",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,9 +1,15 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from wagtail import blocks
|
from wagtail.admin.edit_handlers import (
|
||||||
from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
|
FieldPanel,
|
||||||
from wagtail.fields import StreamField
|
FieldRowPanel,
|
||||||
from wagtail.models import Page
|
MultiFieldPanel,
|
||||||
|
StreamFieldPanel,
|
||||||
|
)
|
||||||
|
from wagtail.core import blocks
|
||||||
|
from wagtail.core.fields import StreamField
|
||||||
|
from wagtail.core.models import Page
|
||||||
|
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||||
from wagtail.snippets.blocks import SnippetChooserBlock
|
from wagtail.snippets.blocks import SnippetChooserBlock
|
||||||
from wagtail.snippets.models import register_snippet
|
from wagtail.snippets.models import register_snippet
|
||||||
|
|
||||||
|
@ -37,7 +43,7 @@ class MemberTeam(models.Model):
|
||||||
FieldPanel("first_name"),
|
FieldPanel("first_name"),
|
||||||
FieldPanel("last_name"),
|
FieldPanel("last_name"),
|
||||||
FieldPanel("nick_name"),
|
FieldPanel("nick_name"),
|
||||||
FieldPanel("photo"),
|
ImageChooserPanel("photo"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -91,9 +97,7 @@ class KFetStreamBlock(ChoicesStreamBlock):
|
||||||
|
|
||||||
|
|
||||||
class KFetPage(Page):
|
class KFetPage(Page):
|
||||||
content = StreamField(
|
content = StreamField(KFetStreamBlock, verbose_name=_("Contenu"))
|
||||||
KFetStreamBlock, verbose_name=_("Contenu"), use_json_field=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Layout fields
|
# Layout fields
|
||||||
|
|
||||||
|
@ -131,7 +135,7 @@ class KFetPage(Page):
|
||||||
|
|
||||||
# Panels
|
# Panels
|
||||||
|
|
||||||
content_panels = Page.content_panels + [FieldPanel("content")]
|
content_panels = Page.content_panels + [StreamFieldPanel("content")]
|
||||||
|
|
||||||
layout_panel = [
|
layout_panel = [
|
||||||
FieldPanel("no_header"),
|
FieldPanel("no_header"),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import djconfig
|
import djconfig
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ class KFetConfig(object):
|
||||||
# Note it should be called only once across requests, if you use
|
# Note it should be called only once across requests, if you use
|
||||||
# kfet_config instance below.
|
# kfet_config instance below.
|
||||||
if not self._conf_init:
|
if not self._conf_init:
|
||||||
sync_to_async(djconfig.reload_maybe)()
|
djconfig.reload_maybe()
|
||||||
self._conf_init = True
|
self._conf_init = True
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
|
|
|
@ -45,47 +45,6 @@ class DateTimeWidget(forms.DateTimeInput):
|
||||||
js = ("kfet/vendor/bootstrap/bootstrap-datetimepicker.min.js",)
|
js = ("kfet/vendor/bootstrap/bootstrap-datetimepicker.min.js",)
|
||||||
|
|
||||||
|
|
||||||
class ContactForm(forms.Form):
|
|
||||||
from_email = forms.EmailField(
|
|
||||||
label="Adresse mail",
|
|
||||||
help_text="Si aucune adresse mail n'est renseignée, la soumission sera anonyme.",
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
subject = forms.CharField(label="Objet", required=True)
|
|
||||||
message = forms.CharField(widget=forms.Textarea, required=True)
|
|
||||||
|
|
||||||
def clean_from_email(self):
|
|
||||||
return self.cleaned_data["from_email"] or "Anonyme <k-fet@ens.psl.eu>"
|
|
||||||
|
|
||||||
|
|
||||||
class DemandeSoireeForm(forms.Form):
|
|
||||||
HORAIRE_CHOICES = map(lambda s: (s, s), ("22h", "23h", "00h", "01h", "02h", "03h"))
|
|
||||||
SERVICE_CHOICES = (
|
|
||||||
("K-Fêt", "K-Fêt standard (L'équipe K-Fêt fait le service normal au bar)"),
|
|
||||||
("Kalô", "Type Kalô (Vous ramenez vos propres boissons et servez vous-mêmes)"),
|
|
||||||
)
|
|
||||||
|
|
||||||
nom = forms.CharField()
|
|
||||||
from_email = forms.EmailField(label="Adresse mail de contact")
|
|
||||||
|
|
||||||
contact_boum = forms.BooleanField(label="Contacter le Boum", required=False)
|
|
||||||
contact_pls = forms.BooleanField(label="Contacter PLS", required=False)
|
|
||||||
|
|
||||||
theme = forms.CharField(label="Thème de la soirée")
|
|
||||||
horaire_fin = forms.ChoiceField(label="Horaire de fin", choices=HORAIRE_CHOICES)
|
|
||||||
service = forms.ChoiceField(label="Mode de service", choices=SERVICE_CHOICES)
|
|
||||||
date = forms.CharField(label="Date souhaitée")
|
|
||||||
|
|
||||||
respo1 = forms.CharField(label="Nom de la personne respo n°1")
|
|
||||||
respo2 = forms.CharField(label="Nom de la personne respo n°2")
|
|
||||||
respo3 = forms.CharField(label="Nom de la personne respo n°3")
|
|
||||||
respo4 = forms.CharField(label="Nom de la personne respo n°4")
|
|
||||||
|
|
||||||
remarques = forms.CharField(
|
|
||||||
label="Remarques supplémentaires", widget=forms.Textarea
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Account forms
|
# Account forms
|
||||||
# -----
|
# -----
|
||||||
|
@ -93,7 +52,7 @@ class DemandeSoireeForm(forms.Form):
|
||||||
|
|
||||||
def default_promo():
|
def default_promo():
|
||||||
now = date.today()
|
now = date.today()
|
||||||
return now.month <= 7 and now.year - 1 or now.year
|
return now.month <= 8 and now.year - 1 or now.year
|
||||||
|
|
||||||
|
|
||||||
def get_promo_choices():
|
def get_promo_choices():
|
||||||
|
@ -118,11 +77,7 @@ class AccountForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
fields = ["trigramme", "promo", "nickname"]
|
fields = ["trigramme", "promo", "nickname"]
|
||||||
widgets = {
|
widgets = {"trigramme": forms.TextInput(attrs={"autocomplete": "off"})}
|
||||||
"trigramme": forms.TextInput(
|
|
||||||
attrs={"autocomplete": "off", "class": "trigramme_field"}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AccountBalanceForm(forms.ModelForm):
|
class AccountBalanceForm(forms.ModelForm):
|
||||||
|
@ -195,13 +150,7 @@ class CofForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CofProfile
|
model = CofProfile
|
||||||
fields = ["login_clipper", "is_cof", "is_kfet", "departement"]
|
fields = ["login_clipper", "is_cof", "departement"]
|
||||||
|
|
||||||
|
|
||||||
class CofKFForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = CofProfile
|
|
||||||
fields = ["is_kfet"]
|
|
||||||
|
|
||||||
|
|
||||||
class UserForm(forms.ModelForm):
|
class UserForm(forms.ModelForm):
|
||||||
|
@ -356,7 +305,6 @@ class ArticleForm(forms.ModelForm):
|
||||||
fields = [
|
fields = [
|
||||||
"name",
|
"name",
|
||||||
"is_sold",
|
"is_sold",
|
||||||
"no_exte",
|
|
||||||
"hidden",
|
"hidden",
|
||||||
"price",
|
"price",
|
||||||
"stock",
|
"stock",
|
||||||
|
@ -371,7 +319,6 @@ class ArticleRestrictForm(ArticleForm):
|
||||||
fields = [
|
fields = [
|
||||||
"name",
|
"name",
|
||||||
"is_sold",
|
"is_sold",
|
||||||
"no_exte",
|
|
||||||
"hidden",
|
"hidden",
|
||||||
"price",
|
"price",
|
||||||
"category",
|
"category",
|
||||||
|
@ -416,11 +363,7 @@ class KPsulAccountForm(forms.ModelForm):
|
||||||
fields = ["trigramme"]
|
fields = ["trigramme"]
|
||||||
widgets = {
|
widgets = {
|
||||||
"trigramme": forms.TextInput(
|
"trigramme": forms.TextInput(
|
||||||
attrs={
|
attrs={"autocomplete": "off", "spellcheck": "false"}
|
||||||
"autocomplete": "off",
|
|
||||||
"spellcheck": "false",
|
|
||||||
"class": "trigramme_field",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +609,7 @@ class OrderArticleForm(forms.Form):
|
||||||
self.v_moy = kwargs["initial"]["v_moy"]
|
self.v_moy = kwargs["initial"]["v_moy"]
|
||||||
self.v_et = kwargs["initial"]["v_et"]
|
self.v_et = kwargs["initial"]["v_et"]
|
||||||
self.v_prev = kwargs["initial"]["v_prev"]
|
self.v_prev = kwargs["initial"]["v_prev"]
|
||||||
self.c_rec_1w = kwargs["initial"]["c_rec_1w"]
|
self.c_rec = kwargs["initial"]["c_rec"]
|
||||||
self.is_sold = kwargs["initial"]["is_sold"]
|
self.is_sold = kwargs["initial"]["is_sold"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Gestion en ligne de commande des mails de rappel K-Fet.
|
Gestion en ligne de commande des mails de rappel K-Fet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import smtplib
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
@ -11,14 +10,6 @@ from django.utils import timezone
|
||||||
from kfet.models import AccountNegative
|
from kfet.models import AccountNegative
|
||||||
|
|
||||||
|
|
||||||
def send_mail(neg: AccountNegative, stdout) -> None:
|
|
||||||
try:
|
|
||||||
neg.send_rappel()
|
|
||||||
stdout.write(f"Mail de rappel pour {neg.account} envoyé avec succès.")
|
|
||||||
except smtplib.SMTPException:
|
|
||||||
stdout.write(f"Erreur lors de l'envoi du mail de rappel pour {neg.account}.")
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = (
|
help = (
|
||||||
"Envoie un mail de rappel aux personnes en négatif.\n"
|
"Envoie un mail de rappel aux personnes en négatif.\n"
|
||||||
|
@ -35,9 +26,8 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
# On n'envoie des mails qu'aux comptes qui ont un négatif vraiment actif
|
# On n'envoie des mails qu'aux comptes qui ont un négatif vraiment actif
|
||||||
# et dont la balance est négative
|
# et dont la balance est négative
|
||||||
# On ignore les comptes gelés qui signinfient une adresse mail plus valide
|
|
||||||
account_negatives = AccountNegative.objects.filter(
|
account_negatives = AccountNegative.objects.filter(
|
||||||
account__balance__lt=0, account__is_frozen=False
|
account__balance__lt=0
|
||||||
).exclude(end__lte=now)
|
).exclude(end__lte=now)
|
||||||
|
|
||||||
accounts_first_mail = account_negatives.filter(
|
accounts_first_mail = account_negatives.filter(
|
||||||
|
@ -48,10 +38,12 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
|
|
||||||
for neg in accounts_first_mail:
|
for neg in accounts_first_mail:
|
||||||
send_mail(neg, self.stdout)
|
neg.send_rappel()
|
||||||
|
self.stdout.write(f"Mail de rappel pour {neg.account} envoyé avec succès.")
|
||||||
|
|
||||||
for neg in accounts_periodic_mail:
|
for neg in accounts_periodic_mail:
|
||||||
send_mail(neg, self.stdout)
|
neg.send_rappel()
|
||||||
|
self.stdout.write("Mail de rappel pour {neg.account} envoyé avec succès.")
|
||||||
|
|
||||||
if not (accounts_first_mail.exists() or accounts_periodic_mail.exists()):
|
if not (accounts_first_mail.exists() or accounts_periodic_mail.exists()):
|
||||||
self.stdout.write("Aucun mail à envoyer.")
|
self.stdout.write("Aucun mail à envoyer.")
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import unicode_literals
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
@ -16,9 +17,7 @@ class Migration(migrations.Migration):
|
||||||
name="at",
|
name="at",
|
||||||
field=models.DateTimeField(
|
field=models.DateTimeField(
|
||||||
auto_now_add=True,
|
auto_now_add=True,
|
||||||
default=datetime.datetime(
|
default=datetime.datetime(2016, 8, 29, 18, 35, 3, 419033, tzinfo=utc),
|
||||||
2016, 8, 29, 18, 35, 3, 419033, tzinfo=datetime.timezone.utc
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-01-06 16:35
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfet", "0080_accountnegative_last_rappel"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="article",
|
|
||||||
name="no_exte",
|
|
||||||
field=models.BooleanField(
|
|
||||||
default=False, verbose_name="Réservé au adhérents"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,34 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-01-18 10:01
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfet", "0081_article_no_exte"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="operation",
|
|
||||||
options={
|
|
||||||
"permissions": (
|
|
||||||
("perform_deposit", "Effectuer une charge"),
|
|
||||||
(
|
|
||||||
"perform_negative_operations",
|
|
||||||
"Enregistrer des commandes en négatif",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"perform_liq_reserved",
|
|
||||||
"Effectuer une opération réservé aux adhérents sur LIQ",
|
|
||||||
),
|
|
||||||
("cancel_old_operations", "Annuler des commandes non récentes"),
|
|
||||||
(
|
|
||||||
"perform_commented_operations",
|
|
||||||
"Enregistrer des commandes avec commentaires",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-03-18 10:25
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfet", "0082_alter_operation_options"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="operationgroup",
|
|
||||||
name="is_kfet",
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-05-03 21:26
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfet", "0083_operationgroup_is_kfet"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="account",
|
|
||||||
options={
|
|
||||||
"permissions": (
|
|
||||||
("is_team", "Is part of the team"),
|
|
||||||
("change_adh", "Gérer les adhésions K-Fêt"),
|
|
||||||
("manage_perms", "Gérer les permissions K-Fêt"),
|
|
||||||
("manage_addcosts", "Gérer les majorations"),
|
|
||||||
("edit_balance_account", "Modifier la balance d'un compte"),
|
|
||||||
(
|
|
||||||
"change_account_password",
|
|
||||||
"Modifier le mot de passe d'une personne de l'équipe",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"special_add_account",
|
|
||||||
"Créer un compte avec une balance initiale",
|
|
||||||
),
|
|
||||||
("can_force_close", "Fermer manuellement la K-Fêt"),
|
|
||||||
("see_config", "Voir la configuration K-Fêt"),
|
|
||||||
("change_config", "Modifier la configuration K-Fêt"),
|
|
||||||
("access_old_history", "Peut accéder à l'historique plus ancien"),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,41 +0,0 @@
|
||||||
# Generated by Django 4.2.16 on 2025-05-12 10:37
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("kfet", "0084_alter_account_options"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="operation",
|
|
||||||
options={
|
|
||||||
"permissions": (
|
|
||||||
("perform_deposit", "Effectuer une charge"),
|
|
||||||
(
|
|
||||||
"perform_negative_operations",
|
|
||||||
"Enregistrer des commandes en négatif",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"perform_liq_reserved",
|
|
||||||
"Effectuer une opération réservé aux adhérent⋅e⋅s sur LIQ",
|
|
||||||
),
|
|
||||||
("cancel_old_operations", "Annuler des commandes non récentes"),
|
|
||||||
(
|
|
||||||
"perform_commented_operations",
|
|
||||||
"Enregistrer des commandes avec commentaires",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="article",
|
|
||||||
name="no_exte",
|
|
||||||
field=models.BooleanField(
|
|
||||||
default=False, verbose_name="Réservé au adhérent⋅e⋅s"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -2,8 +2,7 @@ import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import Site
|
from django.core.mail import send_mail
|
||||||
from django.core.mail import EmailMessage
|
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
|
@ -73,7 +72,6 @@ class Account(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
permissions = (
|
||||||
("is_team", "Is part of the team"),
|
("is_team", "Is part of the team"),
|
||||||
("change_adh", "Gérer les adhésions K-Fêt"),
|
|
||||||
("manage_perms", "Gérer les permissions K-Fêt"),
|
("manage_perms", "Gérer les permissions K-Fêt"),
|
||||||
("manage_addcosts", "Gérer les majorations"),
|
("manage_addcosts", "Gérer les majorations"),
|
||||||
("edit_balance_account", "Modifier la balance d'un compte"),
|
("edit_balance_account", "Modifier la balance d'un compte"),
|
||||||
|
@ -120,10 +118,6 @@ class Account(models.Model):
|
||||||
def is_cof(self):
|
def is_cof(self):
|
||||||
return self.cofprofile.is_cof
|
return self.cofprofile.is_cof
|
||||||
|
|
||||||
@property
|
|
||||||
def is_kfet(self):
|
|
||||||
return self.cofprofile.is_kfet
|
|
||||||
|
|
||||||
# Propriétés supplémentaires
|
# Propriétés supplémentaires
|
||||||
@property
|
@property
|
||||||
def balance_ukf(self):
|
def balance_ukf(self):
|
||||||
|
@ -275,36 +269,6 @@ class Account(models.Model):
|
||||||
def __init__(self, trigramme):
|
def __init__(self, trigramme):
|
||||||
self.trigramme = trigramme
|
self.trigramme = trigramme
|
||||||
|
|
||||||
def send_creation_email(self):
|
|
||||||
"""
|
|
||||||
Envoie un mail à la création du trigramme.
|
|
||||||
"""
|
|
||||||
mail_data = settings.MAIL_DATA["kfet"]
|
|
||||||
|
|
||||||
email = EmailMessage(
|
|
||||||
subject="Création d'un trigramme",
|
|
||||||
body=loader.render_to_string(
|
|
||||||
"kfet/mails/creation_trigramme.txt",
|
|
||||||
context={
|
|
||||||
"account": self,
|
|
||||||
"site": Site.objects.get_current(),
|
|
||||||
"url_read": reverse("kfet.account.read", args=(self.trigramme,)),
|
|
||||||
"url_update": reverse(
|
|
||||||
"kfet.account.update", args=(self.trigramme,)
|
|
||||||
),
|
|
||||||
"url_delete": reverse(
|
|
||||||
"kfet.account.delete", args=(self.trigramme,)
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
from_email=mail_data["FROM"],
|
|
||||||
to=[self.email],
|
|
||||||
reply_to=[mail_data["REPLYTO"]],
|
|
||||||
)
|
|
||||||
|
|
||||||
# On envoie le mail
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
|
|
||||||
def get_deleted_account():
|
def get_deleted_account():
|
||||||
return Account.objects.get(trigramme=KFET_DELETED_TRIGRAMME)
|
return Account.objects.get(trigramme=KFET_DELETED_TRIGRAMME)
|
||||||
|
@ -334,11 +298,10 @@ class AccountNegative(models.Model):
|
||||||
"""
|
"""
|
||||||
Envoie un mail de rappel signalant que la personne est en négatif.
|
Envoie un mail de rappel signalant que la personne est en négatif.
|
||||||
"""
|
"""
|
||||||
mail_data = settings.MAIL_DATA["kfet"]
|
# On envoie le mail
|
||||||
|
send_mail(
|
||||||
email = EmailMessage(
|
"Compte K-Psul négatif",
|
||||||
subject="Compte K-Psul négatif",
|
loader.render_to_string(
|
||||||
body=loader.render_to_string(
|
|
||||||
"kfet/mails/rappel.txt",
|
"kfet/mails/rappel.txt",
|
||||||
context={
|
context={
|
||||||
"account": self.account,
|
"account": self.account,
|
||||||
|
@ -346,17 +309,13 @@ class AccountNegative(models.Model):
|
||||||
"start_date": self.start,
|
"start_date": self.start,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
from_email=mail_data["FROM"],
|
settings.MAIL_DATA["rappel_negatif"]["FROM"],
|
||||||
to=[self.account.email],
|
[self.account.email],
|
||||||
reply_to=[mail_data["REPLYTO"]],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# On envoie le mail
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
# On enregistre le fait que l'envoi a bien eu lieu
|
# On enregistre le fait que l'envoi a bien eu lieu
|
||||||
self.last_rappel = timezone.now()
|
self.last_rappel = timezone.now()
|
||||||
self.save()
|
self.save()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class CheckoutQuerySet(models.QuerySet):
|
class CheckoutQuerySet(models.QuerySet):
|
||||||
|
@ -499,7 +458,6 @@ class ArticleCategory(models.Model):
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
name = models.CharField("nom", max_length=45)
|
name = models.CharField("nom", max_length=45)
|
||||||
is_sold = models.BooleanField("en vente", default=True)
|
is_sold = models.BooleanField("en vente", default=True)
|
||||||
no_exte = models.BooleanField("Réservé au adhérent⋅e⋅s", default=False)
|
|
||||||
hidden = models.BooleanField(
|
hidden = models.BooleanField(
|
||||||
"caché",
|
"caché",
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -688,7 +646,6 @@ class OperationGroup(models.Model):
|
||||||
at = models.DateTimeField(default=timezone.now)
|
at = models.DateTimeField(default=timezone.now)
|
||||||
amount = models.DecimalField(max_digits=6, decimal_places=2, default=0)
|
amount = models.DecimalField(max_digits=6, decimal_places=2, default=0)
|
||||||
is_cof = models.BooleanField(default=False)
|
is_cof = models.BooleanField(default=False)
|
||||||
is_kfet = models.BooleanField(default=False)
|
|
||||||
# Optional
|
# Optional
|
||||||
comment = models.CharField(max_length=255, blank=True, default="")
|
comment = models.CharField(max_length=255, blank=True, default="")
|
||||||
valid_by = models.ForeignKey(
|
valid_by = models.ForeignKey(
|
||||||
|
@ -761,10 +718,6 @@ class Operation(models.Model):
|
||||||
permissions = (
|
permissions = (
|
||||||
("perform_deposit", "Effectuer une charge"),
|
("perform_deposit", "Effectuer une charge"),
|
||||||
("perform_negative_operations", "Enregistrer des commandes en négatif"),
|
("perform_negative_operations", "Enregistrer des commandes en négatif"),
|
||||||
(
|
|
||||||
"perform_liq_reserved",
|
|
||||||
"Effectuer une opération réservé aux adhérent⋅e⋅s sur LIQ",
|
|
||||||
),
|
|
||||||
("cancel_old_operations", "Annuler des commandes non récentes"),
|
("cancel_old_operations", "Annuler des commandes non récentes"),
|
||||||
(
|
(
|
||||||
"perform_commented_operations",
|
"perform_commented_operations",
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
|
|
||||||
from ..decorators import kfet_is_team
|
from ..decorators import kfet_is_team
|
||||||
from ..utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
|
from ..utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
|
||||||
from .open import kfet_open
|
from .open import kfet_open
|
||||||
|
@ -21,7 +19,7 @@ class OpenKfetConsumer(PermConsumerMixin, DjangoJsonWebsocketConsumer):
|
||||||
"""Send current status on connect."""
|
"""Send current status on connect."""
|
||||||
await super().connect()
|
await super().connect()
|
||||||
|
|
||||||
group = "team" if await sync_to_async(kfet_is_team)(self.user) else "base"
|
group = "team" if kfet_is_team(self.user) else "base"
|
||||||
|
|
||||||
await self.channel_layer.group_add(f"kfet.open.{group}", self.channel_name)
|
await self.channel_layer.group_add(f"kfet.open.{group}", self.channel_name)
|
||||||
|
|
||||||
|
|
|
@ -3,22 +3,20 @@ var OpenWS = new KfetWebsocket({
|
||||||
});
|
});
|
||||||
|
|
||||||
var OpenKfet = function (force_close_url, admin) {
|
var OpenKfet = function (force_close_url, admin) {
|
||||||
that = this;
|
this.force_close_url = force_close_url;
|
||||||
$( function() {
|
this.admin = admin;
|
||||||
that.force_close_url = force_close_url;
|
|
||||||
that.admin = admin;
|
|
||||||
|
|
||||||
that.status = that.UNKNOWN;
|
this.status = this.UNKNOWN;
|
||||||
that.dom = {
|
this.dom = {
|
||||||
status_text: $('.kfetopen .status-text'),
|
status_text: $('.kfetopen .status-text'),
|
||||||
force_close_btn: $('.kfetopen .force-close-btn'),
|
force_close_btn: $('.kfetopen .force-close-btn'),
|
||||||
warning: $('.kfetopen .warning')
|
warning: $('.kfetopen .warning')
|
||||||
}
|
}
|
||||||
|
|
||||||
that.dom.force_close_btn.click(() => that.toggle_force_close());
|
this.dom.force_close_btn.click(() => this.toggle_force_close());
|
||||||
setInterval(() => that.refresh(), that.refresh_interval * 1000);
|
setInterval(() => this.refresh(), this.refresh_interval * 1000);
|
||||||
OpenWS.add_handler(data => that.refresh(data));
|
OpenWS.add_handler(data => this.refresh(data));
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenKfet.prototype = {
|
OpenKfet.prototype = {
|
||||||
|
@ -51,8 +49,6 @@ OpenKfet.prototype = {
|
||||||
deactivate: "Réouvrir la K-Fêt"
|
deactivate: "Réouvrir la K-Fêt"
|
||||||
},
|
},
|
||||||
|
|
||||||
callbacks: [ ],
|
|
||||||
|
|
||||||
get is_recent() {
|
get is_recent() {
|
||||||
return this.last_update && moment().diff(this.last_update, 'minute') <= this.time_unknown;
|
return this.last_update && moment().diff(this.last_update, 'minute') <= this.time_unknown;
|
||||||
},
|
},
|
||||||
|
@ -73,9 +69,6 @@ OpenKfet.prototype = {
|
||||||
|
|
||||||
this.add_class(status);
|
this.add_class(status);
|
||||||
this.dom.status_text.html(this.status_text[status]);
|
this.dom.status_text.html(this.status_text[status]);
|
||||||
for (callback of this.callbacks) {
|
|
||||||
callback(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
// admin specific
|
// admin specific
|
||||||
if (this.admin) {
|
if (this.admin) {
|
||||||
|
@ -116,9 +109,5 @@ OpenKfet.prototype = {
|
||||||
|
|
||||||
add_class: function (status) {
|
add_class: function (status) {
|
||||||
$(this.target).addClass(this.class_prefix + status);
|
$(this.target).addClass(this.class_prefix + status);
|
||||||
},
|
|
||||||
|
|
||||||
add_callback: function (callback) {
|
|
||||||
this.callbacks.push(callback);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
{% extends 'kfet/base.html' %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block extra_head %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
kfet_open.add_callback(function(status) {
|
|
||||||
const div = document.getElementById("main");
|
|
||||||
switch (status) {
|
|
||||||
case "opened":
|
|
||||||
div.className = "green";
|
|
||||||
document.title = "🟢 Ouvert | K-Fêt";
|
|
||||||
break;
|
|
||||||
case "closed":
|
|
||||||
div.className = "red";
|
|
||||||
document.title = "🔴 Fermé | K-Fêt";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
div.className = "orange";
|
|
||||||
document.title = "🟠 Indéfini | K-Fêt";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
#main {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: min(15vw, 0.75*(100vh - 50px));
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
width: 100vw;
|
|
||||||
top: 50px;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orange {
|
|
||||||
background-color: orange;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.green {
|
|
||||||
background-color: green;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main > p {
|
|
||||||
overflow: hidden;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orange > #orange {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.green > #green {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red > #red {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block title %}Indicateur{% endblock %}
|
|
||||||
|
|
||||||
{% block header %}{% endblock %}
|
|
||||||
{% block help %}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div id="main" class="orange">
|
|
||||||
<p id="orange">Non défini</p>
|
|
||||||
<p id="red">Fermé</p>
|
|
||||||
<p id="green">Ouvert</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -4,8 +4,10 @@
|
||||||
<script type="text/javascript" src="{% static "kfetopen/kfet-open.js" %}"></script>
|
<script type="text/javascript" src="{% static "kfetopen/kfet-open.js" %}"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
kfet_open = new OpenKfet(
|
$( function() {
|
||||||
|
kfet_open = new OpenKfet(
|
||||||
"{% url "kfet.open.edit_force_close" %}",
|
"{% url "kfet.open.edit_force_close" %}",
|
||||||
{{ perms.kfet.is_team|yesno:"true,false" }}
|
{{ perms.kfet.is_team|yesno:"true,false" }}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,5 +5,4 @@ from . import views
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("raw_open", views.raw_open, name="kfet.open.edit_raw_open"),
|
path("raw_open", views.raw_open, name="kfet.open.edit_raw_open"),
|
||||||
path("force_close", views.force_close, name="kfet.open.edit_force_close"),
|
path("force_close", views.force_close, name="kfet.open.edit_force_close"),
|
||||||
path("", views.indicator, name="kfet.open.indicator"),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,7 +3,6 @@ from django.conf import settings
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.decorators.http import require_POST
|
from django.views.decorators.http import require_POST
|
||||||
|
|
||||||
|
@ -31,10 +30,3 @@ def force_close(request):
|
||||||
kfet_open.force_close = force_close
|
kfet_open.force_close = force_close
|
||||||
async_to_sync(kfet_open.send_ws)()
|
async_to_sync(kfet_open.send_ws)()
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
|
|
||||||
def indicator(request):
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"kfetopen/indicator.html",
|
|
||||||
)
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ var Account = Backbone.Model.extend({
|
||||||
'name': '',
|
'name': '',
|
||||||
'email': '',
|
'email': '',
|
||||||
'is_cof': '',
|
'is_cof': '',
|
||||||
'is_kfet': '',
|
|
||||||
'promo': '',
|
'promo': '',
|
||||||
'balance': '',
|
'balance': '',
|
||||||
'is_frozen': false,
|
'is_frozen': false,
|
||||||
|
@ -70,7 +69,7 @@ var AccountView = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
get_is_cof: function () {
|
get_is_cof: function () {
|
||||||
return this.model.get("is_cof") ? 'Membre COF' : (this.model.get("is_kfet") ? 'Membre K-Fêt' : 'Non-COF');
|
return this.model.get("is_cof") ? 'COF' : 'Non-COF';
|
||||||
},
|
},
|
||||||
|
|
||||||
get_balance: function () {
|
get_balance: function () {
|
||||||
|
@ -92,7 +91,7 @@ var AccountView = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
get_buttons: function () {
|
get_buttons: function () {
|
||||||
var url = django_urls["kfet.account.read"](encodeURIComponent(this.model.get("trigramme")));
|
var url = django_urls["kfet.account.read"](this.model.get("trigramme"));
|
||||||
|
|
||||||
return `<a href="${url}" class="btn btn-primary" target="_blank" title="Modifier"><span class="glyphicon glyphicon-cog"></span></a>`;
|
return `<a href="${url}" class="btn btn-primary" target="_blank" title="Modifier"><span class="glyphicon glyphicon-cog"></span></a>`;
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String.prototype.format_trigramme = function () {
|
String.prototype.format_trigramme = function () {
|
||||||
return _.toArray(this.toUpperCase()).splice(0,3).join('');
|
return this.toUpperCase().substr(0, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
String.prototype.is_valid_trigramme = function () {
|
String.prototype.is_valid_trigramme = function () {
|
||||||
var arr = _.toArray(this);
|
var pattern = /^[^a-z]{3}$/;
|
||||||
return arr && arr.length == 3;
|
return pattern.test(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class KfetWebsocket {
|
||||||
|
|
||||||
listen() {
|
listen() {
|
||||||
var that = this;
|
var that = this;
|
||||||
this.socket = new ReconnectingWebSocket(this.url, [], { minReconnectionDelay: 100 });
|
this.socket = new ReconnectingWebSocket(this.url);
|
||||||
|
|
||||||
this.socket.onmessage = function (e) {
|
this.socket.onmessage = function (e) {
|
||||||
var data = $.extend({}, that.default_msg, JSON.parse(e.data));
|
var data = $.extend({}, that.default_msg, JSON.parse(e.data));
|
||||||
|
|
117
kfet/static/kfet/vendor/lodash.min.js
vendored
117
kfet/static/kfet/vendor/lodash.min.js
vendored
|
@ -1,117 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* lodash 4.0.0 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
|
|
||||||
* Build: `lodash -o ./dist/lodash.js`
|
|
||||||
*/
|
|
||||||
;(function(){function n(n,t){return n.set(t[0],t[1]),n}function t(n,t){return n.add(t),n}function r(n,t,r){switch(r?r.length:0){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function e(n,t){for(var r=-1,e=n.length;++r<e&&false!==t(n[r],r,n););return n}function u(n,t){for(var r=-1,e=n.length;++r<e;)if(!t(n[r],r,n))return false;return true}function o(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r<e;){var i=n[r];t(i,r,n)&&(o[++u]=i);
|
|
||||||
}return o}function i(n,t){return!!n.length&&-1<v(n,t,0)}function f(n,t,r){for(var e=-1,u=n.length;++e<u;)if(r(t,n[e]))return true;return false}function c(n,t){for(var r=-1,e=n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function a(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function l(n,t,r,e){var u=-1,o=n.length;for(e&&o&&(r=n[++u]);++u<o;)r=t(r,n[u],u,n);return r}function s(n,t,r,e){var u=n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function h(n,t){for(var r=-1,e=n.length;++r<e;)if(t(n[r],r,n))return true;
|
|
||||||
return false}function p(n,t,r){for(var e=-1,u=n.length;++e<u;){var o=n[e],i=t(o);if(null!=i&&(f===Z?i===i:r(i,f)))var f=i,c=o}return c}function _(n,t,r,e){var u;return r(n,function(n,r,o){return t(n,r,o)?(u=e?r:n,false):void 0}),u}function g(n,t,r){for(var e=n.length,u=r?e:-1;r?u--:++u<e;)if(t(n[u],u,n))return u;return-1}function v(n,t,r){if(t!==t)return W(n,r);--r;for(var e=n.length;++r<e;)if(n[r]===t)return r;return-1}function d(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function y(n,t){
|
|
||||||
var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;return n}function b(n,t){for(var r,e=-1,u=n.length;++e<u;){var o=t(n[e]);o!==Z&&(r=r===Z?o:r+o)}return r}function x(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function m(n,t){return c(t,function(t){return[t,n[t]]})}function j(n){return function(t){return n(t)}}function w(n,t){return c(t,function(t){return n[t]})}function A(n,t){for(var r=-1,e=n.length;++r<e&&-1<v(t,n[r],0););return r}function O(n,t){for(var r=n.length;r--&&-1<v(t,n[r],0););
|
|
||||||
return r}function E(n){return n&&n.Object===Object?n:null}function k(n,t){if(n!==t){var r=null===n,e=n===Z,u=n===n,o=null===t,i=t===Z,f=t===t;if(n>t&&!o||!u||r&&!i&&f||e&&f)return 1;if(t>n&&!r||!f||o&&!e&&u||i&&u)return-1}return 0}function I(n){return Un[n]}function R(n){return zn[n]}function S(n){return"\\"+$n[n]}function W(n,t,r){var e=n.length;for(t+=r?0:-1;r?t--:++t<e;){var u=n[t];if(u!==u)return t}return-1}function C(n){var t=false;if(null!=n&&typeof n.toString!="function")try{t=!!(n+"")}catch(r){}
|
|
||||||
return t}function U(n,t){return n=typeof n=="number"||dn.test(n)?+n:-1,n>-1&&0==n%1&&(null==t?9007199254740991:t)>n}function z(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}function B(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function L(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r<e;)n[r]===t&&(n[r]="__lodash_placeholder__",o[++u]=r);return o}function $(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function F(n){if(!n||!En.test(n))return n.length;
|
|
||||||
for(var t=On.lastIndex=0;On.test(n);)t++;return t}function M(n){return Bn[n]}function N(E){function dn(n){if(_e(n)&&!Wo(n)&&!(n instanceof wn)){if(n instanceof jn)return n;if(tu.call(n,"__wrapped__"))return Br(n)}return new jn(n)}function mn(){}function jn(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=Z}function wn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[];
|
|
||||||
}function Un(){}function zn(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Bn(n){var t=-1,r=n?n.length:0;for(this.__data__=new zn;++t<r;)this.push(n[t])}function Ln(n,t){var r=n.__data__;return kr(t)?(r=r.__data__,"__lodash_hash_undefined__"===(typeof t=="string"?r.string:r.hash)[t]):r.has(t)}function $n(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Nn(n,t){var r=Dn(n,t);return 0>r?false:(r==n.length-1?n.pop():du.call(n,r,1),
|
|
||||||
!0)}function Zn(n,t){var r=Dn(n,t);return 0>r?Z:n[r][1]}function Dn(n,t){for(var r=n.length;r--;)if(ue(n[r][0],t))return r;return-1}function qn(n,t,r){var e=Dn(n,t);0>e?n.push([t,r]):n[e][1]=r}function Pn(n,t,r,e){return n===Z||ue(n,Xe[r])&&!tu.call(e,r)?t:n}function Tn(n,t,r){(r!==Z&&!ue(n[t],r)||typeof t=="number"&&r===Z&&!(t in n))&&(n[t]=r)}function Vn(n,t,r){var e=n[t];(!ue(e,r)||ue(e,Xe[t])&&!tu.call(n,t)||r===Z&&!(t in n))&&(n[t]=r)}function Jn(n,t){return n&&Tt(t,Ce(t),n)}function Yn(n,t){
|
|
||||||
for(var r=-1,e=null==n,u=t.length,o=Array(u);++r<u;)o[r]=e?Z:Re(n,t[r]);return o}function Hn(n,t,r){return n===n&&(r!==Z&&(n=n>r?r:n),t!==Z&&(n=t>n?t:n)),n}function Qn(n,t,r,u,o,i){var f;if(r&&(f=o?r(n,u,o,i):r(n)),f!==Z)return f;if(!pe(n))return n;if(u=Wo(n)){if(f=mr(n),!t)return Pt(n,f)}else{var c=br(n),a="[object Function]"==c||"[object GeneratorFunction]"==c;if("[object Object]"!=c&&"[object Arguments]"!=c&&(!a||o))return Cn[c]?wr(n,c,t):o?n:{};if(C(n))return o?n:{};if(f=jr(a?{}:n),!t)return Gt(n,Jn(f,n));
|
|
||||||
}return i||(i=new $n),(o=i.get(n))?o:(i.set(n,f),(u?e:it)(n,function(e,u){Vn(f,u,Qn(e,t,r,u,n,i))}),u?f:Gt(n,f))}function Xn(n){var t=Ce(n),r=t.length;return function(e){if(null==e)return!r;for(var u=r;u--;){var o=t[u],i=n[o],f=e[o];if(f===Z&&!(o in Object(e))||!i(f))return false}return true}}function nt(n,t,r){if(typeof n!="function")throw new He("Expected a function");return vu(function(){n.apply(Z,r)},t)}function tt(n,t,r,e){var u=-1,o=i,a=true,l=n.length,s=[],h=t.length;if(!l)return s;r&&(t=c(t,j(r))),
|
|
||||||
e?(o=f,a=false):t.length>=200&&(o=Ln,a=false,t=new Bn(t));n:for(;++u<l;){var p=n[u],_=r?r(p):p;if(a&&_===_){for(var g=h;g--;)if(t[g]===_)continue n;s.push(p)}else o(t,_,e)||s.push(p)}return s}function rt(n,t){var r=true;return Nu(n,function(n,e,u){return r=!!t(n,e,u)}),r}function et(n,t){var r=[];return Nu(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function ut(n,t,r,e){e||(e=[]);for(var u=-1,o=n.length;++u<o;){var i=n[u];ce(i)&&(r||Wo(i)||ie(i))?t?ut(i,t,r,e):a(e,i):r||(e[e.length]=i)}return e}function ot(n,t){
|
|
||||||
null==n||Du(n,t,Ue)}function it(n,t){return n&&Du(n,t,Ce)}function ft(n,t){return n&&qu(n,t,Ce)}function ct(n,t){return o(t,function(t){return le(n[t])})}function at(n,t){t=Er(t,n)?[t+""]:Lt(t);for(var r=0,e=t.length;null!=n&&e>r;)n=n[t[r++]];return r&&r==e?n:Z}function lt(n,t){return tu.call(n,t)||typeof n=="object"&&t in n&&null===hu(n)}function st(n,t){return t in Object(n)}function ht(n,t,r){for(var e=r?f:i,u=n.length,o=u,a=Array(u),l=[];o--;){var s=n[o];o&&t&&(s=c(s,j(t))),a[o]=r||!t&&120>s.length?Z:new Bn(o&&s);
|
|
||||||
}var s=n[0],h=-1,p=s.length,_=a[0];n:for(;++h<p;){var g=s[h],v=t?t(g):g;if(_?!Ln(_,v):!e(l,v,r)){for(o=u;--o;){var d=a[o];if(d?!Ln(d,v):!e(n[o],v,r))continue n}_&&_.push(v),l.push(g)}}return l}function pt(n,t,e){return Er(t,n)||(t=Lt(t),n=Wr(n,t),t=Mr(t)),t=null==n?n:n[t],null==t?Z:r(t,n,e)}function _t(n,t,r,e,u){if(n===t)n=true;else if(null==n||null==t||!pe(n)&&!_e(t))n=n!==n&&t!==t;else n:{var o=Wo(n),i=Wo(t),f="[object Array]",c="[object Array]";o||(f=br(n),"[object Arguments]"==f?f="[object Object]":"[object Object]"!=f&&(o=me(n))),
|
|
||||||
i||(c=br(t),"[object Arguments]"==c?c="[object Object]":"[object Object]"!=c&&me(t));var a="[object Object]"==f&&!C(n),i="[object Object]"==c&&!C(t),c=f==c;if(!c||o||a){if(!(2&e)&&(f=a&&tu.call(n,"__wrapped__"),i=i&&tu.call(t,"__wrapped__"),f||i)){n=_t(f?n.value():n,i?t.value():t,r,e,u);break n}c?(u||(u=new $n),n=(o?hr:_r)(n,t,_t,r,e,u)):n=false}else n=pr(n,t,f,_t,r,e)}return n}function gt(n,t,r,e){var u=r.length,o=u,i=!e;if(null==n)return!o;for(n=Object(n);u--;){var f=r[u];if(i&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return false;
|
|
||||||
}for(;++u<o;){var f=r[u],c=f[0],a=n[c],l=f[1];if(i&&f[2]){if(a===Z&&!(c in n))return false}else if(f=new $n,c=e?e(a,l,c,n,t,f):Z,c===Z?!_t(l,a,e,3,f):!c)return false}return true}function vt(n){var t=typeof n;return"function"==t?n:null==n?Ne:"object"==t?Wo(n)?xt(n[0],n[1]):bt(n):Te(n)}function dt(n){n=null==n?n:Object(n);var t,r=[];for(t in n)r.push(t);return r}function yt(n,t){var r=-1,e=fe(n)?Array(n.length):[];return Nu(n,function(n,u,o){e[++r]=t(n,u,o)}),e}function bt(n){var t=dr(n);if(1==t.length&&t[0][2]){
|
|
||||||
var r=t[0][0],e=t[0][1];return function(n){return null==n?false:n[r]===e&&(e!==Z||r in Object(n))}}return function(r){return r===n||gt(r,n,t)}}function xt(n,t){return function(r){var e=Re(r,n);return e===Z&&e===t?We(r,n):_t(t,e,Z,3)}}function mt(n,t,r,u){if(n!==t){var o=Wo(t)||me(t)?Z:Ue(t);e(o||t,function(e,i){if(o&&(i=e,e=t[i]),pe(e)){u||(u=new $n);var f=i,c=u,a=n[f],l=t[f],s=c.get(l)||c.get(a);if(s)Tn(n,f,s);else{var s=r?r(a,l,f+"",n,t,c):Z,h=s===Z;h&&(s=l,Wo(l)||me(l)?s=Wo(a)?a:ce(a)?Pt(a):Qn(l):de(l)||ie(l)?s=ie(a)?ke(a):pe(a)?a:Qn(l):h=le(l)),
|
|
||||||
c.set(l,s),h&&mt(s,l,r,c),Tn(n,f,s)}}else f=r?r(n[i],e,i+"",n,t,u):Z,f===Z&&(f=e),Tn(n,i,f)})}}function jt(n,t,r){var e=-1,u=vr();return t=c(t.length?t:Array(1),function(n){return u(n)}),n=yt(n,function(n){return{a:c(t,function(t){return t(n)}),b:++e,c:n}}),y(n,function(n,t){var e;n:{e=-1;for(var u=n.a,o=t.a,i=u.length,f=r.length;++e<i;){var c=k(u[e],o[e]);if(c){e=f>e?c*("desc"==r[e]?-1:1):c;break n}}e=n.b-t.b}return e})}function wt(n,t){return n=Object(n),l(t,function(t,r){return r in n&&(t[r]=n[r]),
|
|
||||||
t},{})}function At(n,t){var r={};return ot(n,function(n,e){t(n)&&(r[e]=n)}),r}function Ot(n){return function(t){return null==t?Z:t[n]}}function Et(n){return function(t){return at(t,n)}}function kt(n,t,r){var e=-1,u=t.length,o=n;for(r&&(o=c(n,function(n){return r(n)}));++e<u;)for(var i=0,f=t[e],f=r?r(f):f;-1<(i=v(o,f,i));)o!==n&&du.call(o,i,1),du.call(n,i,1);return n}function It(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(e==r||u!=o){var o=u;if(U(u))du.call(n,u,1);else if(Er(u,n))delete n[u];else{
|
|
||||||
var u=Lt(u),i=Wr(n,u);null!=i&&delete i[Mr(u)]}}}}function Rt(n,t){return n+bu(Eu()*(t-n+1))}function St(n,t,r,e){t=Er(t,n)?[t+""]:Lt(t);for(var u=-1,o=t.length,i=o-1,f=n;null!=f&&++u<o;){var c=t[u];if(pe(f)){var a=r;if(u!=i){var l=f[c],a=e?e(l,c,f):Z;a===Z&&(a=null==l?U(t[u+1])?[]:{}:l)}Vn(f,c,a)}f=f[c]}return n}function Wt(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Array(u);++e<u;)r[e]=n[e+t];return r}function Ct(n,t){var r;return Nu(n,function(n,e,u){
|
|
||||||
return r=t(n,e,u),!r}),!!r}function Ut(n,t,r){var e=0,u=n?n.length:e;if(typeof t=="number"&&t===t&&2147483647>=u){for(;u>e;){var o=e+u>>>1,i=n[o];(r?t>=i:t>i)&&null!==i?e=o+1:u=o}return u}return zt(n,t,Ne,r)}function zt(n,t,r,e){t=r(t);for(var u=0,o=n?n.length:0,i=t!==t,f=null===t,c=t===Z;o>u;){var a=bu((u+o)/2),l=r(n[a]),s=l!==Z,h=l===l;(i?h||e:f?h&&s&&(e||null!=l):c?h&&(e||s):null==l?0:e?t>=l:t>l)?u=a+1:o=a}return Au(o,4294967294)}function Bt(n,t){for(var r=0,e=n.length,u=n[0],o=t?t(u):u,i=o,f=0,c=[u];++r<e;)u=n[r],
|
|
||||||
o=t?t(u):u,ue(o,i)||(i=o,c[++f]=u);return c}function Lt(n){return Wo(n)?n:Cr(n)}function $t(n,t,r){var e=-1,u=i,o=n.length,c=true,a=[],l=a;if(r)c=false,u=f;else if(o<200)l=t?[]:a;else{if(u=t?null:Tu(n))return $(u);c=false,u=Ln,l=new Bn}n:for(;++e<o;){var s=n[e],h=t?t(s):s;if(c&&h===h){for(var p=l.length;p--;)if(l[p]===h)continue n;t&&l.push(h),a.push(s)}else u(l,h,r)||(l!==a&&l.push(h),a.push(s))}return a}function Ft(n,t,r,e){for(var u=n.length,o=e?u:-1;(e?o--:++o<u)&&t(n[o],o,n););return r?Wt(n,e?0:o,e?o+1:u):Wt(n,e?o+1:0,e?u:o);
|
|
||||||
}function Mt(n,t){var r=n;return r instanceof wn&&(r=r.value()),l(t,function(n,t){return t.func.apply(t.thisArg,a([n],t.args))},r)}function Nt(n,t,r){for(var e=-1,u=n.length;++e<u;)var o=o?a(tt(o,n[e],t,r),tt(n[e],o,t,r)):n[e];return o&&o.length?$t(o,t,r):[]}function Zt(n){var t=new n.constructor(n.byteLength);return new au(t).set(new au(n)),t}function Dt(n,t,r){for(var e=r.length,u=-1,o=wu(n.length-e,0),i=-1,f=t.length,c=Array(f+o);++i<f;)c[i]=t[i];for(;++u<e;)c[r[u]]=n[u];for(;o--;)c[i++]=n[u++];
|
|
||||||
return c}function qt(n,t,r){for(var e=-1,u=r.length,o=-1,i=wu(n.length-u,0),f=-1,c=t.length,a=Array(i+c);++o<i;)a[o]=n[o];for(i=o;++f<c;)a[i+f]=t[f];for(;++e<u;)a[i+r[e]]=n[o++];return a}function Pt(n,t){var r=-1,e=n.length;for(t||(t=Array(e));++r<e;)t[r]=n[r];return t}function Tt(n,t,r){return Kt(n,t,r)}function Kt(n,t,r,e){r||(r={});for(var u=-1,o=t.length;++u<o;){var i=t[u],f=e?e(r[i],n[i],i,r,n):n[i];Vn(r,i,f)}return r}function Gt(n,t){return Tt(n,Vu(n),t)}function Vt(n,t){return function(r,e){
|
|
||||||
var u=t?t():{};if(e=vr(e),Wo(r))for(var o=-1,i=r.length;++o<i;){var f=r[o];n(u,f,e(f),r)}else Nu(r,function(t,r,o){n(u,t,e(t),o)});return u}}function Jt(n){return ee(function(t,r){var e=-1,u=r.length,o=u>1?r[u-1]:Z,i=u>2?r[2]:Z,o=typeof o=="function"?(u--,o):Z;for(i&&Or(r[0],r[1],i)&&(o=3>u?Z:o,u=1),t=Object(t);++e<u;)(i=r[e])&&n(t,i,o);return t})}function Yt(n,t){return function(r,e){if(null==r)return r;if(!fe(r))return n(r,e);for(var u=r.length,o=t?u:-1,i=Object(r);(t?o--:++o<u)&&false!==e(i[o],o,i););
|
|
||||||
return r}}function Ht(n){return function(t,r,e){var u=-1,o=Object(t);e=e(t);for(var i=e.length;i--;){var f=e[n?i:++u];if(false===r(o[f],f,o))break}return t}}function Qt(n,t,r){function e(){return(this&&this!==Kn&&this instanceof e?o:n).apply(u?r:this,arguments)}var u=1&t,o=tr(n);return e}function Xt(n){return function(t){t=Ie(t);var r=En.test(t)?t.match(On):Z,e=r?r[0]:t.charAt(0);return t=r?r.slice(1).join(""):t.slice(1),e[n]()+t}}function nr(n){return function(t){return l(Me($e(t)),n,"")}}function tr(n){
|
|
||||||
return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=Mu(n.prototype),t=n.apply(r,t);return pe(t)?t:r}}function rr(n,t,e){function u(){for(var i=arguments.length,f=i,c=Array(i),a=this&&this!==Kn&&this instanceof u?o:n,l=u.placeholder;f--;)c[f]=arguments[f];
|
|
||||||
return f=3>i&&c[0]!==l&&c[i-1]!==l?[]:L(c,l),i-=f.length,e>i?ar(n,t,ur,l,Z,c,f,Z,Z,e-i):r(a,this,c)}var o=tr(n);return u}function er(n){return ee(function(t){t=ut(t);var r=t.length,e=r,u=jn.prototype.thru;for(n&&t.reverse();e--;){var o=t[e];if(typeof o!="function")throw new He("Expected a function");if(u&&!i&&"wrapper"==gr(o))var i=new jn([],true)}for(e=i?e:r;++e<r;)var o=t[e],u=gr(o),f="wrapper"==u?Ku(o):Z,i=f&&Ir(f[0])&&424==f[1]&&!f[4].length&&1==f[9]?i[gr(f[0])].apply(i,f[3]):1==o.length&&Ir(o)?i[u]():i.thru(o);
|
|
||||||
return function(){var n=arguments,e=n[0];if(i&&1==n.length&&Wo(e)&&e.length>=200)return i.plant(e).value();for(var u=0,n=r?t[u].apply(this,n):e;++u<r;)n=t[u].call(this,n);return n}})}function ur(n,t,r,e,u,o,i,f,c,a){function l(){for(var y=arguments.length,b=y,x=Array(y);b--;)x[b]=arguments[b];if(e&&(x=Dt(x,e,u)),o&&(x=qt(x,o,i)),_||g){var b=l.placeholder,m=L(x,b),y=y-m.length;if(a>y)return ar(n,t,ur,b,r,x,m,f,c,a-y)}if(y=h?r:this,b=p?y[n]:n,f)for(var m=x.length,j=Au(f.length,m),w=Pt(x);j--;){var A=f[j];
|
|
||||||
x[j]=U(A,m)?w[A]:Z}else v&&x.length>1&&x.reverse();return s&&x.length>c&&(x.length=c),this&&this!==Kn&&this instanceof l&&(b=d||tr(b)),b.apply(y,x)}var s=128&t,h=1&t,p=2&t,_=8&t,g=16&t,v=512&t,d=p?Z:tr(n);return l}function or(n){return ee(function(t){return t=c(ut(t),vr()),ee(function(e){var u=this;return n(t,function(n){return r(n,u,e)})})})}function ir(n,t,r){return t=Ae(t),n=F(n),t&&t>n?(t-=n,r=r===Z?" ":r+"",n=Fe(r,yu(t/F(r))),En.test(r)?n.match(On).slice(0,t).join(""):n.slice(0,t)):""}function fr(n,t,e,u){
|
|
||||||
function o(){for(var t=-1,c=arguments.length,a=-1,l=u.length,s=Array(l+c),h=this&&this!==Kn&&this instanceof o?f:n;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++t];return r(h,i?e:this,s)}var i=1&t,f=tr(n);return o}function cr(n){return function(t,r,e){e&&typeof e!="number"&&Or(t,r,e)&&(r=e=Z),t=Ee(t),t=t===t?t:0,r===Z?(r=t,t=0):r=Ee(r)||0,e=e===Z?r>t?1:-1:Ee(e)||0;var u=-1;r=wu(yu((r-t)/(e||1)),0);for(var o=Array(r);r--;)o[n?r:++u]=t,t+=e;return o}}function ar(n,t,r,e,u,o,i,f,c,a){var l=8&t;f=f?Pt(f):Z;
|
|
||||||
var s=l?i:Z;i=l?Z:i;var h=l?o:Z;return o=l?Z:o,t=(t|(l?32:64))&~(l?64:32),4&t||(t&=-4),t=[n,t,u,h,s,o,i,f,c,a],r=r.apply(Z,t),Ir(n)&&Ju(r,t),r.placeholder=e,r}function lr(n){var t=Je[n];return function(n,r){if(n=Ee(n),r=Ae(r)){var e=(Ie(n)+"e").split("e"),e=t(e[0]+"e"+(+e[1]+r)),e=(Ie(e)+"e").split("e");return+(e[0]+"e"+(+e[1]-r))}return t(n)}}function sr(n,t,r,e,u,o,i,f){var c=2&t;if(!c&&typeof n!="function")throw new He("Expected a function");var a=e?e.length:0;if(a||(t&=-97,e=u=Z),i=i===Z?i:wu(Ae(i),0),
|
|
||||||
f=f===Z?f:Ae(f),a-=u?u.length:0,64&t){var l=e,s=u;e=u=Z}var h=c?Z:Ku(n);return o=[n,t,r,e,u,l,s,o,i,f],h&&(r=o[1],n=h[1],t=r|n,e=128==n&&8==r||128==n&&256==r&&h[8]>=o[7].length||384==n&&h[8]>=h[7].length&&8==r,131>t||e)&&(1&n&&(o[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=o[3],o[3]=e?Dt(e,r,h[4]):Pt(r),o[4]=e?L(o[3],"__lodash_placeholder__"):Pt(h[4])),(r=h[5])&&(e=o[5],o[5]=e?qt(e,r,h[6]):Pt(r),o[6]=e?L(o[5],"__lodash_placeholder__"):Pt(h[6])),(r=h[7])&&(o[7]=Pt(r)),128&n&&(o[8]=null==o[8]?h[8]:Au(o[8],h[8])),
|
|
||||||
null==o[9]&&(o[9]=h[9]),o[0]=h[0],o[1]=t),n=o[0],t=o[1],r=o[2],e=o[3],u=o[4],f=o[9]=null==o[9]?c?0:n.length:wu(o[9]-a,0),!f&&24&t&&(t&=-25),(h?Pu:Ju)(t&&1!=t?8==t||16==t?rr(n,t,f):32!=t&&33!=t||u.length?ur.apply(Z,o):fr(n,t,r,e):Qt(n,t,r),o)}function hr(n,t,r,e,u,o){var i=-1,f=2&u,c=1&u,a=n.length,l=t.length;if(!(a==l||f&&l>a))return false;if(l=o.get(n))return l==t;for(l=true,o.set(n,t);++i<a;){var s=n[i],p=t[i];if(e)var _=f?e(p,s,i,t,n,o):e(s,p,i,n,t,o);if(_!==Z){if(_)continue;l=false;break}if(c){if(!h(t,function(n){
|
|
||||||
return s===n||r(s,n,e,u,o)})){l=false;break}}else if(s!==p&&!r(s,p,e,u,o)){l=false;break}}return o["delete"](n),l}function pr(n,t,r,e,u,o){switch(r){case"[object ArrayBuffer]":if(n.byteLength!=t.byteLength||!e(new au(n),new au(t)))break;return true;case"[object Boolean]":case"[object Date]":return+n==+t;case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object Number]":return n!=+n?t!=+t:n==+t;case"[object RegExp]":case"[object String]":return n==t+"";case"[object Map]":var i=B;case"[object Set]":
|
|
||||||
return i||(i=$),(2&o||n.size==t.size)&&e(i(n),i(t),u,1|o);case"[object Symbol]":return!!fu&&Lu.call(n)==Lu.call(t)}return false}function _r(n,t,r,e,u,o){var i=2&u,f=1&u,c=Ce(n),a=c.length,l=Ce(t);if(a!=l.length&&!i)return false;for(var s=a;s--;){var h=c[s];if(!(i?h in t:lt(t,h))||!f&&h!=l[s])return false}if(h=o.get(n))return h==t;for(f=true,o.set(n,t),l=i;++s<a;){var h=c[s],p=n[h],_=t[h];if(e)var g=i?e(_,p,h,t,n,o):e(p,_,h,n,t,o);if(g===Z?p!==_&&!r(p,_,e,u,o):!g){f=false;break}l||(l="constructor"==h)}return f&&!l&&(r=n.constructor,
|
|
||||||
e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(f=false)),o["delete"](n),f}function gr(n){for(var t=n.name+"",r=Fu[t],e=r?r.length:0;e--;){var u=r[e],o=u.func;if(null==o||o==n)return u.name}return t}function vr(){var n=dn.iteratee||Ze,n=n===Ze?vt:n;return arguments.length?n(arguments[0],arguments[1]):n}function dr(n){n=ze(n);for(var t=n.length;t--;){var r=n[t][1];n[t][2]=r===r&&!pe(r)}return n}function yr(n,t){
|
|
||||||
var r=null==n?Z:n[t];return ge(r)?r:Z}function br(n){return uu.call(n)}function xr(n,t,r){if(null==n)return false;var e=r(n,t);return e||Er(t)||(t=Lt(t),n=Wr(n,t),null!=n&&(t=Mr(t),e=r(n,t))),e||he(n&&n.length)&&U(t,n.length)&&(Wo(n)||be(n)||ie(n))}function mr(n){var t=n.length,r=n.constructor(t);return t&&"string"==typeof n[0]&&tu.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function jr(n){return n=n.constructor,Mu(le(n)?n.prototype:Z)}function wr(r,e,u){var o=r.constructor;switch(e){case"[object ArrayBuffer]":
|
|
||||||
return Zt(r);case"[object Boolean]":case"[object Date]":return new o(+r);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return e=r.buffer,new r.constructor(u?Zt(e):e,r.byteOffset,r.length);case"[object Map]":return u=r.constructor,l(B(r),n,new u);case"[object Number]":case"[object String]":return new o(r);
|
|
||||||
case"[object RegExp]":return u=new r.constructor(r.source,sn.exec(r)),u.lastIndex=r.lastIndex,u;case"[object Set]":return u=r.constructor,l($(r),t,new u);case"[object Symbol]":return fu?Object(Lu.call(r)):{}}}function Ar(n){var t=n?n.length:Z;return he(t)&&(Wo(n)||be(n)||ie(n))?x(t,String):null}function Or(n,t,r){if(!pe(r))return false;var e=typeof t;return("number"==e?fe(r)&&U(t,r.length):"string"==e&&t in r)?ue(r[t],n):false}function Er(n,t){return typeof n=="number"?true:!Wo(n)&&(tn.test(n)||!nn.test(n)||null!=t&&n in Object(t));
|
|
||||||
}function kr(n){var t=typeof n;return"number"==t||"boolean"==t||"string"==t&&"__proto__"!==n||null==n}function Ir(n){var t=gr(n),r=dn[t];return typeof r=="function"&&t in wn.prototype?n===r?true:(t=Ku(r),!!t&&n===t[0]):false}function Rr(n){var t=n&&n.constructor;return n===(typeof t=="function"&&t.prototype||Xe)}function Sr(n,t,r,e,u,o){return pe(n)&&pe(t)&&(o.set(t,n),mt(n,t,Sr,o)),n===Z?Qn(t):n}function Wr(n,t){return 1==t.length?n:Re(n,Wt(t,0,-1))}function Cr(n){var t=[];return Ie(n).replace(rn,function(n,r,e,u){
|
|
||||||
t.push(e?u.replace(an,"$1"):r||n)}),t}function Ur(n){return ce(n)?n:[]}function zr(n){return typeof n=="function"?n:Ne}function Br(n){if(n instanceof wn)return n.clone();var t=new jn(n.__wrapped__,n.__chain__);return t.__actions__=Pt(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function Lr(n,t,r){var e=n?n.length:0;return e?(t=r||t===Z?1:Ae(t),Wt(n,0>t?0:t,e)):[]}function $r(n,t,r){var e=n?n.length:0;return e?(t=r||t===Z?1:Ae(t),t=e-t,Wt(n,0,0>t?0:t)):[]}function Fr(n){return n?n[0]:Z;
|
|
||||||
}function Mr(n){var t=n?n.length:0;return t?n[t-1]:Z}function Nr(n,t){return n&&n.length&&t&&t.length?kt(n,t):n}function Zr(n){return n?ku.call(n):n}function Dr(n){if(!n||!n.length)return[];var t=0;return n=o(n,function(n){return ce(n)?(t=wu(n.length,t),true):void 0}),x(t,function(t){return c(n,Ot(t))})}function qr(n,t){if(!n||!n.length)return[];var e=Dr(n);return null==t?e:c(e,function(n){return r(t,Z,n)})}function Pr(n){return n=dn(n),n.__chain__=true,n}function Tr(n,t){return t(n)}function Kr(){return this;
|
|
||||||
}function Gr(n,t){return typeof t=="function"&&Wo(n)?e(n,t):Nu(n,zr(t))}function Vr(n,t){var r;if(typeof t=="function"&&Wo(n)){for(r=n.length;r--&&false!==t(n[r],r,n););r=n}else r=Zu(n,zr(t));return r}function Jr(n,t){var r=-1,e=we(n),u=e.length,o=u-1;for(t=Hn(Ae(t),0,u);++r<t;){var u=Rt(r,o),i=e[u];e[u]=e[r],e[r]=i}return e.length=t,e}function Yr(n){if(null==n)return 0;if(fe(n)){var t=n.length;return t&&be(n)?F(n):t}return Ce(n).length}function Hr(n,t,r){return t=r?Z:t,t=n&&null==t?n.length:t,sr(n,128,Z,Z,Z,Z,t);
|
|
||||||
}function Qr(n,t){var r;if(typeof t!="function")throw new He("Expected a function");return n=Ae(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=Z),r}}function Xr(n,t,r){return t=r?Z:t,n=sr(n,8,Z,Z,Z,Z,Z,t),n.placeholder=Xr.placeholder,n}function ne(n,t,r){return t=r?Z:t,n=sr(n,16,Z,Z,Z,Z,Z,t),n.placeholder=ne.placeholder,n}function te(n,t,r){function e(){p&&lu(p),a&&lu(a),g=0,c=a=h=p=_=Z}function u(t,r){r&&lu(r),a=p=_=Z,t&&(g=jo(),l=n.apply(h,c),p||a||(c=h=Z))}function o(){var n=t-(jo()-s);
|
|
||||||
0>=n||n>t?u(_,a):p=vu(o,n)}function i(){u(y,p)}function f(){if(c=arguments,s=jo(),h=this,_=y&&(p||!v),false===d)var r=v&&!p;else{a||v||(g=s);var e=d-(s-g),u=0>=e||e>d;u?(a&&(a=lu(a)),g=s,l=n.apply(h,c)):a||(a=vu(i,e))}return u&&p?p=lu(p):p||t===d||(p=vu(o,t)),r&&(u=true,l=n.apply(h,c)),!u||p||a||(c=h=Z),l}var c,a,l,s,h,p,_,g=0,v=false,d=false,y=true;if(typeof n!="function")throw new He("Expected a function");return t=Ee(t)||0,pe(r)&&(v=!!r.leading,d="maxWait"in r&&wu(Ee(r.maxWait)||0,t),y="trailing"in r?!!r.trailing:y),
|
|
||||||
f.cancel=e,f.flush=function(){return(p&&_||a&&y)&&(l=n.apply(h,c)),e(),l},f}function re(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],o=r.cache;return o.has(u)?o.get(u):(e=n.apply(this,e),r.cache=o.set(u,e),e)}if(typeof n!="function"||t&&typeof t!="function")throw new He("Expected a function");return r.cache=new re.Cache,r}function ee(n,t){if(typeof n!="function")throw new He("Expected a function");return t=wu(t===Z?n.length-1:Ae(t),0),function(){for(var e=arguments,u=-1,o=wu(e.length-t,0),i=Array(o);++u<o;)i[u]=e[t+u];
|
|
||||||
switch(t){case 0:return n.call(this,i);case 1:return n.call(this,e[0],i);case 2:return n.call(this,e[0],e[1],i)}for(o=Array(t+1),u=-1;++u<t;)o[u]=e[u];return o[t]=i,r(n,this,o)}}function ue(n,t){return n===t||n!==n&&t!==t}function oe(n,t){return n>t}function ie(n){return ce(n)&&tu.call(n,"callee")&&(!gu.call(n,"callee")||"[object Arguments]"==uu.call(n))}function fe(n){return null!=n&&!(typeof n=="function"&&le(n))&&he(Gu(n))}function ce(n){return _e(n)&&fe(n)}function ae(n){return _e(n)&&typeof n.message=="string"&&"[object Error]"==uu.call(n);
|
|
||||||
}function le(n){return n=pe(n)?uu.call(n):"","[object Function]"==n||"[object GeneratorFunction]"==n}function se(n){return typeof n=="number"&&n==Ae(n)}function he(n){return typeof n=="number"&&n>-1&&0==n%1&&9007199254740991>=n}function pe(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function _e(n){return!!n&&typeof n=="object"}function ge(n){return null==n?false:le(n)?iu.test(nu.call(n)):_e(n)&&(C(n)?iu:gn).test(n)}function ve(n){return typeof n=="number"||_e(n)&&"[object Number]"==uu.call(n);
|
|
||||||
}function de(n){if(!_e(n)||"[object Object]"!=uu.call(n)||C(n))return false;var t=Xe;return typeof n.constructor=="function"&&(t=hu(n)),null===t?true:(n=t.constructor,typeof n=="function"&&n instanceof n&&nu.call(n)==eu)}function ye(n){return pe(n)&&"[object RegExp]"==uu.call(n)}function be(n){return typeof n=="string"||!Wo(n)&&_e(n)&&"[object String]"==uu.call(n)}function xe(n){return typeof n=="symbol"||_e(n)&&"[object Symbol]"==uu.call(n)}function me(n){return _e(n)&&he(n.length)&&!!Wn[uu.call(n)]}function je(n,t){
|
|
||||||
return t>n}function we(n){if(!n)return[];if(fe(n))return be(n)?n.match(On):Pt(n);if(_u&&n[_u])return z(n[_u]());var t=br(n);return("[object Map]"==t?B:"[object Set]"==t?$:Be)(n)}function Ae(n){if(!n)return 0===n?n:0;if(n=Ee(n),n===D||n===-D)return 1.7976931348623157e308*(0>n?-1:1);var t=n%1;return n===n?t?n-t:n:0}function Oe(n){return n?Hn(Ae(n),0,4294967295):0}function Ee(n){if(pe(n)&&(n=le(n.valueOf)?n.valueOf():n,n=pe(n)?n+"":n),typeof n!="string")return 0===n?n:+n;n=n.replace(on,"");var t=_n.test(n);
|
|
||||||
return t||vn.test(n)?Mn(n.slice(2),t?2:8):pn.test(n)?q:+n}function ke(n){return Tt(n,Ue(n))}function Ie(n){if(typeof n=="string")return n;if(null==n)return"";if(xe(n))return fu?$u.call(n):"";var t=n+"";return"0"==t&&1/n==-D?"-0":t}function Re(n,t,r){return n=null==n?Z:at(n,t),n===Z?r:n}function Se(n,t){return xr(n,t,lt)}function We(n,t){return xr(n,t,st)}function Ce(n){var t=Rr(n);if(!t&&!fe(n))return ju(Object(n));var r,e=Ar(n),u=!!e,e=e||[],o=e.length;for(r in n)!lt(n,r)||u&&("length"==r||U(r,o))||t&&"constructor"==r||e.push(r);
|
|
||||||
return e}function Ue(n){for(var t=-1,r=Rr(n),e=dt(n),u=e.length,o=Ar(n),i=!!o,o=o||[],f=o.length;++t<u;){var c=e[t];i&&("length"==c||U(c,f))||"constructor"==c&&(r||!tu.call(n,c))||o.push(c)}return o}function ze(n){return m(n,Ce(n))}function Be(n){return n?w(n,Ce(n)):[]}function Le(n){return Vo(Ie(n).toLowerCase())}function $e(n){return(n=Ie(n))&&n.replace(yn,I).replace(An,"")}function Fe(n,t){n=Ie(n),t=Ae(t);var r="";if(!n||1>t||t>9007199254740991)return r;do t%2&&(r+=n),t=bu(t/2),n+=n;while(t);return r;
|
|
||||||
}function Me(n,t,r){return n=Ie(n),t=r?Z:t,t===Z&&(t=Rn.test(n)?In:kn),n.match(t)||[]}function Ne(n){return n}function Ze(n){return _e(n)&&!Wo(n)?De(n):vt(n)}function De(n){return bt(Qn(n,true))}function qe(n,t,r){var u=Ce(t),o=ct(t,u);null!=r||pe(t)&&(o.length||!u.length)||(r=t,t=n,n=this,o=ct(t,Ce(t)));var i=pe(r)&&"chain"in r?r.chain:true,f=le(n);return e(o,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=Pt(this.__actions__)).push({
|
|
||||||
func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,a([this.value()],arguments))})}),n}function Pe(){}function Te(n){return Er(n)?Ot(n):Et(n)}function Ke(n){return n&&n.length?b(n,Ne):Z}E=E?Gn.defaults({},E,Gn.pick(Kn,Sn)):Kn;var Ge=E.Date,Ve=E.Error,Je=E.Math,Ye=E.RegExp,He=E.TypeError,Qe=E.Array.prototype,Xe=E.Object.prototype,nu=E.Function.prototype.toString,tu=Xe.hasOwnProperty,ru=0,eu=nu.call(Object),uu=Xe.toString,ou=Kn._,iu=Ye("^"+nu.call(tu).replace(en,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),fu=E.Symbol,cu=E.f,au=E.Uint8Array,lu=E.clearTimeout,su=cu?cu.g:Z,hu=Object.getPrototypeOf,pu=Object.getOwnPropertySymbols,_u=typeof(_u=fu&&fu.iterator)=="symbol"?_u:Z,gu=Xe.propertyIsEnumerable,vu=E.setTimeout,du=Qe.splice,yu=Je.ceil,bu=Je.floor,xu=E.isFinite,mu=Qe.join,ju=Object.keys,wu=Je.max,Au=Je.min,Ou=E.parseInt,Eu=Je.random,ku=Qe.reverse,Iu=yr(E,"Map"),Ru=yr(E,"Set"),Su=yr(E,"WeakMap"),Wu=yr(Object,"create"),Cu=Su&&new Su,Uu=Iu?nu.call(Iu):"",zu=Ru?nu.call(Ru):"",Bu=fu?fu.prototype:Z,Lu=fu?Bu.valueOf:Z,$u=fu?Bu.toString:Z,Fu={};
|
|
||||||
dn.templateSettings={escape:H,evaluate:Q,interpolate:X,variable:"",imports:{_:dn}};var Mu=function(){function n(){}return function(t){if(pe(t)){n.prototype=t;var r=new n;n.prototype=Z}return r||{}}}(),Nu=Yt(it),Zu=Yt(ft,true),Du=Ht(),qu=Ht(true);su&&!gu.call({valueOf:1},"valueOf")&&(dt=function(n){return z(su(n))});var Pu=Cu?function(n,t){return Cu.set(n,t),n}:Ne,Tu=Ru&&2===new Ru([1,2]).size?function(n){return new Ru(n)}:Pe,Ku=Cu?function(n){return Cu.get(n)}:Pe,Gu=Ot("length"),Vu=pu||function(){return[];
|
|
||||||
};(Iu&&"[object Map]"!=br(new Iu)||Ru&&"[object Set]"!=br(new Ru))&&(br=function(n){var t=uu.call(n);if(n="[object Object]"==t?n.constructor:null,n=typeof n=="function"?nu.call(n):""){if(n==Uu)return"[object Map]";if(n==zu)return"[object Set]"}return t});var Ju=function(){var n=0,t=0;return function(r,e){var u=jo(),o=16-(u-t);if(t=u,o>0){if(150<=++n)return r}else n=0;return Pu(r,e)}}(),Yu=ee(function(n,t){t=ut(t);for(var r=Wo(n)?n:[Object(n)],e=t,u=-1,o=r.length,i=-1,f=e.length,c=Array(o+f);++u<o;)c[u]=r[u];
|
|
||||||
for(;++i<f;)c[u++]=e[i];return c}),Hu=ee(function(n,t){return ce(n)?tt(n,ut(t,false,true)):[]}),Qu=ee(function(n,t){var r=Mr(t);return ce(r)&&(r=Z),ce(n)?tt(n,ut(t,false,true),vr(r)):[]}),Xu=ee(function(n,t){var r=Mr(t);return ce(r)&&(r=Z),ce(n)?tt(n,ut(t,false,true),Z,r):[]}),no=ee(function(n){var t=c(n,Ur);return t.length&&t[0]===n[0]?ht(t):[]}),to=ee(function(n){var t=Mr(n),r=c(n,Ur);return t===Mr(r)?t=Z:r.pop(),r.length&&r[0]===n[0]?ht(r,vr(t)):[]}),ro=ee(function(n){var t=Mr(n),r=c(n,Ur);return t===Mr(r)?t=Z:r.pop(),
|
|
||||||
r.length&&r[0]===n[0]?ht(r,Z,t):[]}),eo=ee(Nr),uo=ee(function(n,t){t=c(ut(t),String);var r=Yn(n,t);return It(n,t.sort(k)),r}),oo=ee(function(n){return $t(ut(n,false,true))}),io=ee(function(n){var t=Mr(n);return ce(t)&&(t=Z),$t(ut(n,false,true),vr(t))}),fo=ee(function(n){var t=Mr(n);return ce(t)&&(t=Z),$t(ut(n,false,true),Z,t)}),co=ee(function(n,t){return ce(n)?tt(n,t):[]}),ao=ee(function(n){return Nt(o(n,ce))}),lo=ee(function(n){var t=Mr(n);return ce(t)&&(t=Z),Nt(o(n,ce),vr(t))}),so=ee(function(n){var t=Mr(n);return ce(t)&&(t=Z),
|
|
||||||
Nt(o(n,ce),Z,t)}),ho=ee(Dr),po=ee(function(n){var t=n.length,t=t>1?n[t-1]:Z,t=typeof t=="function"?(n.pop(),t):Z;return qr(n,t)}),_o=ee(function(n){function t(t){return Yn(t,n)}n=ut(n);var r=n.length,e=r?n[0]:0,u=this.__wrapped__;return 1>=r&&!this.__actions__.length&&u instanceof wn&&U(e)?(u=u.slice(e,+e+(r?1:0)),u.__actions__.push({func:Tr,args:[t],thisArg:Z}),new jn(u,this.__chain__).thru(function(n){return r&&!n.length&&n.push(Z),n})):this.thru(t)}),go=Vt(function(n,t,r){tu.call(n,r)?++n[r]:n[r]=1;
|
|
||||||
}),vo=Vt(function(n,t,r){tu.call(n,r)?n[r].push(t):n[r]=[t]}),yo=ee(function(n,t,e){var u=-1,o=typeof t=="function",i=Er(t),f=fe(n)?Array(n.length):[];return Nu(n,function(n){var c=o?t:i&&null!=n?n[t]:Z;f[++u]=c?r(c,n,e):pt(n,t,e)}),f}),bo=Vt(function(n,t,r){n[r]=t}),xo=Vt(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),mo=ee(function(n,t){if(null==n)return[];var r=t.length;return r>1&&Or(n,t[0],t[1])?t=[]:r>2&&Or(t[0],t[1],t[2])&&(t.length=1),jt(n,ut(t),[])}),jo=Ge.now,wo=ee(function(n,t,r){
|
|
||||||
var e=1;if(r.length)var u=L(r,wo.placeholder),e=32|e;return sr(n,e,t,r,u)}),Ao=ee(function(n,t,r){var e=3;if(r.length)var u=L(r,Ao.placeholder),e=32|e;return sr(t,e,n,r,u)}),Oo=ee(function(n,t){return nt(n,1,t)}),Eo=ee(function(n,t,r){return nt(n,Ee(t)||0,r)}),ko=ee(function(n,t){t=c(ut(t),vr());var e=t.length;return ee(function(u){for(var o=-1,i=Au(u.length,e);++o<i;)u[o]=t[o].call(this,u[o]);return r(n,this,u)})}),Io=ee(function(n,t){var r=L(t,Io.placeholder);return sr(n,32,Z,t,r)}),Ro=ee(function(n,t){
|
|
||||||
var r=L(t,Ro.placeholder);return sr(n,64,Z,t,r)}),So=ee(function(n,t){return sr(n,256,Z,Z,Z,ut(t))}),Wo=Array.isArray,Co=Jt(function(n,t){Tt(t,Ce(t),n)}),Uo=Jt(function(n,t){Tt(t,Ue(t),n)}),zo=Jt(function(n,t,r){Kt(t,Ue(t),n,r)}),Bo=Jt(function(n,t,r){Kt(t,Ce(t),n,r)}),Lo=ee(function(n,t){return Yn(n,ut(t))}),$o=ee(function(n){return n.push(Z,Pn),r(zo,Z,n)}),Fo=ee(function(n){return n.push(Z,Sr),r(Zo,Z,n)}),Mo=ee(pt),No=Jt(function(n,t){mt(n,t)}),Zo=Jt(function(n,t,r){mt(n,t,r)}),Do=ee(function(n,t){
|
|
||||||
return null==n?{}:(t=c(ut(t),String),wt(n,tt(Ue(n),t)))}),qo=ee(function(n,t){return null==n?{}:wt(n,ut(t))}),Po=nr(function(n,t,r){return t=t.toLowerCase(),n+(r?Le(t):t)}),To=nr(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Ko=nr(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Go=Xt("toLowerCase"),Vo=Xt("toUpperCase"),Jo=nr(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),Yo=nr(function(n,t,r){return n+(r?" ":"")+Le(t)}),Ho=nr(function(n,t,r){return n+(r?" ":"")+t.toUpperCase();
|
|
||||||
}),Qo=ee(function(n,t){try{return r(n,Z,t)}catch(e){return ae(e)?e:new Ve(e)}}),Xo=ee(function(n,t){return e(ut(t),function(t){n[t]=wo(n[t],n)}),n}),ni=er(),ti=er(true),ri=ee(function(n,t){return function(r){return pt(r,n,t)}}),ei=ee(function(n,t){return function(r){return pt(n,r,t)}}),ui=or(c),oi=or(u),ii=or(h),fi=cr(),ci=cr(true),ai=lr("ceil"),li=lr("floor"),si=lr("round");return dn.prototype=mn.prototype,jn.prototype=Mu(mn.prototype),jn.prototype.constructor=jn,wn.prototype=Mu(mn.prototype),wn.prototype.constructor=wn,
|
|
||||||
Un.prototype=Wu?Wu(null):Xe,zn.prototype.clear=function(){this.__data__={hash:new Un,map:Iu?new Iu:[],string:new Un}},zn.prototype["delete"]=function(n){var t=this.__data__;return kr(n)?(t=typeof n=="string"?t.string:t.hash,n=(Wu?t[n]!==Z:tu.call(t,n))&&delete t[n]):n=Iu?t.map["delete"](n):Nn(t.map,n),n},zn.prototype.get=function(n){var t=this.__data__;return kr(n)?(t=typeof n=="string"?t.string:t.hash,Wu?(n=t[n],n="__lodash_hash_undefined__"===n?Z:n):n=tu.call(t,n)?t[n]:Z):n=Iu?t.map.get(n):Zn(t.map,n),
|
|
||||||
n},zn.prototype.has=function(n){var t=this.__data__;return kr(n)?(t=typeof n=="string"?t.string:t.hash,n=Wu?t[n]!==Z:tu.call(t,n)):n=Iu?t.map.has(n):-1<Dn(t.map,n),n},zn.prototype.set=function(n,t){var r=this.__data__;return kr(n)?(typeof n=="string"?r.string:r.hash)[n]=Wu&&t===Z?"__lodash_hash_undefined__":t:Iu?r.map.set(n,t):qn(r.map,n,t),this},Bn.prototype.push=function(n){var t=this.__data__;kr(n)?(t=t.__data__,(typeof n=="string"?t.string:t.hash)[n]="__lodash_hash_undefined__"):t.set(n,"__lodash_hash_undefined__");
|
|
||||||
},$n.prototype.clear=function(){this.__data__={array:[],map:null}},$n.prototype["delete"]=function(n){var t=this.__data__,r=t.array;return r?Nn(r,n):t.map["delete"](n)},$n.prototype.get=function(n){var t=this.__data__,r=t.array;return r?Zn(r,n):t.map.get(n)},$n.prototype.has=function(n){var t=this.__data__,r=t.array;return r?-1<Dn(r,n):t.map.has(n)},$n.prototype.set=function(n,t){var r=this.__data__,e=r.array;return e&&(199>e.length?qn(e,n,t):(r.array=null,r.map=new zn(e))),(r=r.map)&&r.set(n,t),
|
|
||||||
this},re.Cache=zn,dn.after=function(n,t){if(typeof t!="function")throw new He("Expected a function");return n=Ae(n),function(){return 1>--n?t.apply(this,arguments):void 0}},dn.ary=Hr,dn.assign=Co,dn.assignIn=Uo,dn.assignInWith=zo,dn.assignWith=Bo,dn.at=Lo,dn.before=Qr,dn.bind=wo,dn.bindAll=Xo,dn.bindKey=Ao,dn.chain=Pr,dn.chunk=function(n,t){t=wu(Ae(t),0);var r=n?n.length:0;if(!r||1>t)return[];for(var e=0,u=-1,o=Array(yu(r/t));r>e;)o[++u]=Wt(n,e,e+=t);return o},dn.compact=function(n){for(var t=-1,r=n?n.length:0,e=-1,u=[];++t<r;){
|
|
||||||
var o=n[t];o&&(u[++e]=o)}return u},dn.concat=Yu,dn.cond=function(n){var t=n?n.length:0,e=vr();return n=t?c(n,function(n){if("function"!=typeof n[1])throw new He("Expected a function");return[e(n[0]),n[1]]}):[],ee(function(e){for(var u=-1;++u<t;){var o=n[u];if(r(o[0],this,e))return r(o[1],this,e)}})},dn.conforms=function(n){return Xn(Qn(n,true))},dn.constant=function(n){return function(){return n}},dn.countBy=go,dn.create=function(n,t){var r=Mu(n);return t?Jn(r,t):r},dn.curry=Xr,dn.curryRight=ne,dn.debounce=te,
|
|
||||||
dn.defaults=$o,dn.defaultsDeep=Fo,dn.defer=Oo,dn.delay=Eo,dn.difference=Hu,dn.differenceBy=Qu,dn.differenceWith=Xu,dn.drop=Lr,dn.dropRight=$r,dn.dropRightWhile=function(n,t){return n&&n.length?Ft(n,vr(t,3),true,true):[]},dn.dropWhile=function(n,t){return n&&n.length?Ft(n,vr(t,3),true):[]},dn.fill=function(n,t,r,e){var u=n?n.length:0;if(!u)return[];for(r&&typeof r!="number"&&Or(n,t,r)&&(r=0,e=u),u=n.length,r=Ae(r),0>r&&(r=-r>u?0:u+r),e=e===Z||e>u?u:Ae(e),0>e&&(e+=u),e=r>e?0:Oe(e);e>r;)n[r++]=t;return n},
|
|
||||||
dn.filter=function(n,t){return(Wo(n)?o:et)(n,vr(t,3))},dn.flatMap=function(n,t){return n&&n.length?ut(c(n,vr(t,3))):[]},dn.flatten=function(n){return n&&n.length?ut(n):[]},dn.flattenDeep=function(n){return n&&n.length?ut(n,true):[]},dn.flip=function(n){return sr(n,512)},dn.flow=ni,dn.flowRight=ti,dn.fromPairs=function(n){for(var t=-1,r=n?n.length:0,e={};++t<r;){var u=n[t];St(e,u[0],u[1])}return e},dn.functions=function(n){return null==n?[]:ct(n,Ce(n))},dn.functionsIn=function(n){return null==n?[]:ct(n,Ue(n));
|
|
||||||
},dn.groupBy=vo,dn.initial=function(n){return $r(n,1)},dn.intersection=no,dn.intersectionBy=to,dn.intersectionWith=ro,dn.invert=function(n,t,r){return l(Ce(n),function(e,u){var o=n[u];return t&&!r?tu.call(e,o)?e[o].push(u):e[o]=[u]:e[o]=u,e},{})},dn.invokeMap=yo,dn.iteratee=Ze,dn.keyBy=bo,dn.keys=Ce,dn.keysIn=Ue,dn.map=function(n,t){return(Wo(n)?c:yt)(n,vr(t,3))},dn.mapKeys=function(n,t){var r={};return t=vr(t,3),it(n,function(n,e,u){r[t(n,e,u)]=n}),r},dn.mapValues=function(n,t){var r={};return t=vr(t,3),
|
|
||||||
it(n,function(n,e,u){r[e]=t(n,e,u)}),r},dn.matches=De,dn.matchesProperty=function(n,t){return xt(n,Qn(t,true))},dn.memoize=re,dn.merge=No,dn.mergeWith=Zo,dn.method=ri,dn.methodOf=ei,dn.mixin=qe,dn.negate=function(n){if(typeof n!="function")throw new He("Expected a function");return function(){return!n.apply(this,arguments)}},dn.nthArg=function(n){return n=Ae(n),function(){return arguments[n]}},dn.omit=Do,dn.omitBy=function(n,t){return t=vr(t),At(n,function(n){return!t(n)})},dn.once=function(n){return Qr(2,n);
|
|
||||||
},dn.orderBy=function(n,t,r,e){return null==n?[]:(Wo(t)||(t=null==t?[]:[t]),r=e?Z:r,Wo(r)||(r=null==r?[]:[r]),jt(n,t,r))},dn.over=ui,dn.overArgs=ko,dn.overEvery=oi,dn.overSome=ii,dn.partial=Io,dn.partialRight=Ro,dn.partition=xo,dn.pick=qo,dn.pickBy=function(n,t){return null==n?{}:At(n,vr(t))},dn.property=Te,dn.propertyOf=function(n){return function(t){return null==n?Z:at(n,t)}},dn.pull=eo,dn.pullAll=Nr,dn.pullAllBy=function(n,t,r){return n&&n.length&&t&&t.length?kt(n,t,vr(r)):n},dn.pullAt=uo,dn.range=fi,
|
|
||||||
dn.rangeRight=ci,dn.rearg=So,dn.reject=function(n,t){var r=Wo(n)?o:et;return t=vr(t,3),r(n,function(n,r,e){return!t(n,r,e)})},dn.remove=function(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],o=n.length;for(t=vr(t,3);++e<o;){var i=n[e];t(i,e,n)&&(r.push(i),u.push(e))}return It(n,u),r},dn.rest=ee,dn.reverse=Zr,dn.sampleSize=Jr,dn.set=function(n,t,r){return null==n?n:St(n,t,r)},dn.setWith=function(n,t,r,e){return e=typeof e=="function"?e:Z,null==n?n:St(n,t,r,e)},dn.shuffle=function(n){return Jr(n,4294967295);
|
|
||||||
},dn.slice=function(n,t,r){var e=n?n.length:0;return e?(r&&typeof r!="number"&&Or(n,t,r)?(t=0,r=e):(t=null==t?0:Ae(t),r=r===Z?e:Ae(r)),Wt(n,t,r)):[]},dn.sortBy=mo,dn.sortedUniq=function(n){return n&&n.length?Bt(n):[]},dn.sortedUniqBy=function(n,t){return n&&n.length?Bt(n,vr(t)):[]},dn.split=function(n,t,r){return Ie(n).split(t,r)},dn.spread=function(n){if(typeof n!="function")throw new He("Expected a function");return function(t){return r(n,this,t)}},dn.tail=function(n){return Lr(n,1)},dn.take=function(n,t,r){
|
|
||||||
return n&&n.length?(t=r||t===Z?1:Ae(t),Wt(n,0,0>t?0:t)):[]},dn.takeRight=function(n,t,r){var e=n?n.length:0;return e?(t=r||t===Z?1:Ae(t),t=e-t,Wt(n,0>t?0:t,e)):[]},dn.takeRightWhile=function(n,t){return n&&n.length?Ft(n,vr(t,3),false,true):[]},dn.takeWhile=function(n,t){return n&&n.length?Ft(n,vr(t,3)):[]},dn.tap=function(n,t){return t(n),n},dn.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new He("Expected a function");return pe(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),
|
|
||||||
te(n,t,{leading:e,maxWait:t,trailing:u})},dn.thru=Tr,dn.toArray=we,dn.toPairs=ze,dn.toPairsIn=function(n){return m(n,Ue(n))},dn.toPath=function(n){return Wo(n)?c(n,String):Cr(n)},dn.toPlainObject=ke,dn.transform=function(n,t,r){var u=Wo(n)||me(n);if(t=vr(t,4),null==r)if(u||pe(n)){var o=n.constructor;r=u?Wo(n)?new o:[]:Mu(le(o)?o.prototype:Z)}else r={};return(u?e:it)(n,function(n,e,u){return t(r,n,e,u)}),r},dn.unary=function(n){return Hr(n,1)},dn.union=oo,dn.unionBy=io,dn.unionWith=fo,dn.uniq=function(n){
|
|
||||||
return n&&n.length?$t(n):[]},dn.uniqBy=function(n,t){return n&&n.length?$t(n,vr(t)):[]},dn.uniqWith=function(n,t){return n&&n.length?$t(n,Z,t):[]},dn.unset=function(n,t){var r;if(null==n)r=true;else{r=n;var e=t,e=Er(e,r)?[e+""]:Lt(e);r=Wr(r,e),e=Mr(e),r=null!=r&&Se(r,e)?delete r[e]:true}return r},dn.unzip=Dr,dn.unzipWith=qr,dn.values=Be,dn.valuesIn=function(n){return null==n?w(n,Ue(n)):[]},dn.without=co,dn.words=Me,dn.wrap=function(n,t){return t=null==t?Ne:t,Io(t,n)},dn.xor=ao,dn.xorBy=lo,dn.xorWith=so,
|
|
||||||
dn.zip=ho,dn.zipObject=function(n,t){for(var r=-1,e=n?n.length:0,u=t?t.length:0,o={};++r<e;)St(o,n[r],u>r?t[r]:Z);return o},dn.zipWith=po,dn.each=Gr,dn.eachRight=Vr,dn.extend=Uo,dn.extendWith=zo,qe(dn,dn),dn.add=function(n,t){var r;return n!==Z&&(r=n),t!==Z&&(r=r===Z?t:r+t),r},dn.attempt=Qo,dn.camelCase=Po,dn.capitalize=Le,dn.ceil=ai,dn.clamp=function(n,t,r){return r===Z&&(r=t,t=Z),r!==Z&&(r=Ee(r),r=r===r?r:0),t!==Z&&(t=Ee(t),t=t===t?t:0),Hn(Ee(n),t,r)},dn.clone=function(n){return Qn(n)},dn.cloneDeep=function(n){
|
|
||||||
return Qn(n,true)},dn.cloneDeepWith=function(n,t){return Qn(n,true,t)},dn.cloneWith=function(n,t){return Qn(n,false,t)},dn.deburr=$e,dn.endsWith=function(n,t,r){n=Ie(n),t=typeof t=="string"?t:t+"";var e=n.length;return r=r===Z?e:Hn(Ae(r),0,e),r-=t.length,r>=0&&n.indexOf(t,r)==r},dn.eq=ue,dn.escape=function(n){return(n=Ie(n))&&Y.test(n)?n.replace(V,R):n},dn.escapeRegExp=function(n){return(n=Ie(n))&&un.test(n)?n.replace(en,"\\$&"):n},dn.every=function(n,t,r){var e=Wo(n)?u:rt;return r&&Or(n,t,r)&&(t=Z),e(n,vr(t,3));
|
|
||||||
},dn.find=function(n,t){if(t=vr(t,3),Wo(n)){var r=g(n,t);return r>-1?n[r]:Z}return _(n,t,Nu)},dn.findIndex=function(n,t){return n&&n.length?g(n,vr(t,3)):-1},dn.findKey=function(n,t){return _(n,vr(t,3),it,true)},dn.findLast=function(n,t){if(t=vr(t,3),Wo(n)){var r=g(n,t,true);return r>-1?n[r]:Z}return _(n,t,Zu)},dn.findLastIndex=function(n,t){return n&&n.length?g(n,vr(t,3),true):-1},dn.findLastKey=function(n,t){return _(n,vr(t,3),ft,true)},dn.floor=li,dn.forEach=Gr,dn.forEachRight=Vr,dn.forIn=function(n,t){
|
|
||||||
return null==n?n:Du(n,zr(t),Ue)},dn.forInRight=function(n,t){return null==n?n:qu(n,zr(t),Ue)},dn.forOwn=function(n,t){return n&&it(n,zr(t))},dn.forOwnRight=function(n,t){return n&&ft(n,zr(t))},dn.get=Re,dn.gt=oe,dn.gte=function(n,t){return n>=t},dn.has=Se,dn.hasIn=We,dn.head=Fr,dn.identity=Ne,dn.includes=function(n,t,r,e){return n=fe(n)?n:Be(n),r=r&&!e?Ae(r):0,e=n.length,0>r&&(r=wu(e+r,0)),be(n)?e>=r&&-1<n.indexOf(t,r):!!e&&-1<v(n,t,r)},dn.indexOf=function(n,t,r){var e=n?n.length:0;return e?(r=Ae(r),
|
|
||||||
0>r&&(r=wu(e+r,0)),v(n,t,r)):-1},dn.inRange=function(n,t,r){return t=Ee(t)||0,r===Z?(r=t,t=0):r=Ee(r)||0,n=Ee(n),n>=Au(t,r)&&n<wu(t,r)},dn.invoke=Mo,dn.isArguments=ie,dn.isArray=Wo,dn.isArrayLike=fe,dn.isArrayLikeObject=ce,dn.isBoolean=function(n){return true===n||false===n||_e(n)&&"[object Boolean]"==uu.call(n)},dn.isDate=function(n){return _e(n)&&"[object Date]"==uu.call(n)},dn.isElement=function(n){return!!n&&1===n.nodeType&&_e(n)&&!de(n)},dn.isEmpty=function(n){return!_e(n)||le(n.splice)?!Yr(n):!Ce(n).length;
|
|
||||||
},dn.isEqual=function(n,t){return _t(n,t)},dn.isEqualWith=function(n,t,r){var e=(r=typeof r=="function"?r:Z)?r(n,t):Z;return e===Z?_t(n,t,r):!!e},dn.isError=ae,dn.isFinite=function(n){return typeof n=="number"&&xu(n)},dn.isFunction=le,dn.isInteger=se,dn.isLength=he,dn.isMatch=function(n,t){return n===t||gt(n,t,dr(t))},dn.isMatchWith=function(n,t,r){return r=typeof r=="function"?r:Z,gt(n,t,dr(t),r)},dn.isNaN=function(n){return ve(n)&&n!=+n},dn.isNative=ge,dn.isNil=function(n){return null==n},dn.isNull=function(n){
|
|
||||||
return null===n},dn.isNumber=ve,dn.isObject=pe,dn.isObjectLike=_e,dn.isPlainObject=de,dn.isRegExp=ye,dn.isSafeInteger=function(n){return se(n)&&n>=-9007199254740991&&9007199254740991>=n},dn.isString=be,dn.isSymbol=xe,dn.isTypedArray=me,dn.isUndefined=function(n){return n===Z},dn.join=function(n,t){return n?mu.call(n,t):""},dn.kebabCase=To,dn.last=Mr,dn.lastIndexOf=function(n,t,r){var e=n?n.length:0;if(!e)return-1;var u=e;if(r!==Z&&(u=Ae(r),u=(0>u?wu(e+u,0):Au(u,e-1))+1),t!==t)return W(n,u,true);for(;u--;)if(n[u]===t)return u;
|
|
||||||
return-1},dn.lowerCase=Ko,dn.lowerFirst=Go,dn.lt=je,dn.lte=function(n,t){return t>=n},dn.max=function(n){return n&&n.length?p(n,Ne,oe):Z},dn.maxBy=function(n,t){return n&&n.length?p(n,vr(t),oe):Z},dn.mean=function(n){return Ke(n)/(n?n.length:0)},dn.min=function(n){return n&&n.length?p(n,Ne,je):Z},dn.minBy=function(n,t){return n&&n.length?p(n,vr(t),je):Z},dn.noConflict=function(){return Kn._=ou,this},dn.noop=Pe,dn.now=jo,dn.pad=function(n,t,r){n=Ie(n),t=Ae(t);var e=F(n);return t&&t>e?(e=(t-e)/2,t=bu(e),
|
|
||||||
e=yu(e),ir("",t,r)+n+ir("",e,r)):n},dn.padEnd=function(n,t,r){return n=Ie(n),n+ir(n,t,r)},dn.padStart=function(n,t,r){return n=Ie(n),ir(n,t,r)+n},dn.parseInt=function(n,t,r){return r||null==t?t=0:t&&(t=+t),n=Ie(n).replace(on,""),Ou(n,t||(hn.test(n)?16:10))},dn.random=function(n,t,r){if(r&&typeof r!="boolean"&&Or(n,t,r)&&(t=r=Z),r===Z&&(typeof t=="boolean"?(r=t,t=Z):typeof n=="boolean"&&(r=n,n=Z)),n===Z&&t===Z?(n=0,t=1):(n=Ee(n)||0,t===Z?(t=n,n=0):t=Ee(t)||0),n>t){var e=n;n=t,t=e}return r||n%1||t%1?(r=Eu(),
|
|
||||||
Au(n+r*(t-n+Fn("1e-"+((r+"").length-1))),t)):Rt(n,t)},dn.reduce=function(n,t,r){var e=Wo(n)?l:d,u=3>arguments.length;return e(n,vr(t,4),r,u,Nu)},dn.reduceRight=function(n,t,r){var e=Wo(n)?s:d,u=3>arguments.length;return e(n,vr(t,4),r,u,Zu)},dn.repeat=Fe,dn.replace=function(){var n=arguments,t=Ie(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},dn.result=function(n,t,r){if(Er(t,n))e=null==n?Z:n[t];else{t=Lt(t);var e=Re(n,t);n=Wr(n,t)}return e===Z&&(e=r),le(e)?e.call(n):e},dn.round=si,dn.runInContext=N,
|
|
||||||
dn.sample=function(n){n=fe(n)?n:Be(n);var t=n.length;return t>0?n[Rt(0,t-1)]:Z},dn.size=Yr,dn.snakeCase=Jo,dn.some=function(n,t,r){var e=Wo(n)?h:Ct;return r&&Or(n,t,r)&&(t=Z),e(n,vr(t,3))},dn.sortedIndex=function(n,t){return Ut(n,t)},dn.sortedIndexBy=function(n,t,r){return zt(n,t,vr(r))},dn.sortedIndexOf=function(n,t){var r=n?n.length:0;if(r){var e=Ut(n,t);if(r>e&&ue(n[e],t))return e}return-1},dn.sortedLastIndex=function(n,t){return Ut(n,t,true)},dn.sortedLastIndexBy=function(n,t,r){return zt(n,t,vr(r),true);
|
|
||||||
},dn.sortedLastIndexOf=function(n,t){if(n&&n.length){var r=Ut(n,t,true)-1;if(ue(n[r],t))return r}return-1},dn.startCase=Yo,dn.startsWith=function(n,t,r){return n=Ie(n),r=Hn(Ae(r),0,n.length),n.lastIndexOf(t,r)==r},dn.subtract=function(n,t){var r;return n!==Z&&(r=n),t!==Z&&(r=r===Z?t:r-t),r},dn.sum=Ke,dn.sumBy=function(n,t){return n&&n.length?b(n,vr(t)):Z},dn.template=function(n,t,r){var e=dn.templateSettings;r&&Or(n,t,r)&&(t=Z),n=Ie(n),t=zo({},t,e,Pn),r=zo({},t.imports,e.imports,Pn);var u,o,i=Ce(r),f=w(r,i),c=0;
|
|
||||||
r=t.interpolate||bn;var a="__p+='";r=Ye((t.escape||bn).source+"|"+r.source+"|"+(r===X?ln:bn).source+"|"+(t.evaluate||bn).source+"|$","g");var l="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,i,f,l){return e||(e=i),a+=n.slice(c,l).replace(xn,S),r&&(u=true,a+="'+__e("+r+")+'"),f&&(o=true,a+="';"+f+";\n__p+='"),e&&(a+="'+((__t=("+e+"))==null?'':__t)+'"),c=l+t.length,t}),a+="';",(t=t.variable)||(a="with(obj){"+a+"}"),a=(o?a.replace(P,""):a).replace(T,"$1").replace(K,"$1;"),
|
|
||||||
a="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(u?",__e=_.escape":"")+(o?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+a+"return __p}",t=Qo(function(){return Function(i,l+"return "+a).apply(Z,f)}),t.source=a,ae(t))throw t;return t},dn.times=function(n,t){if(n=Ae(n),1>n||n>9007199254740991)return[];var r=4294967295,e=Au(n,4294967295);for(t=zr(t),n-=4294967295,e=x(e,t);++r<n;)t(r);return e},dn.toInteger=Ae,dn.toLength=Oe,dn.toLower=function(n){
|
|
||||||
return Ie(n).toLowerCase()},dn.toNumber=Ee,dn.toSafeInteger=function(n){return Hn(Ae(n),-9007199254740991,9007199254740991)},dn.toString=Ie,dn.toUpper=function(n){return Ie(n).toUpperCase()},dn.trim=function(n,t,r){return(n=Ie(n))?r||t===Z?n.replace(on,""):(t+="")?(n=n.match(On),t=t.match(On),n.slice(A(n,t),O(n,t)+1).join("")):n:n},dn.trimEnd=function(n,t,r){return(n=Ie(n))?r||t===Z?n.replace(cn,""):(t+="")?(n=n.match(On),n.slice(0,O(n,t.match(On))+1).join("")):n:n},dn.trimStart=function(n,t,r){return(n=Ie(n))?r||t===Z?n.replace(fn,""):(t+="")?(n=n.match(On),
|
|
||||||
n.slice(A(n,t.match(On))).join("")):n:n},dn.truncate=function(n,t){var r=30,e="...";if(pe(t))var u="separator"in t?t.separator:u,r="length"in t?Ae(t.length):r,e="omission"in t?Ie(t.omission):e;n=Ie(n);var o=n.length;if(En.test(n))var i=n.match(On),o=i.length;if(r>=o)return n;if(o=r-F(e),1>o)return e;if(r=i?i.slice(0,o).join(""):n.slice(0,o),u===Z)return r+e;if(i&&(o+=r.length-o),ye(u)){if(n.slice(o).search(u)){var f=r;for(u.global||(u=Ye(u.source,Ie(sn.exec(u))+"g")),u.lastIndex=0;i=u.exec(f);)var c=i.index;
|
|
||||||
r=r.slice(0,c===Z?o:c)}}else n.indexOf(u,o)!=o&&(u=r.lastIndexOf(u),u>-1&&(r=r.slice(0,u)));return r+e},dn.unescape=function(n){return(n=Ie(n))&&J.test(n)?n.replace(G,M):n},dn.uniqueId=function(n){var t=++ru;return Ie(n)+t},dn.upperCase=Ho,dn.upperFirst=Vo,dn.first=Fr,qe(dn,function(){var n={};return it(dn,function(t,r){tu.call(dn.prototype,r)||(n[r]=t)}),n}(),{chain:false}),dn.VERSION="4.0.0",e("bind bindKey curry curryRight partial partialRight".split(" "),function(n){dn[n].placeholder=dn}),e(["drop","take"],function(n,t){
|
|
||||||
wn.prototype[n]=function(r){var e=this.__filtered__;if(e&&!t)return new wn(this);r=r===Z?1:wu(Ae(r),0);var u=this.clone();return e?u.__takeCount__=Au(r,u.__takeCount__):u.__views__.push({size:Au(r,4294967295),type:n+(0>u.__dir__?"Right":"")}),u},wn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),e(["filter","map","takeWhile"],function(n,t){var r=t+1,e=1==r||3==r;wn.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:vr(n,3),type:r}),t.__filtered__=t.__filtered__||e,
|
|
||||||
t}}),e(["head","last"],function(n,t){var r="take"+(t?"Right":"");wn.prototype[n]=function(){return this[r](1).value()[0]}}),e(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");wn.prototype[n]=function(){return this.__filtered__?new wn(this):this[r](1)}}),wn.prototype.compact=function(){return this.filter(Ne)},wn.prototype.find=function(n){return this.filter(n).head()},wn.prototype.findLast=function(n){return this.reverse().find(n)},wn.prototype.invokeMap=ee(function(n,t){return typeof n=="function"?new wn(this):this.map(function(r){
|
|
||||||
return pt(r,n,t)})}),wn.prototype.reject=function(n){return n=vr(n,3),this.filter(function(t){return!n(t)})},wn.prototype.slice=function(n,t){n=Ae(n);var r=this;return r.__filtered__&&(n>0||0>t)?new wn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==Z&&(t=Ae(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},wn.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},wn.prototype.toArray=function(){return this.take(4294967295)},it(wn.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=dn[e?"take"+("last"==t?"Right":""):t],o=e||/^find/.test(t);
|
|
||||||
u&&(dn.prototype[t]=function(){function t(n){return n=u.apply(dn,a([n],f)),e&&h?n[0]:n}var i=this.__wrapped__,f=e?[1]:arguments,c=i instanceof wn,l=f[0],s=c||Wo(i);s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false);var h=this.__chain__,p=!!this.__actions__.length,l=o&&!h,c=c&&!p;return!o&&s?(i=c?i:new wn(this),i=n.apply(i,f),i.__actions__.push({func:Tr,args:[t],thisArg:Z}),new jn(i,h)):l&&c?n.apply(this,f):(i=this.thru(t),l?e?i.value()[0]:i.value():i)})}),e("pop push shift sort splice unshift".split(" "),function(n){
|
|
||||||
var t=Qe[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);dn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),it(wn.prototype,function(n,t){var r=dn[t];if(r){var e=r.name+"";(Fu[e]||(Fu[e]=[])).push({name:t,func:r})}}),Fu[ur(Z,2).name]=[{name:"wrapper",func:Z}],wn.prototype.clone=function(){var n=new wn(this.__wrapped__);return n.__actions__=Pt(this.__actions__),n.__dir__=this.__dir__,
|
|
||||||
n.__filtered__=this.__filtered__,n.__iteratees__=Pt(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Pt(this.__views__),n},wn.prototype.reverse=function(){if(this.__filtered__){var n=new wn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},wn.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=Wo(t),u=0>r,o=e?t.length:0;n=o;for(var i=this.__views__,f=0,c=-1,a=i.length;++c<a;){var l=i[c],s=l.size;switch(l.type){case"drop":f+=s;
|
|
||||||
break;case"dropRight":n-=s;break;case"take":n=Au(n,f+s);break;case"takeRight":f=wu(f,n-s)}}if(n={start:f,end:n},i=n.start,f=n.end,n=f-i,u=u?f:i-1,i=this.__iteratees__,f=i.length,c=0,a=Au(n,this.__takeCount__),!e||200>o||o==n&&a==n)return Mt(t,this.__actions__);e=[];n:for(;n--&&a>c;){for(u+=r,o=-1,l=t[u];++o<f;){var h=i[o],s=h.type,h=(0,h.iteratee)(l);if(2==s)l=h;else if(!h){if(1==s)continue n;break n}}e[c++]=l}return e},dn.prototype.at=_o,dn.prototype.chain=function(){return Pr(this)},dn.prototype.commit=function(){
|
|
||||||
return new jn(this.value(),this.__chain__)},dn.prototype.flatMap=function(n){return this.map(n).flatten()},dn.prototype.next=function(){this.__values__===Z&&(this.__values__=we(this.value()));var n=this.__index__>=this.__values__.length,t=n?Z:this.__values__[this.__index__++];return{done:n,value:t}},dn.prototype.plant=function(n){for(var t,r=this;r instanceof mn;){var e=Br(r);e.__index__=0,e.__values__=Z,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},dn.prototype.reverse=function(){
|
|
||||||
var n=this.__wrapped__;return n instanceof wn?(this.__actions__.length&&(n=new wn(this)),n=n.reverse(),n.__actions__.push({func:Tr,args:[Zr],thisArg:Z}),new jn(n,this.__chain__)):this.thru(Zr)},dn.prototype.toJSON=dn.prototype.valueOf=dn.prototype.value=function(){return Mt(this.__wrapped__,this.__actions__)},_u&&(dn.prototype[_u]=Kr),dn}var Z,D=1/0,q=NaN,P=/\b__p\+='';/g,T=/\b(__p\+=)''\+/g,K=/(__e\(.*?\)|\b__t\))\+'';/g,G=/&(?:amp|lt|gt|quot|#39|#96);/g,V=/[&<>"'`]/g,J=RegExp(G.source),Y=RegExp(V.source),H=/<%-([\s\S]+?)%>/g,Q=/<%([\s\S]+?)%>/g,X=/<%=([\s\S]+?)%>/g,nn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,tn=/^\w*$/,rn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g,en=/[\\^$.*+?()[\]{}|]/g,un=RegExp(en.source),on=/^\s+|\s+$/g,fn=/^\s+/,cn=/\s+$/,an=/\\(\\)?/g,ln=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,sn=/\w*$/,hn=/^0x/i,pn=/^[-+]0x[0-9a-f]+$/i,_n=/^0b[01]+$/i,gn=/^\[object .+?Constructor\]$/,vn=/^0o[0-7]+$/i,dn=/^(?:0|[1-9]\d*)$/,yn=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,bn=/($^)/,xn=/['\n\r\u2028\u2029\\]/g,mn="[\\ufe0e\\ufe0f]?(?:\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:\\ud83c[\\udffb-\\udfff])?)*",jn="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+mn,wn="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe23]?|[\\u0300-\\u036f\\ufe20-\\ufe23]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",An=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe23]","g"),On=RegExp(wn+mn,"g"),En=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe23\\ufe0e\\ufe0f]"),kn=/[a-zA-Z0-9]+/g,In=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+|\\d+(?:(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2018\\u2019\\u201c\\u201d \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+)?",jn].join("|"),"g"),Rn=/[a-z][A-Z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Sn="Array Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Reflect RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Wn={};
|
|
||||||
Wn["[object Float32Array]"]=Wn["[object Float64Array]"]=Wn["[object Int8Array]"]=Wn["[object Int16Array]"]=Wn["[object Int32Array]"]=Wn["[object Uint8Array]"]=Wn["[object Uint8ClampedArray]"]=Wn["[object Uint16Array]"]=Wn["[object Uint32Array]"]=true,Wn["[object Arguments]"]=Wn["[object Array]"]=Wn["[object ArrayBuffer]"]=Wn["[object Boolean]"]=Wn["[object Date]"]=Wn["[object Error]"]=Wn["[object Function]"]=Wn["[object Map]"]=Wn["[object Number]"]=Wn["[object Object]"]=Wn["[object RegExp]"]=Wn["[object Set]"]=Wn["[object String]"]=Wn["[object WeakMap]"]=false;
|
|
||||||
var Cn={};Cn["[object Arguments]"]=Cn["[object Array]"]=Cn["[object ArrayBuffer]"]=Cn["[object Boolean]"]=Cn["[object Date]"]=Cn["[object Float32Array]"]=Cn["[object Float64Array]"]=Cn["[object Int8Array]"]=Cn["[object Int16Array]"]=Cn["[object Int32Array]"]=Cn["[object Map]"]=Cn["[object Number]"]=Cn["[object Object]"]=Cn["[object RegExp]"]=Cn["[object Set]"]=Cn["[object String]"]=Cn["[object Symbol]"]=Cn["[object Uint8Array]"]=Cn["[object Uint8ClampedArray]"]=Cn["[object Uint16Array]"]=Cn["[object Uint32Array]"]=true,
|
|
||||||
Cn["[object Error]"]=Cn["[object Function]"]=Cn["[object WeakMap]"]=false;var Un={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O",
|
|
||||||
"\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss"},zn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Bn={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},Ln={"function":true,object:true},$n={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"
|
|
||||||
},Fn=parseFloat,Mn=parseInt,Nn=Ln[typeof exports]&&exports&&!exports.nodeType?exports:null,Zn=Ln[typeof module]&&module&&!module.nodeType?module:null,Dn=E(Ln[typeof self]&&self),qn=E(Ln[typeof window]&&window),Pn=Zn&&Zn.exports===Nn?Nn:null,Tn=E(Ln[typeof this]&&this),Kn=E(Nn&&Zn&&typeof global=="object"&&global)||qn!==(Tn&&Tn.window)&&qn||Dn||Tn||Function("return this")(),Gn=N();(qn||Dn||{})._=Gn,typeof define=="function"&&typeof define.amd=="object"&&define.amd? define(function(){return Gn}):Nn&&Zn?(Pn&&((Zn.exports=Gn)._=Gn),
|
|
||||||
Nn._=Gn):Kn._=Gn}).call(this);
|
|
1
kfet/static/kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js
vendored
Normal file
1
kfet/static/kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -31,28 +31,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside>
|
|
||||||
<div class="heading">
|
|
||||||
{{ positive_count }}
|
|
||||||
<span class="sub">compte{{ positive_count|pluralize }} en positif</span>
|
|
||||||
</div>
|
|
||||||
<div class="heading">
|
|
||||||
{{ positives_sum|floatformat:2 }}€
|
|
||||||
<span class="sub">de positif total</span>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<aside>
|
|
||||||
<div class="heading">
|
|
||||||
{{ negative_count }}
|
|
||||||
<span class="sub">compte{{ negative_count|pluralize }} en négatif</span>
|
|
||||||
</div>
|
|
||||||
<div class="heading">
|
|
||||||
{{ negatives_sum|floatformat:2 }}€
|
|
||||||
<span class="sub">de négatif total</span>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
|
@ -60,7 +60,8 @@
|
||||||
$('#id_trigramme').on('input', function() {
|
$('#id_trigramme').on('input', function() {
|
||||||
var trigramme = $('#id_trigramme').val().toUpperCase();
|
var trigramme = $('#id_trigramme').val().toUpperCase();
|
||||||
|
|
||||||
if (!(trigramme.is_valid_trigramme())) {
|
var pattern = /^[^a-z]{3}$/;
|
||||||
|
if (!(trigramme.match(pattern))) {
|
||||||
$('#id_trigramme')
|
$('#id_trigramme')
|
||||||
.css('background', '#fff')
|
.css('background', '#fff')
|
||||||
.css('color', '#000');
|
.css('color', '#000');
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/fr.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/fr.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||||
{% if account.user == request.user %}
|
{% if account.user == request.user %}
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/Chart.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/Chart.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/statistic.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/statistic.js' %}"></script>
|
||||||
|
|
|
@ -34,7 +34,6 @@ Modification de mes informations
|
||||||
{% include 'kfet/form_snippet.html' with form=account_form %}
|
{% include 'kfet/form_snippet.html' with form=account_form %}
|
||||||
{% include 'kfet/form_snippet.html' with form=frozen_form %}
|
{% include 'kfet/form_snippet.html' with form=frozen_form %}
|
||||||
{% include 'kfet/form_snippet.html' with form=group_form %}
|
{% include 'kfet/form_snippet.html' with form=group_form %}
|
||||||
{% include 'kfet/form_snippet.html' with form=cof_form %}
|
|
||||||
{% include 'kfet/form_snippet.html' with form=pwd_form %}
|
{% include 'kfet/form_snippet.html' with form=pwd_form %}
|
||||||
|
|
||||||
{% include 'kfet/form_authentication_snippet.html' %}
|
{% include 'kfet/form_authentication_snippet.html' %}
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
<td class="text-right">Prix</td>
|
<td class="text-right">Prix</td>
|
||||||
<td class="text-right">Stock</td>
|
<td class="text-right">Stock</td>
|
||||||
<td class="text-right" data-sorter="article__is_sold">En vente</td>
|
<td class="text-right" data-sorter="article__is_sold">En vente</td>
|
||||||
<td class="text-right" data-sorter="article__is_no_exte">Reservé aux adhérent⋅e⋅s</td>
|
|
||||||
<td class="text-right" data-sorter="article__hidden">Affiché</td>
|
<td class="text-right" data-sorter="article__hidden">Affiché</td>
|
||||||
<td class="text-right" data-sorter="shortDate">Dernier inventaire</td>
|
<td class="text-right" data-sorter="shortDate">Dernier inventaire</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -64,7 +63,6 @@
|
||||||
<td class="text-right">{{ article.price }}€</td>
|
<td class="text-right">{{ article.price }}€</td>
|
||||||
<td class="text-right">{{ article.stock }}</td>
|
<td class="text-right">{{ article.stock }}</td>
|
||||||
<td class="text-right">{{ article.is_sold | yesno:"En vente,Non vendu"}}</td>
|
<td class="text-right">{{ article.is_sold | yesno:"En vente,Non vendu"}}</td>
|
||||||
<td class="text-right">{{ article.no_exte | yesno:"Réservé,Non réservé"}}</td>
|
|
||||||
<td class="text-right">{{ article.hidden | yesno:"Caché,Affiché" }}</td>
|
<td class="text-right">{{ article.hidden | yesno:"Caché,Affiché" }}</td>
|
||||||
{% with last_inventory=article.inventory.0 %}
|
{% with last_inventory=article.inventory.0 %}
|
||||||
<td class="text-right" title="{{ last_inventory.at }}">
|
<td class="text-right" title="{{ last_inventory.at }}">
|
||||||
|
@ -90,7 +88,6 @@
|
||||||
<td class="text-right">Prix</td>
|
<td class="text-right">Prix</td>
|
||||||
<td class="text-right">Stock</td>
|
<td class="text-right">Stock</td>
|
||||||
<td class="text-right" data-sorter="article__is_sold">En vente</td>
|
<td class="text-right" data-sorter="article__is_sold">En vente</td>
|
||||||
<td class="text-right" data-sorter="article__is_no_exte">Reservé aux adhérent⋅e⋅s</td>
|
|
||||||
<td class="text-right" data-sorter="article__hidden">Affiché</td>
|
<td class="text-right" data-sorter="article__hidden">Affiché</td>
|
||||||
<td class="text-right" data-sorter="shortDate">Dernier inventaire</td>
|
<td class="text-right" data-sorter="shortDate">Dernier inventaire</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -114,7 +111,6 @@
|
||||||
<td class="text-right">{{ article.price }}€</td>
|
<td class="text-right">{{ article.price }}€</td>
|
||||||
<td class="text-right">{{ article.stock }}</td>
|
<td class="text-right">{{ article.stock }}</td>
|
||||||
<td class="text-right">{{ article.is_sold | yesno:"En vente,Non vendu"}}</td>
|
<td class="text-right">{{ article.is_sold | yesno:"En vente,Non vendu"}}</td>
|
||||||
<td class="text-right">{{ article.no_exte | yesno:"Réservé,Non réservé"}}</td>
|
|
||||||
<td class="text-right">{{ article.hidden | yesno:"Caché,Affiché" }}</td>
|
<td class="text-right">{{ article.hidden | yesno:"Caché,Affiché" }}</td>
|
||||||
{% with last_inventory=article.inventory.0 %}
|
{% with last_inventory=article.inventory.0 %}
|
||||||
<td class="text-right" title="{{ last_inventory.at }}">
|
<td class="text-right" title="{{ last_inventory.at }}">
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
<li><b>Stock:</b> {{ article.stock }}</li>
|
<li><b>Stock:</b> {{ article.stock }}</li>
|
||||||
<li><b>En vente:</b> {{ article.is_sold|yesno|title }}</li>
|
<li><b>En vente:</b> {{ article.is_sold|yesno|title }}</li>
|
||||||
<li><b>Affiché:</b> {{ article.hidden|yesno|title }}</li>
|
<li><b>Affiché:</b> {{ article.hidden|yesno|title }}</li>
|
||||||
<li><b>Réservé aux adhérent⋅e⋅s:</b> {{ article.no_exte|yesno|title }}</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/index.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/index.css' %}">
|
||||||
|
|
||||||
{# JS #}
|
{# JS #}
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/lodash.min.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/js.cookie.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/js.cookie.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'vendor/jquery/jquery-3.3.1.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'vendor/jquery/jquery-3.3.1.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'vendor/bootstrap/js/bootstrap.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'vendor/bootstrap/js/bootstrap.min.js' %}"></script>
|
||||||
|
@ -30,17 +29,6 @@
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/fr.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/fr.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/kfet.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/kfet.js' %}"></script>
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('.trigramme_field').map(function() {
|
|
||||||
elt = $(this);
|
|
||||||
elt.attr('maxlength','');
|
|
||||||
elt.on('input', function() {
|
|
||||||
elt.val(elt.val().format_trigramme());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% include "kfetopen/init.html" %}
|
{% include "kfetopen/init.html" %}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
{% load wagtailcore_tags %}
|
{% load wagtailcore_tags %}
|
||||||
|
|
||||||
|
{% with "k-fet@ens.fr" as kfet_mail %}
|
||||||
|
|
||||||
<footer class="row">
|
<footer class="row">
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<span>
|
<span>
|
||||||
<b><a href="{% url "kfet.contact" %}">Formulaire de contact</a></b>
|
<a href="{% slugurl "mentions-legales" %}">Mentions légales</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
|
||||||
<span>
|
<span>
|
||||||
<a href="{% slugurl "mentions-legales" %}">Mentions légales</a>
|
En cas de pépin : <a href="mailto:{{ kfet_mail }}"><tt>{{ kfet_mail }}</tt></a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</div>
|
||||||
|
|
||||||
|
{% endwith %}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
<b><span class="status-text">
|
<b><span class="status-text">
|
||||||
<span class="glyphicon glyphicon-refresh spinning"></span>
|
<span class="glyphicon glyphicon-refresh spinning"></span>
|
||||||
</span></b>.
|
</span></b>.
|
||||||
<br/><a href="{% url 'kfet.open.indicator' %}">Grand indicateur</a>
|
|
||||||
{% if perms.kfet.is_team %}
|
{% if perms.kfet.is_team %}
|
||||||
<button class="btn btn-primary force-close-btn"> </button>
|
<button class="btn btn-primary force-close-btn"> </button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
{% extends "kfet/base_form.html" %}
|
|
||||||
|
|
||||||
{% block extra_head %}
|
|
||||||
{{ negative_form.media }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Contacter la K-Fêt
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block header-title %}
|
|
||||||
Contacter la K-Fêt
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block footer %}
|
|
||||||
{% include "kfet/base_footer.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
|
|
||||||
<div class="messages">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<b>Votre message sera envoyé aux Chef·fe·s et aux Wo·men K-Fêt.</b>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<form action="" method="post" class="form-horizontal" autocomplete="off">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% include 'kfet/form_snippet.html' %}
|
|
||||||
|
|
||||||
{% include 'kfet/form_submit_snippet.html' with value="Envoyer" %}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,28 +0,0 @@
|
||||||
{% extends "kfet/base_form.html" %}
|
|
||||||
|
|
||||||
{% block extra_head %}
|
|
||||||
{{ negative_form.media }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Effectuer une demande de soirée
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block header-title %}
|
|
||||||
Effectuer une demande de soirée
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block footer %}
|
|
||||||
{% include "kfet/base_footer.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
|
|
||||||
<form action="" method="post" class="form-horizontal" autocomplete="off">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% include 'kfet/form_snippet.html' %}
|
|
||||||
|
|
||||||
{% include 'kfet/form_submit_snippet.html' with value="Envoyer" %}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -7,7 +7,7 @@
|
||||||
{{ filter_form.media }}
|
{{ filter_form.media }}
|
||||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}Historique{% endblock %}
|
{% block title %}Historique{% endblock %}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<link rel="stylesheet" style="text/css" href="{% static 'kfet/css/kpsul_grid.css' %}">
|
<link rel="stylesheet" style="text/css" href="{% static 'kfet/css/kpsul_grid.css' %}">
|
||||||
<script type="text/javascript" src="{% static 'vendor/jquery/jquery.autocomplete-light.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'vendor/jquery/jquery.autocomplete-light.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/underscore-min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/underscore-min.js' %}"></script>
|
||||||
|
@ -397,8 +397,8 @@ $(document).ready(function() {
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
var articles_container = $('#articles_data tbody');
|
var articles_container = $('#articles_data tbody');
|
||||||
var article_category_default_html = '<tr class="category"><td colspan="4"></td></tr>';
|
var article_category_default_html = '<tr class="category"><td colspan="3"></td></tr>';
|
||||||
var article_default_html = '<tr class="article"><td class="name"></td><td class="price"></td><td class="no_exte"></td><td class="stock" style="width: 0;white-space: nowrap;"></td></tr>';
|
var article_default_html = '<tr class="article"><td class="name"></td><td class="price"></td><td class="stock"></td></tr>';
|
||||||
|
|
||||||
function addArticle(article) {
|
function addArticle(article) {
|
||||||
var article_html = $(article_default_html);
|
var article_html = $(article_default_html);
|
||||||
|
@ -411,7 +411,6 @@ $(document).ready(function() {
|
||||||
article_html.addClass('low-stock');
|
article_html.addClass('low-stock');
|
||||||
}
|
}
|
||||||
article_html.find('.price').text(amountToUKF(article['price'], false, false)+' UKF');
|
article_html.find('.price').text(amountToUKF(article['price'], false, false)+' UKF');
|
||||||
article_html.find('.no_exte').text(article['no_exte'] ? "Réservé aux adhérent⋅e⋅s" : "");
|
|
||||||
var category_html = articles_container
|
var category_html = articles_container
|
||||||
.find('#data-category-'+article['category_id']);
|
.find('#data-category-'+article['category_id']);
|
||||||
if (category_html.length == 0) {
|
if (category_html.length == 0) {
|
||||||
|
|
|
@ -43,9 +43,7 @@
|
||||||
<li>
|
<li>
|
||||||
{% if account.is_cof %}
|
{% if account.is_cof %}
|
||||||
<span title="Réduction de {{ kfet_config.reduction_cof }} % sur tes commandes" data-toggle="tooltip"
|
<span title="Réduction de {{ kfet_config.reduction_cof }} % sur tes commandes" data-toggle="tooltip"
|
||||||
data-placement="right">Membre COF</span>
|
data-placement="right">Adhérent COF</span>
|
||||||
{% elif account.is_kfet %}
|
|
||||||
Membre K-Fêt
|
|
||||||
{% else %}
|
{% else %}
|
||||||
Non-COF
|
Non-COF
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
Salut {{ account.name }},
|
|
||||||
|
|
||||||
Ton compte K-Fêt a bien été créé le {{ account.created_at }} avec le trigramme {{ account.trigramme }}.
|
|
||||||
|
|
||||||
Tu peux désormais :
|
|
||||||
- Accéder à ton historique personnel des consommations : https://{{ site }}{{ url_read }}
|
|
||||||
- Modifier tes informations : https://{{ site }}{{ url_update }}
|
|
||||||
- Supprimer ton compte : https://{{ site }}{{ url_delete }}
|
|
||||||
|
|
||||||
En espérant te revoir bientôt,
|
|
||||||
--
|
|
||||||
L'équipe K-Fêt
|
|
|
@ -1,16 +0,0 @@
|
||||||
Bonjour,
|
|
||||||
|
|
||||||
J'aimerais organiser une soirée le {{ date }}, au thème « {{ theme|safe }} », en K-Fêt.
|
|
||||||
Elle se terminerait à {{ horaire_fin }}, et le service serait en mode {{ service }}.
|
|
||||||
|
|
||||||
Les 4 responsables de la soirée seraient :
|
|
||||||
- {{ respo1 }}
|
|
||||||
- {{ respo2 }}
|
|
||||||
- {{ respo3 }}
|
|
||||||
- {{ respo4 }}
|
|
||||||
|
|
||||||
Quelques remarques supplémentaires :
|
|
||||||
{{ remarques|safe }}
|
|
||||||
|
|
||||||
Bien cordialement,
|
|
||||||
{{ nom|safe }}
|
|
|
@ -7,20 +7,11 @@
|
||||||
{% block main-size %}col-lg-8 col-lg-offset-2{% endblock %}
|
{% block main-size %}col-lg-8 col-lg-offset-2{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="form-horizontal">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="nb_weeks" class="control-label col-sm-10">Nombre de semaines</label>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
<input type="number" name="nb_weeks" id="nb_weeks" spellcheck="false" value="1" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table
|
<table
|
||||||
id="#new-order-table"
|
|
||||||
class="table table-hover table-condensed table-condensed-input text-center table-striped sortable"
|
class="table table-hover table-condensed table-condensed-input text-center table-striped sortable"
|
||||||
{# Initial sort: [(name,asc)] #}
|
{# Initial sort: [(name,asc)] #}
|
||||||
data-sortlist="[[0,0]]">
|
data-sortlist="[[0,0]]">
|
||||||
|
@ -34,7 +25,7 @@
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
V. moy.
|
V. moy.
|
||||||
<br>
|
<br>
|
||||||
<i class='glyphicon glyphicon-question-sign' title="Moyenne des ventes<br>sur les trois semaines les plus élevées" data-placement="bottom"></i>
|
<i class='glyphicon glyphicon-question-sign' title="Moyenne des ventes" data-placement="bottom"></i>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2" data-sorter="false">
|
<td rowspan="2" data-sorter="false">
|
||||||
E.T.
|
E.T.
|
||||||
|
@ -44,7 +35,7 @@
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
Prév.
|
Prév.
|
||||||
<br>
|
<br>
|
||||||
<i class='glyphicon glyphicon-question-sign' title="Prévision de ventes<br>moyenne + écart-type" data-placement="bottom"></i>
|
<i class='glyphicon glyphicon-question-sign' title="Prévision de ventes" data-placement="bottom"></i>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2">Stock</td>
|
<td rowspan="2">Stock</td>
|
||||||
<td rowspan="2" data-sorter="false">
|
<td rowspan="2" data-sorter="false">
|
||||||
|
@ -55,7 +46,7 @@
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
Rec.
|
Rec.
|
||||||
<br>
|
<br>
|
||||||
<i class='glyphicon glyphicon-question-sign' title="Quantité conseillée<br>(Prév. * Nb_semaines - stock) / (capacité d'une boîte)" data-placement="bottom"></i>
|
<i class='glyphicon glyphicon-question-sign' title="Quantité conseillée" data-placement="bottom"></i>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2" data-sorter="false" class="small-width">
|
<td rowspan="2" data-sorter="false" class="small-width">
|
||||||
Commande
|
Commande
|
||||||
|
@ -83,7 +74,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for form in category.list %}
|
{% for form in category.list %}
|
||||||
<tr class="article-row">
|
<tr>
|
||||||
{{ form.article }}
|
{{ form.article }}
|
||||||
<td class="text-left">{{ form.name }}</td>
|
<td class="text-left">{{ form.name }}</td>
|
||||||
{% for v_chunk in form.v_all %}
|
{% for v_chunk in form.v_all %}
|
||||||
|
@ -91,10 +82,10 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<td>{{ form.v_moy }}</td>
|
<td>{{ form.v_moy }}</td>
|
||||||
<td>{{ form.v_et }}</td>
|
<td>{{ form.v_et }}</td>
|
||||||
<td class="prev-1w">{{ form.v_prev }}</td>
|
<td>{{ form.v_prev }}</td>
|
||||||
<td class="stock">{{ form.stock }}</td>
|
<td>{{ form.stock }}</td>
|
||||||
<td class="capacity">{{ form.box_capacity|default:"" }}</td>
|
<td>{{ form.box_capacity|default:"" }}</td>
|
||||||
<td class="recommended">{{ form.c_rec_1w }}</td>
|
<td>{{ form.c_rec }}</td>
|
||||||
<td class="nopadding">{{ form.quantity_ordered|add_class:"form-control" }}</td>
|
<td class="nopadding">{{ form.quantity_ordered|add_class:"form-control" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -116,42 +107,6 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.glyphicon-question-sign').tooltip({'html': true}) ;
|
$('.glyphicon-question-sign').tooltip({'html': true}) ;
|
||||||
});
|
});
|
||||||
|
|
||||||
function compute_recommended(nb_weeks, prevision_1w, stock, box_capacity) {
|
|
||||||
if (!box_capacity) box_capacity = 1;
|
|
||||||
return Math.ceil(Math.max(Number(nb_weeks) * Number(prevision_1w) - Math.max(Number(stock), 0), 0) / Number(box_capacity))
|
|
||||||
}
|
|
||||||
|
|
||||||
function reload_recommended(nb_weeks) {
|
|
||||||
$(".article-row").each(function () {
|
|
||||||
const article_row = $(this)
|
|
||||||
article_row.find(".recommended").text(compute_recommended(nb_weeks, article_row.find(".prev-1w").text(),
|
|
||||||
article_row.find(".stock").text(),
|
|
||||||
article_row.find(".capacity").text()
|
|
||||||
));
|
|
||||||
})
|
|
||||||
$("#new-order-table").trigger("updateAll", [true, () => {
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#nb_weeks").on("change", function (e) {
|
|
||||||
const nb_weeks = e.target.value;
|
|
||||||
reload_recommended(nb_weeks);
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
#nb_weeks {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
-moz-appearance: revert;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nb_weeks::-webkit-inner-spin-button,
|
|
||||||
#nb_weeks::-webkit-outer-spin-button {
|
|
||||||
-webkit-appearance: revert;
|
|
||||||
margin: revert;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block fixed %}
|
{% block fixed %}
|
||||||
|
|
|
@ -35,12 +35,12 @@
|
||||||
<tr class="transfer_form" id="{{ form.prefix }}">
|
<tr class="transfer_form" id="{{ form.prefix }}">
|
||||||
<td class="from_acc_data"></td>
|
<td class="from_acc_data"></td>
|
||||||
<td class="from_acc">
|
<td class="from_acc">
|
||||||
<input type="text" name="from_acc" class="input_from_acc" autocomplete="off" spellcheck="false">
|
<input type="text" name="from_acc" class="input_from_acc" maxlength="3" autocomplete="off" spellcheck="false">
|
||||||
{{ form.from_acc }}
|
{{ form.from_acc }}
|
||||||
</td>
|
</td>
|
||||||
<td class="amount">{{ form.amount }}</td>
|
<td class="amount">{{ form.amount }}</td>
|
||||||
<td class="to_acc">
|
<td class="to_acc">
|
||||||
<input type="text" name="to_acc" class="input_to_acc" autocomplete="off" spellcheck="false">
|
<input type="text" name="to_acc" class="input_to_acc" maxlength="3" autocomplete="off" spellcheck="false">
|
||||||
{{ form.to_acc }}
|
{{ form.to_acc }}
|
||||||
</td>
|
</td>
|
||||||
<td class="to_acc_data"></td>
|
<td class="to_acc_data"></td>
|
||||||
|
@ -91,8 +91,7 @@ $(document).ready(function () {
|
||||||
|
|
||||||
$(document).on("input", '.input_from_acc, .input_to_acc', function(e) {
|
$(document).on("input", '.input_from_acc, .input_to_acc', function(e) {
|
||||||
var target = $(e.target)
|
var target = $(e.target)
|
||||||
var tri = target.val().format_trigramme();
|
var tri = target.val().toUpperCase();
|
||||||
target.val(tri);
|
|
||||||
updateAccountData(tri, target);
|
updateAccountData(tri, target);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,6 @@ register_converter(converters.TrigrammeConverter, "trigramme")
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("login/generic", views.login_generic, name="kfet.login.generic"),
|
path("login/generic", views.login_generic, name="kfet.login.generic"),
|
||||||
path("history", views.history, name="kfet.history"),
|
path("history", views.history, name="kfet.history"),
|
||||||
path("contact", views.ContactView.as_view(), name="kfet.contact"),
|
|
||||||
path(
|
|
||||||
"demande-soiree", views.DemandeSoireeView.as_view(), name="kfet.demande-soiree"
|
|
||||||
),
|
|
||||||
# -----
|
# -----
|
||||||
# Account urls
|
# Account urls
|
||||||
# -----
|
# -----
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
@ -72,6 +71,9 @@ class DjangoJsonWebsocketConsumer(AsyncJsonWebsocketConsumer):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def encode_json(cls, content):
|
async def encode_json(cls, content):
|
||||||
|
# Remove the type value, only used by Channels to choose the group to send to
|
||||||
|
content.pop("type")
|
||||||
|
|
||||||
return json.dumps(content, cls=DjangoJSONEncoder)
|
return json.dumps(content, cls=DjangoJSONEncoder)
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ class PermConsumerMixin:
|
||||||
"""Check permissions on connection."""
|
"""Check permissions on connection."""
|
||||||
self.user = self.scope["user"]
|
self.user = self.scope["user"]
|
||||||
|
|
||||||
if await sync_to_async(self.user.has_perms)(self.perms_connect):
|
if self.user.has_perms(self.perms_connect):
|
||||||
await super().connect()
|
await super().connect()
|
||||||
else:
|
else:
|
||||||
await self.close()
|
await self.close()
|
||||||
|
|
139
kfet/views.py
139
kfet/views.py
|
@ -13,7 +13,6 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.contrib.auth.models import Permission, User
|
from django.contrib.auth.models import Permission, User
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
from django.core.mail import EmailMessage
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
Count,
|
Count,
|
||||||
|
@ -35,7 +34,6 @@ from django.http import (
|
||||||
JsonResponse,
|
JsonResponse,
|
||||||
)
|
)
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.template import loader
|
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
@ -66,9 +64,6 @@ from kfet.forms import (
|
||||||
CheckoutStatementCreateForm,
|
CheckoutStatementCreateForm,
|
||||||
CheckoutStatementUpdateForm,
|
CheckoutStatementUpdateForm,
|
||||||
CofForm,
|
CofForm,
|
||||||
CofKFForm,
|
|
||||||
ContactForm,
|
|
||||||
DemandeSoireeForm,
|
|
||||||
FilterHistoryForm,
|
FilterHistoryForm,
|
||||||
InventoryArticleForm,
|
InventoryArticleForm,
|
||||||
KFetConfigForm,
|
KFetConfigForm,
|
||||||
|
@ -119,61 +114,6 @@ def put_cleaned_data_in_dict(dict, form):
|
||||||
dict[field] = form.cleaned_data[field]
|
dict[field] = form.cleaned_data[field]
|
||||||
|
|
||||||
|
|
||||||
class ContactView(FormView):
|
|
||||||
template_name = "kfet/contact.html"
|
|
||||||
form_class = ContactForm
|
|
||||||
success_url = reverse_lazy("kfet.contact")
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
# Envoie un mail lorsque le formulaire est valide
|
|
||||||
EmailMessage(
|
|
||||||
form.cleaned_data["subject"],
|
|
||||||
form.cleaned_data["message"],
|
|
||||||
from_email=form.cleaned_data["from_email"],
|
|
||||||
to=("chefs-k-fet@ens.psl.eu",),
|
|
||||||
).send()
|
|
||||||
|
|
||||||
messages.success(
|
|
||||||
self.request,
|
|
||||||
"Votre message a bien été envoyé aux Wo·men K-Fêt.",
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
class DemandeSoireeView(FormView):
|
|
||||||
template_name = "kfet/demande_soiree.html"
|
|
||||||
form_class = DemandeSoireeForm
|
|
||||||
success_url = reverse_lazy("kfet.demande-soiree")
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
destinataires = ["chefs-k-fet@ens.psl.eu"]
|
|
||||||
|
|
||||||
if form.cleaned_data["contact_boum"]:
|
|
||||||
destinataires.append("boum@ens.psl.eu")
|
|
||||||
|
|
||||||
if form.cleaned_data["contact_pls"]:
|
|
||||||
destinataires.append("pls@ens.psl.eu")
|
|
||||||
|
|
||||||
# Envoie un mail lorsque le formulaire est valide
|
|
||||||
EmailMessage(
|
|
||||||
f"Demande de soirée le {form.cleaned_data['date']}",
|
|
||||||
loader.render_to_string(
|
|
||||||
"kfet/mails/demande_soiree.txt", context=form.cleaned_data
|
|
||||||
),
|
|
||||||
from_email=form.cleaned_data["from_email"],
|
|
||||||
to=destinataires,
|
|
||||||
cc=[form.cleaned_data["from_email"]],
|
|
||||||
).send()
|
|
||||||
|
|
||||||
messages.success(
|
|
||||||
self.request,
|
|
||||||
"Votre demande de soirée a bien été envoyée.",
|
|
||||||
)
|
|
||||||
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Account views
|
# Account views
|
||||||
# -----
|
# -----
|
||||||
|
@ -185,20 +125,7 @@ class DemandeSoireeView(FormView):
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def account(request):
|
def account(request):
|
||||||
accounts = Account.objects.select_related("cofprofile__user").order_by("trigramme")
|
accounts = Account.objects.select_related("cofprofile__user").order_by("trigramme")
|
||||||
positive_accounts = Account.objects.filter(balance__gte=0).exclude(trigramme="#13")
|
return render(request, "kfet/account.html", {"accounts": accounts})
|
||||||
negative_accounts = Account.objects.filter(balance__lt=0).exclude(trigramme="#13")
|
|
||||||
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"kfet/account.html",
|
|
||||||
{
|
|
||||||
"accounts": accounts,
|
|
||||||
"positive_count": positive_accounts.count(),
|
|
||||||
"positives_sum": sum(acc.balance for acc in positive_accounts),
|
|
||||||
"negative_count": negative_accounts.count(),
|
|
||||||
"negatives_sum": sum(acc.balance for acc in negative_accounts),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -257,13 +184,7 @@ def account_create(request):
|
||||||
account = trigramme_form.save(data=data)
|
account = trigramme_form.save(data=data)
|
||||||
account_form = AccountNoTriForm(request.POST, instance=account)
|
account_form = AccountNoTriForm(request.POST, instance=account)
|
||||||
account_form.save()
|
account_form.save()
|
||||||
was_kfet = account.is_kfet
|
|
||||||
account.cofprofile.is_kfet = cof_form.cleaned_data["is_kfet"]
|
|
||||||
account.cofprofile.save()
|
|
||||||
if account.cofprofile.is_kfet:
|
|
||||||
account.cofprofile.make_adh_kfet(request, was_kfet)
|
|
||||||
messages.success(request, "Compte créé : %s" % account.trigramme)
|
messages.success(request, "Compte créé : %s" % account.trigramme)
|
||||||
account.send_creation_email()
|
|
||||||
return redirect("kfet.account.create")
|
return redirect("kfet.account.create")
|
||||||
except Account.UserHasAccount as e:
|
except Account.UserHasAccount as e:
|
||||||
messages.error(
|
messages.error(
|
||||||
|
@ -441,8 +362,7 @@ def account_update(request, trigramme):
|
||||||
user_info_form = UserInfoForm(instance=account.user)
|
user_info_form = UserInfoForm(instance=account.user)
|
||||||
account_form = AccountForm(instance=account)
|
account_form = AccountForm(instance=account)
|
||||||
group_form = UserGroupForm(instance=account.user)
|
group_form = UserGroupForm(instance=account.user)
|
||||||
frozen_form = AccountFrozenForm(instance=account)
|
frozen_form = AccountFrozenForm(request.POST, instance=account)
|
||||||
cof_form = CofKFForm(instance=account.cofprofile)
|
|
||||||
pwd_form = AccountPwdForm()
|
pwd_form = AccountPwdForm()
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -450,7 +370,6 @@ def account_update(request, trigramme):
|
||||||
account_form = AccountForm(request.POST, instance=account)
|
account_form = AccountForm(request.POST, instance=account)
|
||||||
group_form = UserGroupForm(request.POST, instance=account.user)
|
group_form = UserGroupForm(request.POST, instance=account.user)
|
||||||
frozen_form = AccountFrozenForm(request.POST, instance=account)
|
frozen_form = AccountFrozenForm(request.POST, instance=account)
|
||||||
cof_form = CofKFForm(request.POST, instance=account.cofprofile)
|
|
||||||
pwd_form = AccountPwdForm(request.POST, account=account)
|
pwd_form = AccountPwdForm(request.POST, account=account)
|
||||||
|
|
||||||
forms = []
|
forms = []
|
||||||
|
@ -467,11 +386,6 @@ def account_update(request, trigramme):
|
||||||
elif group_form.has_changed():
|
elif group_form.has_changed():
|
||||||
warnings.append("statut d'équipe")
|
warnings.append("statut d'équipe")
|
||||||
|
|
||||||
if request.user.has_perm("kfet.change_adh"):
|
|
||||||
forms.append(cof_form)
|
|
||||||
elif cof_form.has_changed():
|
|
||||||
warnings.append("adhésion kfet")
|
|
||||||
|
|
||||||
# Il ne faut pas valider `pwd_form` si elle est inchangée
|
# Il ne faut pas valider `pwd_form` si elle est inchangée
|
||||||
if pwd_form.has_changed():
|
if pwd_form.has_changed():
|
||||||
if self_update or request.user.has_perm("kfet.change_account_password"):
|
if self_update or request.user.has_perm("kfet.change_account_password"):
|
||||||
|
@ -488,11 +402,8 @@ def account_update(request, trigramme):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if all(form.is_valid() for form in forms):
|
if all(form.is_valid() for form in forms):
|
||||||
was_kfet = account.is_kfet
|
|
||||||
for form in forms:
|
for form in forms:
|
||||||
form.save()
|
form.save()
|
||||||
if account.is_kfet:
|
|
||||||
account.cofprofile.make_adh_kfet(request, was_kfet)
|
|
||||||
|
|
||||||
if len(warnings):
|
if len(warnings):
|
||||||
messages.warning(
|
messages.warning(
|
||||||
|
@ -524,7 +435,6 @@ def account_update(request, trigramme):
|
||||||
"frozen_form": frozen_form,
|
"frozen_form": frozen_form,
|
||||||
"group_form": group_form,
|
"group_form": group_form,
|
||||||
"pwd_form": pwd_form,
|
"pwd_form": pwd_form,
|
||||||
"cof_form": cof_form,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1009,7 +919,6 @@ def account_read_json(request, trigramme):
|
||||||
"name": account.name,
|
"name": account.name,
|
||||||
"email": account.email,
|
"email": account.email,
|
||||||
"is_cof": account.is_cof,
|
"is_cof": account.is_cof,
|
||||||
"is_kfet": account.is_kfet,
|
|
||||||
"promo": account.promo,
|
"promo": account.promo,
|
||||||
"balance": account.balance,
|
"balance": account.balance,
|
||||||
"is_frozen": account.is_frozen,
|
"is_frozen": account.is_frozen,
|
||||||
|
@ -1186,22 +1095,6 @@ def kpsul_perform_operations(request):
|
||||||
if is_addcost and operation.article.category.has_addcost:
|
if is_addcost and operation.article.category.has_addcost:
|
||||||
operation.addcost_amount /= cof_grant_divisor
|
operation.addcost_amount /= cof_grant_divisor
|
||||||
operation.amount = operation.amount / cof_grant_divisor
|
operation.amount = operation.amount / cof_grant_divisor
|
||||||
if not on_acc.is_cof and not on_acc.is_kfet and operation.article.no_exte:
|
|
||||||
if on_acc.is_cash:
|
|
||||||
required_perms.add("kfet.perform_liq_reserved")
|
|
||||||
else:
|
|
||||||
data["errors"].append(
|
|
||||||
{
|
|
||||||
"code": "reserved",
|
|
||||||
"message": (
|
|
||||||
"L'article "
|
|
||||||
+ operation.article.name
|
|
||||||
+ " est réservé aux adhérent⋅e⋅s du COF, or "
|
|
||||||
+ on_acc.trigramme
|
|
||||||
+ " ne l'est pas"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
to_articles_stocks[operation.article] -= operation.article_nb
|
to_articles_stocks[operation.article] -= operation.article_nb
|
||||||
else:
|
else:
|
||||||
if on_acc.is_cash:
|
if on_acc.is_cash:
|
||||||
|
@ -1218,13 +1111,6 @@ def kpsul_perform_operations(request):
|
||||||
operationgroup.amount += operation.amount
|
operationgroup.amount += operation.amount
|
||||||
if operation.type == Operation.DEPOSIT:
|
if operation.type == Operation.DEPOSIT:
|
||||||
required_perms.add("kfet.perform_deposit")
|
required_perms.add("kfet.perform_deposit")
|
||||||
if request.user.profile.account_kfet == on_acc:
|
|
||||||
data["errors"].append(
|
|
||||||
{
|
|
||||||
"code": "auto_deposit",
|
|
||||||
"message": ("Impossible de charger son propre trigramme"),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if operation.type == Operation.EDIT:
|
if operation.type == Operation.EDIT:
|
||||||
required_perms.add("kfet.edit_balance_account")
|
required_perms.add("kfet.edit_balance_account")
|
||||||
need_comment = True
|
need_comment = True
|
||||||
|
@ -1259,7 +1145,6 @@ def kpsul_perform_operations(request):
|
||||||
operationgroup.valid_by = request.user.profile.account_kfet
|
operationgroup.valid_by = request.user.profile.account_kfet
|
||||||
# Filling cof status for statistics
|
# Filling cof status for statistics
|
||||||
operationgroup.is_cof = on_acc.is_cof
|
operationgroup.is_cof = on_acc.is_cof
|
||||||
operationgroup.is_kfet = on_acc.is_kfet
|
|
||||||
|
|
||||||
# Starting transaction to ensure data consistency
|
# Starting transaction to ensure data consistency
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
@ -1310,7 +1195,6 @@ def kpsul_perform_operations(request):
|
||||||
"checkout__name": operationgroup.checkout.name,
|
"checkout__name": operationgroup.checkout.name,
|
||||||
"at": operationgroup.at,
|
"at": operationgroup.at,
|
||||||
"is_cof": operationgroup.is_cof,
|
"is_cof": operationgroup.is_cof,
|
||||||
"is_kfet": operationgroup.is_kfet,
|
|
||||||
"comment": operationgroup.comment,
|
"comment": operationgroup.comment,
|
||||||
"valid_by__trigramme": (
|
"valid_by__trigramme": (
|
||||||
operationgroup.valid_by and operationgroup.valid_by.trigramme or None
|
operationgroup.valid_by and operationgroup.valid_by.trigramme or None
|
||||||
|
@ -1526,7 +1410,7 @@ def cancel_operations(request):
|
||||||
# Sort objects by pk to get deterministic responses.
|
# Sort objects by pk to get deterministic responses.
|
||||||
opegroups_pk = [opegroup.pk for opegroup in to_groups_amounts]
|
opegroups_pk = [opegroup.pk for opegroup in to_groups_amounts]
|
||||||
opegroups = (
|
opegroups = (
|
||||||
OperationGroup.objects.values("id", "amount", "is_cof", "is_kfet")
|
OperationGroup.objects.values("id", "amount", "is_cof")
|
||||||
.filter(pk__in=opegroups_pk)
|
.filter(pk__in=opegroups_pk)
|
||||||
.order_by("pk")
|
.order_by("pk")
|
||||||
)
|
)
|
||||||
|
@ -1755,7 +1639,6 @@ def kpsul_articles_data(request):
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"price",
|
"price",
|
||||||
"no_exte",
|
|
||||||
"stock",
|
"stock",
|
||||||
"category_id",
|
"category_id",
|
||||||
"category__name",
|
"category__name",
|
||||||
|
@ -2258,10 +2141,20 @@ def order_create(request, pk):
|
||||||
v_et = statistics.pstdev(v_3max, v_moy)
|
v_et = statistics.pstdev(v_3max, v_moy)
|
||||||
# Expected sales for next week
|
# Expected sales for next week
|
||||||
v_prev = v_moy + v_et
|
v_prev = v_moy + v_et
|
||||||
|
# We want to have 1.5 * the expected sales in stock
|
||||||
c_rec_tot = max(v_prev - max(article.stock, 0), 0)
|
# (because sometimes some articles are not delivered)
|
||||||
|
c_rec_tot = max(v_prev * 1.5 - article.stock, 0)
|
||||||
|
# If ordered quantity is close enough to a level which can led to free
|
||||||
|
# boxes, we increase it to this level.
|
||||||
if article.box_capacity:
|
if article.box_capacity:
|
||||||
c_rec_temp = c_rec_tot / article.box_capacity
|
c_rec_temp = c_rec_tot / article.box_capacity
|
||||||
|
if c_rec_temp >= 10:
|
||||||
|
c_rec = round(c_rec_temp)
|
||||||
|
elif c_rec_temp > 5:
|
||||||
|
c_rec = 10
|
||||||
|
elif c_rec_temp > 2:
|
||||||
|
c_rec = 5
|
||||||
|
else:
|
||||||
c_rec = round(c_rec_temp)
|
c_rec = round(c_rec_temp)
|
||||||
initial.append(
|
initial.append(
|
||||||
{
|
{
|
||||||
|
@ -2275,7 +2168,7 @@ def order_create(request, pk):
|
||||||
"v_moy": round(v_moy),
|
"v_moy": round(v_moy),
|
||||||
"v_et": round(v_et),
|
"v_et": round(v_et),
|
||||||
"v_prev": round(v_prev),
|
"v_prev": round(v_prev),
|
||||||
"c_rec_1w": article.box_capacity and c_rec or round(c_rec_tot),
|
"c_rec": article.box_capacity and c_rec or round(c_rec_tot),
|
||||||
"is_sold": article.is_sold,
|
"is_sold": article.is_sold,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
# Generated by npins. Do not modify; will be overwritten regularly
|
|
||||||
let
|
|
||||||
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
|
||||||
version = data.version;
|
|
||||||
|
|
||||||
mkSource =
|
|
||||||
spec:
|
|
||||||
assert spec ? type;
|
|
||||||
let
|
|
||||||
path =
|
|
||||||
if spec.type == "Git" then
|
|
||||||
mkGitSource spec
|
|
||||||
else if spec.type == "GitRelease" then
|
|
||||||
mkGitSource spec
|
|
||||||
else if spec.type == "PyPi" then
|
|
||||||
mkPyPiSource spec
|
|
||||||
else if spec.type == "Channel" then
|
|
||||||
mkChannelSource spec
|
|
||||||
else
|
|
||||||
builtins.throw "Unknown source type ${spec.type}";
|
|
||||||
in
|
|
||||||
spec // { outPath = path; };
|
|
||||||
|
|
||||||
mkGitSource =
|
|
||||||
{
|
|
||||||
repository,
|
|
||||||
revision,
|
|
||||||
url ? null,
|
|
||||||
hash,
|
|
||||||
branch ? null,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
assert repository ? type;
|
|
||||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
|
||||||
# In the latter case, there we will always be an url to the tarball
|
|
||||||
if url != null then
|
|
||||||
(builtins.fetchTarball {
|
|
||||||
inherit url;
|
|
||||||
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
|
||||||
})
|
|
||||||
else
|
|
||||||
assert repository.type == "Git";
|
|
||||||
let
|
|
||||||
urlToName =
|
|
||||||
url: rev:
|
|
||||||
let
|
|
||||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
|
|
||||||
|
|
||||||
short = builtins.substring 0 7 rev;
|
|
||||||
|
|
||||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
|
||||||
in
|
|
||||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
|
||||||
name = urlToName repository.url revision;
|
|
||||||
in
|
|
||||||
builtins.fetchGit {
|
|
||||||
url = repository.url;
|
|
||||||
rev = revision;
|
|
||||||
inherit name;
|
|
||||||
allRefs = true;
|
|
||||||
# hash = hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
mkPyPiSource =
|
|
||||||
{ url, hash, ... }:
|
|
||||||
builtins.fetchurl {
|
|
||||||
inherit url;
|
|
||||||
sha256 = hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
mkChannelSource =
|
|
||||||
{ url, hash, ... }:
|
|
||||||
builtins.fetchTarball {
|
|
||||||
inherit url;
|
|
||||||
sha256 = hash;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
if version == 3 then
|
|
||||||
builtins.mapAttrs (_: mkSource) data.pins
|
|
||||||
else
|
|
||||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"pins": {
|
|
||||||
"kat-pkgs": {
|
|
||||||
"type": "Git",
|
|
||||||
"repository": {
|
|
||||||
"type": "Git",
|
|
||||||
"url": "https://git.dgnum.eu/lbailly/kat-pkgs.git"
|
|
||||||
},
|
|
||||||
"branch": "master",
|
|
||||||
"revision": "6b600b716f409c6012b424de006eac3b02148b81",
|
|
||||||
"url": null,
|
|
||||||
"hash": "0204f91vxa5qglihpfkf3j5w3k7v98wry861xf2skl024faf9idf"
|
|
||||||
},
|
|
||||||
"nix-pkgs": {
|
|
||||||
"type": "Git",
|
|
||||||
"repository": {
|
|
||||||
"type": "Git",
|
|
||||||
"url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs"
|
|
||||||
},
|
|
||||||
"branch": "main",
|
|
||||||
"revision": "ac4ff5a34789ae3398aff9501735b67b6a5a285a",
|
|
||||||
"url": null,
|
|
||||||
"hash": "16n37f74p6h30hhid98vab9w5b08xqj4qcshz2kc1jh67z5n49p6"
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"type": "Channel",
|
|
||||||
"name": "nixos-unstable",
|
|
||||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-25.05beta719504.a73246e2eef4/nixexprs.tar.xz",
|
|
||||||
"hash": "1jjmg13jzbqxm5m5ql51n2kq1qggfyb0rhmjwhqhvqxhl350z58a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"version": 3
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue