Compare commits

...

79 commits

Author SHA1 Message Date
Sinavir
98a6f98fda Fireworks hotfix 2024-11-13 10:50:46 +01:00
sinavir
0aae767a3e
fireworks 2024-11-13 10:35:37 +01:00
sinavir
d88768311e
cvec 2024-11-08 14:33:16 +01:00
sinavir
abc6c62a89 make forgotten migration 2024-06-15 15:03:37 +02:00
sinavir
3e065f30c0 Bugfix 2024-06-15 14:57:39 +02:00
sinavir
0ee798a64e Improve requirements.txt 2024-06-15 14:28:41 +02:00
sinavir
1e8b993739 Revert "add poll for 10y anniversary"
This reverts commit 56d7490879.
2022-10-26 21:57:01 +02:00
Lucie Galland
8398805b54 proposition migration 2022-09-14 12:45:30 +02:00
sinavir
56d7490879 add poll for 10y anniversary 2022-09-14 10:24:32 +02:00
Lucie Galland
aa430fa4d2 add propositions back 2022-03-22 15:05:51 +01:00
Lucie Galland
5eb27e2171 Merge branch 'mdebray/date_des_reponses_aux_sondages' into 'master'
Date des reponses aux sondages

See merge request klub-dev-ens/Ernesto!22
2022-03-15 11:29:37 +01:00
Lucie Galland
31f6dc0961 bug fix 2022-03-15 11:28:44 +01:00
Maurice Debray
764ffea61f on est moins laxiste 2022-03-15 11:10:55 +01:00
Maurice Debray
7122c1c0c4 black puis isort 2022-03-15 01:08:18 +01:00
Maurice Debray
14e8d963d6 Ajout de la date de création/mise à jour dans le modèle Participants 2022-03-15 01:04:01 +01:00
Lucie Galland
99e3438ead Merge branch 'mdebray/linting' into 'master'
Linting

See merge request klub-dev-ens/Ernesto!20
2022-02-21 11:13:02 +01:00
Maurice Debray
8a36b051a1 Merge branch 'master' into mdebray/linting 2022-02-21 10:29:47 +01:00
Lucie Galland
07d2e30b32 Merge branch 'mdebray/bugfix_respo_instru' into 'master'
Bugfix : Le chef instru peut maintenant changer les infos d'instru

See merge request klub-dev-ens/Ernesto!19
2022-02-21 09:55:25 +01:00
Maurice Debray
f88ed9ece6 Chef instru peut maintenant changer les infos d'instru 2022-02-21 00:47:03 +01:00
Maurice Debray
5062a1e84e linting 2022-02-05 16:18:00 +01:00
Lucie Galland
bc7430cb5d fix 2022-01-18 15:47:50 +01:00
Lucie Galland
a7851ff123 fix morceau ordering 2022-01-18 15:44:08 +01:00
Lucie Galland
50f888a07c add partitions to admin 2022-01-18 15:36:19 +01:00
Lucie Galland
343eaeb72e add partitions to admin 2022-01-18 15:36:04 +01:00
Lucie Galland
5aebd7bbe1 Merge branch 'mdebray/bug_affichage_musescore' into 'master'
bugfix affichage tableau partitions

See merge request klub-dev-ens/Ernesto!18
2022-01-17 14:18:20 +01:00
Maurice Debray
cb2577c04b bugfix affichage tableau partitions 2022-01-16 11:15:20 +01:00
Lucie Galland
bd42fe6fb9 add respo mu 2022-01-11 16:21:22 +01:00
Lucie Galland
bbff984513 remove partcipants from admin 2022-01-09 20:47:58 +01:00
Lucie Galland
9aed5d1758 Merge branch 'setlist_repet' into 'master'
Setlist de repet

See merge request klub-dev-ens/Ernesto!17
2022-01-09 20:46:50 +01:00
Maurice Debray
f961722fa8 black+isort 2022-01-09 19:40:58 +01:00
Maurice Debray
904f9fc74a migration 2022-01-09 19:39:48 +01:00
Maurice Debray
280e0c625d suppresion migrations 2022-01-09 19:39:27 +01:00
Maurice Debray
8e6ca0cc86 internationnalisation 2022-01-09 18:03:36 +01:00
Maurice Debray
0673e64083 Modifications de l'affichage parce que j'avais fais ça n'importe comment 2022-01-09 17:43:19 +01:00
Maurice Debray
82bc6c1e1b Setlists de repet 2022-01-09 01:18:50 +01:00
Maurice Debray
26bd2484a2 Merge branch 'master' into setlist_repet 2022-01-06 17:42:45 +01:00
Lucie Galland
4d8b97c2cb Merge branch 'actu_chef_arc_en_ciel' into 'master'
Actu chef arc en ciel

See merge request klub-dev-ens/Ernesto!16
2022-01-06 14:51:16 +01:00
Maurice Debray
b62d6f47a4 Migrations + black/isort 2022-01-06 13:11:16 +01:00
Maurice Debray
10159393f1 Set list de repet: front end random fanfaron 2022-01-06 00:27:53 +01:00
Maurice Debray
d217a74da5 Diclaimer: Ne pas mettre d'émoji car c'est moche 2021-12-26 16:12:58 +01:00
Maurice Debray
079e0d1c3f Changement de champ rainbow du modèle : Bool > Choice 2021-12-24 00:40:17 +01:00
Maurice Debray
45fdd4683b Amélioration mineure du gradient de couleur 2021-12-23 23:39:23 +01:00
Maurice Debray
95cf80c234 Affichage des arcs-en-ciel 2021-12-23 23:36:23 +01:00
Maurice Debray
e6f9173c62 Modification du modèle et des vues 2021-12-23 23:25:32 +01:00
Lucie Galland
149cc3b9f0 yearbook final de final 2021-12-16 11:43:25 +01:00
Lucie Galland
67cc2e658a yearbookfinal 2021-12-14 11:50:56 +01:00
Lucie Galland
dba4498cd7 force main.css reload 2021-12-13 16:44:59 +01:00
Lucie Galland
9ea37de108 Merge branch 'ernestocouleurs' into 'master'
Ajout des arc en ciel. Rainbow power

See merge request klub-dev-ens/Ernesto!13
2021-12-13 13:01:46 +01:00
Maurice Debray
f48605210e amélioration des couleurs 2021-12-13 12:54:25 +01:00
Maurice Debray
eab532bf7e Ajout des arc en ciel dans les templates. Rainbow power git add calendrier/templates/calendrier/home.html partitions/templates/partitions/part.html partitions/templates/partitions/repertoire.html 2021-12-13 00:04:08 +01:00
Maurice Debray
2633829f83 ajout du css arc-en-ciel 2021-12-12 22:28:14 +01:00
Lucie Galland
451a5cc83d flipbook 2021-12-09 18:03:14 +01:00
Lucie Galland
d35772e116 yearbook 2021-11-25 10:01:11 +01:00
Lucie Galland
bfb1f32132 yearbook 2021-11-25 10:00:01 +01:00
Lucie Galland
ec0dbd2282 add yearbook2021 2021-11-23 18:38:59 +01:00
Lucie Galland
a5c1fb48fb change banner 2021-11-16 16:58:06 +01:00
Lucie Galland
a1a8a6d9aa calendar update 2021-11-03 14:33:39 +01:00
Lucie Galland
d7fd5e5537 new respos 2021-10-23 11:16:07 +02:00
Lucie Galland
662764b581 addtocalendar 2021-10-14 09:06:12 +02:00
Lucie Galland
2a33ba5cd1 addtocalendar 2021-10-13 17:55:26 +02:00
Lucie Galland
0d443407a7 addtocalendar 2021-10-13 16:49:23 +02:00
Lucie Galland
38b0f12201 add respo event 2021-10-06 13:46:45 +02:00
Lucie Galland
80a7f99f28 add responsabilité instru 2021-10-04 16:19:30 +02:00
Lucie Galland
fc4577c661 instru liste for multiinstrumentiste answer in doodle 2021-09-30 08:38:47 +02:00
Lucie Galland
446acd1cb7 corrections 2021-09-29 13:31:15 +02:00
Lucie Galland
d1d0980778 ev only for chefs 2021-08-09 12:41:44 +02:00
Lucie Galland
e36311774b fix image 2021-06-08 13:31:41 +02:00
Lucie Galland
de50d9b187 fix 2021-06-07 13:50:57 +02:00
Lucie Galland
b260ae8eb8 add photo/video from site + choice instru in response event 2021-06-07 00:56:03 +02:00
Lucie Galland
d6036766c7 html minor corrections 2021-05-31 22:15:55 +02:00
Martin Pepin
9bd21283c0 Merge branch 'v1.1' into 'master'
v1.1

See merge request klub-dev-ens/Ernesto!12
2021-05-27 11:58:41 +00:00
Lucie Galland
ab120e5e63 navbar 2021-05-27 14:27:30 +02:00
Lucie Galland
7b19a581cf minor adjustements 2021-04-29 01:00:17 +02:00
Lucie Galland
777bd930c6 add migrations 2021-04-29 00:36:43 +02:00
Lucie Galland
0fbec31d14 black + isort 2021-04-29 00:33:58 +02:00
Lucie Galland
6ba168d286 corrections + class views 2021-04-29 00:27:33 +02:00
Lucie Galland
406f92098f listing d'instruments 2021-04-01 21:27:17 +02:00
Lucie Galland
5d1d3f8eff v1.1 2021-03-31 16:05:26 +02:00
Martin Pépin
7a7979c91a
Remove empty tests.py files
Some of them were shadowing tests/ directories
2020-09-12 19:06:14 +02:00
179 changed files with 7126 additions and 3030 deletions

View file

@ -1,4 +1,5 @@
import os
from django.utils.translation import gettext_lazy as _
try:
@ -31,63 +32,61 @@ DBPASSWD = import_secret("DBPASSWD")
ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS")
BASE_DIR = os.path.join(
os.path.dirname(__file__), "..", ".."
)
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..")
INSTALLED_APPS = [
'trombonoscope',
'actu',
'colorful',
'pads',
'calendrier',
'gestion.apps.GestionConfig',
'partitions.apps.PartitionsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'avatar',
"propositions",
"trombonoscope",
"actu",
"colorful",
"pads",
"calendrier",
"gestion.apps.GestionConfig",
"partitions.apps.PartitionsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"avatar",
"instruments",
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'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.locale.LocaleMiddleware',
"django.middleware.security.SecurityMiddleware",
"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.locale.LocaleMiddleware",
]
ROOT_URLCONF = "Ernestophone.urls"
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
'libraries':{
'changelang': 'gestion.templatetags.changelang',
'modulo': 'gestion.templatetags.modulo',
'autotranslate': 'gestion.templatetags.autotranslate',
'halflength': 'gestion.templatetags.halflength',
}
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
],
"libraries": {
"changelang": "gestion.templatetags.changelang",
"modulo": "gestion.templatetags.modulo",
"autotranslate": "gestion.templatetags.autotranslate",
"halflength": "gestion.templatetags.halflength",
},
},
}
}]
]
WSGI_APPLICATION = "Ernestophone.wsgi.application"
@ -103,51 +102,51 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# I18n
# I18n
LANGUAGE_CODE = 'fr'
LANGUAGE_CODE = "fr"
LANGUAGES = (
('fr', _('Français')),
('en', _('English')),
("fr", _("Français")),
("en", _("English")),
)
TIME_ZONE = 'UTC'
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale'), )
LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
AUTH_PROFILE_MODEL = 'gestion.ErnestoUser'
AUTH_PROFILE_MODEL = "gestion.ErnestoUser"
LOGIN_URL = "/login"
AVATAR_CLEANUP_DELETED = True
AVATAR_AUTO_GENERATE_SIZES = (250,)
AVATAR_CHANGE_TEMPLATE = "trombonoscope/change_avatar.html"
AVATAR_MAX_AVATARS_PER_USER=1
AVATAR_EXPOSE_USERNAMES=False
AVATAR_STORAGE_DIR="trombonoscope"
AVATAR_ADD_TEMPLATE="trombonoscope/add_avatar.html"
AVATAR_DELETE_TEMPLATE="trombonoscope/delete_avatar.html"
AVATAR_DEFAULT_URL="Ernesto"
AVATAR_PROVIDERS=(
'avatar.providers.PrimaryAvatarProvider',
'avatar.providers.DefaultAvatarProvider',
)
AVATAR_THUMB_FORMAT = 'JPEG'
AVATAR_MAX_AVATARS_PER_USER = 1
AVATAR_EXPOSE_USERNAMES = False
AVATAR_STORAGE_DIR = "trombonoscope"
AVATAR_ADD_TEMPLATE = "trombonoscope/add_avatar.html"
AVATAR_DELETE_TEMPLATE = "trombonoscope/delete_avatar.html"
AVATAR_DEFAULT_URL = "Ernesto"
AVATAR_PROVIDERS = (
"avatar.providers.PrimaryAvatarProvider",
"avatar.providers.DefaultAvatarProvider",
)
AVATAR_THUMB_FORMAT = "JPEG"

View file

@ -1,19 +1,14 @@
import os
from .common import * # noqa
from .common import BASE_DIR, INSTALLED_APPS, MIDDLEWARE
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
DEBUG = True
INSTALLED_APPS += ["debug_toolbar"]
MIDDLEWARE = (
["debug_toolbar.middleware.DebugToolbarMiddleware"]
+ MIDDLEWARE
)
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
STATIC_URL = "/static/"
STATIC_ROOT = "static"

View file

@ -3,7 +3,6 @@ import os
from .common import * # noqa
from .common import BASE_DIR
DEBUG = False
ALLOWED_HOSTS = [
@ -12,11 +11,7 @@ ALLOWED_HOSTS = [
]
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(
BASE_DIR, "..", "..", "public", "ernesto", "static"
)
STATIC_ROOT = os.path.join(BASE_DIR, "..", "..", "public", "ernesto", "static")
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(
BASE_DIR, "..", "media"
)
MEDIA_ROOT = os.path.join(BASE_DIR, "..", "media")

View file

@ -13,36 +13,60 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from gestion import views as gestion_views
from django.contrib.auth import views as auth_views
import django.contrib.auth.urls as urls
from django.conf.urls.static import static
from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import include, path
from gestion import views as gestion_views
urlpatterns = []
urlpatterns += i18n_patterns(
path('', gestion_views.home, name="home"),
path("registration", gestion_views.inscription_membre, name="registration"),
path("change", gestion_views.change_membre, name="change_membre"),
path("password", gestion_views.change_password, name="change_password"),
path("thanks", gestion_views.thanks, name="thanks"),
path("changename", gestion_views.changename, name="change-doodle-name"),
path("", gestion_views.Home.as_view(), name="home"),
path("registration", gestion_views.Inscription.as_view(), name="registration"),
path("change", gestion_views.ChangeMembre.as_view(), name="change_membre"),
path("password", gestion_views.ChangePassword.as_view(), name="change_password"),
path("thanks", gestion_views.Thanks.as_view(), name="thanks"),
path("social", gestion_views.Social.as_view(), name="social"),
path("chef", gestion_views.Chef.as_view(), name="chef"),
path("yearbook2021", gestion_views.YearBook2021.as_view(), name="yearbook2021"),
path("profil", gestion_views.Profil.as_view(), name="profile"),
path("changename", gestion_views.ChangeName.as_view(), name="change-doodle-name"),
path("logout", auth_views.LogoutView.as_view(next_page="home"), name="logout"),
path("login", gestion_views.MyLoginView.as_view(), name="login"),
path("agenda/", include("calendrier.urls", namespace="calendrier")),
path("partitions/", include("partitions.urls")),
path("instruments/", include("instruments.urls")),
path("pads/", include("pads.urls")),
path(
"login",
auth_views.LoginView.as_view(template_name="gestion/login.html"),
name="login"
"admin/",
admin.site.urls,
),
path('agenda/', include('calendrier.urls',namespace='calendrier')),
path('partitions/', include('partitions.urls')),
path('pads/', include('pads.urls')),
path('admin/', admin.site.urls,),
path('trombonoscope/',include('trombonoscope.urls')),
path("actu/",include('actu.urls')),
path('avatar/', include('avatar.urls')),
prefix_default_language=False )
path("trombonoscope/", include("trombonoscope.urls")),
path("actu/", include("actu.urls")),
path("avatar/", include("avatar.urls")),
path("photos", gestion_views.PhotoList.as_view(), name="liste_photo"),
path("add_photo", gestion_views.PhotoCreate.as_view(), name="add_photo"),
path(
"photo_edition/<int:pk>", gestion_views.PhotoUpdate.as_view(), name="edit_photo"
),
path(
"photo_delete/<int:pk>",
gestion_views.PhotoDelete.as_view(),
name="delete_photo",
),
path("videos", gestion_views.VideoList.as_view(), name="liste_video"),
path("add_video", gestion_views.VideoCreate.as_view(), name="add_video"),
path(
"video_edition/<int:pk>", gestion_views.VideoUpdate.as_view(), name="edit_video"
),
path(
"video_delete/<int:pk>",
gestion_views.VideoDelete.as_view(),
name="delete_video",
),
prefix_default_language=False,
)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -1,4 +1,3 @@
"""
WSGI config for Ernestophone project.
@ -10,10 +9,8 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
import os
os.environ.setdefault(
"DJANGO_SETTINGS_MODULE",
"Ernestophone.settings.prod"
)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings.prod")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

View file

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here.

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class ActuConfig(AppConfig):
name = 'actu'
name = "actu"

View file

@ -7,22 +7,34 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Actu',
name="Actu",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(null=True, verbose_name='Info')),
('text_en', models.TextField(blank=True, null=True, verbose_name='Info en anglais')),
('order', models.IntegerField(verbose_name='ordre')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField(null=True, verbose_name="Info")),
(
"text_en",
models.TextField(
blank=True, null=True, verbose_name="Info en anglais"
),
),
("order", models.IntegerField(verbose_name="ordre")),
],
options={
'ordering': ('order',),
'verbose_name_plural': 'Actualités',
'verbose_name': 'Actualité',
"ordering": ("order",),
"verbose_name_plural": "Actualités",
"verbose_name": "Actualité",
},
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 2.2.25 on 2022-01-06 12:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("actu", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="actu",
name="rainbow",
field=models.CharField(
choices=[("y", "Oui"), ("n", "Non")],
default="n",
max_length=1,
verbose_name="Actu en arc-en-ciel (ne pas mettre d'émoji, il prennent aussi la couleur et c'est moche)",
),
),
]

View file

@ -1,14 +1,26 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class Actu(models.Model):
text = models.TextField(_("Info"), null=True, blank=False)
text_en = models.TextField(("Info en anglais"), null=True, blank=True)
order = models.IntegerField(verbose_name=_("ordre"))
rainbow = models.CharField(
verbose_name=_(
"Actu en arc-en-ciel (ne pas mettre d'émoji, il prennent aussi la couleur et c'est moche)"
),
max_length=1,
choices=(("y", "Oui"), ("n", "Non")),
default="n",
blank=False,
)
def __str__(self):
return self.text
class Meta:
verbose_name = _("Actualité")
verbose_name_plural = _("Actualités")
ordering = ('order',)
ordering = ("order",)

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -2,11 +2,10 @@ from django.urls import path
from actu import views
app_name = "actu"
urlpatterns = [
path("", views.ActuList.as_view(), name="liste"),
path("ajouter", views.ActuCreate.as_view(), name="add_actu"),
path("edition/<int:pk>", views.ActuUpdate.as_view(), name="edit_actu"),
path("supprimer/<int:pk>", views.ActuDelete.as_view(), name="delete_actu")
path("supprimer/<int:pk>", views.ActuDelete.as_view(), name="delete_actu"),
]

View file

@ -1,9 +1,9 @@
from django.shortcuts import render
from gestion.mixins import ChefRequiredMixin
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from django.urls import reverse_lazy
from actu.models import Actu
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from actu.models import Actu
from gestion.mixins import ChefRequiredMixin
class ActuList(ChefRequiredMixin, ListView):
@ -14,7 +14,7 @@ class ActuList(ChefRequiredMixin, ListView):
class ActuCreate(ChefRequiredMixin, CreateView):
model = Actu
fields = ["text","order","text_en"]
fields = ["text", "order", "text_en", "rainbow"]
template_name = "actu/create_actu.html"
success_url = reverse_lazy("actu:liste")
@ -26,7 +26,7 @@ class ActuCreate(ChefRequiredMixin, CreateView):
class ActuUpdate(ChefRequiredMixin, UpdateView):
model = Actu
fields = ["text","order","text_en"]
fields = ["text", "order", "text_en", "rainbow"]
template_name = "actu/update_actu.html"
success_url = reverse_lazy("actu:liste")

View file

@ -1,6 +1,28 @@
from django.contrib import admin
from .models import Event, Participants
from .models import Event
class ParticipantsAdmin(admin.ModelAdmin):
fields = [
"event",
"participant",
"reponse",
"instrument",
"instrument_autre",
"dont_play_main",
"details",
"creationDate",
"updateDate",
]
readonly_fields = ["creationDate", "updateDate"]
list_display = ["participant", "event", "reponse", "creationDate", "updateDate"]
def has_add_permission(self, req):
return False
def has_change_permission(self,obj, change=False):
return False
# Add event by admin page return a 502 error
admin.site.register(Event)
admin.site.register(Participants, ParticipantsAdmin)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class CalendrierConfig(AppConfig):
name = 'calendrier'
name = "calendrier"

View file

@ -1,44 +1,49 @@
from django.utils.html import conditional_escape as esc
from itertools import groupby
from calendar import HTMLCalendar
from django.utils.translation import gettext_lazy as _
from datetime import date
from itertools import groupby
from django.utils.html import conditional_escape as esc
from django.utils.translation import gettext_lazy as _
class EventCalendar(HTMLCalendar):
def __init__(self, pEvents):
super(EventCalendar, self).__init__()
self.events = self.group_by_day(pEvents.order_by('date'))
self.events = self.group_by_day(pEvents.order_by("date"))
def formatday(self, day, weekday):
if day != 0:
cssclass = self.cssclasses[weekday]
if date.today() == date(self.year, self.month, day):
cssclass += ' today'
cssclass += " today"
if day in self.events:
cssclass += ' filled'
cssclass += " filled"
body = []
for ev in self.events[day]:
body.append(_('<a href="/agenda/') + '%s">' % ev.id)
body.append(esc(ev.nom))
body.append('</a><br/>')
return self.day_cell(cssclass,
'<div class="dayNumber">%d</div> %s'
% (day, ''.join(body)))
return self.day_cell(cssclass,
'<div class="dayNumber">%d</div>' % day)
return self.day_cell('noday', '&nbsp;')
body.append('<a href="/agenda/' + '%s"' % ev.id)
if ev.calendrier == "C":
body.append('style="color:#160083">' + esc(ev.nom))
elif ev.calendrier == "D":
body.append('style="color:#770083">' + esc(ev.nom))
else:
body.append(">" + esc(ev.nom))
body.append("</a><br/>")
return self.day_cell(
cssclass,
'<div class="dayNumber">%d</div> %s' % (day, "".join(body)),
)
return self.day_cell(cssclass, '<div class="dayNumber">%d</div>' % day)
return self.day_cell("noday", "&nbsp;")
def formatmonth(self, year, month):
self.year, self.month = year, month
return super(EventCalendar, self).formatmonth(year, month)
def group_by_day(self, pEvents):
def field(ev): return(ev.date.day)
return dict(
[(dat, list(items)) for dat, items in groupby(pEvents, field)]
)
def field(ev):
return ev.date.day
return dict([(dat, list(items)) for dat, items in groupby(pEvents, field)])
def day_cell(self, cssclass, body):
return '<td class="%s">%s</td>' % (cssclass, body)

View file

@ -1,61 +1,65 @@
from django import forms
from calendrier.models import Event, Participants
from gestion.models import ErnestoUser
from django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
from calendrier.models import Event, Participants
class ModifEventForm(forms.ModelForm):
class Meta:
model = Event
exclude = ['slug']
exclude = ["slug"]
widgets = {
'description': forms.Textarea(attrs={
"placeholder": _("facultatif, balises html supportées")}),
'date': forms.TextInput(attrs={"placeholder": 'jj/mm/aaaa'}),
'debut': forms.TextInput(attrs={"placeholder": 'hh:mm'}),
'fin': forms.TextInput(attrs={"placeholder": _('hh:mm facultatif')})
"description": forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}
),
"date": forms.TextInput(attrs={"placeholder": "jj/mm/aaaa"}),
"debut": forms.TextInput(attrs={"placeholder": "hh:mm"}),
"fin": forms.TextInput(attrs={"placeholder": _("hh:mm facultatif")}),
}
class EventForm(forms.ModelForm):
class Meta:
model = Event
exclude = ['slug']
exclude = ["slug"]
widgets = {
'nomcourt': forms.TextInput(
attrs={"placeholder": _('9 caractères max')}),
'description': forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}),
'date': forms.TextInput(attrs={"placeholder": 'jj/mm/aaaa'}),
'debut': forms.TextInput(attrs={"placeholder": 'hh:mm'}),
'fin': forms.TextInput(attrs={"placeholder": _('hh:mm facultatif')}),
"nomcourt": forms.TextInput(attrs={"placeholder": _("9 caractères max")}),
"description": forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}
),
"date": forms.TextInput(attrs={"placeholder": "jj/mm/aaaa"}),
"debut": forms.TextInput(attrs={"placeholder": "hh:mm"}),
"fin": forms.TextInput(attrs={"placeholder": _("hh:mm facultatif")}),
}
class ParticipantsForm(forms.ModelForm):
class Meta:
model = Participants
fields = ('reponse', 'details')
fields = (
"reponse",
"details",
"dont_play_main",
"instrument",
"instrument_autre",
)
widgets = {
'details': forms.Textarea(
attrs={"placeholder": _("50 caractères max")}),
"details": forms.Textarea(attrs={"placeholder": _("50 caractères max")}),
}
class ChangeDoodleName(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ChangeDoodleName, self).__init__(*args, **kwargs)
self.fields['doodlename'].initial = self.instance.profile.get_doodlename()
self.fields["doodlename"].initial = self.instance.profile.get_doodlename()
def save(self, *args, **kwargs):
super(ChangeDoodleName, self).save(*args, **kwargs)
self.instance.profile.doodlename = self.cleaned_data['doodlename']
self.instance.profile.doodlename = self.cleaned_data["doodlename"]
self.instance.profile.save()
self.instance.save()
class Meta:
model = ErnestoUser
fields = ('doodlename',)
model = ErnestoUser
fields = ("doodlename",)

View file

@ -7,37 +7,82 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0001_initial'),
("gestion", "0001_initial"),
]
operations = [
migrations.CreateModel(
name='Event',
name="Event",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('nom', models.CharField(max_length=100)),
('nomcourt', models.CharField(max_length=9, verbose_name='Nom court')),
('date', models.DateField()),
('debut', models.TimeField()),
('fin', models.TimeField(blank=True, null=True)),
('slug', models.CharField(max_length=7, editable=False, unique=True)),
('lieu', models.CharField(max_length=200)),
('description', models.TextField(blank=True)),
('desc_users', models.TextField(blank=True, verbose_name='Infos (visible seulement des fanfaron-ne-s)', null=True)),
('calendrier', models.BooleanField(verbose_name='Afficher dans le calendrier pour tous', default=False)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("nomcourt", models.CharField(max_length=9, verbose_name="Nom court")),
("date", models.DateField()),
("debut", models.TimeField()),
("fin", models.TimeField(blank=True, null=True)),
("slug", models.CharField(max_length=7, editable=False, unique=True)),
("lieu", models.CharField(max_length=200)),
("description", models.TextField(blank=True)),
(
"desc_users",
models.TextField(
blank=True,
verbose_name="Infos (visible seulement des fanfaron-ne-s)",
null=True,
),
),
(
"calendrier",
models.BooleanField(
verbose_name="Afficher dans le calendrier pour tous",
default=False,
),
),
],
options={
'verbose_name': 'Événement',
"verbose_name": "Événement",
},
),
migrations.CreateModel(
name='Participants',
name="Participants",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('reponse', models.CharField(max_length=20, choices=[('oui', 'Oui'), ('non', 'Non'), ('pe', 'Peut-être')], default='non', verbose_name='Réponse')),
('details', models.CharField(blank=True, max_length=50)),
('event', models.ForeignKey(to='calendrier.Event', on_delete=models.CASCADE)),
('participant', models.ForeignKey(to='gestion.ErnestoUser', on_delete=models.CASCADE)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
(
"reponse",
models.CharField(
max_length=20,
choices=[("oui", "Oui"), ("non", "Non"), ("pe", "Peut-être")],
default="non",
verbose_name="Réponse",
),
),
("details", models.CharField(blank=True, max_length=50)),
(
"event",
models.ForeignKey(to="calendrier.Event", on_delete=models.CASCADE),
),
(
"participant",
models.ForeignKey(
to="gestion.ErnestoUser", on_delete=models.CASCADE
),
),
],
),
]

View file

@ -1,43 +1,63 @@
# Generated by Django 2.2.14 on 2020-07-14 15:59
from django.db import migrations, models
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('calendrier', '0001_initial'),
("calendrier", "0001_initial"),
]
operations = [
migrations.AlterModelOptions(
name='event',
options={'verbose_name': 'Evenement'},
name="event",
options={"verbose_name": "Evenement"},
),
migrations.AddField(
model_name='event',
name='desc_users_en',
field=models.TextField(blank=True, null=True, verbose_name='Infos en anglais (visible seulement des fanfaron-ne-s)'),
model_name="event",
name="desc_users_en",
field=models.TextField(
blank=True,
null=True,
verbose_name="Infos en anglais (visible seulement des fanfaron-ne-s)",
),
),
migrations.AddField(
model_name='event',
name='description_en',
model_name="event",
name="description_en",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='event',
name='calendrier',
field=models.CharField(choices=[('F', 'Visible seulement par les fanfarons'), ('T', 'Afficher dans le calendrier pour tous'), ('H', 'Hall of fame')], default='F', max_length=1),
model_name="event",
name="calendrier",
field=models.CharField(
choices=[
("F", "Visible seulement par les fanfarons"),
("T", "Afficher dans le calendrier pour tous"),
("H", "Hall of fame"),
],
default="F",
max_length=1,
),
),
migrations.AlterField(
model_name='event',
name='slug',
field=models.CharField(default=uuid.uuid1, editable=False, max_length=7, unique=True),
model_name="event",
name="slug",
field=models.CharField(
default=uuid.uuid1, editable=False, max_length=7, unique=True
),
),
migrations.AlterField(
model_name='participants',
name='reponse',
field=models.CharField(choices=[('oui', 'Oui'), ('non', 'Non'), ('pe', 'Peut-etre')], default='non', max_length=20, verbose_name='Réponse'),
model_name="participants",
name="reponse",
field=models.CharField(
choices=[("oui", "Oui"), ("non", "Non"), ("pe", "Peut-etre")],
default="non",
max_length=20,
verbose_name="Réponse",
),
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 2.2.17 on 2021-04-27 18:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0002_auto_20200714_1559"),
]
operations = [
migrations.AlterField(
model_name="event",
name="desc_users_en",
field=models.TextField(
blank=True,
null=True,
verbose_name="Infos en anglais (visible seulement des fanfaron-ne-s",
),
),
]

View file

@ -0,0 +1,28 @@
# Generated by Django 2.2.17 on 2021-06-06 16:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0003_auto_20210427_1834"),
]
operations = [
migrations.AddField(
model_name="participants",
name="dont_play_main",
field=models.CharField(
choices=[("Non", "Non"), ("Oui", "Oui")],
default="Non",
max_length=3,
verbose_name="Je veux jouer d'un instrument different de mon instrument principal:",
),
),
migrations.AddField(
model_name="participants",
name="instrument",
field=models.CharField(blank=True, max_length=50, null=True),
),
]

View file

@ -0,0 +1,46 @@
# Generated by Django 2.2.24 on 2021-07-26 07:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0004_auto_20210606_1640"),
]
operations = [
migrations.AlterField(
model_name="event",
name="calendrier",
field=models.CharField(
choices=[
("F", "Visible seulement par les fanfarons"),
("T", "Afficher dans le calendrier pour tous"),
("H", "Hall of fame"),
("C", "Visible seulement par les cheff·e·s"),
("D", "Visible seulement par les cheff·e·s et sur l'agenda public"),
],
default="F",
max_length=1,
),
),
migrations.AlterField(
model_name="event",
name="desc_users",
field=models.TextField(
blank=True,
null=True,
verbose_name="Infos (visible seulement des fanfaron·ne·s)",
),
),
migrations.AlterField(
model_name="event",
name="desc_users_en",
field=models.TextField(
blank=True,
null=True,
verbose_name="Infos en anglais (visible seulement des fanfaron·ne·s",
),
),
]

View file

@ -0,0 +1,41 @@
# Generated by Django 2.2.24 on 2021-09-29 14:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0005_auto_20210726_0949"),
]
operations = [
migrations.AddField(
model_name="participants",
name="instrument_autre",
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AlterField(
model_name="participants",
name="instrument",
field=models.CharField(
blank=True,
choices=[
("Clarinette", "Clarinette"),
("Euphonium", "Euphonium"),
("Percussion", "Percussion"),
("Piccolo", "Piccolo"),
("Saxophone Alto", "Saxophone Alto"),
("Saxophone Ténor", "Saxophone Ténor"),
("Saxophone Baryton", "Saxophone Baryton"),
("Souba", "Souba"),
("Trombone", "Trombone"),
("Trompette", "Trompette"),
("Autre", "Autre"),
("ne sais pas", "Je ne sais pas encore"),
],
max_length=50,
null=True,
),
),
]

View file

@ -0,0 +1,31 @@
# Generated by Django 2.2.25 on 2022-03-14 23:20
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0006_auto_20210929_1629"),
]
operations = [
migrations.AddField(
model_name="participants",
name="creationDate",
field=models.DateTimeField(
auto_now_add=True,
default=django.utils.timezone.now,
verbose_name="Date de création",
),
preserve_default=False,
),
migrations.AddField(
model_name="participants",
name="updateDate",
field=models.DateTimeField(
auto_now=True, verbose_name="Dernière mise à jour"
),
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 2.2.27 on 2022-03-22 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('calendrier', '0007_auto_20220314_2320'),
]
operations = [
migrations.AddConstraint(
model_name='participants',
constraint=models.UniqueConstraint(fields=('event', 'participant'), name='reponse unique aux event'),
),
]

View file

@ -1,54 +1,82 @@
from django.db import models
import uuid
from gestion.models import ErnestoUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from gestion.models import INSTRU_CHOICES, ErnestoUser
ANSWERS = (
('oui', _('Oui')),
('non', _('Non')),
('pe', _('Peut-etre')),
)
("oui", _("Oui")),
("non", _("Non")),
("pe", _("Peut-etre")),
)
class Event(models.Model):
nom = models.CharField(max_length=100)
nomcourt = models.CharField(max_length=9, verbose_name=_("Nom court"))
date = models.DateField()
debut = models.TimeField()
fin = models.TimeField(blank=True, null=True)
slug = models.CharField(max_length=7, editable=False, unique=True, default=uuid.uuid1)
slug = models.CharField(
max_length=7, editable=False, unique=True, default=uuid.uuid1
)
lieu = models.CharField(max_length=200)
description = models.TextField(blank=True)
description_en = models.TextField(blank=True)
desc_users = models.TextField(
blank=True,
verbose_name=_("Infos (visible seulement des fanfaron-ne-s)"),
null=True)
blank=True,
verbose_name=_("Infos (visible seulement des fanfaron·ne·s)"),
null=True,
)
desc_users_en = models.TextField(
blank=True,
verbose_name=_("Infos en anglais (visible seulement des fanfaron-ne-s)"),
null=True)
blank=True,
verbose_name=_("Infos en anglais (visible seulement des fanfaron·ne·s"),
null=True,
)
CALENDRIER_CHOICES = [
('F', _('Visible seulement par les fanfarons')),
('T', _('Afficher dans le calendrier pour tous')),
('H', _('Hall of fame')),
("F", _("Visible seulement par les fanfarons")),
("T", _("Afficher dans le calendrier pour tous")),
("H", _("Hall of fame")),
("C", _("Visible seulement par les cheff·e·s")),
("D", _("Visible seulement par les cheff·e·s et sur l'agenda public")),
]
calendrier = models.CharField(
max_length=1,
choices=CALENDRIER_CHOICES,
default='F',
default="F",
)
def __str__(self):
return self.nom
class Meta:
verbose_name = _("Evenement")
class Participants(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
participant = models.ForeignKey(ErnestoUser, on_delete=models.CASCADE)
reponse = models.CharField(_("Réponse"), max_length=20, default="non",
choices=ANSWERS)
reponse = models.CharField(
_("Réponse"), max_length=20, default="non", choices=ANSWERS
)
instrument = models.CharField(
max_length=50, blank=True, null=True, choices=INSTRU_CHOICES
)
instrument_autre = models.CharField(max_length=50, blank=True, null=True)
dont_play_main = models.CharField(
_("Je veux jouer d'un instrument different de mon instrument principal:"),
default="Non",
null=False,
max_length=3,
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
)
details = models.CharField(max_length=50, blank=True)
creationDate = models.DateTimeField(
auto_now_add=True, verbose_name=_("Date de création")
)
updateDate = models.DateTimeField(
auto_now=True, verbose_name=_("Dernière mise à jour")
)
class Meta:
constraints = [ models.UniqueConstraint(fields=['event', 'participant'], name='reponse unique aux event') ]

View file

@ -0,0 +1,38 @@
.a2cldr {
height: 46px;
width: 246px;
position: relative;
color: #032c53;
font-family: sans-serif;
}
.a2cldr.active .a2cldr-list {
display: block;
}
.a2cldr-list {
position: relative;
z-index: 2;
padding: 0 12px;
display: none;
background-color: #000;
box-shadow: 0px 8px 20px 0px #bababa;
}
.a2cldr-item {
list-style: none;
padding: 14px 0;
border-bottom: 1px solid #f3f3f3;
}
.a2cldr-item a {
color: #032c53;
text-decoration: none;
width: 100%;
display: block;
}
.a2cldr-item a:hover {
color: #032c53;
text-decoration: underline;
}
.a2cldr-item:last-child {
border-bottom: 0;
}

View file

@ -0,0 +1,683 @@
/* global module */
// prefix: a2cldr
var Add2Calendar = function(eventData) {
/*================================================================ Util
*/
/**
* Check if the element has this class name
*
* @param {[type]} ele
* @param {String} cls
* @return {Boolean}
*/
this.hasClass = function(ele, cls) {
return (' ' + ele.className + ' ').indexOf(' ' + cls + ' ') > -1;
};
this.mergeObj = function(obj1, obj2) {
var result = {}
for (var attr1 in obj1) { result[attr1] = obj1[attr1]; }
for (var attr2 in obj2) { result[attr2] = obj2[attr2]; }
return result;
};
/**
* @see https://stackoverflow.com/questions/2998784/how-to-output-numbers-with-leading-zeros-in-javascript
* @param {Number} number
* @param {Number} size
*/
this.pad = function(number, size) {
var num = number.toString();
while (num.length < size) num = "0" + num;
return num;
};
/**
* formatTime
*
* @todo change naming
* @param {Date} date
* @return {string} e.g. "20191223T110000Z", "20191223T230000Z"
*/
this.formatTime = function(date) {
return date.toISOString().replace(/-|:|\.\d+/g, '');
};
/**
* [formatTime2 description]
* this method ignore timezone
*
* @see https://stackoverflow.com/questions/43670062/get-iso-string-from-a-date-without-time-zone
* @todo change naming
* @param {Date} date
* @return {string} e.g. "20191223", "20191224"
*/
this.formatTime2 = function(date) {
return this.pad(date.getFullYear(), 4) + this.pad(date.getMonth() + 1, 2) + this.pad(date.getDate(), 2)
};
/**
* [isValidEventData description]
* UNUSED, UNCOMPLETE
* TODO
* - validate `eventData`
* - require only `start`
* - validate both single and multi
*
* @see http://stackoverflow.com/questions/5812220/how-to-validate-a-date
* @see http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript
*
* @param {[type]} args [description]
* @return {Boolean} [description]
*/
this.isValidEventData = function(eventData) {
if (this.isSingleEvent) {
// HACK
return true;
} else {
if (eventData.length > 0) {
// HACK
return true;
}
}
return false;
};
this.isObjectType = function(obj, type) {
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
};
/**
* [isDateObject description]
* UNUSED
*
* @see http://stackoverflow.com/questions/643782/how-to-check-whether-an-object-is-a-date
*
* @param {[type]} obj [description]
* @return {Boolean} [description]
*/
this.isDateObject = function(obj) {
return this.isObjectType(obj, 'Date');
};
this.isArray = function(obj) {
return this.isObjectType(obj, 'Array');
};
this.isFunc = function(obj) {
return this.isObjectType(obj, 'Function');
};
/**
* [serialize description]
* Object to query string (encode)
*
* @see http://stackoverflow.com/questions/1714786/querystring-encoding-of-a-javascript-object
*
* @param {[type]} obj [description]
* @return {[type]} [description]
*/
this.serialize = function(obj) {
var str = [];
for (var p in obj) {
// eslint-disable-next-line
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
}
}
return str.join('&');
};
/**
* [replaceSpecialCharacterAndSpaceWithHyphen description]
*
* @see http://stackoverflow.com/questions/18936483/regex-for-replacing-all-special-characters-and-spaces-in-a-string-with-hyphens
*
* @param {[type]} str [description]
* @return {[type]} [description]
*/
this.replaceSpecialCharacterAndSpaceWithHyphen = function(str) {
// eslint-disable-next-line
return str.replace(/([~!@#$%^&*()_+=`{}\[\]\|\\:;'<>,.\/? ])+/g, '-').replace(/^(-)+|(-)+$/g,'');
};
this.getLinkHtml = function(text, url, customClass, isEnableDownloadAttr, uniqueId) {
if (typeof isEnableDownloadAttr === 'undefined') { isEnableDownloadAttr = false; }
if (typeof uniqueId === 'undefined') { uniqueId = this.getCurrentUtcTimestamp(); }
var downloadAttr = '';
if (isEnableDownloadAttr) {
var fileName = 'add2Calendar-' + this.replaceSpecialCharacterAndSpaceWithHyphen(text).toLowerCase() + '-' + uniqueId;
downloadAttr = ' download="' + fileName + '" ';
}
return '<a ' + downloadAttr + ' class="' + customClass + '" target="_blank" href="' + url + '">' + text + '</a>';
};
/**
* [getLiHtml description]
*
* @see http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
*
* @param {[type]} text [description]
* @param {[type]} url [description]
* @param {[type]} customClass [description]
* @param {Boolean} isEnableDownloadAttr [description]
* @return {[type]} [description]
*/
this.getLiHtml = function(text, url, customClass, isEnableDownloadAttr, uniqueId) {
var result = '',
isValid = false;
// Validate
if (url) {
if (customClass === 'ical' || customClass === 'outlook') {
isValid = true;
} else {
var urlLength = url.length;
if (urlLength <= 20000) {
isValid = true;
} else {
console.log('Url longer than 2000');
}
}
}
if (isValid) {
var linkHtml = this.getLinkHtml(text, url, 'icon-' + customClass, isEnableDownloadAttr, uniqueId);
result = '<li class="a2cldr-item a2cldr-' + customClass + '">' + linkHtml + '</li>';
}
return result;
};
this.getCurrentUtcTimestamp = function() {
return Date.now();
};
/*================================================================ Google
*/
/**
* @todo take an arguments and return it instead of doing internal manipulation
*/
this.updateGoogleUrl = function() {
if (this.isSingleEvent) {
var startDate = this.eventData.isAllDay
? this.formatTime2(new Date(this.eventData.start))
: this.formatTime(new Date(this.eventData.start));
var endDate = this.eventData.isAllDay
? this.formatTime2(new Date(this.eventData.end))
: this.formatTime(new Date(this.eventData.end));
var googleArgs = {
'text' : (this.eventData.title || ''),
'dates' : startDate + '/' + endDate,
'location' : (this.eventData.location || ''),
'details' : (this.eventData.description || ''),
'ctz' : (this.eventData.timezone || ''),
'locale' : (this.eventData.locale || ''),
'sprop' : ''
};
this.googleUrl = 'https://www.google.com/calendar/render?action=TEMPLATE&' + this.serialize(googleArgs);
}
return this.googleUrl;
}
this.getGoogleUrl = function() {
return this.googleUrl;
};
this.getGoogleLiHtml = function() {
return this.getLiHtml('Google', this.googleUrl, 'google');
};
this.openGoogle = function() {
window.open(this.googleUrl);
};
/*================================================================ iCal / Outlook
*/
/**
* @todo take an arguments and return it instead of doing internal manipulation
*/
this.updateICalUrl = function() {
var url = typeof document !== 'undefined' ? document.URL : ''; // todo fix it
var startDate = ''
var endDate = ''
if (this.isSingleEvent) {
startDate = this.eventData.isAllDay
? this.formatTime2(new Date(this.eventData.start))
: this.formatTime(new Date(this.eventData.start));
endDate = this.eventData.isAllDay
? this.formatTime2(new Date(this.eventData.end))
: this.formatTime(new Date(this.eventData.end));
this.iCalUrl = encodeURI(
'data:text/calendar;charset=utf8,' +
[
'BEGIN:VCALENDAR',
'VERSION:2.0',
'BEGIN:VEVENT',
'URL:' + url,
'DTSTART:' + startDate,
'DTEND:' + endDate,
'SUMMARY:' + (this.eventData.title || ''),
'DESCRIPTION:' + (this.eventData.description || ''),
'LOCATION:' + (this.eventData.location || ''),
'END:VEVENT',
'END:VCALENDAR'
].join('\n')
);
} else {
var i = 0,
n = this.eventData.length;
var iCalData = [];
for (i = 0; i < n; i++) {
var data = this.eventData[i];
startDate = this.eventData.isAllDay
? this.formatTime2(new Date(data.start))
: this.formatTime(new Date(data.start));
endDate = this.eventData.isAllDay
? this.formatTime2(new Date(data.end))
: this.formatTime(new Date(data.end));
var tmp = [
'BEGIN:VEVENT',
'URL:' + url,
'DTSTART:' + startDate,
'DTEND:' + endDate,
'SUMMARY:' + (data.title || ''),
'DESCRIPTION:' + (data.description || ''),
'LOCATION:' + (data.location || ''),
'END:VEVENT',
];
iCalData = iCalData.concat(tmp);
}
var iCalDataBegin = [
'BEGIN:VCALENDAR',
'VERSION:2.0'
];
var iCalDataAfter = [
'END:VCALENDAR'
];
iCalData = iCalDataBegin.concat(iCalData, iCalDataAfter).join('\n');
this.iCalUrl = encodeURI('data:text/calendar;charset=utf8,' + iCalData);
}
// data is truncated when it contains a "#" character
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
// https://en.wikipedia.org/wiki/Percent-encoding
this.iCalUrl = this.iCalUrl.replace(/#/g, '%23');
return this.iCalUrl;
};
this.getICalUrl = function() {
return this.iCalUrl;
};
this.getICalLiHtml = function() {
return this.getLiHtml('iCal', this.iCalUrl, 'ical', true);
};
this.openICal = function() {
window.open(this.iCalUrl);
};
// Same as getICalUrl
this.getOutlookUrl = function() {
return this.iCalUrl;
};
// Same as getICalLiHtml
this.getOutlookLiHtml = function() {
return this.getLiHtml('Outlook', this.iCalUrl, 'outlook', true);
};
// Same as openICal
this.openOutlook = function() {
window.open(this.iCalUrl);
};
/*================================================================ Outlook Online
*/
/**
* @todo complete it
* @todo take an arguments and return it instead of doing internal manipulation
*/
this.updateOutlookOnlineUrl = function() {
if (this.isSingleEvent) {
var startDate = new Date(this.eventData.start),
endDate = new Date(this.eventData.end);
var startDateTimezoneOffset = startDate.getTimezoneOffset();
startDate.setMinutes(startDate.getMinutes() - 2 * startDateTimezoneOffset); // HACK
var endDateTimezoneOffset = endDate.getTimezoneOffset();
endDate.setMinutes(endDate.getMinutes() - endDateTimezoneOffset); // HACK
startDate = this.formatTime(startDate).slice(0, -1);
endDate = this.formatTime(endDate).slice(0, -1);
var outlookOnlineArgs = {
'summary' : (this.eventData.title || ''),
'dtstart' : startDate,
'dtend' : endDate,
'location' : (this.eventData.location || ''),
'description' : (this.eventData.description || '')
};
this.outlookOnlineUrl = 'http://calendar.live.com/calendar/calendar.aspx?rru=addevent&' + this.serialize(outlookOnlineArgs);
}
return this.outlookOnlineUrl;
};
this.getOutlookOnlineUrl = function() {
return this.outlookOnlineUrl;
};
this.getOutlookOnlineLiHtml = function() {
return this.getLiHtml('Outlook Online', this.outlookOnlineUrl, 'outlook-online');
};
this.openOutlookOnline = function() {
window.open(this.outlookOnlineUrl);
};
/*================================================================ Yahoo
*/
/**
* @todo take an arguments and return it instead of doing internal manipulation
*/
this.updateYahooUrl = function() {
if (this.isSingleEvent) {
var startDate = this.eventData.isAllDay
? this.formatTime2(new Date(this.eventData.start))
: this.formatTime(new Date(this.eventData.start))
// FIXED: Yahoo! calendar bug
//
// Yahoo! did calculate timezone for `start`
// but they did not calculate timezone for `end`
var tmp = new Date(this.eventData.end);
var timezoneOffset = tmp.getTimezoneOffset();
tmp.setMinutes(tmp.getMinutes() - timezoneOffset);
var endDate = this.eventData.isAllDay
? this.formatTime2(tmp)
: this.formatTime(tmp)
var yahooArgs = {
'view' : 'd',
'type' : '20',
'title' : (this.eventData.title || ''),
'st' : startDate,
'et' : endDate,
// 'dur' : '',
'in_loc' : (this.eventData.location || ''),
'desc' : (this.eventData.description || '')
};
this.yahooUrl = 'https://calendar.yahoo.com/?v=60&' + this.serialize(yahooArgs);
}
return this.yahooUrl;
};
this.getYahooUrl = function() {
return this.yahooUrl;
};
this.getYahooLiHtml = function() {
return this.getLiHtml('Yahoo!', this.yahooUrl, 'yahoo');
};
this.openYahoo = function() {
window.open(this.yahooUrl);
};
/*================================================================ Widget
*/
this.getEventListHtml = function() {
var html = '<ul class="a2cldr-list">';
html += this.getEventListItemsHtml();
html += '</ul>';
return html;
};
this.getEventListItemsHtml = function() {
var html = '';
html += this.getGoogleLiHtml();
html += this.getICalLiHtml();
html += this.getOutlookLiHtml();
html += this.getOutlookOnlineLiHtml();
html += this.getYahooLiHtml();
return html;
};
// UNUSED
// QUITE DUPLICATE
this.getEventNotFoundListHtml = function() {
var html = '<ul class="a2cldr-list">';
html += this.getEventNotFoundListItemsHtml();
html += '</ul>';
return html;
};
// UNUSED
// QUITE DUPLICATE
this.getEventNotFoundListItemsHtml = function() {
var html = '';
html += '<li class="a2cldr-item a2cldr-not-found">';
html += '<span class="not-found" href="javascript:;">Not Found</span>';
html += '</li>';
return html;
};
this.getWidgetNode = function() {
var html = '<button class="a2cldr-btn" type="button">';
html += this.getWidgetBtnText();
html += '</button>';
html += this.getEventListHtml();
var result = document.createElement('div');
result.innerHTML = html;
result.className = this.textDomain;
return result;
};
this.getWidgetBtnText = function() {
var result = (this.option.buttonText)
? this.option.buttonText
: this.add2calendarBtnTextMap[this.option.lang];
return result;
};
/*================================================================ API (Public)
*/
this.createWidget = function(selector, cb) {
this.selector = selector;
this.eWidget = document.querySelector(selector);
// create and append into the DOM
var node = this.getWidgetNode();
this.eWidget.appendChild(node);
// bind an event
this.eButton = document.querySelector(selector + ' > .a2cldr > .a2cldr-btn');
this.bindClickEvent();
// callback
if (this.isFunc(cb)) {
cb();
}
};
this.bindClickEvent = function() {
var activeClassName = 'active';
var self = this;
var ele = this.eButton;
ele.onclick = function() {
var parent = ele.parentNode;
if (self.hasClass(parent, activeClassName)) {
parent.classList.remove(activeClassName);
} else {
parent.classList.add(activeClassName);
}
}
};
this.unBindClickEvent = function() {
if (this.eButton && this.eButton.onclick) {
this.eButton.onclick = null;
}
};
this.setOption = function(option) {
this.userOption = option;
this.option = this.mergeObj(this.defaultOption, this.userOption);
};
this.resetOption = function() {
this.option = this.defaultOption;
};
/*================================================================ API (Public) - In progress
*/
this.update = function(eventData) {
this.init(eventData);
};
this.updateWidget = function(eventData, cb) {
this.update(eventData);
var ele = document.querySelector(this.selector + ' .a2cldr-list');
ele.innerHTML = this.getEventListItemsHtml();
if (this.isFunc(cb)) {
cb();
}
};
/*================================================================ Global var
*/
this.textDomain = 'a2cldr';
this.add2calendarBtnTextMap = {
'en': 'Add to Calendar',
'th': 'เพิ่มเข้าปฏิทิน',
'jp': 'カレンダーに追加',
'kr': '캘린더에 추가',
'ja': 'カレンダーに追加',
'cn': '添加到日历',
'de': 'In den Kalender',
'es': 'Añadir al Calendario',
'fr': 'Ajouter au calendrier',
'ru': 'Добавить в календарь'
};
this.isSingleEvent;
// constructor parameter
this.eventData;
this.selector;
this.eWidget;
// option
this.defaultOption;
this.userOption;
this.option;
this.googleUrl;
this.iCalUrl; // iCal and Outlook
this.yahooUrl;
this.outlookOnlineUrl;
/*================================================================ Init & Others
*/
this.updateAllCalendars = function() {
this.updateGoogleUrl();
this.updateICalUrl();
this.updateYahooUrl();
// disabled@01112016-1146 - cause it's not working
// this.updateOutlookOnlineUrl();
};
this.init = function(eventData) {
this.isSingleEvent = ! this.isArray(eventData);
if (! this.isValidEventData(eventData)) {
console.log('Event data format is not valid');
return false;
}
this.eventData = eventData;
this.selector = '';
this.eWidget = null; // widget element
this.eButton = null; // button element to click for opening the list
this.defaultOption = {
lang: 'fr',
buttonText: '',
};
this.option = this.defaultOption;
this.googleUrl = '';
this.iCalUrl = ''; // iCal and Outlook
this.yahooUrl = '';
this.outlookOnlineUrl = '';
this.updateAllCalendars();
};
this.init(eventData);
};
if (typeof module !== 'undefined' &&
module.exports != null) {
module.exports = Add2Calendar
}

View file

@ -13,10 +13,23 @@
<!-- One -->
<section class="wrapper style1" >
<div class="inner">
<p align="center"><div><span class="image right"><img src="{% static 'images/agenda.jpg' %}" alt="" />
<p align="center"><div><span class="image right">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/agenda.jpg' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div>
{% endif %}
</span></div>
<h2 align="center">{% trans "Découvrez les différents évènements de l'Ernestophone !" %}</h2>
@ -33,15 +46,7 @@
<a href="mailto:fanfare@ens.fr" class="icon fa-envelope fa-5x "><span
class="label">Mail</span></a>
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
<a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ"
class="icon fa-youtube-play fa-5x"><span class="label">Youtube</span></a>
</div>
</div>
</div>
@ -98,7 +103,7 @@
</tbody>
</table>
</div>
<h1> {% blocktrans count counter=events_passe|length %}Evénement passé :{% plural %}Evénements passés :{% endblocktrans %} </h1>
<div class="table-wrapper" color="white">
@ -154,4 +159,5 @@
</div>
{% endblock %}

View file

@ -4,6 +4,7 @@
{% load i18n %}
{% load translate %}
{% load autotranslate %}
{% get_current_language as current_language %}
{% block extrahead %}
@ -16,28 +17,28 @@
<div id="main">
<section class="wrapper style1">
<div class="inner">
<span class="image fit">
<img src="{% static 'images/home.png' %}"/>
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="" class="icon fa-copyright">lor_tie</a>
</div>
</span>
{% if actu %}
<div class="box" style="background-color:rgba(228,82,47,0.5)">
<h4> {% blocktrans count counter=actu|length %}Actualité des chef·fe·s:{% plural %}Actualités des chef·fe·s:{% endblocktrans %}</h4>
<ul>
{% for a in actu %}
<li>{% autotranslate current_language a.text a.text_en %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div id="instagram-feed" class="instagram_feed"> </div>
<h4>{% trans "Agenda :" %} </h4>
<div class="row">
<div class="6u 12u$(small)">
{% if actu %}
<div class="box" style="background-color:rgba(228,82,47,0.5)">
<h4> <span class="ernestocouleur">{% blocktrans count counter=actu|length %}Actualité des chef·fe·s:{% plural %}Actualités des chef·fe·s:{% endblocktrans %}</span></h4>
<ul>
{% for a in actu %}
<li>{% if a.rainbow == 'y' %}<span class="ernestocouleur font-weight-bold">{% endif %}{% autotranslate current_language a.text a.text_en %}{% if a.rainbow %}</span>{% endif %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<h4><span class="ernestocouleur">{% trans "Agenda :" %}</span></h4>
<table width="100%" style="background-color:#e4522f" >
<tr>
<td width="20%" align="left">
@ -59,18 +60,98 @@
</tr>
</table>
<div id="calendar">
{% if user.profile.is_chef_event or user.profile.is_chef %}
{% ifequal current_language "fr" %}
{{Calendar_chef|translate}}
{% else %}
{{Calendar_chef}}
{% endifequal %}
{% else %}
{% ifequal current_language "fr" %}
{{Calendar|translate}}
{% else %}
{{Calendar}}
{% endifequal %}
{% endif%}
</div>
{% if user.profile.is_chef %}
{% if user.profile.is_chef_event or user.profile.is_chef %}
<a href="{% url "calendrier:create_event" %}" class="button">{% trans "Ajouter un évènement" %}</a>
{% endif %}
</div>
<div class="1u 12u$(small)"><p></p></div>
<div class="5u 12u$(small)">
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/home.png' %}"/>
<div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright"> lor_tie</div>
</div>
{% endif %}
</span>
{% if user.profile.is_chef_event or user.profile.is_chef %}
{% if events_a_venir_chef %}
<div class="box" style="background-color:#4169E1">
<h1> {% blocktrans count counter=events_a_venir_chef|length %}Doodle seulement visible par les cheff·e·s :{% plural %}Doodles seulement visibles par les cheff·e·s :{% endblocktrans %} </h1>
<div class="table-wrapper">
<table class="default">
<thead>
<tr>
<th>{% trans "Nom" %}</th>
<th>{% trans "Date" %}</th>
<th>{% trans "Lieu" %}</th>
</tr>
</thead>
<tbody>
{% for e in events_a_venir_chef %}
<tr>
<td><b><u><a href="{% url 'calendrier:view-event' e.id %}">{{ e.nom }}</a></u></b></td>
<td>{% blocktrans with date=e.date debut=e.debut %}Le {{ date }} à {{ debut }} {% endblocktrans %} </td>
<td> {{e.lieu}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% if events_a_venir_chef_public %}
<div class="box" style="background-color:#a9008a">
<h1> {% blocktrans count counter=events_a_venir_chef_public|length %}Doodle visible par les cheff·e·s et le public :{% plural %}Doodles seulement visibles par les cheff·e·s :{% endblocktrans %} </h1>
<div class="table-wrapper">
<table class="default">
<thead>
<tr>
<th>{% trans "Nom" %}</th>
<th>{% trans "Date" %}</th>
<th>{% trans "Lieu" %}</th>
</tr>
</thead>
<tbody>
{% for e in events_a_venir_chef_public %}
<tr>
<td><b><u><a href="{% url 'calendrier:view-event' e.id %}">{{ e.nom }}</a></u></b></td>
<td>{% blocktrans with date=e.date debut=e.debut %}Le {{ date }} à {{ debut }} {% endblocktrans %} </td>
<td> {{e.lieu}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% endif %}
{% if events_a_venir_not_answered %}
<div class="box" style="background-color:#e4522f">
<h1> {% blocktrans count counter=events_a_venir_not_answered|length %}Doodle à remplir !!!! :{% plural %}Doodles à remplir !!!! :{% endblocktrans %} </h1>
@ -182,10 +263,29 @@
</div>
{% endif %}
</div>
</div>
</div>
</section>
</div>
<script src="{% static 'js/InstagramFeed.min.js' %}"></script>
<script>
(function(){
new InstagramFeed({
'username': 'ernestophone',
'container': "#instagram-feed" ,
'display_profile': false,
'display_biography': false,
'display_gallery': true,
'display_captions': true,
'callback': null,
'styling': true,
'items': 8,
'items_per_row': 8,
'margin': 1
});
})();
</script>
{% endblock %}

View file

@ -6,6 +6,12 @@
<div id="main">
<section class="wrapper style1">
<div class="inner">
{% if not user.is_superuser or not user.profile.is_chef %}
{% if user.is_superuser or user.profile.is_chef %}
{% trans "Cet événement est encore en construction ! Reviens plus tard." %}
{% endif %}
{% endif %}
{% if user.is_superuser or user.profile.is_chef or not chef_only%}
<div class="row">
<div class="6u 12u$(small)">
{% if envoi %}<p>{% trans "Votre réponse a été enregistrée !" %}</p>{% endif %}
@ -13,15 +19,69 @@
<p><a href="{% url 'calendrier:view-event' id %}" class="button alt">{% trans "Retour à l'événement" %}</a></p>
<div><h4> {% blocktrans with nom=ev.nom date=ev.date debut=ev.debut|time:"H:i" %} Voulez vous participer à l'événement {{ nom }}, le {{ date }} à {{ debut }} ?{% endblocktrans %}</h4></div>
<p> <b>{% trans "Instrument principal"%} : {% if request.user.profile.instru == "Autre" %}{{request.user.profile.instru_autre}}{% else %}{{request.user.profile.instru}}{% endif %}</b></p>
<form action="{% url 'calendrier:reponse' id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
{{ form.non_field_errors }}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{% if field.id_for_label == "id_dont_play_main" %}
<div id="dont_play_main_field" {% if request.user.profile.multi_instrumentiste == "Non" %} style="display: none; "{% endif %}>
{% elif field.id_for_label == "id_instrument" %}
<div id="instru_ev_field" style="display: none; ">
{% elif field.id_for_label == "id_instrument_autre" %}
<div id="instru_autre_ev_field" style="display: none; ">
{% else %}
<div>
{% endif %}
<p>{{ field.label_tag }}
{{ field }} {% if field.help_text %}
{{ field.help_text|safe }}
{% endif %}</p>
</div>
</div>
{% endfor %}
<input type="submit" value="{% trans "Valider" %}" />
</form>
</div>
</div>
{% endif %}
</div>
</section>
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
$('#id_dont_play_main').on('change', function() {
if (this.value == "Oui" ) {
$('#instru_ev_field').show();
}
else {
$('#instru_ev_field').hide();
}
});
</script>
<script type="text/javascript">
$('#id_instrument').on('change', function() {
if (this.value == "Autre" ) {
$('#instru_autre_ev_field').show();
}
else {
$('#instru_autre_ev_field').hide();
}
});
</script>
{% endblock %}

View file

@ -1,17 +0,0 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Participation à un événement" %}{% endblock %}
{% block content %}
{% if envoi %}<p>{% trans "Votre réponse a été enregistrée !" %}</p>{% endif %}
<p><a href="{% url 'calendrier:view-event' id %}">{% trans "Retour à l'événement" %}</a></p>
<div> {% blocktrans with nom=ev.nom date=ev.date debut=ev.debut%} Voulez vous participer à l'événement {{ nom }}, le {{ date }} à {{ debut|time:"H:i" }} ?{% endblocktrans %}</div>
<form action="{% url 'calendrier:reponse' id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Valider" %}" />
</form>
{% endblock %}

View file

@ -3,15 +3,23 @@
{% load autotranslate %}
{% get_current_language as current_language %}
{% block titre %}{{ event.nom.capitalize }}{% endblock %}
{% block extrahead %}
{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
{% if not user.profile.is_chef and not user.profile.is_chef_event %}
{% if chef_only %}
{% trans "Cet événement est encore en construction ! Reviens plus tard." %}
{% endif %}
{% endif %}
{% if user.profile.is_chef_event or user.profile.is_chef or not chef_only%}
<div class="row">
<div class="6u 12u$(small)">
<div id="viewevent">
<div id="viewevent">
<h2>{{ event.nom.capitalize }}</h2>
<h4>
{% blocktrans with date=event.date%} Le {{ date }}{% endblocktrans %}
@ -24,6 +32,7 @@
</h4>
{% if user.is_authenticated and event.desc_users %}
<div class="box">
{% autotranslate current_language event.desc_users event.desc_users_en %}
@ -76,12 +85,12 @@
</tbody>
</table>
</div>
<p><a href="{% url 'calendrier:reponse' event.id %}" class="button">{% trans "Répondre à l'événement" %}</a></p>
<p><a href="{% url 'calendrier:reponse' event.id %}" class="button">{% trans "Répondre à l'événement" %}</a> <div class="event-box" id="single-normal"></div></p>
</div>
{% endif %}
</div>
<div class="6u 12u$(small)">
{% if instrument_count and user.profile.is_chef %}
{% if user.profile.is_chef or user.profile.is_chef_event %}
<table class="table">
<tr>
<th>{% trans "Instrument" %}</th>
@ -153,14 +162,14 @@
{% endfor %}
</table>
{% endif %}
{% if multi_instrumentistes and user.profile.is_chef %}
{% if user.profile.is_chef or user.profile.is_chef_event %}
{% if multi_instrumentistes %}
<h1>{% blocktrans count counter=multi_instrumentistes|length %}Multi-instrumentiste présent :{% plural %}Multi-instrumentistes présents{% endblocktrans %}</h1>
<table class="table">
<tr>
<th>{% trans "Nom" %}</th>
<th>{% trans "Instrument principal" %}</th>
<th>{% trans "Instrument" %}</th>
<th>{% trans "Instrument·s bonus" %}</th>
<th>{% trans "Réponse" %}</th>
</tr>
@ -173,21 +182,36 @@
{% endif %}
</td>
<td>{% if participant.participant.instru == "Autre" %}
<td>{% if participant.dont_play_main == 'Oui' %}
{% if participant.instrument == "Autre" %}
{{participant.instrument_autre}}
{% else %}
{{participant.instrument}}
{% endif %}
{% elif participant.participant.instru == "Autre" %}
{{participant.participant.instru_autre}}
{% else %}
{{ participant.participant.instru }}
{% endif %}</td>
<td>{{ participant.participant.instru_bonus }}</td>
<td>{% if participant.dont_play_main == 'Oui' %}
{% if participant.participant.instru == "Autre" %}
{{participant.participant.instru_autre}}
{% else %}
{{ participant.participant.instru }}
{% endif %}<br>{% endif %}
{% if participant.instrument != participant.participant.instru_bonus %}
{{ participant.participant.instru_bonus }}
{% endif %}</td>
<td>{{participant.reponse}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
</div>
<div class="6u 12u$(small)">
{% if user.is_authenticated %}
<div id="actions"> {% if user.profile.is_chef %}
<div id="actions"> {% if user.profile.is_chef or user.profile.is_chef_event %}
<p><a href="{% url "calendrier:edit_event" event.id %}" class="button alt">{% trans "Modifier l'événement" %}</a> &nbsp <a href="{% url "calendrier:delete_event" event.id %}" class="button alt">{% trans "Supprimer l'événement" %}</a></p>
{% endif %}
<p><a href="{% url 'calendrier:change-doodle-name' event.id %}" class="button">{% trans "Changer mon nom pour le doodle" %}</a> &nbsp <a href="{% url 'calendrier:home' %}" class="button">{% trans "Retour au calendrier" %}</a></p>
@ -195,7 +219,61 @@
{% endif %}
</div>
</div>
{% endif %}
</div>
</section>
</div>
{% if event.id == 573 %}
<div class="fireworks" style="pointer-events: none; position:fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100%; weight: 100%;"></div>
{% endif %}
{% endblock %}
{% block script %}
<script>
/*================================ Single Event
*/
var startDate,
endDate;
var tmpstart = new Date('{{ event.date.isoformat }}'+' '+'{{ event.debut.isoformat }}'+':00');
startDate = tmpstart.toString();
{% if event.fin %}
var tmpend = new Date('{{ event.date.isoformat }}'+' '+'{{ event.fin.isoformat }}'+':00');
endDate = tmpend.toString();
{% else %}
var tmpend = new Date('{{ event.date.isoformat }}'+' '+'{{ event.debut.isoformat }}'+':00');
tmpend.setHours(tmpend.getHours() +2)
endDate = tmpend.toString();
{% endif %}
var singleEventArgs = {
title : '{{ event.nomcourt}}',
start : startDate,
end : endDate,
location : '{{ event.lieu}}',
description : ''
};
var singleEvent = new Add2Calendar(singleEventArgs);
// widget 1 - normal
singleEvent.createWidget('#single-normal', function() {
console.log('#single-normal widget has been created');
});
{% ifequal current_language "fr" %}
singleEvent.setOption({ lang: 'fr' });
{% else %}
singleEvent.setOption({ lang: 'en' });
{% endifequal %}
</script>
{% if event.id == 573 %}
<script src="https://unpkg.com/fireworks-js@2.x/dist/index.umd.js"></script>
<script>
const container = document.querySelector('.fireworks');
const fireworks = new Fireworks.default(container);
fireworks.updateOptions({ acceleration: 1.01, traceSpeed: 5 });
fireworks.start();
</script>
{% endif %}
{% endblock %}

View file

@ -20,7 +20,7 @@ def translate(tex):
tex = tex.replace("December", "Décembre", 1)
tex = tex.replace("Mon", "Lun", 1)
tex = tex.replace("Tue", "Mar", 1)
tex = tex.replace('Wed', "Mer", 1)
tex = tex.replace("Wed", "Mer", 1)
tex = tex.replace("Thu", "Jeu", 1)
tex = tex.replace("Fri", "Ven", 1)
tex = tex.replace("Sat", "Sam", 1)

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -4,8 +4,8 @@ from django.contrib.auth import get_user_model
from django.template.defaultfilters import urlencode
from django.test import Client, TestCase
from django.utils import timezone
from gestion.models import ErnestoUser
from ..models import Event
User = get_user_model()
@ -28,11 +28,7 @@ class TestViews(TestCase):
ernesto = new_user("ernesto", ernesto=True)
ernesto_c = Client()
ernesto_c.force_login(ernesto)
self.client_matrix = [
(chef, chef_c),
(ernesto, ernesto_c),
(None, Client())
]
self.client_matrix = [(chef, chef_c), (ernesto, ernesto_c), (None, Client())]
# A private and a public event
now = timezone.now()
later = now + timedelta(seconds=3600)
@ -44,7 +40,7 @@ class TestViews(TestCase):
fin=later.time(),
slug="privevt",
lieu="somewhere",
calendrier=False
calendrier=False,
)
self.pub_event = Event.objects.create(
nom="public event",
@ -54,7 +50,7 @@ class TestViews(TestCase):
fin=later.time(),
slug="pubevt",
lieu="somewhere",
calendrier=True
calendrier=True,
)
# Everyone can see theses pages
@ -88,13 +84,16 @@ class TestViews(TestCase):
chef, _ = self.client_matrix[0]
codereps = ["oui", "non", "pe"]
for coderep in codereps:
url = "/calendar/rep/{}/{}/{}".format(chef.profile.slug, self.priv_event.slug, coderep)
url = "/calendar/rep/{}/{}/{}".format(
chef.profile.slug, self.priv_event.slug, coderep
)
self._everyone_can_get(url, redirect_url="/calendar/")
# Only ernesto members can get theses pages
def _get_restricted_page(self, url, chef_only=False, redirect_url=None):
"""Shorthand for testing wether a page in only accessible by ernesto members"""
def user_allowed(user):
if user is None:
return False

View file

@ -1,17 +1,17 @@
from django.urls import path
from . import views
from .views import EventUpdate, EventDelete
from .views import EventDelete, EventUpdate
app_name = 'calendrier'
app_name = "calendrier"
urlpatterns = [
path('', views.liste, name='liste'),
path("calendar", views.home, name="home"),
path("new", views.create_event, name="create_event"),
path("", views.Agenda.as_view(), name="liste"),
path("calendar", views.Home.as_view(), name="home"),
path("new", views.CreateEvent.as_view(), name="create_event"),
path("edition/<int:pk>", EventUpdate.as_view(), name="edit_event"),
path("supprimer/<int:pk>", EventDelete.as_view(), name="delete_event"),
path("<int:id>/changename", views.changename, name="change-doodle-name"),
path("<int:id>/reponse", views.reponse, name="reponse"),
path("<int:pYear>/<int:pMonth>", views.calendar, name="view-month"),
path("<int:id>", views.view_event, name="view-event"),
path("<int:id>/changename", views.ChangeName.as_view(), name="change-doodle-name"),
path("<int:id>/reponse", views.ReponseEvent.as_view(), name="reponse"),
path("<int:pYear>/<int:pMonth>", views.Calendar.as_view(), name="view-month"),
path("<int:id>", views.ViewEvent.as_view(), name="view-event"),
]

View file

@ -1,261 +1,418 @@
import random
import string
from calendar import monthrange
from collections import defaultdict
from datetime import date, datetime
import string
import random
from django.db.models import Q
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.sites.shortcuts import get_current_site
from django.db.models import Count
from django.utils.safestring import mark_safe
from django.views.generic import UpdateView, DeleteView
from django.urls import reverse, reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.core.mail import send_mail
from django.http import Http404
from gestion.models import ErnestoUser
from actu.models import Actu
from calendrier.calend import EventCalendar
from calendar import monthrange
from calendrier.forms import ModifEventForm, EventForm, ParticipantsForm, ChangeDoodleName
from calendrier.models import Event, Participants
from partitions.decorators import chef_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.utils.safestring import mark_safe
from django.views.generic import DeleteView, TemplateView, UpdateView
from gestion.mixins import ChefEventRequiredMixin
from gestion.models import Photo
from calendrier.calend import EventCalendar
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
ParticipantsForm)
from calendrier.models import Event, Participants
def generer(*args):
caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire)
def liste(request):
if request.user.is_authenticated :
return redirect('calendrier:home')
lToday = datetime.today()
events_a_venir = Event.objects.filter(date__gte = lToday).exclude(calendrier__iexact = 'F')
events_passe = Event.objects.filter(date__lt = lToday).filter(calendrier__iexact = 'H')
return render(request, 'calendrier/agenda.html', {"events_a_venir": events_a_venir,"events_passe":events_passe})
return "".join(aleatoire)
def named_month(pMonthNumber):
return date(1900, pMonthNumber, 1).strftime('%B')
@login_required
def home(request):
lToday = datetime.now()
return calendar(request, lToday.year, lToday.month)
@login_required
def calendar(request, pYear, pMonth):
actu = Actu.objects.all()
lToday = datetime.now()
lYear = int(pYear)
lMonth = int(pMonth)
lCalendarFromMonth = datetime(lYear, lMonth, 1)
lCalendarToMonth = datetime(lYear, lMonth, monthrange(lYear, lMonth)[1])
lEvents = Event.objects.filter(
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
)
if request.user.is_authenticated:
lEvents = Event.objects.filter(date__gte=lCalendarFromMonth,
date__lte=lCalendarToMonth)
lCalendar = EventCalendar(lEvents).formatmonth(lYear, lMonth)
lPreviousYear = lYear
lPreviousMonth = lMonth - 1
if lPreviousMonth == 0:
lPreviousMonth = 12
lPreviousYear -= 1
lNextYear = lYear
lNextMonth = lMonth + 1
if lNextMonth == 13:
lNextMonth = 1
lNextYear = lYear + 1
lYearAfterThis = lYear + 1
lYearBeforeThis = lYear - 1
try:
events_a_venir_not_answered = Event.objects.filter(date__gte = lToday).exclude(participants__participant=request.user.profile)
events_a_venir_answered = Event.objects.filter(date__gte = lToday).filter(participants__participant=request.user.profile)
events_a_venir_answered_yes = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile )& Q(participants__reponse= 'oui'))
events_a_venir_answered_no = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile) & Q(participants__reponse= 'non'))
events_a_venir_answered_pe = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile)& Q(participants__reponse= 'pe'))
except:
events_a_venir_not_answered = Event.objects.filter(date__gte = lToday).exclude(participants__participant__user__username=request.user)
events_a_venir_answered = Event.objects.filter(date__gte = lToday).filter(participants__participant__user__username=request.user)
events_a_venir_answered_yes = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user )& Q(participants__reponse= 'oui'))
events_a_venir_answered_no = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user) & Q(participants__reponse= 'non'))
events_a_venir_answered_pe = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user)& Q(participants__reponse= 'pe'))
return render(request, 'calendrier/home.html', {
'Calendar': mark_safe(lCalendar),
'Month': lMonth,
'MonthName': named_month(lMonth),
'Year': lYear,
'PreviousMonth': lPreviousMonth,
'PreviousMonthName': named_month(lPreviousMonth),
'PreviousYear': lPreviousYear,
'NextMonth': lNextMonth,
'NextMonthName': named_month(lNextMonth),
'NextYear': lNextYear,
'YearBeforeThis': lYearBeforeThis,
'YearAfterThis': lYearAfterThis,
"events_a_venir_answered_yes": events_a_venir_answered_yes,
"events_a_venir_answered_no": events_a_venir_answered_no,
"events_a_venir_answered_pe": events_a_venir_answered_pe,
"events_a_venir_not_answered": events_a_venir_not_answered,
"actu" : actu,
})
@login_required
def view_event(request, id):
event = get_object_or_404(Event, id=id)
participants = event.participants_set.all()
multi_instrumentistes = event.participants_set.filter(Q(participant__multi_instrumentiste = 'Oui')& ~Q(reponse = 'non'))
# Restricted event, only erneso users can see it
if not request.user.is_authenticated and not event.calendrier:
return redirect(reverse('calendrier:home'))
# Count the number of occurences of each instrument
instrument_count = defaultdict(lambda: (0, 0,[],[],[]))
for participant in participants:
instrument = participant.participant.instru
if (instrument == "Autre"):
instrument = participant.participant.instru_autre
sure, maybe, namesoui, namespe, namesnon = instrument_count[instrument]
if participant.reponse == "oui":
namesoui += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure + 1, maybe,namesoui,namespe,namesnon)
elif participant.reponse == "pe":
namespe += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure, maybe + 1,namesoui,namespe,namesnon)
else:
namesnon += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure, maybe,namesoui,namespe,namesnon)
instrument_count = [
(instrument, sure, maybe,namesoui, namespe ,namesnon)
for instrument, (sure, maybe,namesoui,namespe,namesnon) in instrument_count.items()
]
context = {
"event": event,
"instrument_count": instrument_count,
"participants": participants,
"nboui": len(participants.filter(reponse="oui")),
"nbpe": len(participants.filter(reponse="pe")),
"nbnon": len(participants.filter(reponse="non")),
"multi_instrumentistes":multi_instrumentistes,
}
return render(request, 'calendrier/view_event.html', context=context)
return date(1900, pMonthNumber, 1).strftime("%B")
class Agenda(TemplateView):
template_name = "calendrier/agenda.html"
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect("calendrier:home")
return super(Agenda, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
lToday = datetime.today()
context["photo"] = Photo.objects.filter(cat="liste").order_by("?").first()
context["events_a_venir"] = (
Event.objects.filter(date__gte=lToday)
.exclude(calendrier__iexact="F")
.exclude(calendrier__iexact="C")
.order_by("date")
)
context["events_passe"] = (
Event.objects.filter(date__lt=lToday)
.filter(calendrier__iexact="H")
.order_by("-date")
)
return context
class Calendar(LoginRequiredMixin, TemplateView):
template_name = "calendrier/home.html"
@property
def pYear(self):
return self.kwargs["pYear"]
@property
def pMonth(self):
return self.kwargs["pMonth"]
def get_context_data(self, **kwargs):
context = super(Calendar, self).get_context_data(**kwargs)
actu = Actu.objects.all()
photo = Photo.objects.filter(cat="home").order_by("?").first()
lToday = datetime.now()
lYear = self.pYear
lMonth = self.pMonth
lCalendarFromMonth = datetime(lYear, lMonth, 1)
lCalendarToMonth = datetime(lYear, lMonth, monthrange(lYear, lMonth)[1])
lEvents = (
Event.objects.filter(
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
)
.exclude(calendrier__iexact="C")
.exclude(calendrier__iexact="D")
)
lEvents_chef = Event.objects.filter(
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
)
lCalendar = EventCalendar(lEvents).formatmonth(lYear, lMonth)
lCalendar_chef = EventCalendar(lEvents_chef).formatmonth(lYear, lMonth)
lPreviousYear = lYear
lPreviousMonth = lMonth - 1
if lPreviousMonth == 0:
lPreviousMonth = 12
lPreviousYear -= 1
lNextYear = lYear
lNextMonth = lMonth + 1
if lNextMonth == 13:
lNextMonth = 1
lNextYear = lYear + 1
lYearAfterThis = lYear + 1
lYearBeforeThis = lYear - 1
events_a_venir_not_answered = (
Event.objects.filter(date__gte=lToday)
.exclude(participants__participant=self.request.user.profile)
.exclude(calendrier__iexact="C")
.exclude(calendrier__iexact="D")
.order_by("date")
)
events_a_venir_answered_yes = (
Event.objects.filter(date__gte=lToday)
.filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="oui")
)
.exclude(calendrier__iexact="C")
.exclude(calendrier__iexact="D")
.order_by("date")
)
events_a_venir_answered_no = (
Event.objects.filter(date__gte=lToday)
.filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="non")
)
.exclude(calendrier__iexact="C")
.exclude(calendrier__iexact="D")
.order_by("date")
)
events_a_venir_answered_pe = (
Event.objects.filter(date__gte=lToday)
.filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="pe")
)
.exclude(calendrier__iexact="C")
.exclude(calendrier__iexact="D")
.order_by("date")
)
events_a_venir_chef = (
Event.objects.filter(date__gte=lToday)
.filter(calendrier__in=["C"])
.order_by("date")
)
events_a_venir_chef_public = (
Event.objects.filter(date__gte=lToday)
.filter(calendrier__in=["D"])
.order_by("date")
)
context["Calendar"] = mark_safe(lCalendar)
context["Calendar_chef"] = mark_safe(lCalendar_chef)
context["Month"] = lMonth
context["MonthName"] = named_month(lMonth)
context["Year"] = lYear
context["PreviousMonth"] = lPreviousMonth
context["PreviousMonthName"] = named_month(lPreviousMonth)
context["PreviousYear"] = lPreviousYear
context["NextMonth"] = lNextMonth
context["NextMonthName"] = named_month(lNextMonth)
context["NextYear"] = lNextYear
context["YearBeforeThis"] = lYearBeforeThis
context["YearAfterThis"] = lYearAfterThis
context["events_a_venir_answered_yes"] = events_a_venir_answered_yes
context["events_a_venir_answered_no"] = events_a_venir_answered_no
context["events_a_venir_answered_pe"] = events_a_venir_answered_pe
context["events_a_venir_not_answered"] = events_a_venir_not_answered
context["events_a_venir_chef"] = events_a_venir_chef
context["events_a_venir_chef_public"] = events_a_venir_chef_public
context["actu"] = actu
context["photo"] = photo
return context
@login_required
def changename(request,id):
if request.method == 'POST':
class Home(Calendar):
@property
def pYear(self):
lToday = datetime.now()
return lToday.year
@property
def pMonth(self):
lToday = datetime.now()
return lToday.month
class ViewEvent(LoginRequiredMixin, TemplateView):
template_name = "calendrier/view_event.html"
def get_context_data(self, **kwargs):
context = super(ViewEvent, self).get_context_data(**kwargs)
event = get_object_or_404(Event, id=self.kwargs["id"])
participants = event.participants_set.all()
multi_instrumentistes = event.participants_set.filter(
Q(participant__multi_instrumentiste="Oui") & ~Q(reponse="non")
)
# Restricted event, only erneso users can see it
if not self.request.user.is_authenticated and not event.calendrier:
return redirect(reverse("calendrier:home"))
# Count the number of occurences of each instrument
instrument_count = defaultdict(lambda: (0, 0, [], [], []))
for participant in participants:
instru = participant.participant.instru
if instru == "Autre":
instru = participant.participant.instru_autre
if participant.dont_play_main == "Oui":
if participant.instrument == "Autre":
instru = participant.instrument_autre
else:
instru = participant.instrument
instru = "" if instru is None else instru
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
if participant.reponse == "oui":
namesoui += [participant.participant.get_doodlename()]
instrument_count[instru] = (
sure + 1,
maybe,
namesoui,
namespe,
namesnon,
)
elif participant.reponse == "pe":
namespe += [participant.participant.get_doodlename()]
instrument_count[instru] = (
sure,
maybe + 1,
namesoui,
namespe,
namesnon,
)
else:
namesnon += [participant.participant.get_doodlename()]
instrument_count[instru] = (sure, maybe, namesoui, namespe, namesnon)
instrument_count_l = []
instru_order = [
"Clarinette",
"Piccolo",
"Flute",
"Glockenspiel",
"Saxophone Alto",
"Trompette",
"Trombone",
"Cor",
"Saxophone Ténor",
"Saxophone Baryton",
"Clarinette Basse",
"Euphonium",
"Souba",
"Percussion",
]
for instrument in instru_order:
if instrument in instrument_count.keys():
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
instrument
]
instrument_count_l.append(
(
instrument,
sure,
maybe,
namesoui,
namespe,
namesnon,
)
)
for instrument in sorted(instrument_count.keys()):
if instrument not in instru_order:
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
instrument
]
instrument_count_l.append(
(
instrument,
sure,
maybe,
namesoui,
namespe,
namesnon,
)
)
context["event"] = event
context["instrument_count"] = instrument_count_l
context["participants"] = participants
context["nboui"] = len(participants.filter(reponse="oui"))
context["nbpe"] = len(participants.filter(reponse="pe"))
context["nbnon"] = len(participants.filter(reponse="non"))
context["multi_instrumentistes"] = multi_instrumentistes
context["chef_only"] = (event.calendrier == "C") | (event.calendrier == "D")
return context
class ChangeName(LoginRequiredMixin, TemplateView):
form_class = ChangeDoodleName
template_name = "calendrier/changename.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class(instance=self.request.user)
context["id"] = self.kwargs["id"]
return context
def post(self, request, *args, **kwargs):
success = False
requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user)
form = self.form_class(requbis, instance=request.user)
if form.is_valid():
form.save()
success = True
return redirect('calendrier:view-event',id=id)
else:
form = ChangeDoodleName(instance=request.user)
return render(request, 'calendrier/changename.html',locals())
return redirect("calendrier:view-event", id=self.kwargs["id"])
else:
context = self.get_context_data()
context["success"] = success
return render(request, self.template_name, context)
@chef_required
def create_event(request):
if request.method == "POST":
form = EventForm(request.POST)
class CreateEvent(ChefEventRequiredMixin, TemplateView):
form_class = EventForm
template_name = "calendrier/create.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class()
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
temp = True
while temp:
code = generer()
try:
Event.objects.get(slug=code)
except:
except Event.DoesNotExist:
temp = False
nom = form.cleaned_data["nom"]
date = form.cleaned_data["date"]
date = date.strftime('%d/%m/%Y')
debut = form.cleaned_data["debut"]
date = date.strftime("%d/%m/%Y")
obj = form.save(commit=False)
obj.slug = code
obj.save()
id = obj.id
envoi = True
return redirect('calendrier:view-event',id=id)
else:
form = EventForm()
return render(request, "calendrier/create.html", locals())
return redirect("calendrier:view-event", id=id)
else:
context = self.get_context_data()
return render(request, self.template_name, context)
class ReponseEvent(LoginRequiredMixin, TemplateView):
form_class = ParticipantsForm
template_name = "calendrier/reponse.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
ev = get_object_or_404(Event, id=self.kwargs["id"])
try:
context["form"] = self.form_class(
instance=Participants.objects.get(
event=ev, participant=self.request.user.profile
)
)
except Participants.DoesNotExist:
context["form"] = self.form_class()
context["ev"] = get_object_or_404(Event, id=self.kwargs["id"])
context["id"] = self.kwargs["id"]
context["chef_only"] = (context["ev"].calendrier == "C") | (
context["ev"].calendrier == "D"
)
return context
@login_required
def reponse(request, id):
part = request.user.profile
ev = get_object_or_404(Event, id=id)
if request.method == "POST":
form = ParticipantsForm(request.POST)
def post(self, request, *args, **kwargs):
ev = get_object_or_404(Event, id=self.kwargs["id"])
part = request.user.profile
try:
p = Participants.objects.get(event=ev, participant=part)
except Participants.DoesNotExist:
p = None
form = self.form_class(request.POST, instance=p)
if form.is_valid():
try:
p = Participants.objects.get(event=ev, participant=part)
p.delete()
except Participants.DoesNotExist:
pass
obj = form.save(commit=False)
# Si la participation existe déjà, ces 2 ligne sont redondantes
obj.event = ev
obj.participant = part
obj.save()
envoi = True
return redirect('calendrier:view-event',id=id)
else:
form = ParticipantsForm()
return render(request, "calendrier/reponse.html", locals())
return redirect("calendrier:view-event", id=self.kwargs["id"])
else:
context = self.get_context_data()
return render(request, self.template_name, context)
class EventUpdate(UpdateView):
class EventUpdate(ChefEventRequiredMixin, UpdateView):
model = Event
template_name = "calendrier/update.html"
form_class = ModifEventForm
def get_context_data(self, **kwargs):
ctx = super(EventUpdate, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id
ctx["id"] = self.get_object().id
return ctx
def get_success_url(self):
return reverse('calendrier:view-event', kwargs={'id' : self.get_object().id})
@method_decorator(chef_required)
def dispatch(self, *args, **kwargs):
return super(EventUpdate, self).dispatch(*args, **kwargs)
return reverse("calendrier:view-event", kwargs={"id": self.get_object().id})
class EventDelete(DeleteView):
class EventDelete(ChefEventRequiredMixin, DeleteView):
model = Event
template_name = "calendrier/delete.html"
success_url = reverse_lazy("calendrier:home")
def get_context_data(self, **kwargs):
ctx = super(EventDelete, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id
ctx["id"] = self.get_object().id
return ctx
@method_decorator(chef_required)
def dispatch(self, *args, **kwargs):
return super(EventDelete,self).dispatch(*args, **kwargs)

View file

@ -6,12 +6,11 @@ les permissions.
"""
from django.contrib import admin
from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import Group, Permission, User
from gestion.models import ErnestoUser, VideoGallery
from actu.models import Actu
from gestion.models import ErnestoUser, Photo, VideoGallery
class UserProfileInline(admin.StackedInline):
@ -37,6 +36,7 @@ User.profile_phone = ProfileInfo("phone", "Téléphone")
User.profile_instru = ProfileInfo("instru", "Instrument joué")
User.profile_is_ern = ProfileInfo("is_ernesto", "Ernestophoniste")
User.profile_is_chef = ProfileInfo("is_chef", "Chef Fanfare")
User.profile_is_chef_event = ProfileInfo("is_chef_event", "Respo événement")
User.profile_get_mails = ProfileInfo("mails", "Recevoir les mails")
@ -58,6 +58,7 @@ class UserProfileAdmin(UserAdmin):
"profile_instru",
"profile_is_ern",
"profile_is_chef",
"profile_is_chef_event",
]
list_display_links = ["username", "email", "first_name", "last_name"]
list_filter = ["profile__instru"]
@ -112,7 +113,9 @@ class UserProfileAdmin(UserAdmin):
user.groups.add(chef_group)
user.save()
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
admin.site.register(VideoGallery)
admin.site.register(Photo)
admin.site.register(Actu)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class GestionConfig(AppConfig):
name = 'gestion'
name = "gestion"

View file

@ -1,47 +1,71 @@
from django import forms
from gestion.models import ErnestoUser
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.tokens import default_token_generator
from django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
class RegistrationFormUser(UserCreationForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'password1',
'password2', 'email',)
fields = (
"username",
"first_name",
"last_name",
"password1",
"password2",
"email",
)
class ChangeFormUser(UserChangeForm):
password = None
class Meta:
model = User
fields = ('first_name', 'last_name', 'email',)
fields = (
"first_name",
"last_name",
"email",
)
class ChangeMembreForm(forms.ModelForm):
def clean(self):
cleaned_data = super(ChangeMembreForm, self).clean()
instru=cleaned_data.get("instru")
instru = cleaned_data.get("instru")
instru_autre = cleaned_data.get("instru_autre")
if (instru == "Autre") and not (instru_autre):
raise forms.ValidationError(_("Préçisez quel autre instrument"))
multi_instru=cleaned_data.get("multi_instrumentiste")
multi_instru = cleaned_data.get("multi_instrumentiste")
instru_bonus = cleaned_data.get("instru_bonus")
if (multi_instru == "Oui") and not (instru_bonus):
raise forms.ValidationError(_("Préçisez quel·s instrument·s supplémentaire·s vous pouvez jouer"))
raise forms.ValidationError(
_("Préçisez quel·s instrument·s supplémentaire·s vous pouvez jouer")
)
return cleaned_data
class Meta:
model = ErnestoUser
fields = ("phone", "instru","instru_autre","multi_instrumentiste","instru_bonus")
fields = (
"phone",
"instru",
"instru_autre",
"multi_instrumentiste",
"instru_bonus",
)
class InscriptionMembreForm(ChangeMembreForm):
validation = forms.CharField(max_length=100, widget=forms.PasswordInput)
class Meta:
model = ErnestoUser
fields = ("phone", "instru","instru_autre",'multi_instrumentiste',
'instru_bonus' )
fields = (
"phone",
"instru",
"instru_autre",
"multi_instrumentiste",
"instru_bonus",
)

View file

@ -1,5 +1,5 @@
from django.db import migrations, models
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
@ -10,28 +10,64 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='ErnestoUser',
name="ErnestoUser",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('is_ernesto', models.BooleanField(verbose_name="Membre de l'Ernestophone", default=True)),
('is_chef', models.BooleanField(verbose_name='Chef Fanfare', default=False)),
('phone', models.CharField(blank=True, max_length=20, verbose_name='Téléphone')),
('instru', models.CharField(blank=True, max_length=40, verbose_name='Instrument joué')),
('slug', models.CharField(max_length=7, editable=False, unique=True)),
('doodlename', models.CharField(blank=True, max_length=30, verbose_name='Nom pour le doodle')),
('mails', models.BooleanField(verbose_name='Recevoir les mails', default=True)),
(
'user',
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
(
"is_ernesto",
models.BooleanField(
verbose_name="Membre de l'Ernestophone", default=True
),
),
(
"is_chef",
models.BooleanField(verbose_name="Chef Fanfare", default=False),
),
(
"phone",
models.CharField(
blank=True, max_length=20, verbose_name="Téléphone"
),
),
(
"instru",
models.CharField(
blank=True, max_length=40, verbose_name="Instrument joué"
),
),
("slug", models.CharField(max_length=7, editable=False, unique=True)),
(
"doodlename",
models.CharField(
blank=True, max_length=30, verbose_name="Nom pour le doodle"
),
),
(
"mails",
models.BooleanField(
verbose_name="Recevoir les mails", default=True
),
),
(
"user",
models.OneToOneField(
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='profile'
)
related_name="profile",
),
),
],
options={
'verbose_name': 'Profil Ernestophoniste',
'verbose_name_plural': 'Profil Ernestophoniste',
"verbose_name": "Profil Ernestophoniste",
"verbose_name_plural": "Profil Ernestophoniste",
},
),
]

View file

@ -7,80 +7,157 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0001_initial'),
("gestion", "0001_initial"),
]
operations = [
migrations.CreateModel(
name='VideoGallery',
name="VideoGallery",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=127)),
('order', models.IntegerField(verbose_name='ordre')),
('url', models.URLField()),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=127)),
("order", models.IntegerField(verbose_name="ordre")),
("url", models.URLField()),
],
options={
'verbose_name_plural': 'Videos',
'verbose_name': 'Video',
"verbose_name_plural": "Videos",
"verbose_name": "Video",
},
),
migrations.RemoveField(
model_name='ernestouser',
name='mails',
model_name="ernestouser",
name="mails",
),
migrations.AddField(
model_name='ernestouser',
name='instru_autre',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Lequel ?'),
model_name="ernestouser",
name="instru_autre",
field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Lequel ?"
),
),
migrations.AddField(
model_name='ernestouser',
name='instru_bonus',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Le·s·quel·s ?'),
model_name="ernestouser",
name="instru_bonus",
field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Le·s·quel·s ?"
),
),
migrations.AddField(
model_name='ernestouser',
name='instru_trombonoscope',
field=models.CharField(blank=True, max_length=30, verbose_name='Instrument affiché sur le trombonoscope'),
model_name="ernestouser",
name="instru_trombonoscope",
field=models.CharField(
blank=True,
max_length=30,
verbose_name="Instrument affiché sur le trombonoscope",
),
),
migrations.AddField(
model_name='ernestouser',
name='multi_instrumentiste',
field=models.CharField(choices=[('Non', 'Non'), ('Oui', 'Oui')], default='Non', help_text='Seulement si tu connais les partitions par coeur', max_length=3, verbose_name="Je suis capable de jouer d'un autre instrument en manche :"),
model_name="ernestouser",
name="multi_instrumentiste",
field=models.CharField(
choices=[("Non", "Non"), ("Oui", "Oui")],
default="Non",
help_text="Seulement si tu connais les partitions par coeur",
max_length=3,
verbose_name="Je suis capable de jouer d'un autre instrument en manche :",
),
),
migrations.AddField(
model_name='ernestouser',
name='nom_trombonoscope',
field=models.CharField(blank=True, max_length=30, verbose_name='Nom affiché sur le trombonoscope'),
model_name="ernestouser",
name="nom_trombonoscope",
field=models.CharField(
blank=True,
max_length=30,
verbose_name="Nom affiché sur le trombonoscope",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope',
field=models.CharField(choices=[('non', 'Non'), ('o_a', 'Oui en tant que fanfaron actuel'), ('o_v', 'Oui en tant que vie·ille·ux')], default='non', max_length=3, null=True, verbose_name='Je souhaite apparaitre dans le trombonoscope :'),
model_name="ernestouser",
name="trombonoscope",
field=models.CharField(
choices=[
("non", "Non"),
("o_a", "Oui en tant que fanfaron actuel"),
("o_v", "Oui en tant que vie·ille·ux"),
],
default="non",
max_length=3,
null=True,
verbose_name="Je souhaite apparaitre dans le trombonoscope :",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_colors',
field=models.CharField(choices=[('#e4522f#ffffff', 'Orange et Blanc'), ('#ffffff#000000', 'Blanc et Noir'), ('#A8107C#000000', 'Rose et Noir'), ('#10A4A8#ffffff', 'Bleu et Blanc'), ('#26A810#000000', 'Vert et Noir'), ('#A81026#ffffff', 'Rouge et Blanc'), ('#E3E54C#000000', 'Jaune et Noir'), ('autre', 'Autre')], default='OrangeBlanc', max_length=40, verbose_name='Couleur du profil'),
model_name="ernestouser",
name="trombonoscope_colors",
field=models.CharField(
choices=[
("#e4522f#ffffff", "Orange et Blanc"),
("#ffffff#000000", "Blanc et Noir"),
("#A8107C#000000", "Rose et Noir"),
("#10A4A8#ffffff", "Bleu et Blanc"),
("#26A810#000000", "Vert et Noir"),
("#A81026#ffffff", "Rouge et Blanc"),
("#E3E54C#000000", "Jaune et Noir"),
("autre", "Autre"),
],
default="OrangeBlanc",
max_length=40,
verbose_name="Couleur du profil",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_fond',
field=colorful.fields.RGBColorField(default='#e4522f', verbose_name='Couleur de fond du profil'),
model_name="ernestouser",
name="trombonoscope_fond",
field=colorful.fields.RGBColorField(
default="#e4522f", verbose_name="Couleur de fond du profil"
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_texte',
field=colorful.fields.RGBColorField(default='#ffffff', verbose_name='Couleur du texte du profil'),
model_name="ernestouser",
name="trombonoscope_texte",
field=colorful.fields.RGBColorField(
default="#ffffff", verbose_name="Couleur du texte du profil"
),
),
migrations.AlterField(
model_name='ernestouser',
name='instru',
field=models.CharField(choices=[('Clarinette', 'Clarinette'), ('Euphonium', 'Euphonium'), ('Percussion', 'Percussion'), ('Piccolo', 'Piccolo'), ('Saxophone Alto', 'Saxophone Alto'), ('Saxophone Ténor', 'Saxophone Ténor'), ('Saxophone Baryton', 'Saxophone Baryton'), ('Souba', 'Souba'), ('Trombone', 'Trombone'), ('Trompette', 'Trompette'), ('Autre', 'Autre'), ('ne sais pas', 'Je ne sais pas encore')], default='ne sais pas', max_length=40, verbose_name='Instrument joué'),
model_name="ernestouser",
name="instru",
field=models.CharField(
choices=[
("Clarinette", "Clarinette"),
("Euphonium", "Euphonium"),
("Percussion", "Percussion"),
("Piccolo", "Piccolo"),
("Saxophone Alto", "Saxophone Alto"),
("Saxophone Ténor", "Saxophone Ténor"),
("Saxophone Baryton", "Saxophone Baryton"),
("Souba", "Souba"),
("Trombone", "Trombone"),
("Trompette", "Trompette"),
("Autre", "Autre"),
("ne sais pas", "Je ne sais pas encore"),
],
default="ne sais pas",
max_length=40,
verbose_name="Instrument joué",
),
),
migrations.AlterField(
model_name='ernestouser',
name='phone',
field=models.CharField(blank=True, help_text='seulement visible par les chef·fe·s', max_length=20, verbose_name='Téléphone'),
model_name="ernestouser",
name="phone",
field=models.CharField(
blank=True,
help_text="seulement visible par les chef·fe·s",
max_length=20,
verbose_name="Téléphone",
),
),
]

View file

@ -0,0 +1,85 @@
# Generated by Django 2.2.17 on 2021-03-31 13:50
import colorful.fields
from django.db import migrations, models
import gestion.models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0002_auto_20200908_2222"),
]
operations = [
migrations.CreateModel(
name="Photo",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=127)),
(
"cat",
models.CharField(
choices=[
("home_join", "Rejoignez nous"),
("home_contact", "Nous Contacter"),
("home_rep", "Répertoire de l'acceuil"),
("login", "Connexion"),
("change_membre", "Modification du profil"),
("inscription_membre", "Inscription"),
("home", "Calendrier connecté"),
("liste", "Agenda public"),
("part", "Répertoire"),
("n", "N'apparait pas"),
],
default="n",
max_length=127,
),
),
(
"auteur",
models.CharField(
blank=True,
max_length=127,
null=True,
verbose_name="Auteur de l'image",
),
),
(
"url",
models.URLField(
blank=True,
null=True,
verbose_name="Lien vers le site de l'auteur",
),
),
(
"color",
colorful.fields.RGBColorField(
default="#ffffff", verbose_name="Couleur du nom de l'auteur"
),
),
(
"image",
models.ImageField(
default=None,
upload_to="deco",
validators=[gestion.models.Photo.validate_image],
),
),
],
options={
"verbose_name": "Photo",
"verbose_name_plural": "Photos",
},
),
]

View file

@ -0,0 +1,34 @@
# Generated by Django 2.2.17 on 2021-03-31 20:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0003_photo"),
]
operations = [
migrations.AlterField(
model_name="photo",
name="cat",
field=models.CharField(
choices=[
("home_join", "Rejoignez nous"),
("home_contact", "Nous Contacter"),
("home_rep", "Répertoire de l'acceuil"),
("login", "Connexion"),
("change_membre", "Modification du profil"),
("inscription_membre", "Inscription"),
("home", "Calendrier connecté"),
("liste", "Agenda public"),
("part", "Répertoire"),
("instru", "Instruments"),
("n", "N'apparait pas"),
],
default="n",
max_length=127,
),
),
]

View file

@ -0,0 +1,28 @@
# Generated by Django 2.2.17 on 2021-04-27 18:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0004_auto_20210331_2031"),
]
operations = [
migrations.AlterField(
model_name="ernestouser",
name="trombonoscope",
field=models.CharField(
choices=[
("non", "Non"),
("o_a", "Oui en tant que fanfaron actuel"),
("o_v", "Oui en tant que vie·ille·ux"),
],
default="non",
max_length=3,
null=True,
verbose_name="Je souhaite apparaitre dans le trombonoscope:",
),
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 2.2.17 on 2021-06-08 10:29
from django.db import migrations, models
import gestion.models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0005_auto_20210427_1834"),
]
operations = [
migrations.AlterField(
model_name="photo",
name="image",
field=models.ImageField(
default=None,
upload_to="trombonoscope/deco",
validators=[gestion.models.Photo.validate_image],
),
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 2.2.24 on 2021-10-06 09:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0006_auto_20210608_1029"),
]
operations = [
migrations.AddField(
model_name="ernestouser",
name="is_chef_event",
field=models.BooleanField(
default=False, verbose_name="Respo événement Fanfare"
),
),
]

View file

@ -0,0 +1,28 @@
# Generated by Django 2.2.24 on 2021-10-22 17:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0007_ernestouser_is_chef_event"),
]
operations = [
migrations.AddField(
model_name="ernestouser",
name="is_chef_com",
field=models.BooleanField(default=False, verbose_name="Respo com"),
),
migrations.AddField(
model_name="ernestouser",
name="is_chef_instru",
field=models.BooleanField(default=False, verbose_name="Respo instruments"),
),
migrations.AlterField(
model_name="ernestouser",
name="is_chef_event",
field=models.BooleanField(default=False, verbose_name="Respo événements"),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 2.2.24 on 2022-01-11 15:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gestion", "0008_auto_20211022_1923"),
]
operations = [
migrations.AddField(
model_name="ernestouser",
name="is_chef_mu",
field=models.BooleanField(default=False, verbose_name="Respo musique"),
),
]

View file

@ -5,3 +5,76 @@ class ChefRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
return (user is not None) and hasattr(user, "profile") and user.profile.is_chef
class ChefEventRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
is_chef = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
)
is_chef_event = (
(user is not None)
and hasattr(user, "profile")
and user.profile.is_chef_event
)
return is_chef or is_chef_event
class ChefInstruRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
is_chef = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
)
is_chef_instru = (
(user is not None)
and hasattr(user, "profile")
and user.profile.is_chef_instru
)
return is_chef or is_chef_instru
class ChefComRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
is_chef = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
)
is_chef_com = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
)
return is_chef or is_chef_com
class ChefMuRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
is_chef = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
)
is_chef_mu = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_mu
)
return is_chef or is_chef_mu
class AllChefRequiredMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
is_chef = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
)
is_su = (user is not None) and user.is_superuser
is_chef_com = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
)
is_chef_event = (
(user is not None)
and hasattr(user, "profile")
and user.profile.is_chef_event
)
is_chef_mu = (
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_mu
)
return is_chef or is_chef_com or is_chef_event or is_su or is_chef_mu

View file

@ -1,63 +1,167 @@
# -*- coding: utf-8 -*-
from django.db import models
import os
from colorful.fields import RGBColorField
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
INSTRU_CHOICES = [
("Clarinette", _("Clarinette")),
("Euphonium", _("Euphonium")),
("Percussion", _("Percussion")),
("Piccolo", _("Piccolo")),
("Saxophone Alto", _("Saxophone Alto")),
("Saxophone Ténor", _("Saxophone Ténor")),
("Saxophone Baryton", _("Saxophone Baryton")),
("Souba", _("Souba")),
("Trombone", _("Trombone")),
("Trompette", _("Trompette")),
("Autre", _("Autre")),
("ne sais pas", _("Je ne sais pas encore")),
]
class Photo(models.Model):
PHOTO_PLACEMENT = (
("home_join", _("Rejoignez nous")),
("home_contact", _("Nous Contacter")),
("home_rep", _("Répertoire de l'acceuil")),
("login", _("Connexion")),
("change_membre", _("Modification du profil")),
("inscription_membre", _("Inscription")),
("home", _("Calendrier connecté")),
("liste", _("Agenda public")),
("part", _("Répertoire")),
("instru", _("Instruments")),
("n", _("N'apparait pas")),
)
def validate_image(fieldfile_obj):
filesize = fieldfile_obj.file.size
mb_limit = 1.0
if filesize > mb_limit * 1024 * 1024:
raise ValidationError("La taille max est %sMB" % str(mb_limit))
name = models.CharField(max_length=127)
cat = models.CharField(max_length=127, choices=PHOTO_PLACEMENT, default="n")
auteur = models.CharField(
max_length=127, verbose_name=_("Auteur de l'image"), null=True, blank=True
)
url = models.URLField(
verbose_name=_("Lien vers le site de l'auteur"), null=True, blank=True
)
color = RGBColorField(_("Couleur du nom de l'auteur"), default="#ffffff")
image = models.ImageField(
upload_to="trombonoscope/deco", default=None, validators=[validate_image]
)
def __str__(self):
return self.name
def delete(self):
os.remove(self.image.path)
return super(Photo, self).delete()
def save(self, *args, **kwargs):
try:
this = Photo.objects.get(id=self.id)
if this.image.path != self.image.path:
os.remove(this.image.path)
except Photo.DoesNotExist:
pass
super(Photo, self).save(*args, **kwargs)
class Meta:
verbose_name = _("Photo")
verbose_name_plural = _("Photos")
class ErnestoUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"), default=True)
is_chef = models.BooleanField(_("Chef Fanfare"), default=False)
phone = models.CharField(_("Téléphone"), max_length=20, blank=True ,help_text= _("seulement visible par les chef·fe·s"))
INSTRU_CHOICES = [
('Clarinette', _('Clarinette')),
('Euphonium', _('Euphonium')),
('Percussion', _('Percussion')),
('Piccolo', _('Piccolo')),
('Saxophone Alto', _('Saxophone Alto')),
('Saxophone Ténor', _('Saxophone Ténor')),
('Saxophone Baryton', _('Saxophone Baryton')),
('Souba', _('Souba')),
('Trombone', _('Trombone')),
('Trompette', _('Trompette')),
('Autre', _('Autre')),
('ne sais pas', _('Je ne sais pas encore')),
]
is_chef_event = models.BooleanField(_("Respo événements"), default=False)
is_chef_com = models.BooleanField(_("Respo com"), default=False)
is_chef_instru = models.BooleanField(_("Respo instruments"), default=False)
is_chef_mu = models.BooleanField(_("Respo musique"), default=False)
phone = models.CharField(
_("Téléphone"),
max_length=20,
blank=True,
help_text=_("seulement visible par les chef·fe·s"),
)
COLORS_CHOICES = [
('#e4522f#ffffff', _('Orange et Blanc')),
('#ffffff#000000', _('Blanc et Noir')),
('#A8107C#000000', _('Rose et Noir')),
('#10A4A8#ffffff', _('Bleu et Blanc')),
('#26A810#000000', _('Vert et Noir')),
('#A81026#ffffff', _('Rouge et Blanc')),
('#E3E54C#000000', _('Jaune et Noir')),
('autre',_('Autre')),
("#e4522f#ffffff", _("Orange et Blanc")),
("#ffffff#000000", _("Blanc et Noir")),
("#A8107C#000000", _("Rose et Noir")),
("#10A4A8#ffffff", _("Bleu et Blanc")),
("#26A810#000000", _("Vert et Noir")),
("#A81026#ffffff", _("Rouge et Blanc")),
("#E3E54C#000000", _("Jaune et Noir")),
("autre", _("Autre")),
]
]
instru = models.CharField(_("Instrument joué"), max_length=40, blank=False,choices=INSTRU_CHOICES,default='ne sais pas')
instru_autre = models.CharField(_("Lequel ?"),null=True,max_length=100,blank=True)
instru = models.CharField(
_("Instrument joué"),
max_length=40,
blank=False,
choices=INSTRU_CHOICES,
default="ne sais pas",
)
instru_autre = models.CharField(
_("Lequel ?"), null=True, max_length=100, blank=True
)
slug = models.CharField(max_length=7, editable=False, unique=True)
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30,
blank=True)
trombonoscope = models.CharField(_('Je souhaite apparaitre dans le trombonoscope :'),max_length=3,blank=False,null=True,choices=[('non',_('Non')),('o_a',_('Oui en tant que fanfaron actuel')),('o_v',_('Oui en tant que vie·ille·ux'))],default='non')
instru_trombonoscope = models.CharField(_("Instrument affiché sur le trombonoscope"), max_length=30,
blank=True)
nom_trombonoscope = models.CharField(_("Nom affiché sur le trombonoscope"), max_length=30,
blank=True)
trombonoscope_colors = models.CharField(_("Couleur du profil"), max_length=40, blank=False,choices=COLORS_CHOICES,default='OrangeBlanc')
trombonoscope_fond = RGBColorField(_("Couleur de fond du profil"),default='#e4522f')
trombonoscope_texte = RGBColorField(_("Couleur du texte du profil"),default='#ffffff')
multi_instrumentiste = models.CharField(_("Je suis capable de jouer d'un autre instrument en manche :"),default='Non',null=False,max_length=3,choices=[('Non',_('Non')),('Oui',_('Oui'))],help_text= _("Seulement si tu connais les partitions par coeur"))
instru_bonus = models.CharField(_("Le·s·quel·s ?"),null=True,max_length=100,blank=True)
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30, blank=True)
trombonoscope = models.CharField(
_("Je souhaite apparaitre dans le trombonoscope:"),
max_length=3,
blank=False,
null=True,
choices=[
("non", _("Non")),
("o_a", _("Oui en tant que fanfaron actuel")),
("o_v", _("Oui en tant que vie·ille·ux")),
],
default="non",
)
instru_trombonoscope = models.CharField(
_("Instrument affiché sur le trombonoscope"), max_length=30, blank=True
)
nom_trombonoscope = models.CharField(
_("Nom affiché sur le trombonoscope"), max_length=30, blank=True
)
trombonoscope_colors = models.CharField(
_("Couleur du profil"),
max_length=40,
blank=False,
choices=COLORS_CHOICES,
default="OrangeBlanc",
)
trombonoscope_fond = RGBColorField(
_("Couleur de fond du profil"), default="#e4522f"
)
trombonoscope_texte = RGBColorField(
_("Couleur du texte du profil"), default="#ffffff"
)
multi_instrumentiste = models.CharField(
_("Je suis capable de jouer d'un autre instrument en manche :"),
default="Non",
null=False,
max_length=3,
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
help_text=_("Seulement si tu connais les partitions par coeur"),
)
instru_bonus = models.CharField(
_("Le·s·quel·s ?"), null=True, max_length=100, blank=True
)
class Meta:
verbose_name = _("Profil Ernestophoniste")

View file

@ -545,7 +545,7 @@ pre code {
overflow-y: scroll;
}
.container {
.container_carousel {
width: 100%;
padding-right: 15px;
padding-left: 15px;
@ -554,25 +554,25 @@ pre code {
}
@media (min-width: 576px) {
.container {
.container_carousel {
max-width: 540px;
}
}
@media (min-width: 768px) {
.container {
.container_carousel {
max-width: 720px;
}
}
@media (min-width: 992px) {
.container {
.container_carousel {
max-width: 960px;
}
}
@media (min-width: 1200px) {
.container {
.container_carousel {
max-width: 1140px;
}
}
@ -4157,7 +4157,7 @@ input[type="button"].btn-block {
padding: 0.5rem 1rem;
}
.navbar > .container,
.navbar > .container_carousel,
.navbar > .container-fluid {
display: -ms-flexbox;
display: flex;
@ -4242,7 +4242,7 @@ input[type="button"].btn-block {
}
@media (max-width: 575.98px) {
.navbar-expand-sm > .container,
.navbar-expand-sm > .container_carousel,
.navbar-expand-sm > .container-fluid {
padding-right: 0;
padding-left: 0;
@ -4267,7 +4267,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-sm > .container,
.navbar-expand-sm > .container_carousel,
.navbar-expand-sm > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
@ -4284,7 +4284,7 @@ input[type="button"].btn-block {
}
@media (max-width: 767.98px) {
.navbar-expand-md > .container,
.navbar-expand-md > .container_carousel,
.navbar-expand-md > .container-fluid {
padding-right: 0;
padding-left: 0;
@ -4309,7 +4309,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-md > .container,
.navbar-expand-md > .container_carousel,
.navbar-expand-md > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
@ -4326,7 +4326,7 @@ input[type="button"].btn-block {
}
@media (max-width: 991.98px) {
.navbar-expand-lg > .container,
.navbar-expand-lg > .container_carousel,
.navbar-expand-lg > .container-fluid {
padding-right: 0;
padding-left: 0;
@ -4351,7 +4351,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-lg > .container,
.navbar-expand-lg > .container_carousel,
.navbar-expand-lg > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
@ -4368,7 +4368,7 @@ input[type="button"].btn-block {
}
@media (max-width: 1199.98px) {
.navbar-expand-xl > .container,
.navbar-expand-xl > .container_carousel,
.navbar-expand-xl > .container-fluid {
padding-right: 0;
padding-left: 0;
@ -4393,7 +4393,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-xl > .container,
.navbar-expand-xl > .container_carousel,
.navbar-expand-xl > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
@ -4416,7 +4416,7 @@ input[type="button"].btn-block {
justify-content: flex-start;
}
.navbar-expand > .container,
.navbar-expand > .container_carousel,
.navbar-expand > .container-fluid {
padding-right: 0;
padding-left: 0;
@ -4436,7 +4436,7 @@ input[type="button"].btn-block {
padding-left: 0.5rem;
}
.navbar-expand > .container,
.navbar-expand > .container_carousel,
.navbar-expand > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
@ -10001,7 +10001,7 @@ a.text-dark:hover, a.text-dark:focus {
body {
min-width: 992px !important;
}
.container {
.container_carousel {
min-width: 992px !important;
}
.navbar {
@ -10035,4 +10035,4 @@ a.text-dark:hover, a.text-dark:focus {
border-color: #dee2e6;
}
}
/*# sourceMappingURL=bootstrap.css.map */
/*# sourceMappingURL=bootstrap.css.map */

File diff suppressed because one or more lines are too long

View file

@ -9,8 +9,37 @@
Released for free under the Creative Commons Attribution 3.0 license (templated.co/license)
*/
/* Instagram feed*/
#app{
display: grid;
grid-gap: var(--spacing);
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
min-height: calc(100vh - var(--spacing)*2);
}
a.error{
grid-column: 1 / -1;
justify-self: center;
}
a.loading{
width: calc(var(--spacing)*3);
height: calc(var(--spacing)*3);
grid-column: 1 / -1;
justify-self: center;
align-self: center;
background: var(--color);
animation: load var(--speed) infinite ease-in-out;
transform: rotate(0);
}
@keyframes load{
100%{
transform: rotate(360deg);
}
}
/* Reset */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
@ -219,6 +248,7 @@
}
/* Grid */
.row {
@ -1558,9 +1588,7 @@
width: device-width;
}
body {
-ms-overflow-style: scrollbar;
}
@media screen and (max-width: 480px) {
@ -1574,16 +1602,7 @@
background: #e4522f;
}
body.is-loading *, body.is-loading *:before, body.is-loading *:after {
-moz-animation: none !important;
-webkit-animation: none !important;
-ms-animation: none !important;
animation: none !important;
-moz-transition: none !important;
-webkit-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
/* Type */
@ -2284,7 +2303,7 @@ div.spoiler
display: block;
float: left;
margin-right: -2em;
opacity: 0;
height: 1em;
width: 1em;
z-index: -1;
}
@ -2704,31 +2723,7 @@ div.spoiler
text-align: center;
}
header p {
position: relative;
margin: 0 0 1.5em 0;
}
header h2 + p {
font-size: 1.25em;
margin-top: -1em;
}
header h3 + p {
font-size: 1.1em;
margin-top: -0.8em;
}
header h4 + p,
header h5 + p,
header h6 + p {
font-size: 0.9em;
margin-top: -0.6em;
}
header p {
color: #676d71;
}
/* Tab */
@ -2888,17 +2883,8 @@ div.spoiler
z-index: 99;
}
.wrapper header {
margin-bottom: 4em;
}
@media screen and (max-width: 736px) {
.wrapper header {
margin-bottom: 2em;
}
}
.wrapper.style1 {
background-color: #e39576;
@ -3104,9 +3090,7 @@ div.spoiler
border-top-color: rgba(255, 255, 255, 0.15);
}
.wrapper.style1 header p {
color: #ffffff;
}
.wrapper.style1 table tbody tr {
border-color: rgba(255, 255, 255, 0.15);
@ -3327,9 +3311,7 @@ div.spoiler
border-top-color: rgba(255, 255, 255, 0.15);
}
.wrapper.style2 header p {
color: #9ba2a8;
}
.wrapper.style2 table tbody tr {
border-color: rgba(255, 255, 255, 0.15);
@ -3463,281 +3445,7 @@ div.spoiler
display: none;
}
/* Header */
body.subpage {
padding-top: 3.125em;
}
#header {
background: #e4522f;
color: #e4522f;
cursor: default;
height: 3.25em;
left: 0;
line-height: 3.25em;
position: fixed;
text-align: right;
top: 0;
width: 100%;
z-index: 10001;
}
#header > h1 {
color:#000000;
display: inline-block;
height: inherit;
left: 1.25em;
line-height: inherit;
margin: 0;
padding: 0;
position: absolute;
top: 0;
}
#header > h1 a {
font-size: 1.25em;
}
#header > h1 a:hover {
color: #ffffff;
}
#header > h1 span {
font-weight: 300;
font-size: .8em;
}
#header > a {
-moz-transition: color 0.2s ease-in-out;
-webkit-transition: color 0.2s ease-in-out;
-ms-transition: color 0.2s ease-in-out;
transition: color 0.2s ease-in-out;
display: inline-block;
padding: 0 0.75em;
color: #ffffff;
text-decoration: none;
}
#header > a:hover {
color: #e4522f;
}
#header > a[href="#menu"]:hover {
color: #000000;
}
#header > a[href="#menu"] {
text-decoration: none;
font-size: larger;
-webkit-tap-highlight-color: transparent;
}
#header > a[href="#menu"]:before {
content: "";
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
#header > a[href="#menu"]:before {
margin: 0 0.5em 0 0;
}
#header > a + a[href="#menu"]:last-child {
border-left: solid 1px rgba(228, 82, 47, 0.15);
padding-left: 1.25em;
margin-left: 0.5em;
}
#header > a:last-child {
padding-right: 1.25em;
}
#logo
{
position: absolute;
left:0;
top:0;
}
@media screen and (max-width: 736px) {
#header > a {
padding: 0 0.5em;
}
#header > a + a[href="#menu"]:last-child {
padding-left: 1em;
margin-left: 0.25em;
}
#header > a:last-child {
padding-right: 1em;
}
}
@media screen and (max-width: 980px) {
body {
padding-top: 44px;
}
#header {
height: 44px;
line-height: 44px;
}
#header > h1 {
left: 1em;
}
#header > h1 a {
font-size: 1em;
}
}
@media screen and (max-width: 480px) {
#header {
min-width: 320px;
}
}
/* Menu */
#menu {
-moz-transform: translateX(20em);
-webkit-transform: translateX(20em);
-ms-transform: translateX(20em);
transform: translateX(20em);
-moz-transition: -moz-transform 0.5s ease, box-shadow 0.5s ease, visibility 0.5s;
-webkit-transition: -webkit-transform 0.5s ease, box-shadow 0.5s ease, visibility 0.5s;
-ms-transition: -ms-transform 0.5s ease, box-shadow 0.5s ease, visibility 0.5s;
transition: transform 0.5s ease, box-shadow 0.5s ease, visibility 0.5s;
-webkit-overflow-scrolling: touch;
background: #e4522f;
box-shadow: none;
color: #ffffff;
height: 100%;
max-width: 80%;
overflow-y: auto;
padding: 3em 2em;
position: fixed;
font-size: larger;
right: 0;
top: 0;
visibility: hidden;
width: 20em;
z-index: 10002;
}
#menu > ul {
margin: 0 0 1em 0;
}
#menu > ul.links {
list-style: none;
padding: 0;
}
#menu > ul.links > li {
padding: 0;
}
#menu > ul.links > li > a:not(.button) {
border: 0;
border-top: solid 1px rgba(255, 255, 255, 0.15);
color: inherit;
display: block;
line-height: 3.5em;
text-decoration: none;
}
#menu > ul.links > li > .button {
display: block;
margin: 0.5em 0 0 0;
}
#menu > ul.links > li > a:not(.button):hover {
color: rgba(255,255,255,0.2);
}
#menu > ul.links > li:first-child > a:not(.button) {
border-top: 0 !important;
}
#menu .close {
text-decoration: none;
-moz-transition: color 0.2s ease-in-out;
-webkit-transition: color 0.2s ease-in-out;
-ms-transition: color 0.2s ease-in-out;
transition: color 0.2s ease-in-out;
-webkit-tap-highlight-color: transparent;
border: 0;
color: #ffffff;
cursor: pointer;
display: block;
height: 2.75em;
line-height: 3.25em;
padding-right: 1.25em;
position: absolute;
right: 0;
text-align: right;
top: 0;
vertical-align: middle;
width: 2.75em;
}
#menu .close:before {
content: "";
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
text-transform: none !important;
}
#menu .close:before {
font-size: 1.25em;
}
#menu .close:hover {
color: rgba(255,255,255,0.2);
}
@media screen and (max-width: 736px) {
#menu .close {
height: 4em;
line-height: 4em;
}
}
#menu.visible {
-moz-transform: translateX(0);
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
box-shadow: 0 0 1.5em 0 rgba(0, 0, 0, 0.2);
visibility: visible;
}
@media screen and (max-width: 736px) {
#menu {
padding: 2.5em 1.75em;
}
}
/* Banner */
@ -3884,6 +3592,9 @@ div.spoiler
/* Main */
/* Footer */
@ -3950,3 +3661,54 @@ div.spoiler
width: 100%;
padding: 20px;
}
#rudr_instafeed{
list-style:none
}
#rudr_instafeed li{
float:left;
width:200px;
height:200px;
margin:10px
}
#rudr_instafeed li img{
max-width:100%;
max-height:100%;
}
/* class to add colorful rainbowed texts */
.ernestocouleur {
background-clip: text;
-webkit-background-clip: text;
background-image: linear-gradient(to right,
hsl(10, 100%, 75%),
hsl(20, 100%, 65%),
hsl(30, 100%, 55%),
hsl(40, 100%, 50%),
hsl(50, 100%, 50%),
hsl(60, 100%, 50%),
hsl(70, 100%, 50%),
hsl(80, 100%, 50%),
hsl(90, 100%, 50%),
hsl(100, 100%, 50%),
hsl(110, 100%, 50%),
hsl(120, 100%, 50%),
hsl(130, 100%, 50%),
hsl(140, 100%, 50%),
hsl(150, 100%, 50%),
hsl(160, 100%, 50%),
hsl(170, 100%, 50%),
hsl(180, 100%, 50%),
hsl(190, 100%, 50%),
hsl(200, 100%, 50%),
hsl(210, 100%, 50%),
hsl(220, 100%, 50%),
hsl(230, 100%, 50%),
hsl(240, 100%, 50%),
hsl(250, 100%, 50%)
);
color: transparent;
}
select[multiple] {
height: 15em;
}

View file

@ -1,7 +1,9 @@
/***** Top content *****/
.top-content { width: 100%; padding: 60px 0 120px 0; }
.top-content .carousel { box-shadow: 0 0 15px 0 #444; }
.top-content .carousel { box-shadow: 0 0 15px 0 #444; }
.top-content .carousel-control-prev { left: -110px; border-bottom: 0; }
.top-content .carousel-control-next { right: -110px; border-bottom: 0; }
.top-content .carousel-indicators { bottom: -80px; }
.top-content .carousel-indicators li { width: 16px; height: 16px; margin-left: 5px; margin-right: 5px; border-radius: 50%; }
.top-content .carousel-indicators { bottom: -80px; }
.top-content .carousel-indicators li { width: 16px; height: 16px; margin-left: 5px; margin-right: 5px; border-radius: 50%; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1,278 @@
/*
* InstagramFeed
*
* @version 1.4.0
*
* @author jsanahuja <bannss1@gmail.com>
* @contributor csanahuja <csanahuja10@gmail.com>
*
* https://github.com/jsanahuja/InstagramFeed
*
*/
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.InstagramFeed = factory();
}
}(this, function() {
var defaults = {
'host': "https://www.instagram.com/",
'username': '',
'tag': '',
'container': '',
'display_profile': true,
'display_biography': true,
'display_gallery': true,
'display_captions': false,
'display_igtv': false,
'callback': null,
'styling': true,
'items': 8,
'items_per_row': 4,
'margin': 0.5,
'image_size': 640,
'lazy_load': false,
'on_error': console.error
};
var image_sizes = {
"150": 0,
"240": 1,
"320": 2,
"480": 3,
"640": 4
};
var escape_map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
function escape_string(str){
return str.replace(/[&<>"'`=\/]/g, function (char) {
return escape_map[char];
});
}
return function(opts) {
this.options = Object.assign({}, defaults);
this.options = Object.assign(this.options, opts);
this.is_tag = this.options.username == "";
this.valid = true;
if (this.options.username == "" && this.options.tag == "") {
this.options.on_error("InstagramFeed: Error, no username or tag defined.", 1);
this.valid = false;
}
if (typeof this.options.get_data !== "undefined") {
console.warn("InstagramFeed: options.get_data is deprecated, options.callback is always called if defined");
}
if (this.options.callback == null && this.options.container == "") {
this.options.on_error("InstagramFeed: Error, neither container found nor callback defined.", 2);
this.valid = false;
}
this.get = function(callback) {
var url = this.is_tag ? this.options.host + "explore/tags/" + this.options.tag + "/" : this.options.host + this.options.username + "/",
xhr = new XMLHttpRequest();
var _this = this;
xhr.onload = function(e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try{
var data = xhr.responseText.split("window._sharedData = ")[1].split("<\/script>")[0];
}catch(error){
_this.options.on_error("InstagramFeed: It looks like the profile you are trying to fetch is age restricted. See https://github.com/jsanahuja/InstagramFeed/issues/26", 3);
return;
}
data = JSON.parse(data.substr(0, data.length - 1));
data = data.entry_data.ProfilePage || data.entry_data.TagPage;
if(typeof data === "undefined"){
_this.options.on_error("InstagramFeed: It looks like YOUR network has been temporary banned because of too many requests. See https://github.com/jsanahuja/jquery.instagramFeed/issues/25", 4);
return;
}
data = data[0].graphql.user || data[0].graphql.hashtag;
callback(data, _this);
} else {
_this.options.on_error("InstagramFeed: Unable to fetch the given user/tag. Instagram responded with the status code: " + xhr.statusText, 5);
}
}
};
xhr.open("GET", url, true);
xhr.send();
};
this.parse_caption = function(igobj, data) {
if (
typeof igobj.node.edge_media_to_caption.edges[0] !== "undefined" &&
typeof igobj.node.edge_media_to_caption.edges[0].node !== "undefined" &&
typeof igobj.node.edge_media_to_caption.edges[0].node.text !== "undefined" &&
igobj.node.edge_media_to_caption.edges[0].node.text !== null
) {
return igobj.node.edge_media_to_caption.edges[0].node.text;
}
if (
typeof igobj.node.title !== "undefined" &&
igobj.node.title !== null &&
igobj.node.title.length != 0
) {
return igobj.node.title;
}
if (
typeof igobj.node.accessibility_caption !== "undefined" &&
igobj.node.accessibility_caption !== null &&
igobj.node.accessibility_caption.length != 0
) {
return igobj.node.accessibility_caption;
}
return (this.is_tag ? data.name : data.username) + " image ";
}
this.display = function(data) {
// Styling
var html = "",
styles;
if (this.options.styling) {
var width = (100 - this.options.margin * 2 * this.options.items_per_row) / this.options.items_per_row;
styles = {
'profile_container': " style='text-align:center;'",
'profile_image': " style='border-radius:10em;width:15%;max-width:125px;min-width:50px;'",
'profile_name': " style='font-size:1.2em;'",
'profile_biography': " style='font-size:1em;'",
'gallery_image': " style='width:100%;'",
'gallery_image_link': " style='width:" + width + "%; margin:" + this.options.margin + "%; position:relative; display: inline-block; height: 100%;'"
};
// Caption Styling
if(this.options.display_captions){
html += "<style>\
a[data-caption]:hover::after {\
content: attr(data-caption);\
text-align: center;\
font-size: 0.8rem;\
color: black;\
position: absolute;\
left: 0;\
right: 0;\
bottom: 0;\
padding: 1%;\
max-height: 100%;\
overflow-y: auto;\
overflow-x: hidden;\
background-color: hsla(0, 100%, 100%, 0.8);\
}\
</style>";
}
} else {
styles = {
'profile_container': "",
'profile_image': "",
'profile_name': "",
'profile_biography': "",
'gallery_image': "",
'gallery_image_link': ""
};
}
// Profile
if (this.options.display_profile) {
html += "<div class='instagram_profile'" + styles.profile_container + ">";
html += "<img class='instagram_profile_image'" + (this.options.lazy_load ? " loading='lazy'" : '') + " src='" + data.profile_pic_url + "' alt='" + (this.is_tag ? data.name + " tag pic" : data.username + " profile pic") + " profile pic'" + styles.profile_image + " />";
if (this.is_tag)
html += "<p class='instagram_tag'" + styles.profile_name + "><a href='https://www.instagram.com/explore/tags/" + this.options.tag + "' rel='noopener' target='_blank'>#" + this.options.tag + "</a></p>";
else
html += "<p class='instagram_username'" + styles.profile_name + ">@" + data.full_name + " (<a href='https://www.instagram.com/" + this.options.username + "' rel='noopener' target='_blank'>@" + this.options.username + "</a>)</p>";
if (!this.is_tag && this.options.display_biography)
html += "<p class='instagram_biography'" + styles.profile_biography + ">" + data.biography + "</p>";
html += "</div>";
}
// Gallery
if (this.options.display_gallery) {
var image_index = typeof image_sizes[this.options.image_size] !== "undefined" ? image_sizes[this.options.image_size] : image_sizes[640];
if (typeof data.is_private !== "undefined" && data.is_private === true) {
html += "<p class='instagram_private'><strong>This profile is private</strong></p>";
} else {
var imgs = (data.edge_owner_to_timeline_media || data.edge_hashtag_to_media).edges;
max = (imgs.length > this.options.items) ? this.options.items : imgs.length;
html += "<div class='instagram_gallery'>";
for (var i = 0; i < max; i++) {
var url = "https://www.instagram.com/p/" + imgs[i].node.shortcode,
image, type_resource,
caption = escape_string(this.parse_caption(imgs[i], data));
switch (imgs[i].node.__typename) {
case "GraphSidecar":
type_resource = "sidecar"
image = imgs[i].node.thumbnail_resources[image_index].src;
break;
case "GraphVideo":
type_resource = "video";
image = imgs[i].node.thumbnail_src
break;
default:
type_resource = "image";
image = imgs[i].node.thumbnail_resources[image_index].src;
}
if (this.is_tag) data.username = '';
html += "<a href='" + url + (this.options.display_captions? "' data-caption='" + caption : "") + "' class='instagram-" + type_resource + "' rel='noopener' target='_blank'" + styles.gallery_image_link + ">";
html += "<img" + (this.options.lazy_load ? " loading='lazy'" : '') + " src='" + image + "' alt='" + caption + "'" + styles.gallery_image + " />";
html += "</a>";
}
html += "</div>";
}
}
// IGTV
if (this.options.display_igtv && typeof data.edge_felix_video_timeline !== "undefined") {
var igtv = data.edge_felix_video_timeline.edges,
max = (igtv.length > this.options.items) ? this.options.items : igtv.length
if (igtv.length > 0) {
html += "<div class='instagram_igtv'>";
for (var i = 0; i < max; i++) {
var url = "https://www.instagram.com/p/" + igtv[i].node.shortcode,
caption = escape_string(this.parse_caption(igtv[i], data));
html += "<a href='" + url + (this.options.display_captions? "' data-caption='" + caption : "") + "' rel='noopener' target='_blank'" + styles.gallery_image_link + ">";
html += "<img" + (this.options.lazy_load ? " loading='lazy'" : '') + " src='" + igtv[i].node.thumbnail_src + "' alt='" + caption + "'" + styles.gallery_image + " />";
html += "</a>";
}
html += "</div>";
}
}
this.options.container.innerHTML = html;
};
this.run = function() {
this.get(function(data, instance) {
if(instance.options.container != ""){
instance.display(data);
}
if(typeof instance.options.callback === "function"){
instance.options.callback(data);
}
});
};
if (this.valid) {
this.run();
}
};
}));

File diff suppressed because one or more lines are too long

View file

@ -1265,7 +1265,7 @@ if (typeof jQuery === 'undefined') {
title: '',
delay: 0,
html: false,
container: false,
container_carousel: false,
viewport: {
selector: 'body',
padding: 0
@ -1407,7 +1407,7 @@ if (typeof jQuery === 'undefined') {
.addClass(placement)
.data('bs.' + this.type, this)
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
this.options.container_carousel ? $tip.appendTo(this.options.container_carousel) : $tip.insertAfter(this.$element)
var pos = this.getPosition()
var actualWidth = $tip[0].offsetWidth
@ -1415,13 +1415,13 @@ if (typeof jQuery === 'undefined') {
if (autoPlace) {
var orgPlacement = placement
var $container = this.options.container ? $(this.options.container) : this.$element.parent()
var containerDim = this.getPosition($container)
var $container_carousel = this.options.container_carousel ? $(this.options.container_carousel) : this.$element.parent()
var container_carouselDim = this.getPosition($container_carousel)
placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
placement = placement == 'bottom' && pos.bottom + actualHeight > container_carouselDim.bottom ? 'top' :
placement == 'top' && pos.top - actualHeight < container_carouselDim.top ? 'bottom' :
placement == 'right' && pos.right + actualWidth > container_carouselDim.width ? 'left' :
placement == 'left' && pos.left - actualWidth < container_carouselDim.left ? 'right' :
placement
$tip
@ -2051,11 +2051,11 @@ if (typeof jQuery === 'undefined') {
})
}
Tab.prototype.activate = function (element, container, callback) {
var $active = container.find('> .active')
Tab.prototype.activate = function (element, container_carousel, callback) {
var $active = container_carousel.find('> .active')
var transition = callback
&& $.support.transition
&& (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
&& (($active.length && $active.hasClass('fade')) || !!container_carousel.find('> .fade').length)
function next() {
$active

File diff suppressed because one or more lines are too long

View file

@ -2755,7 +2755,7 @@
selector: '(string|boolean)',
placement: '(string|function)',
offset: '(number|string|function)',
container: '(string|element|boolean)',
container_carousel: '(string|element|boolean)',
fallbackPlacement: '(string|array)',
boundary: '(string|element)',
sanitize: 'boolean',
@ -2779,7 +2779,7 @@
selector: false,
placement: 'top',
offset: 0,
container: false,
container_carousel: false,
fallbackPlacement: 'flip',
boundary: 'scrollParent',
sanitize: true,
@ -2957,12 +2957,12 @@
this.addAttachmentClass(attachment);
var container = this._getContainer();
var container_carousel = this._getcontainer_carousel();
$(tip).data(this.constructor.DATA_KEY, this);
if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
$(tip).appendTo(container);
$(tip).appendTo(container_carousel);
}
$(this.element).trigger(this.constructor.Event.INSERTED);
@ -3153,16 +3153,16 @@
return offset;
};
_proto._getContainer = function _getContainer() {
if (this.config.container === false) {
_proto._getcontainer_carousel = function _getcontainer_carousel() {
if (this.config.container_carousel === false) {
return document.body;
}
if (Util.isElement(this.config.container)) {
return $(this.config.container);
if (Util.isElement(this.config.container_carousel)) {
return $(this.config.container_carousel);
}
return $(document).find(this.config.container);
return $(document).find(this.config.container_carousel);
};
_proto._getAttachment = function _getAttachment(placement) {
@ -4060,10 +4060,10 @@
} // Private
;
_proto._activate = function _activate(element, container, callback) {
_proto._activate = function _activate(element, container_carousel, callback) {
var _this2 = this;
var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);
var activeElements = container_carousel && (container_carousel.nodeName === 'UL' || container_carousel.nodeName === 'OL') ? $(container_carousel).find(Selector$9.ACTIVE_UL) : $(container_carousel).children(Selector$9.ACTIVE);
var active = activeElements[0];
var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);

File diff suppressed because one or more lines are too long

View file

@ -41,18 +41,7 @@
);
});
// Menu.
$('#menu')
.append('<a href="#menu" class="close"></a>')
.appendTo($body)
.panel({
delay: 500,
hideOnClick: true,
hideOnSwipe: true,
resetScroll: true,
resetForms: true,
side: 'right'
});
$('#id_multi_instrumentiste').on('change', function() {
@ -64,6 +53,8 @@
}
});
$('#id_instru').on('change', function() {

View file

@ -1,6 +1,7 @@
{% load static %}
{% load i18n %}
{% load changelang %}
{% load avatar_tags %}
{% get_current_language as current_language %}
<!DOCTYPE HTML>
@ -13,56 +14,126 @@
<meta charset="utf-8" />
<title>{% block titre %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{% block extrahead %}{% endblock %}
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}">
<link rel="stylesheet" href="{% static 'css/main.css' %}" />
{% block extrahead %}{% endblock %}
<link rel="stylesheet" href="{% static 'css/main.css' %}?version=1" />
<link rel="stylesheet" href="{% static 'css/add2calendar.css' %}">
</head>
<body class="subpage">
<!-- Header -->
<header id="header">
<a href="{% url 'home' %}"><img src="{% static 'images/Ernestophone_white.png' %}"
style="float: left; width: auto; height: 3.1em;" alt="L'Ernestophone" title="white_esnesto" id="logo"></a>
<a href="#menu">Menu</a>
</header>
<nav class="navbar navbar-expand-md">
<div class="container-fluid">
<!-- Brand -->
<a class="navbar-brand" href="{% url 'home' %}"><img style='vertical-align: middle;float:left;height:3em;width:auto' src='{% static "images/Ernestophone_white.png" %}'/></a>
<!-- Nav -->
<nav id="menu">
<ul class="links">
<li><p></p></li>
<li>{% ifequal current_language "fr" %}
<a href="{% changelang "en" %}" >English<span class="image right"><img src="{% static "images/en_flag.jpg" %}"></span></a>
{% else %}
<a href="{% changelang "fr" %}">Français<span class="image right"><img src="{% static "images/fr_flag.jpg" %}"></span></a>
{% endifequal %}</li>
{% if not user.is_authenticated %}
<li><a href="{% url 'home' %}">{% trans "Accueil" %}</a></li>
<li><a href="{% url 'calendrier:liste' %}">{% trans "Agenda" %}</a></li>
{% else %}
<li><a href="{% url 'calendrier:home' %}">{% trans "Agenda" %}</a></li>
{% endif %}
<li><a href="{% url 'partitions:liste' %}">{% trans "Répertoire" %}</a></li>
<!-- Links -->
<ul class="navbar-nav mr-auto" >
{% if not user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'home' %}"><b>{% trans "Accueil" %}</b></a>
</li>
<li class="nav-item">
<a class="nav-link"href="{% url 'calendrier:liste' %}"><b>{% trans "Agenda" %}</b></a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'calendrier:home' %}"><b>{% trans "Agenda" %}</b></a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'partitions:liste' %}"><b>{% trans "Répertoire" %}</b></a>
</li>
{% if user.is_authenticated %}
<li><a href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a></li>
<li><a href="{% url 'pads:list' %}">{% trans "Pads" %}</a></li>
{% if user.is_superuser or user.profile.is_chef %}
<li><a href="/admin/">{% trans "Administration" %}</a></li>
{% if user.profile.is_chef %}
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
{% endif %}
{% endif %}
<li><a href="{% url 'change_membre' %}">{% trans "Modification du profil" %}</a></li>
<li><a href="{% url 'logout' %}">{% trans "Déconnexion" %}</a></li>
{% else %}
<li><a href="{% url 'login' %}">{% trans "Se connecter" %}</a></li>
<li><a href="{% url 'registration' %}">{% trans "Créer un compte" %}</a></li>
<li class="nav-item">
<a class="nav-link" href="{% url 'instruments:liste' %}"><b>{% trans "Instruments" %}</b></a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'pads:list' %}"><b>{% trans "Pads" %}</b></a>
</li>
<!-- Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="{% url 'social' %}" id="navbardrop" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<b>{% trans 'Social'%}</b>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a>
<a class="dropdown-item" href="https://photos.cof.ens.fr/index.php/Clubs-du-COF/L'Ernestophone" target="_blank">{% trans "Galerie Photo" %}</a>
<a class="dropdown-item" href="https://heyzine.com/flip-book/b2cf4809b7.html" target="_blank">{% trans "Year Book 2021" %}</a>
</div>
</li>
{% if user.is_superuser or user.profile.is_chef or user.profile.is_chef_event or user.profile.is_chef_com or user.profile.is_chef_mu %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="{% url 'chef' %}" id="navbardrop" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<b>{% trans 'Le pouvoir des cheff·e·s'%}</b>
</a>
<div class="dropdown-menu">
{% if user.is_superuser or user.profile.is_chef %}
<a class="dropdown-item" href="/admin/">{% trans "Administration" %}</a>
{% endif %}
</ul>
</nav>
{% if user.profile.is_chef %}
<a class="dropdown-item" href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_event %}
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_com %}
<a class="dropdown-item" href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a>
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_mu %}
<a class="dropdown-item" href="{% url 'partitions:list_setlist' %}">{% trans "Gérer les programmes de répétition" %}</a>
{% endif %}
</div>
</li>
{% endif %}
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'home' %}#contact"><b>{% trans "Contact" %}</b></a>
</li>
{% endif %}
</ul>
<ul class="navbar-nav" style="float:right">
{% if user.is_authenticated %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="{% url 'profile' %}" id="navbardrop" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{% if request.user|has_avatar %}
{% avatar request.user 50 class="rounded-circle" style="vertical-align: middle"%}
{% else %}
<img src="{% static "images/Ernestophone_logo.png" %}" width="50" height="50" class="rounded-circle"style="vertical-align: middle">
{% endif %}
</a>
<div class="dropdown-menu" >
<a class="dropdown-item" href="{% url 'change_membre' %}">{% trans "Modifier le profil" %}</a>
<a class="dropdown-item" href="{% url 'trombonoscope:change' %}">{% trans "Modifier le Trombo" %}</a>
<a class="dropdown-item" href="{% url 'logout' %}">{% trans "Déconnexion" %}</a>
</div>
</li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{% url 'login' %}"><b>{% trans "Se connecter" %}</b></a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'registration' %}"><b>{% trans "Créer un compte" %}</b></a></li>
{% endif %}
<li class="nav-item">
{% ifequal current_language "fr" %}
<a class="nav-link" href="{% changelang "en" %}" ><img src="{% static 'images\en_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
{% else %}
<a class="nav-link" href="{% changelang "fr" %}" ><img src="{% static 'images\fr_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
{% endifequal %}
</li>
</ul>
</div>
</nav>
<!-- Main -->
@ -74,6 +145,10 @@
<!-- Footer -->
<footer id="footer" style="background-color:rgb(228, 82, 47);">
<div class="copyright">
<ul class="icons">
<li><a target="_blank" href="https://cvec.etudiant.gouv.fr/"><img alt="Logo de la CVEC" src='{% static "images/cvec.png" %}' width="100px"/></a></li>
</ul>
<ul class="icons">
<li><a target="_blank" href="https://www.facebook.com/ernestophone"
@ -82,19 +157,58 @@
<li><a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ"
class="icon fa-youtube-play"><span class="label">Youtube</span></a></li>
<li><a target="_blank" href="https://www.instagram.com/ernestophone/" class="icon fa-instagram"><span class="label">Instagram</span></a></li>
</ul>
</div>
</footer>
<!-- Scripts -->
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/jquery.scrolly.min.js' %}"></script>
<script src="{% static 'js/skel.min.js' %}"></script>
<script src="{% static 'js/util.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/InstagramFeed.js' %}"></script>
<script src="{% static 'js/add2calendar.js' %}"></script>
<script>
const $dropdown = $(".dropdown");
const $dropdownToggle = $(".dropdown-toggle");
const $dropdownMenu = $(".dropdown-menu");
const showClass = "show";
$(window).on("load resize", function() {
if (this.matchMedia("(min-width: 768px)").matches) {
$dropdown.hover(
function() {
const $this = $(this);
$this.addClass(showClass);
$this.find($dropdownToggle).attr("aria-expanded", "true");
$this.find($dropdownMenu).addClass(showClass);
},
function() {
const $this = $(this);
$this.removeClass(showClass);
$this.find($dropdownToggle).attr("aria-expanded", "false");
$this.find($dropdownMenu).removeClass(showClass);
}
);
} else {
$dropdown.off("mouseenter mouseleave");
}
});
</script>
<script type="text/javascript">
function ouvrirFermerSpoiler(div)
{
var divContenu = div.getElementsByTagName('div')[1];
@ -107,5 +221,7 @@
}
</script>
{% block script %}
{% endblock %}
</body>
</html>

View file

@ -52,9 +52,20 @@
</div>
<div class ="6u 12u (small)">
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/registration.png' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="" class="icon fa-copyright">lor_tie</a>
<div href="" class="icon fa-copyright"> lor_tie</div>
{% endif %}
</div>
</span>
</div>

View file

@ -0,0 +1,38 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Cheff·e·s" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<div class="row">
<div class="6u 12u$(small)">
<h2>{% trans "Le pouvoir des cheff·e·s" %} :</h2>
<ul>
{% if user.profile.is_chef or user.is_superuser %}
<li> <a href="/admin/">{% trans "Administration" %}</a></li>
{% endif %}
{% if user.profile.is_chef %}
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_event%}
<li> <a href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a></li>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_com%}
<li><a href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a></li>
<li><a href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a></li>
{% endif %}
{% if user.profile.is_chef or user.profile.is_chef_mu %}
<li> <a href="{% url 'partitions:list_setlist' %}">{% trans "Gérer les programmes de répétition" %}</a> </li>
{% endif %}
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{%block titre %}{% trans "Ajout d'une photo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<p><a href="{% url "liste_photo" %}" class="button alt">{% trans "Retour à la liste" %}</a></p>
{% if envoi %}<p>{% trans "Cette photo à été enregistrée" %}.{% endif %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Enregistrer" %}" />
</form>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{%block titre %}{% trans "Ajout d'une vidéo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<p><a href="{% url "liste_video" %}" class="button alt">{% trans "Retour à la liste" %}</a></p>
{% if envoi %}<p>{% trans "Cette vidéo à été enregistrée" %}.{% endif %}
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Enregistrer" %}" />
</form>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Suppression d'une photo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post">
{% csrf_token %}
<p><a href="{% url "liste_photo" %}" class="button alt">{% trans "Retour aux photos" %}</a></p>
<p>{% blocktrans with object=object %} Voulez vous vraiment supprimer la photo {{ object.name }}?{% endblocktrans %}</p>
<input type="submit" value="{% trans "Oui" %}" />
</form>
</div></section>
</div>
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Suppression d'une vidéo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post">
{% csrf_token %}
<p><a href="{% url "liste_video" %}" class="button alt">{% trans "Retour aux vidéos" %}</a></p>
<p>{% blocktrans with object=object %} Voulez vous vraiment supprimer la vidéo {{ object.name }}?{% endblocktrans %}</p>
<input type="submit" value="{% trans "Oui" %}" />
</form>
</div></section>
</div>
{% endblock %}

View file

@ -3,6 +3,7 @@
{% load i18n %}
{% load halflength %}
{% block titre %}{% trans "L'Ernestophone : La fanfare de l'Ecole normale supérieure de Paris" %}{% endblock %}
{% block extrahead %} <link rel="stylesheet" href="{% static 'css/style.css' %}" />{% endblock %}
{% block content %}
<!-- Banner -->
@ -32,8 +33,12 @@
grâce à notre énergie et notre répertoire oscillant entre pop et
brass band.{% endblocktrans %}</p>
</header>
<!-- 2 Column Video Section -->
<!-- Carousel row -->
<div class="top-content">
<div class="container_carousel">
<div class="row">
<div class="col col-md-10 offset-md-1 col-lg-8 offset-lg-2">
<!-- Carousel -->
{% if videos %}
<div id="carousel" class="carousel slide">
@ -72,17 +77,24 @@
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
</div>
</div>
{% endif %}
<!-- End carousel -->
</div>
</section>
<!-- Two -->
<section class="wrapper style2" >
<div class="inner">
<div class="inner" id="contact">
<header>
<h2>{% trans "L'Ernestophone in a nutshell" %}</h2>
<div id="instagram-feed" class="instagram_feed"> </div>
<p style="color:white">{% blocktrans %}L'Ernestophone, c'est la fanfare de l'École
normale supérieure, (re)créée en septembre 2011, pour le plus
grand bonheur des petits. Et des grands.{% endblocktrans %}</p>
@ -155,10 +167,20 @@
{% endfor %}
<a href="{% url 'partitions:liste' %}" class="button alt fit" >{% trans "Voir le répertoire présent et passé" %}</a>
<span class="image fit">
{% if photo_rep %}
<img src="{{photo_rep.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo_rep.url %}
<a href="{{photo_rep.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo_rep.color}}"> {% if photo_rep.auteur %}{{photo_rep.auteur}}{%endif%}</a>
{% elif photo_rep.auteur %}
<div class="icon fa-copyright" style="color: {{photo_rep.color}}" > {{photo_rep.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/repertoire.jpg' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="" class="icon fa-copyright"> Lucas Gierzack</a>
<div class="icon fa-copyright"> Lucas Gierzack</div>
</div>
{% endif %}
</span>
</div>
@ -174,12 +196,24 @@
Nous répétons tous les mardis et jeudi soirs de 20h à 22h dans les sous sols du NIR à l'ENS. <br>Fanfaron débutant ou musicien aguerri, n'hésite pas à venir nous rejoindre !
Nous serons heureux de te compter dans nos rangs !<br>
Nous prêtons des instruments à tout membre du COF souhaitant découvrir les joies de la fanfaronnerie !{% endblocktrans %}</p>
<p align="center">{% blocktrans %}Pour un petit aperçu du fun qu'on peux avoir n'hésites pas à consulter notre {% endblocktrans %}<a class="text" href="https://heyzine.com/flip-book/b2cf4809b7.html" target="_blank">year book</a></p>
</div>
<div class="5u 12u$(small)"><div>
<span class="image fit"><img src="{% static 'images/join.jpg' %}" alt="" />
<span class="image fit">
{% if photo_join %}
<img src="{{photo_join.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo_join.url %}
<a href="{{photo_join.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo_join.color}}"> {% if photo_join.auteur %}{{photo_join.auteur}}{%endif%}</a>
{% elif photo_join.auteur %}
<div class="icon fa-copyright" style="color: {{photo_join.color}}" > {{photo_join.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/join.jpg' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div>
{% endif %}
</span>
</div>
</div>
@ -192,12 +226,23 @@
<div class="tab tab-3 flex flex-3 active">
<div class="box">
<div><span class="image right">
{% if photo_contact %}
<img src="{{photo_contact.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo_contact.url %}
<a href="{{photo_contact.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo_contact.color}}"> {% if photo_contact.auteur %}{{photo_contact.auteur}}{%endif%}</a>
{% elif photo_contact.auteur %}
<div class="icon fa-copyright" style="color: {{photo_contact.color}}" > {{photo_contact.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/contact.jpg' %}" alt=""/>
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div></span></div><p style="color:white" align="center">{% blocktrans %}Vous préparez un
</div>
{% endif %}
</span></div><p style="color:white" align="center">{% blocktrans %}Vous préparez un
évenement et vous recherchez une fanfare dynamique ? N'hésitez
pas à nous envoyer un message nous serons ravis de venir
pas à nous envoyer un message par mail ou sur Facebook. Nous serons ravis de venir
fanfaronner pour vous !! Vérifiez notre{% endblocktrans %} <a href="{% url 'calendrier:liste' %}" class="text">{% trans "agenda" %}</a>. <br />
<a target="_blank" href="https://www.facebook.com/ernestophone"
@ -211,10 +256,12 @@
&nbsp;
&nbsp;
&nbsp;
&nbsp;
<a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ"
class="icon fa-youtube-play fa-5x"><span class="label">Youtube</span></a>
class="icon fa-youtube-play fa-5x"><span class="label">Youtube</span> </a> &nbsp;
&nbsp;
<a target="_blank" href="https://www.instagram.com/ernestophone/" class="icon fa-instagram fa-5x"><span class="label">Instagram</span></a>
</p>
</div>
</div>
@ -223,7 +270,25 @@
</div>
</section>
</div>
<script src="{% static 'js/InstagramFeed.min.js' %}"></script>
<script>
(function(){
new InstagramFeed({
'username': 'ernestophone',
'container': "#instagram-feed" ,
'display_profile': false,
'display_biography': false,
'display_gallery': true,
'display_captions': true,
'callback': null,
'styling': true,
'items': 8,
'items_per_row': 8,
'margin': 1
});
})();
</script>
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script src="{% static 'js/jquery-migrate-3.0.0.min.js' %}"></script>
<script src="{% static 'js/popper.min.js' %}"></script>

View file

@ -34,9 +34,22 @@
</div>
</div>
<div class="6u 12u$(xsmall)">
<span class="image fit"><img src="{% static 'images/connect.jpg' %}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/connect.jpg' %}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div></span>
</div>
{% endif %}
</span>
</div>

View file

@ -0,0 +1,42 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% get_current_language as current_language %}
{% load autotranslate %}
{% block titre %}{% trans "Liste des Photos" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<h4>{% trans "Liste des photos" %} :</h4>
<p><a href="{% url "add_photo" %}" class="button">{% trans "Ajouter une photo" %}</a></p>
<ul class="filelist">
{% for p in photos %}
<li>
<p> <b>{{ p.name }}</b> {% if p.cat == 'n' %}: {% trans "Non utilisée" %} <br>( {% trans "Pensez à supprimer les photos non utilisée" %}){% endif %}
{% if p.cat == 'home_join' %}: {% trans "Rejoignez nous" %} {% endif %}
{% if p.cat == 'home_contact' %}: {% trans "Nous Contacter" %} {% endif %}
{% if p.cat == 'home_rep' %}: {% trans "Répertoire de l'acceuil" %} {% endif %}
{% if p.cat == 'login' %}: {% trans "Connexion" %} {% endif %}
{% if p.cat == 'change_membre' %}: {% trans "Modification du profil" %} {% endif %}
{% if p.cat == 'inscription_membre' %}: {% trans "Inscription" %} {% endif %}
{% if p.cat == 'home' %}: {% trans "Calendrier connecté" %} {% endif %}
{% if p.cat == 'liste' %}: {% trans "Agenda public" %} {% endif %}
{% if p.cat == 'part' %}: {% trans "Répertoire" %} {% endif %}
{% if p.cat == 'instru' %}: {% trans "Instruments" %} {% endif %}
&nbsp <a class="button alt" href="{% url "edit_photo" p.id %}">{% trans "Modifier" %}</a>&nbsp<a class="button alt" href="{% url "delete_photo" p.id %}">{% trans "Supprimer" %}</a>
<img src="{{p.image.url}}" alt="" style='vertical-align: middle;height:4em;width:auto' /></p>
</li>
{% empty %}
<p>{% trans "Pas de photos pour le moment" %}</p>
{% endfor %}
</ul>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Profil" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<div class="row">
<div class="6u 12u$(small)">
<h2>{% trans "Profil" %} :</h2>
<ul>
<li> <a href="{% url 'change_membre' %}">{% trans "Modifier le profil" %}</a></li>
<li> <a href="{% url 'trombonoscope:change' %}">{% trans "Modifier le Trombo" %}</a></li>
<li><a href="{% url 'logout' %}">{% trans "Déconnexion" %}</a></li>
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -12,7 +12,7 @@
<section class="wrapper style1" >
<div class="inner">
<h2>{% trans "Créer un compte :" %}</h2>
{% if error %}
{% if error %}
<p>{{ error }}</p>
{% endif %}
<div class="row uniform">
@ -48,10 +48,21 @@
</div>
<div class ="6u 12u (small)">
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/registration.png' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="" class="icon fa-copyright">lor_tie</a>
<div href="" class="icon fa-copyright"> lor_tie</div>
</div>
{%endif%}
</span>
</div>

View file

@ -0,0 +1,24 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% load static %}
{% block titre %}{% trans "Social" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<div class="row">
<div class="6u 12u$(small)">
<h2>{% trans "Social" %} :</h2>
<ul>
<li> <a href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a></li>
<li><a href="https://photos.cof.ens.fr/index.php/Clubs-du-COF/L'Ernestophone" target="_blank">{% trans "Galerie Photo" %}</a></li>
<li><a href="{% url 'yearbook2021' %}" target="_blank">{% trans "Year Book 2021" %}</a></li>
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Modification d'une photo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Enregistrer" %}" />
</form>
</div></section></div>
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% block titre %}{% trans "Modification d'une vidéo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans "Enregistrer" %}" />
</form>
</div></section></div>
{% endblock %}

View file

@ -0,0 +1,30 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% get_current_language as current_language %}
{% load autotranslate %}
{% block titre %}{% trans "Liste des vidéos" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<h4>{% trans "Liste des vidéos" %} :</h4>
<p><a href="{% url "add_video" %}" class="button">{% trans "Ajouter une vidéo" %}</a></p>
<ul class="filelist">
{% for v in videos %}
<li>
<p> <b>{{ v }}</b> &nbsp<a class="button alt" href="{% url "edit_video" v.id %}">{% trans "Modifier" %}</a>
&nbsp <a class="button alt" href="{% url "delete_video" v.id %}">{% trans "Supprimer" %}</a></p>
</li>
{% empty %}
<p>{% trans "Pas de vidéos pour le moment" %}</p>
{% endfor %}
</ul>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% load static %}
{% block titre %}{% trans "Modification d'une photo" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<iframe allowfullscreen="allowfullscreen" scrolling="no" class="fp-iframe" src="https://heyzine.com/flip-book/b2cf4809b7.html" style="border: 1px solid lightgray; width: 100%; height: 600px;"></iframe>
</div></section></div>
{% endblock %}

View file

@ -3,12 +3,13 @@ from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def autotranslate(current_language, description, description_en):
if( current_language != "fr" and description_en):
if current_language != "fr" and description_en:
return mark_safe(description_en)
elif(current_language == "fr" and not description):
elif current_language == "fr" and not description:
return mark_safe(description_en)
else:
return mark_safe(description)

View file

@ -12,7 +12,7 @@ def changelang(context, lang=None, *args, **kwargs):
Usage: {% change_lang 'en' %}
"""
path = context['request'].path
path = context["request"].path
url_parts = resolve(path)
url = path

View file

@ -1,8 +1,10 @@
from django.template import Library
from math import ceil
from django.template import Library
register = Library()
@register.filter
def half_length(liste):
try:

View file

@ -1,8 +1,10 @@
from django import template
from datetime import date, timedelta
from django import template
register = template.Library()
@register.filter
def modulo(num, val):
return num % val

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,115 +1,274 @@
from django.shortcuts import render, redirect
from partitions.models import Category
from gestion.forms import ChangeMembreForm, ChangeFormUser,RegistrationFormUser, InscriptionMembreForm
from django.conf import settings
from django.http import HttpResponseRedirect
from gestion.models import ErnestoUser, VideoGallery
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordChangeForm
from calendrier.forms import ChangeDoodleName
from partitions.decorators import chef_required
from gestion.mixins import ChefRequiredMixin
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from django.urls import reverse_lazy
from django.shortcuts import render_to_response
import string
import os
import random
import string
from django.conf import settings
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.http import HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import (CreateView, DeleteView, ListView,
TemplateView, UpdateView)
from calendrier.forms import ChangeDoodleName
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
InscriptionMembreForm, RegistrationFormUser)
from gestion.mixins import (AllChefRequiredMixin, ChefComRequiredMixin,
ChefRequiredMixin)
from gestion.models import ErnestoUser, Photo, VideoGallery
from partitions.models import Category
def generer(*args):
caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire)
aleatoire = [random.choice(caracteres) for i in range(6)]
return "".join(aleatoire)
def home(request):
if request.user.is_authenticated :
return redirect('calendrier:home')
categories = Category.objects.filter(name = "Partitions actives").prefetch_related("partitionset_set")
videos = VideoGallery.objects.all()
return render_to_response( 'gestion/index.html', {"request":request,"categories": categories,'videos':videos})
def thanks(request):
class Home(TemplateView):
template_name = "gestion/index.html"
return render(request, 'gestion/thanks.html', locals())
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect("calendrier:home")
return super(Home, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["categories"] = Category.objects.filter(
name="Partitions actives"
).prefetch_related("partitionset_set")
context["videos"] = VideoGallery.objects.all().order_by("order")
context["photo_rep"] = (
Photo.objects.filter(cat="home_rep").order_by("?").first()
)
context["photo_join"] = (
Photo.objects.filter(cat="home_join").order_by("?").first()
)
context["photo_contact"] = (
Photo.objects.filter(cat="home_contact").order_by("?").first()
)
return context
@login_required
def changename(request):
if request.method == 'POST':
class MyLoginView(LoginView):
template_name = "gestion/login.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["photo"] = Photo.objects.filter(cat="login").order_by("?").first()
return context
class Thanks(TemplateView):
template_name = "gestion/thanks.html"
class Social(LoginRequiredMixin, TemplateView):
template_name = "gestion/social.html"
class Profil(LoginRequiredMixin, TemplateView):
template_name = "gestion/profile.html"
class Chef(AllChefRequiredMixin, TemplateView):
template_name = "gestion/chef.html"
class YearBook2021(TemplateView):
template_name = "gestion/yearbook2021.html"
class ChangeName(LoginRequiredMixin, TemplateView):
form_class = ChangeDoodleName
template_name = "gestion/changename.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class(instance=self.request.user)
return context
def post(self, request, *args, **kwargs):
requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user)
form = self.form_class(requbis, instance=request.user)
if form.is_valid():
form.save()
success = True
return redirect('change_membre')
else:
form = ChangeDoodleName(instance=request.user)
return render(request, 'gestion/changename.html', locals())
return redirect("change_membre")
context = self.get_context_data()
context["form"] = form
return render(request, self.template_name, context)
class ChangeMembre(LoginRequiredMixin, TemplateView):
comp_form_class = ChangeMembreForm
user_form_class = ChangeFormUser
template_name = "gestion/change.html"
@login_required
def change_membre(request):
if request.method == 'POST':
comp_form = ChangeMembreForm(request.POST, instance=request.user.profile)
user_form = ChangeFormUser(request.POST, instance=request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
comp_form = self.comp_form_class(instance=self.request.user.profile)
user_form = self.user_form_class(instance=self.request.user)
context["comp_form"] = comp_form
context["user_form"] = user_form
context["photo"] = (
Photo.objects.filter(cat="change_membre").order_by("?").first()
)
return context
def post(self, request, *args, **kwargs):
success = False
comp_form = self.comp_form_class(request.POST, instance=request.user.profile)
user_form = self.user_form_class(request.POST, instance=request.user)
if user_form.is_valid() and comp_form.is_valid():
user_form.save()
comp_form.save()
success = True
return redirect('home')
else:
comp_form = ChangeMembreForm(instance=request.user.profile)
user_form = ChangeFormUser(instance=request.user)
return render(request, 'gestion/change.html', locals())
@login_required
def change_password(request):
if request.method == 'POST':
context = self.get_context_data()
context["success"] = success
context["comp_form"] = comp_form
context["user_form"] = user_form
return render(request, self.template_name, context)
class ChangePassword(LoginRequiredMixin, TemplateView):
form_class = PasswordChangeForm
template_name = "gestion/changepasswd.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class(self.request.user)
return context
def post(self, request, *args, **kwargs):
requbis = request.POST.copy()
form = PasswordChangeForm(request.user, data=requbis)
success = False
form = self.form_class(request.user, data=requbis)
if form.is_valid():
request.user.profile.photo.delete()
form.save()
success = True
else:
form = PasswordChangeForm(request.user)
return render(request, 'gestion/changepasswd.html', locals())
context = self.get_context_data()
context["success"] = success
context["form"] = form
return render(request, self.template_name, context)
class Inscription(TemplateView):
user_form_class = RegistrationFormUser
comp_form_class = InscriptionMembreForm
template_name = "gestion/registration.html"
def inscription_membre(request):
if request.method == 'POST':
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["comp_form"] = self.comp_form_class()
context["user_form"] = self.user_form_class()
context["photo"] = (
Photo.objects.filter(cat="inscription_membre").order_by("?").first()
)
return context
user_form = RegistrationFormUser(request.POST)
comp_form = InscriptionMembreForm(request.POST)
def post(self, request, *args, **kwargs):
user_form = self.user_form_class(request.POST)
comp_form = self.comp_form_class(request.POST)
if user_form.is_valid() and comp_form.is_valid():
pseudo = user_form.cleaned_data['username']
if not (comp_form.cleaned_data['validation']
== settings.ACCOUNT_CREATION_PASS):
error = "Le champ Validation ne correspond pas à celui attendu"
return render(request, "gestion/registration.html", locals())
if not (
comp_form.cleaned_data["validation"] == settings.ACCOUNT_CREATION_PASS
):
error = _("Le champ Validation ne correspond pas à celui attendu")
context = self.get_context_data()
context["user_form"] = user_form
context["comp_form"] = comp_form
context["error"] = error
return render(request, self.template_name, context)
member = user_form.save(commit=False)
temp = True
while temp:
code = generer()
try:
ErnestoUser.objects.get(slug=code)
except:
except ErnestoUser.DoesNotExist:
temp = False
member.save()
(profile, _) = ErnestoUser.objects.get_or_create(user=member,
slug=code)
comp_form = InscriptionMembreForm(request.POST, instance=profile)
(profile, k) = ErnestoUser.objects.get_or_create(user=member, slug=code)
comp_form = self.comp_form_class(request.POST, instance=profile)
obj = comp_form.save(commit=False)
obj.slug = code
obj.save()
envoi = True
return redirect('thanks')
else:
comp_form = InscriptionMembreForm()
user_form = RegistrationFormUser()
return render(request, 'gestion/registration.html', locals())
return redirect("thanks")
else:
context = self.get_context_data()
context["user_form"] = user_form
context["comp_form"] = comp_form
return render(request, self.template_name, context)
class PhotoList(ChefComRequiredMixin, ListView):
model = Photo
context_object_name = "photos"
ordering = "cat"
template_name = "gestion/photo.html"
class PhotoCreate(ChefComRequiredMixin, CreateView):
model = Photo
fields = ["name", "cat", "auteur", "url", "color", "image"]
template_name = "gestion/create_photo.html"
success_url = reverse_lazy("liste_photo")
def form_valid(self, form):
photo = form.save(commit=False)
photo.save()
return HttpResponseRedirect(self.success_url)
class PhotoUpdate(ChefComRequiredMixin, UpdateView):
model = Photo
fields = ["name", "cat", "auteur", "url", "color", "image"]
template_name = "gestion/update_photo.html"
success_url = reverse_lazy("liste_photo")
class PhotoDelete(ChefComRequiredMixin, DeleteView):
model = Photo
template_name = "gestion/delete_photo.html"
success_url = reverse_lazy("liste_photo")
class VideoList(ChefComRequiredMixin, ListView):
model = VideoGallery
ordering = "order"
context_object_name = "videos"
template_name = "gestion/video.html"
class VideoCreate(ChefComRequiredMixin, CreateView):
model = VideoGallery
fields = ["name", "url", "order"]
template_name = "gestion/create_video.html"
success_url = reverse_lazy("liste_video")
def form_valid(self, form):
video = form.save(commit=False)
video.save()
return HttpResponseRedirect(self.success_url)
class VideoUpdate(ChefComRequiredMixin, UpdateView):
model = VideoGallery
fields = ["name", "url", "order"]
template_name = "gestion/update_video.html"
success_url = reverse_lazy("liste_video")
class VideoDelete(ChefComRequiredMixin, DeleteView):
model = VideoGallery
template_name = "gestion/delete_video.html"
success_url = reverse_lazy("liste_video")

0
instruments/__init__.py Normal file
View file

6
instruments/admin.py Normal file
View file

@ -0,0 +1,6 @@
from django.contrib import admin
from .models import Instrument, Reparation
admin.site.register(Instrument)
admin.site.register(Reparation)

5
instruments/apps.py Normal file
View file

@ -0,0 +1,5 @@
from django.apps import AppConfig
class InstrumentsConfig(AppConfig):
name = "instruments"

28
instruments/forms.py Normal file
View file

@ -0,0 +1,28 @@
from django import forms
from .models import Instrument, Reparation
class ChefReparationForm(forms.ModelForm):
class Meta:
model = Reparation
fields = ("date", "description", "description_en", "prix", "lieux")
class ChefEditInstrumentForm(forms.ModelForm):
class Meta:
model = Instrument
fields = (
"statut",
"user",
"etat",
"infos",
"type",
"owner",
"marque",
"model",
"serial",
"annee",
"prix",
"infos_en",
)

View file

@ -0,0 +1,174 @@
# Generated by Django 2.2.17 on 2021-04-01 19:25
import django.db.models.deletion
import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Instrument",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"model",
models.CharField(
blank=True, max_length=100, null=True, verbose_name="Modèle"
),
),
(
"prix",
models.CharField(
blank=True, default="", max_length=100, verbose_name="Prix"
),
),
(
"etat",
models.CharField(
choices=[
("Bon état", "Bon état"),
("Etat moyen", "Etat moyen"),
("Mauvais état", "Mauvais état"),
],
default="Bon état",
max_length=100,
),
),
(
"marque",
models.CharField(
blank=True, max_length=100, null=True, verbose_name="Marque"
),
),
(
"serial",
models.CharField(
blank=True,
default=" ",
max_length=100,
null=True,
verbose_name="Numéro de série",
),
),
(
"annee",
models.CharField(
blank=True,
max_length=100,
null=True,
verbose_name="Année d'achat",
),
),
(
"owner",
models.CharField(
default="Fanfare", max_length=100, verbose_name="Propriétaire"
),
),
(
"user",
models.CharField(
blank=True, max_length=100, verbose_name="Utilisateur"
),
),
("type", models.CharField(max_length=40, verbose_name="Instrument")),
(
"statut",
models.CharField(
choices=[("Disponible", "Disponible"), ("Prêté", "Prêté")],
default="Disponible",
max_length=100,
),
),
(
"infos",
models.TextField(
blank=True, default="", verbose_name="Infos utiles"
),
),
(
"infos_en",
models.TextField(
blank=True, default="", verbose_name="Infos utiles en anglais"
),
),
],
options={
"verbose_name": "Instrument",
"verbose_name_plural": "Instruments",
"ordering": (django.db.models.functions.text.Lower("type"),),
},
),
migrations.CreateModel(
name="Reparation",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField(max_length=100, verbose_name="Date")),
(
"description",
models.CharField(
blank=True,
default=" ",
max_length=100,
verbose_name="Description",
),
),
(
"description_en",
models.CharField(
blank=True,
default=" ",
max_length=100,
verbose_name="Description en anglais",
),
),
(
"prix",
models.CharField(
blank=True, default="", max_length=100, verbose_name="Prix"
),
),
(
"lieux",
models.CharField(
blank=True, default=" ", max_length=100, verbose_name="Lieux"
),
),
(
"instru",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="instruments.Instrument",
verbose_name="Instrument",
),
),
],
options={
"verbose_name": "Réparation",
"verbose_name_plural": "Réparations",
"ordering": ("date",),
},
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 2.2.17 on 2021-04-28 21:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("instruments", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="instrument",
name="statut",
field=models.CharField(
choices=[("Disponible", "Disponible"), ("Prêté", "Prêté·e")],
default="Disponible",
max_length=100,
),
),
]

View file

66
instruments/models.py Normal file
View file

@ -0,0 +1,66 @@
from django.db import models
from django.db.models.functions import Lower
from django.utils.translation import gettext_lazy as _
class Instrument(models.Model):
model = models.CharField(_("Modèle"), max_length=100, null=True, blank=True)
prix = models.CharField(_("Prix"), max_length=100, default="", blank=True)
etat = models.CharField(
max_length=100,
default="Bon état",
choices=[
("Bon état", _("Bon état")),
("Etat moyen", _("Etat moyen")),
("Mauvais état", _("Mauvais état")),
],
)
marque = models.CharField(_("Marque"), max_length=100, null=True, blank=True)
serial = models.CharField(
_("Numéro de série"), max_length=100, default=" ", null=True, blank=True
)
annee = models.CharField(_("Année d'achat"), max_length=100, null=True, blank=True)
owner = models.CharField(_("Propriétaire"), max_length=100, default="Fanfare")
user = models.CharField(_("Utilisateur"), max_length=100, blank=True)
type = models.CharField(_("Instrument"), max_length=40, blank=False)
statut = models.CharField(
max_length=100,
default="Disponible",
choices=[("Disponible", _("Disponible")), ("Prêté", _("Prêté·e"))],
)
infos = models.TextField(_("Infos utiles"), null=False, blank=True, default="")
infos_en = models.TextField(
"Infos utiles en anglais", null=False, blank=True, default=""
)
def __str__(self):
return self.type
class Meta:
verbose_name = _("Instrument")
verbose_name_plural = _("Instruments")
ordering = (Lower("type"),)
class Reparation(models.Model):
date = models.DateField(_("Date"), max_length=100)
instru = models.ForeignKey(
"Instrument", on_delete=models.CASCADE, verbose_name=_("Instrument")
)
description = models.CharField(
_("Description"), max_length=100, default=" ", blank=True
)
description_en = models.CharField(
_("Description en anglais"), max_length=100, default=" ", blank=True
)
prix = models.CharField(_("Prix"), max_length=100, default="", blank=True)
lieux = models.CharField(_("Lieux"), max_length=100, default=" ", blank=True)
def __str__(self):
return self.description
class Meta:
verbose_name = _("Réparation")
verbose_name_plural = _("Réparations")
ordering = ("date",)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Some files were not shown because too many files have changed in this diff Show more