Merge branch 'v1.1' into 'master'

v1.1

See merge request klub-dev-ens/Ernesto!12
This commit is contained in:
Martin Pepin 2021-05-27 11:58:41 +00:00
commit 9bd21283c0
112 changed files with 4116 additions and 2910 deletions

View file

@ -1,4 +1,5 @@
import os import os
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
try: try:
@ -31,63 +32,60 @@ DBPASSWD = import_secret("DBPASSWD")
ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS") 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 = [ INSTALLED_APPS = [
'trombonoscope', "trombonoscope",
'actu', "actu",
'colorful', "colorful",
'pads', "pads",
'calendrier', "calendrier",
'gestion.apps.GestionConfig', "gestion.apps.GestionConfig",
'partitions.apps.PartitionsConfig', "partitions.apps.PartitionsConfig",
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
'avatar', "avatar",
"instruments",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
'django.middleware.locale.LocaleMiddleware', "django.middleware.locale.LocaleMiddleware",
] ]
ROOT_URLCONF = "Ernestophone.urls" ROOT_URLCONF = "Ernestophone.urls"
TEMPLATES = [{ TEMPLATES = [
'BACKEND': 'django.template.backends.django.DjangoTemplates', {
'DIRS': [], "BACKEND": "django.template.backends.django.DjangoTemplates",
'APP_DIRS': True, "DIRS": [],
'OPTIONS': { "APP_DIRS": True,
'context_processors': [ "OPTIONS": {
'django.template.context_processors.debug', "context_processors": [
'django.template.context_processors.request', "django.template.context_processors.debug",
'django.contrib.auth.context_processors.auth', "django.template.context_processors.request",
'django.contrib.messages.context_processors.messages', "django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
], ],
'libraries':{ "libraries": {
'changelang': 'gestion.templatetags.changelang', "changelang": "gestion.templatetags.changelang",
'modulo': 'gestion.templatetags.modulo', "modulo": "gestion.templatetags.modulo",
'autotranslate': 'gestion.templatetags.autotranslate', "autotranslate": "gestion.templatetags.autotranslate",
'halflength': 'gestion.templatetags.halflength', "halflength": "gestion.templatetags.halflength",
},
} },
} }
}] ]
WSGI_APPLICATION = "Ernestophone.wsgi.application" WSGI_APPLICATION = "Ernestophone.wsgi.application"
@ -103,51 +101,51 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ 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
# I18n # I18n
LANGUAGE_CODE = 'fr' LANGUAGE_CODE = "fr"
LANGUAGES = ( LANGUAGES = (
('fr', _('Français')), ("fr", _("Français")),
('en', _('English')), ("en", _("English")),
) )
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
USE_TZ = 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" LOGIN_URL = "/login"
AVATAR_CLEANUP_DELETED = True AVATAR_CLEANUP_DELETED = True
AVATAR_AUTO_GENERATE_SIZES = (250,) AVATAR_AUTO_GENERATE_SIZES = (250,)
AVATAR_CHANGE_TEMPLATE = "trombonoscope/change_avatar.html" AVATAR_CHANGE_TEMPLATE = "trombonoscope/change_avatar.html"
AVATAR_MAX_AVATARS_PER_USER=1 AVATAR_MAX_AVATARS_PER_USER = 1
AVATAR_EXPOSE_USERNAMES=False AVATAR_EXPOSE_USERNAMES = False
AVATAR_STORAGE_DIR="trombonoscope" AVATAR_STORAGE_DIR = "trombonoscope"
AVATAR_ADD_TEMPLATE="trombonoscope/add_avatar.html" AVATAR_ADD_TEMPLATE = "trombonoscope/add_avatar.html"
AVATAR_DELETE_TEMPLATE="trombonoscope/delete_avatar.html" AVATAR_DELETE_TEMPLATE = "trombonoscope/delete_avatar.html"
AVATAR_DEFAULT_URL="Ernesto" AVATAR_DEFAULT_URL = "Ernesto"
AVATAR_PROVIDERS=( AVATAR_PROVIDERS = (
'avatar.providers.PrimaryAvatarProvider', "avatar.providers.PrimaryAvatarProvider",
'avatar.providers.DefaultAvatarProvider', "avatar.providers.DefaultAvatarProvider",
) )
AVATAR_THUMB_FORMAT = 'JPEG' AVATAR_THUMB_FORMAT = "JPEG"

View file

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

View file

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

View file

@ -13,36 +13,39 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path 1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 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 import settings
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.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 = []
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
path('', gestion_views.home, name="home"), path("", gestion_views.Home.as_view(), name="home"),
path("registration", gestion_views.inscription_membre, name="registration"), path("registration", gestion_views.Inscription.as_view(), name="registration"),
path("change", gestion_views.change_membre, name="change_membre"), path("change", gestion_views.ChangeMembre.as_view(), name="change_membre"),
path("password", gestion_views.change_password, name="change_password"), path("password", gestion_views.ChangePassword.as_view(), name="change_password"),
path("thanks", gestion_views.thanks, name="thanks"), path("thanks", gestion_views.Thanks.as_view(), name="thanks"),
path("changename", gestion_views.changename, name="change-doodle-name"), path("social", gestion_views.Social.as_view(), name="social"),
path("chef", gestion_views.Chef.as_view(), name="chef"),
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("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( path(
"login", "admin/",
auth_views.LoginView.as_view(template_name="gestion/login.html"), admin.site.urls,
name="login"
), ),
path('agenda/', include('calendrier.urls',namespace='calendrier')), path("trombonoscope/", include("trombonoscope.urls")),
path('partitions/', include('partitions.urls')), path("actu/", include("actu.urls")),
path('pads/', include('pads.urls')), path("avatar/", include("avatar.urls")),
path('admin/', admin.site.urls,), prefix_default_language=False,
path('trombonoscope/',include('trombonoscope.urls')), )
path("actu/",include('actu.urls')),
path('avatar/', include('avatar.urls')),
prefix_default_language=False )
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

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

View file

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

View file

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

View file

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

View file

@ -1,14 +1,17 @@
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class Actu(models.Model): class Actu(models.Model):
text = models.TextField(_("Info"), null=True, blank=False) text = models.TextField(_("Info"), null=True, blank=False)
text_en = models.TextField(("Info en anglais"), null=True, blank=True) text_en = models.TextField(("Info en anglais"), null=True, blank=True)
order = models.IntegerField(verbose_name=_("ordre")) order = models.IntegerField(verbose_name=_("ordre"))
def __str__(self): def __str__(self):
return self.text return self.text
class Meta: class Meta:
verbose_name = _("Actualité") verbose_name = _("Actualité")
verbose_name_plural = _("Actualités") verbose_name_plural = _("Actualités")
ordering = ('order',) ordering = ("order",)

View file

@ -2,11 +2,10 @@ from django.urls import path
from actu import views from actu import views
app_name = "actu" app_name = "actu"
urlpatterns = [ urlpatterns = [
path("", views.ActuList.as_view(), name="liste"), path("", views.ActuList.as_view(), name="liste"),
path("ajouter", views.ActuCreate.as_view(), name="add_actu"), path("ajouter", views.ActuCreate.as_view(), name="add_actu"),
path("edition/<int:pk>", views.ActuUpdate.as_view(), name="edit_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.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): class ActuList(ChefRequiredMixin, ListView):
@ -14,7 +14,7 @@ class ActuList(ChefRequiredMixin, ListView):
class ActuCreate(ChefRequiredMixin, CreateView): class ActuCreate(ChefRequiredMixin, CreateView):
model = Actu model = Actu
fields = ["text","order","text_en"] fields = ["text", "order", "text_en"]
template_name = "actu/create_actu.html" template_name = "actu/create_actu.html"
success_url = reverse_lazy("actu:liste") success_url = reverse_lazy("actu:liste")
@ -26,7 +26,7 @@ class ActuCreate(ChefRequiredMixin, CreateView):
class ActuUpdate(ChefRequiredMixin, UpdateView): class ActuUpdate(ChefRequiredMixin, UpdateView):
model = Actu model = Actu
fields = ["text","order","text_en"] fields = ["text", "order", "text_en"]
template_name = "actu/update_actu.html" template_name = "actu/update_actu.html"
success_url = reverse_lazy("actu:liste") success_url = reverse_lazy("actu:liste")

View file

@ -1,6 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Event from .models import Event
admin.site.register(Event) admin.site.register(Event)

View file

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

View file

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

View file

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

View file

@ -7,37 +7,82 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestion', '0001_initial'), ("gestion", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Event', name="Event",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), (
('nom', models.CharField(max_length=100)), "id",
('nomcourt', models.CharField(max_length=9, verbose_name='Nom court')), models.AutoField(
('date', models.DateField()), auto_created=True,
('debut', models.TimeField()), primary_key=True,
('fin', models.TimeField(blank=True, null=True)), verbose_name="ID",
('slug', models.CharField(max_length=7, editable=False, unique=True)), serialize=False,
('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)), ("nom", models.CharField(max_length=100)),
('calendrier', models.BooleanField(verbose_name='Afficher dans le calendrier pour tous', default=False)), ("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={ options={
'verbose_name': 'Événement', "verbose_name": "Événement",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Participants', name="Participants",
fields=[ 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')), "id",
('details', models.CharField(blank=True, max_length=50)), models.AutoField(
('event', models.ForeignKey(to='calendrier.Event', on_delete=models.CASCADE)), auto_created=True,
('participant', models.ForeignKey(to='gestion.ErnestoUser', on_delete=models.CASCADE)), 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 # Generated by Django 2.2.14 on 2020-07-14 15:59
from django.db import migrations, models
import uuid import uuid
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('calendrier', '0001_initial'), ("calendrier", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='event', name="event",
options={'verbose_name': 'Evenement'}, options={"verbose_name": "Evenement"},
), ),
migrations.AddField( migrations.AddField(
model_name='event', model_name="event",
name='desc_users_en', name="desc_users_en",
field=models.TextField(blank=True, null=True, verbose_name='Infos en anglais (visible seulement des fanfaron-ne-s)'), field=models.TextField(
blank=True,
null=True,
verbose_name="Infos en anglais (visible seulement des fanfaron-ne-s)",
),
), ),
migrations.AddField( migrations.AddField(
model_name='event', model_name="event",
name='description_en', name="description_en",
field=models.TextField(blank=True), field=models.TextField(blank=True),
), ),
migrations.AlterField( migrations.AlterField(
model_name='event', model_name="event",
name='calendrier', 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), 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( migrations.AlterField(
model_name='event', model_name="event",
name='slug', name="slug",
field=models.CharField(default=uuid.uuid1, editable=False, max_length=7, unique=True), field=models.CharField(
default=uuid.uuid1, editable=False, max_length=7, unique=True
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='participants', model_name="participants",
name='reponse', name="reponse",
field=models.CharField(choices=[('oui', 'Oui'), ('non', 'Non'), ('pe', 'Peut-etre')], default='non', max_length=20, verbose_name='Réponse'), 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

@ -1,54 +1,62 @@
from django.db import models
import uuid import uuid
from gestion.models import ErnestoUser
from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
ANSWERS = ( ANSWERS = (
('oui', _('Oui')), ("oui", _("Oui")),
('non', _('Non')), ("non", _("Non")),
('pe', _('Peut-etre')), ("pe", _("Peut-etre")),
) )
class Event(models.Model): class Event(models.Model):
nom = models.CharField(max_length=100) nom = models.CharField(max_length=100)
nomcourt = models.CharField(max_length=9, verbose_name=_("Nom court")) nomcourt = models.CharField(max_length=9, verbose_name=_("Nom court"))
date = models.DateField() date = models.DateField()
debut = models.TimeField() debut = models.TimeField()
fin = models.TimeField(blank=True, null=True) 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) lieu = models.CharField(max_length=200)
description = models.TextField(blank=True) description = models.TextField(blank=True)
description_en = models.TextField(blank=True) description_en = models.TextField(blank=True)
desc_users = models.TextField( desc_users = models.TextField(
blank=True, blank=True,
verbose_name=_("Infos (visible seulement des fanfaron-ne-s)"), verbose_name=_("Infos (visible seulement des fanfaron-ne-s)"),
null=True) null=True,
)
desc_users_en = models.TextField( desc_users_en = models.TextField(
blank=True, blank=True,
verbose_name=_("Infos en anglais (visible seulement des fanfaron-ne-s)"), verbose_name=_("Infos en anglais (visible seulement des fanfaron-ne-s"),
null=True) null=True,
)
CALENDRIER_CHOICES = [ CALENDRIER_CHOICES = [
('F', _('Visible seulement par les fanfarons')), ("F", _("Visible seulement par les fanfarons")),
('T', _('Afficher dans le calendrier pour tous')), ("T", _("Afficher dans le calendrier pour tous")),
('H', _('Hall of fame')), ("H", _("Hall of fame")),
] ]
calendrier = models.CharField( calendrier = models.CharField(
max_length=1, max_length=1,
choices=CALENDRIER_CHOICES, choices=CALENDRIER_CHOICES,
default='F', default="F",
) )
def __str__(self): def __str__(self):
return self.nom return self.nom
class Meta: class Meta:
verbose_name = _("Evenement") verbose_name = _("Evenement")
class Participants(models.Model): class Participants(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE) event = models.ForeignKey(Event, on_delete=models.CASCADE)
participant = models.ForeignKey(ErnestoUser, on_delete=models.CASCADE) participant = models.ForeignKey(ErnestoUser, on_delete=models.CASCADE)
reponse = models.CharField(_("Réponse"), max_length=20, default="non", reponse = models.CharField(
choices=ANSWERS) _("Réponse"), max_length=20, default="non", choices=ANSWERS
)
details = models.CharField(max_length=50, blank=True) details = models.CharField(max_length=50, blank=True)

View file

@ -13,10 +13,23 @@
<!-- One --> <!-- One -->
<section class="wrapper style1" > <section class="wrapper style1" >
<div class="inner"> <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"> <div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a> <a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div> </div>
{% endif %}
</span></div> </span></div>
<h2 align="center">{% trans "Découvrez les différents évènements de l'Ernestophone !" %}</h2> <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 <a href="mailto:fanfare@ens.fr" class="icon fa-envelope fa-5x "><span
class="label">Mail</span></a> 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> </div>
</div> </div>
@ -98,7 +103,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<h1> {% blocktrans count counter=events_passe|length %}Evénement passé :{% plural %}Evénements passés :{% endblocktrans %} </h1> <h1> {% blocktrans count counter=events_passe|length %}Evénement passé :{% plural %}Evénements passés :{% endblocktrans %} </h1>
<div class="table-wrapper" color="white"> <div class="table-wrapper" color="white">
@ -154,4 +159,5 @@
</div> </div>
{% endblock %} {% endblock %}

View file

@ -4,6 +4,7 @@
{% load i18n %} {% load i18n %}
{% load translate %} {% load translate %}
{% load autotranslate %} {% load autotranslate %}
{% get_current_language as current_language %} {% get_current_language as current_language %}
{% block extrahead %} {% block extrahead %}
@ -16,28 +17,28 @@
<div id="main"> <div id="main">
<section class="wrapper style1"> <section class="wrapper style1">
<div class="inner"> <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> <div id="instagram-feed" class="instagram_feed"> </div>
<ul>
{% for a in actu %}
<li>{% autotranslate current_language a.text a.text_en %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<h4>{% trans "Agenda :" %} </h4>
<div class="row"> <div class="row">
<div class="6u 12u$(small)"> <div class="6u 12u$(small)">
{% 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 %}
<h4>{% trans "Agenda :" %} </h4>
<table width="100%" style="background-color:#e4522f" > <table width="100%" style="background-color:#e4522f" >
<tr> <tr>
<td width="20%" align="left"> <td width="20%" align="left">
@ -71,6 +72,25 @@
</div> </div>
<div class="1u 12u$(small)"><p></p></div> <div class="1u 12u$(small)"><p></p></div>
<div class="5u 12u$(small)"> <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 events_a_venir_not_answered %} {% if events_a_venir_not_answered %}
<div class="box" style="background-color:#e4522f"> <div class="box" style="background-color:#e4522f">
<h1> {% blocktrans count counter=events_a_venir_not_answered|length %}Doodle à remplir !!!! :{% plural %}Doodles à remplir !!!! :{% endblocktrans %} </h1> <h1> {% blocktrans count counter=events_a_venir_not_answered|length %}Doodle à remplir !!!! :{% plural %}Doodles à remplir !!!! :{% endblocktrans %} </h1>
@ -182,10 +202,29 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</div> </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 %} {% endblock %}

View file

@ -20,7 +20,7 @@ def translate(tex):
tex = tex.replace("December", "Décembre", 1) tex = tex.replace("December", "Décembre", 1)
tex = tex.replace("Mon", "Lun", 1) tex = tex.replace("Mon", "Lun", 1)
tex = tex.replace("Tue", "Mar", 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("Thu", "Jeu", 1)
tex = tex.replace("Fri", "Ven", 1) tex = tex.replace("Fri", "Ven", 1)
tex = tex.replace("Sat", "Sam", 1) tex = tex.replace("Sat", "Sam", 1)

View file

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

View file

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

View file

@ -1,214 +1,300 @@
import random
import string
from calendar import monthrange
from collections import defaultdict from collections import defaultdict
from datetime import date, datetime from datetime import date, datetime
import string
import random from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
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.urls import reverse, reverse_lazy
from django.contrib.auth.decorators import login_required from django.utils.safestring import mark_safe
from django.utils.decorators import method_decorator from django.views.generic import DeleteView, TemplateView, UpdateView
from django.core.mail import send_mail
from django.http import Http404
from gestion.models import ErnestoUser
from actu.models import Actu from actu.models import Actu
from calendrier.calend import EventCalendar from calendrier.calend import EventCalendar
from calendar import monthrange from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
from calendrier.forms import ModifEventForm, EventForm, ParticipantsForm, ChangeDoodleName ParticipantsForm)
from calendrier.models import Event, Participants from calendrier.models import Event, Participants
from partitions.decorators import chef_required from gestion.mixins import ChefRequiredMixin
from gestion.models import Photo
def generer(*args): def generer(*args):
caracteres = string.ascii_letters + string.digits caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)] aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire) 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})
def named_month(pMonthNumber): def named_month(pMonthNumber):
return date(1900, pMonthNumber, 1).strftime('%B') return date(1900, pMonthNumber, 1).strftime("%B")
@login_required
def home(request): 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")
.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 = int(self.pYear)
lMonth = int(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
)
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=self.request.user.profile)
events_a_venir_answered_yes = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="oui")
)
events_a_venir_answered_no = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="non")
)
events_a_venir_answered_pe = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="pe")
)
except Event.DoesNotExist:
events_a_venir_not_answered = Event.objects.filter(
date__gte=lToday
).exclude(participants__participant__user__username=self.request.user)
events_a_venir_answered_yes = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="oui")
)
events_a_venir_answered_no = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="non")
)
events_a_venir_answered_pe = Event.objects.filter(date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="pe")
)
context["Calendar"] = mark_safe(lCalendar)
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["actu"] = actu
context["photo"] = photo
return context
class Home(Calendar):
lToday = datetime.now() lToday = datetime.now()
return calendar(request, lToday.year, lToday.month)
@login_required @property
def calendar(request, pYear, pMonth): def pYear(self):
actu = Actu.objects.all() return self.lToday.year
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,
}) @property
def pMonth(self):
@login_required return self.lToday.month
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)
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
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 = [
(instrument, sure, maybe, namesoui, namespe, namesnon)
for instrument, (
sure,
maybe,
namesoui,
namespe,
namesnon,
) in instrument_count.items()
]
context["event"] = event
context["instrument_count"] = instrument_count
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
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
@login_required def post(self, request, *args, **kwargs):
def changename(request,id): success = False
if request.method == 'POST':
requbis = request.POST.copy() requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user) form = self.form_class(requbis, instance=request.user)
if form.is_valid(): if form.is_valid():
form.save() form.save()
success = True success = True
return redirect('calendrier:view-event',id=id) return redirect("calendrier:view-event", id=self.kwargs["id"])
else: else:
form = ChangeDoodleName(instance=request.user) context = self.get_context_data()
return render(request, 'calendrier/changename.html',locals()) context["success"] = success
return render(request, self.template_name, context)
@chef_required class CreateEvent(LoginRequiredMixin, TemplateView):
def create_event(request): form_class = EventForm
if request.method == "POST": template_name = "calendrier/create.html"
form = EventForm(request.POST)
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(): if form.is_valid():
temp = True temp = True
while temp: while temp:
code = generer() code = generer()
try: try:
Event.objects.get(slug=code) Event.objects.get(slug=code)
except: except Event.DoesNotExist:
temp = False temp = False
nom = form.cleaned_data["nom"]
date = form.cleaned_data["date"] date = form.cleaned_data["date"]
date = date.strftime('%d/%m/%Y') date = date.strftime("%d/%m/%Y")
debut = form.cleaned_data["debut"]
obj = form.save(commit=False) obj = form.save(commit=False)
obj.slug = code obj.slug = code
obj.save() obj.save()
id = obj.id id = obj.id
envoi = True return redirect("calendrier:view-event", id=id)
return redirect('calendrier:view-event',id=id) else:
context = self.get_context_data()
else: return render(request, self.template_name, context)
form = EventForm()
return render(request, "calendrier/create.html", locals())
class ReponseEvent(LoginRequiredMixin, TemplateView):
form_class = ParticipantsForm
template_name = "calendrier/reponse.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class()
context["ev"] = get_object_or_404(Event, id=self.kwargs["id"])
context["id"] = self.kwargs["id"]
return context
@login_required def post(self, request, *args, **kwargs):
def reponse(request, id): form = self.form_class(request.POST)
part = request.user.profile ev = get_object_or_404(Event, id=self.kwargs["id"])
ev = get_object_or_404(Event, id=id) part = request.user.profile
if request.method == "POST":
form = ParticipantsForm(request.POST)
if form.is_valid(): if form.is_valid():
try: try:
p = Participants.objects.get(event=ev, participant=part) p = Participants.objects.get(event=ev, participant=part)
@ -219,43 +305,32 @@ def reponse(request, id):
obj.event = ev obj.event = ev
obj.participant = part obj.participant = part
obj.save() obj.save()
envoi = True return redirect("calendrier:view-event", id=self.kwargs["id"])
return redirect('calendrier:view-event',id=id) else:
else: context = self.get_context_data()
form = ParticipantsForm() return render(request, self.template_name, context)
return render(request, "calendrier/reponse.html", locals())
class EventUpdate(ChefRequiredMixin, UpdateView):
class EventUpdate(UpdateView):
model = Event model = Event
template_name = "calendrier/update.html" template_name = "calendrier/update.html"
form_class = ModifEventForm form_class = ModifEventForm
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super(EventUpdate, self).get_context_data(**kwargs) ctx = super(EventUpdate, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id ctx["id"] = self.get_object().id
return ctx return ctx
def get_success_url(self): def get_success_url(self):
return reverse('calendrier:view-event', kwargs={'id' : self.get_object().id}) 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)
class EventDelete(DeleteView): class EventDelete(ChefRequiredMixin, DeleteView):
model = Event model = Event
template_name = "calendrier/delete.html" template_name = "calendrier/delete.html"
success_url = reverse_lazy("calendrier:home") success_url = reverse_lazy("calendrier:home")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super(EventDelete, self).get_context_data(**kwargs) ctx = super(EventDelete, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id ctx["id"] = self.get_object().id
return ctx 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 import admin
from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.admin import UserAdmin 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 actu.models import Actu
from gestion.models import ErnestoUser, Photo, VideoGallery
class UserProfileInline(admin.StackedInline): class UserProfileInline(admin.StackedInline):
@ -112,7 +111,9 @@ class UserProfileAdmin(UserAdmin):
user.groups.add(chef_group) user.groups.add(chef_group)
user.save() user.save()
admin.site.unregister(User) admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin) admin.site.register(User, UserProfileAdmin)
admin.site.register(VideoGallery) admin.site.register(VideoGallery)
admin.site.register(Photo)
admin.site.register(Actu) admin.site.register(Actu)

View file

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

View file

@ -1,47 +1,71 @@
from django import forms 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.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 django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
class RegistrationFormUser(UserCreationForm): class RegistrationFormUser(UserCreationForm):
class Meta: class Meta:
model = User model = User
fields = ('username', 'first_name', 'last_name', 'password1', fields = (
'password2', 'email',) "username",
"first_name",
"last_name",
"password1",
"password2",
"email",
)
class ChangeFormUser(UserChangeForm): class ChangeFormUser(UserChangeForm):
password = None password = None
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'email',) fields = (
"first_name",
"last_name",
"email",
)
class ChangeMembreForm(forms.ModelForm): class ChangeMembreForm(forms.ModelForm):
def clean(self): def clean(self):
cleaned_data = super(ChangeMembreForm, self).clean() cleaned_data = super(ChangeMembreForm, self).clean()
instru=cleaned_data.get("instru") instru = cleaned_data.get("instru")
instru_autre = cleaned_data.get("instru_autre") instru_autre = cleaned_data.get("instru_autre")
if (instru == "Autre") and not (instru_autre): if (instru == "Autre") and not (instru_autre):
raise forms.ValidationError(_("Préçisez quel autre instrument")) 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") instru_bonus = cleaned_data.get("instru_bonus")
if (multi_instru == "Oui") and not (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 return cleaned_data
class Meta: class Meta:
model = ErnestoUser model = ErnestoUser
fields = ("phone", "instru","instru_autre","multi_instrumentiste","instru_bonus") fields = (
"phone",
"instru",
"instru_autre",
"multi_instrumentiste",
"instru_bonus",
)
class InscriptionMembreForm(ChangeMembreForm): class InscriptionMembreForm(ChangeMembreForm):
validation = forms.CharField(max_length=100, widget=forms.PasswordInput) validation = forms.CharField(max_length=100, widget=forms.PasswordInput)
class Meta: class Meta:
model = ErnestoUser model = ErnestoUser
fields = ("phone", "instru","instru_autre",'multi_instrumentiste', fields = (
'instru_bonus' ) "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.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -10,28 +10,64 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='ErnestoUser', name="ErnestoUser",
fields=[ 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( models.OneToOneField(
to=settings.AUTH_USER_MODEL, to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='profile' related_name="profile",
) ),
), ),
], ],
options={ options={
'verbose_name': 'Profil Ernestophoniste', "verbose_name": "Profil Ernestophoniste",
'verbose_name_plural': 'Profil Ernestophoniste', "verbose_name_plural": "Profil Ernestophoniste",
}, },
), ),
] ]

View file

@ -7,80 +7,157 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestion', '0001_initial'), ("gestion", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='VideoGallery', name="VideoGallery",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=127)), "id",
('order', models.IntegerField(verbose_name='ordre')), models.AutoField(
('url', models.URLField()), 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={ options={
'verbose_name_plural': 'Videos', "verbose_name_plural": "Videos",
'verbose_name': 'Video', "verbose_name": "Video",
}, },
), ),
migrations.RemoveField( migrations.RemoveField(
model_name='ernestouser', model_name="ernestouser",
name='mails', name="mails",
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='instru_autre', name="instru_autre",
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Lequel ?'), field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Lequel ?"
),
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='instru_bonus', name="instru_bonus",
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Le·s·quel·s ?'), field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Le·s·quel·s ?"
),
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='instru_trombonoscope', name="instru_trombonoscope",
field=models.CharField(blank=True, max_length=30, verbose_name='Instrument affiché sur le trombonoscope'), field=models.CharField(
blank=True,
max_length=30,
verbose_name="Instrument affiché sur le trombonoscope",
),
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='multi_instrumentiste', 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 :"), 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( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='nom_trombonoscope', name="nom_trombonoscope",
field=models.CharField(blank=True, max_length=30, verbose_name='Nom affiché sur le trombonoscope'), field=models.CharField(
blank=True,
max_length=30,
verbose_name="Nom affiché sur le trombonoscope",
),
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='trombonoscope', 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 :'), 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( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='trombonoscope_colors', 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'), 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( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='trombonoscope_fond', name="trombonoscope_fond",
field=colorful.fields.RGBColorField(default='#e4522f', verbose_name='Couleur de fond du profil'), field=colorful.fields.RGBColorField(
default="#e4522f", verbose_name="Couleur de fond du profil"
),
), ),
migrations.AddField( migrations.AddField(
model_name='ernestouser', model_name="ernestouser",
name='trombonoscope_texte', name="trombonoscope_texte",
field=colorful.fields.RGBColorField(default='#ffffff', verbose_name='Couleur du texte du profil'), field=colorful.fields.RGBColorField(
default="#ffffff", verbose_name="Couleur du texte du profil"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='ernestouser', model_name="ernestouser",
name='instru', 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é'), 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( migrations.AlterField(
model_name='ernestouser', model_name="ernestouser",
name='phone', name="phone",
field=models.CharField(blank=True, help_text='seulement visible par les chef·fe·s', max_length=20, verbose_name='Télé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

@ -1,63 +1,147 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.db import models
from colorful.fields import RGBColorField from colorful.fields import RGBColorField
from django.contrib.auth.models import User 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 _ from django.utils.translation import gettext_lazy as _
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="deco", default=None, validators=[validate_image]
)
def __str__(self):
return self.name
class Meta:
verbose_name = _("Photo")
verbose_name_plural = _("Photos")
class ErnestoUser(models.Model): class ErnestoUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile") user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"), default=True) is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"), default=True)
is_chef = models.BooleanField(_("Chef Fanfare"), default=False) 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")) phone = models.CharField(
_("Téléphone"),
max_length=20,
blank=True,
help_text=_("seulement visible par les chef·fe·s"),
)
INSTRU_CHOICES = [ INSTRU_CHOICES = [
('Clarinette', _('Clarinette')), ("Clarinette", _("Clarinette")),
('Euphonium', _('Euphonium')), ("Euphonium", _("Euphonium")),
('Percussion', _('Percussion')), ("Percussion", _("Percussion")),
('Piccolo', _('Piccolo')), ("Piccolo", _("Piccolo")),
('Saxophone Alto', _('Saxophone Alto')), ("Saxophone Alto", _("Saxophone Alto")),
('Saxophone Ténor', _('Saxophone Ténor')), ("Saxophone Ténor", _("Saxophone Ténor")),
('Saxophone Baryton', _('Saxophone Baryton')), ("Saxophone Baryton", _("Saxophone Baryton")),
('Souba', _('Souba')), ("Souba", _("Souba")),
('Trombone', _('Trombone')), ("Trombone", _("Trombone")),
('Trompette', _('Trompette')), ("Trompette", _("Trompette")),
('Autre', _('Autre')), ("Autre", _("Autre")),
('ne sais pas', _('Je ne sais pas encore')), ("ne sais pas", _("Je ne sais pas encore")),
] ]
COLORS_CHOICES = [ COLORS_CHOICES = [
('#e4522f#ffffff', _('Orange et Blanc')), ("#e4522f#ffffff", _("Orange et Blanc")),
('#ffffff#000000', _('Blanc et Noir')), ("#ffffff#000000", _("Blanc et Noir")),
('#A8107C#000000', _('Rose et Noir')), ("#A8107C#000000", _("Rose et Noir")),
('#10A4A8#ffffff', _('Bleu et Blanc')), ("#10A4A8#ffffff", _("Bleu et Blanc")),
('#26A810#000000', _('Vert et Noir')), ("#26A810#000000", _("Vert et Noir")),
('#A81026#ffffff', _('Rouge et Blanc')), ("#A81026#ffffff", _("Rouge et Blanc")),
('#E3E54C#000000', _('Jaune et Noir')), ("#E3E54C#000000", _("Jaune et Noir")),
('autre',_('Autre')), ("autre", _("Autre")),
]
] instru = models.CharField(
_("Instrument joué"),
instru = models.CharField(_("Instrument joué"), max_length=40, blank=False,choices=INSTRU_CHOICES,default='ne sais pas') max_length=40,
instru_autre = models.CharField(_("Lequel ?"),null=True,max_length=100,blank=True) 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) slug = models.CharField(max_length=7, editable=False, unique=True)
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30, doodlename = models.CharField(_("Nom pour le doodle"), max_length=30, blank=True)
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)
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: class Meta:
verbose_name = _("Profil Ernestophoniste") verbose_name = _("Profil Ernestophoniste")

View file

@ -545,7 +545,7 @@ pre code {
overflow-y: scroll; overflow-y: scroll;
} }
.container { .container_carousel {
width: 100%; width: 100%;
padding-right: 15px; padding-right: 15px;
padding-left: 15px; padding-left: 15px;
@ -554,25 +554,25 @@ pre code {
} }
@media (min-width: 576px) { @media (min-width: 576px) {
.container { .container_carousel {
max-width: 540px; max-width: 540px;
} }
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.container { .container_carousel {
max-width: 720px; max-width: 720px;
} }
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.container { .container_carousel {
max-width: 960px; max-width: 960px;
} }
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.container { .container_carousel {
max-width: 1140px; max-width: 1140px;
} }
} }
@ -4157,7 +4157,7 @@ input[type="button"].btn-block {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
} }
.navbar > .container, .navbar > .container_carousel,
.navbar > .container-fluid { .navbar > .container-fluid {
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
@ -4242,7 +4242,7 @@ input[type="button"].btn-block {
} }
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.navbar-expand-sm > .container, .navbar-expand-sm > .container_carousel,
.navbar-expand-sm > .container-fluid { .navbar-expand-sm > .container-fluid {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
@ -4267,7 +4267,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem; padding-right: 0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.navbar-expand-sm > .container, .navbar-expand-sm > .container_carousel,
.navbar-expand-sm > .container-fluid { .navbar-expand-sm > .container-fluid {
-ms-flex-wrap: nowrap; -ms-flex-wrap: nowrap;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -4284,7 +4284,7 @@ input[type="button"].btn-block {
} }
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.navbar-expand-md > .container, .navbar-expand-md > .container_carousel,
.navbar-expand-md > .container-fluid { .navbar-expand-md > .container-fluid {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
@ -4309,7 +4309,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem; padding-right: 0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.navbar-expand-md > .container, .navbar-expand-md > .container_carousel,
.navbar-expand-md > .container-fluid { .navbar-expand-md > .container-fluid {
-ms-flex-wrap: nowrap; -ms-flex-wrap: nowrap;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -4326,7 +4326,7 @@ input[type="button"].btn-block {
} }
@media (max-width: 991.98px) { @media (max-width: 991.98px) {
.navbar-expand-lg > .container, .navbar-expand-lg > .container_carousel,
.navbar-expand-lg > .container-fluid { .navbar-expand-lg > .container-fluid {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
@ -4351,7 +4351,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem; padding-right: 0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.navbar-expand-lg > .container, .navbar-expand-lg > .container_carousel,
.navbar-expand-lg > .container-fluid { .navbar-expand-lg > .container-fluid {
-ms-flex-wrap: nowrap; -ms-flex-wrap: nowrap;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -4368,7 +4368,7 @@ input[type="button"].btn-block {
} }
@media (max-width: 1199.98px) { @media (max-width: 1199.98px) {
.navbar-expand-xl > .container, .navbar-expand-xl > .container_carousel,
.navbar-expand-xl > .container-fluid { .navbar-expand-xl > .container-fluid {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
@ -4393,7 +4393,7 @@ input[type="button"].btn-block {
padding-right: 0.5rem; padding-right: 0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.navbar-expand-xl > .container, .navbar-expand-xl > .container_carousel,
.navbar-expand-xl > .container-fluid { .navbar-expand-xl > .container-fluid {
-ms-flex-wrap: nowrap; -ms-flex-wrap: nowrap;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -4416,7 +4416,7 @@ input[type="button"].btn-block {
justify-content: flex-start; justify-content: flex-start;
} }
.navbar-expand > .container, .navbar-expand > .container_carousel,
.navbar-expand > .container-fluid { .navbar-expand > .container-fluid {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
@ -4436,7 +4436,7 @@ input[type="button"].btn-block {
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.navbar-expand > .container, .navbar-expand > .container_carousel,
.navbar-expand > .container-fluid { .navbar-expand > .container-fluid {
-ms-flex-wrap: nowrap; -ms-flex-wrap: nowrap;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -10001,7 +10001,7 @@ a.text-dark:hover, a.text-dark:focus {
body { body {
min-width: 992px !important; min-width: 992px !important;
} }
.container { .container_carousel {
min-width: 992px !important; min-width: 992px !important;
} }
.navbar { .navbar {
@ -10035,4 +10035,4 @@ a.text-dark:hover, a.text-dark:focus {
border-color: #dee2e6; 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) 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 */ /* 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 { 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 */ /* Grid */
.row { .row {
@ -1558,9 +1588,7 @@
width: device-width; width: device-width;
} }
body {
-ms-overflow-style: scrollbar;
}
@media screen and (max-width: 480px) { @media screen and (max-width: 480px) {
@ -1574,16 +1602,7 @@
background: #e4522f; 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 */ /* Type */
@ -2284,7 +2303,7 @@ div.spoiler
display: block; display: block;
float: left; float: left;
margin-right: -2em; margin-right: -2em;
opacity: 0; height: 1em;
width: 1em; width: 1em;
z-index: -1; z-index: -1;
} }
@ -2704,31 +2723,7 @@ div.spoiler
text-align: center; 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 */ /* Tab */
@ -2888,17 +2883,8 @@ div.spoiler
z-index: 99; z-index: 99;
} }
.wrapper header {
margin-bottom: 4em;
}
@media screen and (max-width: 736px) {
.wrapper header {
margin-bottom: 2em;
}
}
.wrapper.style1 { .wrapper.style1 {
background-color: #e39576; background-color: #e39576;
@ -3104,9 +3090,7 @@ div.spoiler
border-top-color: rgba(255, 255, 255, 0.15); border-top-color: rgba(255, 255, 255, 0.15);
} }
.wrapper.style1 header p {
color: #ffffff;
}
.wrapper.style1 table tbody tr { .wrapper.style1 table tbody tr {
border-color: rgba(255, 255, 255, 0.15); border-color: rgba(255, 255, 255, 0.15);
@ -3327,9 +3311,7 @@ div.spoiler
border-top-color: rgba(255, 255, 255, 0.15); border-top-color: rgba(255, 255, 255, 0.15);
} }
.wrapper.style2 header p {
color: #9ba2a8;
}
.wrapper.style2 table tbody tr { .wrapper.style2 table tbody tr {
border-color: rgba(255, 255, 255, 0.15); border-color: rgba(255, 255, 255, 0.15);
@ -3463,281 +3445,7 @@ div.spoiler
display: none; 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 */ /* Banner */
@ -3884,6 +3592,9 @@ div.spoiler
/* Main */ /* Main */
/* Footer */ /* Footer */
@ -3950,3 +3661,16 @@ div.spoiler
width: 100%; width: 100%;
padding: 20px; 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%;
}

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-prev { left: -110px; border-bottom: 0; }
.top-content .carousel-control-next { right: -110px; border-bottom: 0; } .top-content .carousel-control-next { right: -110px; border-bottom: 0; }
.top-content .carousel-indicators { bottom: -80px; } .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 li { width: 16px; height: 16px; margin-left: 5px; margin-right: 5px; border-radius: 50%; }

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load changelang %} {% load changelang %}
{% load avatar_tags %}
{% get_current_language as current_language %} {% get_current_language as current_language %}
<!DOCTYPE HTML> <!DOCTYPE HTML>
@ -13,56 +14,114 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>{% block titre %}{% endblock %}</title> <title>{% block titre %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <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/bootstrap.css' %}">
<link rel="stylesheet" href="{% static 'css/main.css' %}" /> <link rel="stylesheet" href="{% static 'css/main.css' %}" />
{% block extrahead %}{% endblock %}
</head> </head>
<body class="subpage"> <body class="subpage">
<!-- Header --> <!-- 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> <nav class="navbar navbar-expand-md">
</header> <div class="container-fluid">
<!-- Brand -->
<a class="navbar-brand" href="{% url 'home' %}"><img style='float:left;height:3em;width:auto' src='{% static "images/Ernestophone_white.png" %}'/></a>
<!-- Nav --> <!-- Links -->
<nav id="menu"> <ul class="navbar-nav mr-auto" >
<ul class="links">
<li><p></p></li> {% if not user.is_authenticated %}
<li>{% ifequal current_language "fr" %} <li class="nav-item">
<a href="{% changelang "en" %}" >English<span class="image right"><img src="{% static "images/en_flag.jpg" %}"></span></a> <a class="nav-link" href="{% url 'home' %}"><b>{% trans "Accueil" %}</b></a>
{% else %} </li>
<a href="{% changelang "fr" %}">Français<span class="image right"><img src="{% static "images/fr_flag.jpg" %}"></span></a> <li class="nav-item">
{% endifequal %}</li> <a class="nav-link"href="{% url 'calendrier:liste' %}"><b>{% trans "Agenda" %}</b></a>
{% if not user.is_authenticated %} </li>
<li><a href="{% url 'home' %}">{% trans "Accueil" %}</a></li> {% else %}
<li><a href="{% url 'calendrier:liste' %}">{% trans "Agenda" %}</a></li> <li class="nav-item">
{% else %} <a class="nav-link" href="{% url 'calendrier:home' %}"><b>{% trans "Agenda" %}</b></a>
<li><a href="{% url 'calendrier:home' %}">{% trans "Agenda" %}</a></li> </li>
{% endif %} {% endif %}
<li><a href="{% url 'partitions:liste' %}">{% trans "Répertoire" %}</a></li> <li class="nav-item">
<a class="nav-link" href="{% url 'partitions:liste' %}"><b>{% trans "Répertoire" %}</b></a>
</li>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<li><a href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a></li> <li class="nav-item">
<li><a href="{% url 'pads:list' %}">{% trans "Pads" %}</a></li> <a class="nav-link" href="{% url 'instruments:liste' %}"><b>{% trans "Instruments" %}</b></a>
{% if user.is_superuser or user.profile.is_chef %} </li>
<li><a href="/admin/">{% trans "Administration" %}</a></li> <li class="nav-item">
{% if user.profile.is_chef %} <a class="nav-link" href="{% url 'pads:list' %}"><b>{% trans "Pads" %}</b></a>
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li> </li>
{% endif %} <!-- Dropdown -->
{% endif %} <li class="nav-item dropdown">
<li><a href="{% url 'change_membre' %}">{% trans "Modification du profil" %}</a></li> <a class="nav-link dropdown-toggle" href="{% url 'social' %}" id="navbardrop" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<li><a href="{% url 'logout' %}">{% trans "Déconnexion" %}</a></li> <b>{% trans 'Social'%}
</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>
{% else %} </div>
<li><a href="{% url 'login' %}">{% trans "Se connecter" %}</a></li> </li>
<li><a href="{% url 'registration' %}">{% trans "Créer un compte" %}</a></li> {% if user.is_superuser or user.profile.is_chef %}
<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">
<a class="dropdown-item" href="/admin/">{% trans "Administration" %}</a>
{% if user.profile.is_chef %}
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
<a class="dropdown-item" href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a>
{% endif %} {% endif %}
</ul>
</nav> </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"%}
{% else %}
<img src="{% static "images/Ernestophone_logo.png" %}" width="50" height="50" class="rounded-circle">
{% 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" %}</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" class="rounded-circle"></a>
{% else %}
<a class="nav-link" href="{% changelang "fr" %}" ><img src="{% static 'images\fr_flag.jpg' %}" width="60" height="40" class="rounded-circle"></a>
{% endifequal %}
</li>
</ul>
</div>
</nav>
<!-- Main --> <!-- Main -->
@ -82,19 +141,57 @@
<li><a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ" <li><a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ"
class="icon fa-youtube-play"><span class="label">Youtube</span></a></li> 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> </ul>
</div> </div>
</footer> </footer>
<!-- Scripts --> <!-- Scripts -->
<script src="{% static 'js/jquery.min.js' %}"></script> <script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/jquery.scrolly.min.js' %}"></script> <script src="{% static 'js/jquery.scrolly.min.js' %}"></script>
<script src="{% static 'js/skel.min.js' %}"></script> <script src="{% static 'js/skel.min.js' %}"></script>
<script src="{% static 'js/util.js' %}"></script> <script src="{% static 'js/util.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script> <script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/InstagramFeed.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"> <script type="text/javascript">
function ouvrirFermerSpoiler(div) function ouvrirFermerSpoiler(div)
{ {
var divContenu = div.getElementsByTagName('div')[1]; var divContenu = div.getElementsByTagName('div')[1];

View file

@ -52,9 +52,20 @@
</div> </div>
<div class ="6u 12u (small)"> <div class ="6u 12u (small)">
<span class="image fit"> <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="" /> <img src="{% static 'images/registration.png' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0"> <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> </div>
</span> </span>
</div> </div>

View file

@ -0,0 +1,23 @@
{% 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>
<li> <a href="/admin/">{% trans "Administration" %}</a></li>
<li> <a href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a></li>
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -3,6 +3,7 @@
{% load i18n %} {% load i18n %}
{% load halflength %} {% load halflength %}
{% block titre %}{% trans "L'Ernestophone : La fanfare de l'Ecole normale supérieure de Paris" %}{% endblock %} {% 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 %} {% block content %}
<!-- Banner --> <!-- Banner -->
@ -32,8 +33,12 @@
grâce à notre énergie et notre répertoire oscillant entre pop et grâce à notre énergie et notre répertoire oscillant entre pop et
brass band.{% endblocktrans %}</p> brass band.{% endblocktrans %}</p>
</header> </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 --> <!-- Carousel -->
{% if videos %} {% if videos %}
<div id="carousel" class="carousel slide"> <div id="carousel" class="carousel slide">
@ -72,17 +77,24 @@
<span class="sr-only">Next</span> <span class="sr-only">Next</span>
</a> </a>
</div> </div>
</div>
</div>
</div>
</div>
{% endif %} {% endif %}
<!-- End carousel --> <!-- End carousel -->
</div> </div>
</section> </section>
<!-- Two --> <!-- Two -->
<section class="wrapper style2" > <section class="wrapper style2" >
<div class="inner"> <div class="inner" id="contact">
<header> <header>
<h2>{% trans "L'Ernestophone in a nutshell" %}</h2> <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 <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 normale supérieure, (re)créée en septembre 2011, pour le plus
grand bonheur des petits. Et des grands.{% endblocktrans %}</p> grand bonheur des petits. Et des grands.{% endblocktrans %}</p>
@ -155,10 +167,20 @@
{% endfor %} {% endfor %}
<a href="{% url 'partitions:liste' %}" class="button alt fit" >{% trans "Voir le répertoire présent et passé" %}</a> <a href="{% url 'partitions:liste' %}" class="button alt fit" >{% trans "Voir le répertoire présent et passé" %}</a>
<span class="image fit"> <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="" /> <img src="{% static 'images/repertoire.jpg' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0"> <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> </div>
{% endif %}
</span> </span>
</div> </div>
@ -176,10 +198,21 @@
Nous prêtons des instruments à tout membre du COF souhaitant découvrir les joies de la fanfaronnerie !{% endblocktrans %}</p> Nous prêtons des instruments à tout membre du COF souhaitant découvrir les joies de la fanfaronnerie !{% endblocktrans %}</p>
</div> </div>
<div class="5u 12u$(small)"><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"> <div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a> <a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div> </div>
{% endif %}
</span> </span>
</div> </div>
</div> </div>
@ -192,12 +225,23 @@
<div class="tab tab-3 flex flex-3 active"> <div class="tab tab-3 flex flex-3 active">
<div class="box"> <div class="box">
<div><span class="image right"> <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=""/> <img src="{% static 'images/contact.jpg' %}" alt=""/>
<div style="position:absolute;z-index:1;right:0;bottom:0"> <div style="position:absolute;z-index:1;right:0;bottom:0">
<a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a> <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 é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 /> 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" <a target="_blank" href="https://www.facebook.com/ernestophone"
@ -211,10 +255,12 @@
&nbsp; &nbsp;
&nbsp; &nbsp;
&nbsp; &nbsp;
&nbsp;
<a target="_blank" href="https://www.youtube.com/channel/UC_RahrdZLoBGpJQHwegV4tQ" <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> </p>
</div> </div>
</div> </div>
@ -223,7 +269,25 @@
</div> </div>
</section> </section>
</div> </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-3.3.1.min.js' %}"></script>
<script src="{% static 'js/jquery-migrate-3.0.0.min.js' %}"></script> <script src="{% static 'js/jquery-migrate-3.0.0.min.js' %}"></script>
<script src="{% static 'js/popper.min.js' %}"></script> <script src="{% static 'js/popper.min.js' %}"></script>

View file

@ -34,9 +34,22 @@
</div> </div>
</div> </div>
<div class="6u 12u$(xsmall)"> <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> <a href="https://evarin.fr/" target="_blank" class="icon fa-copyright"> Evarin</a>
</div></span> </div>
{% endif %}
</span>
</div> </div>

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 'login' %}">{% trans "Se connecter" %}</a></li>
<li> <a href="{% url 'trombonoscope:change' %}">{% trans "Modifier le Trombo" %}</a></li>
<li><a href="{% url 'registration' %}">{% trans "Créer un compte" %}</a></li>
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -12,7 +12,7 @@
<section class="wrapper style1" > <section class="wrapper style1" >
<div class="inner"> <div class="inner">
<h2>{% trans "Créer un compte :" %}</h2> <h2>{% trans "Créer un compte :" %}</h2>
{% if error %} {% if error %}
<p>{{ error }}</p> <p>{{ error }}</p>
{% endif %} {% endif %}
<div class="row uniform"> <div class="row uniform">
@ -48,10 +48,21 @@
</div> </div>
<div class ="6u 12u (small)"> <div class ="6u 12u (small)">
<span class="image fit"> <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="" /> <img src="{% static 'images/registration.png' %}" alt="" />
<div style="position:absolute;z-index:1;right:0;bottom:0"> <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> </div>
{%endif%}
</span> </span>
</div> </div>

View file

@ -0,0 +1,22 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% 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>
</ul>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -3,12 +3,13 @@ from django.utils.safestring import mark_safe
register = template.Library() register = template.Library()
@register.simple_tag @register.simple_tag
def autotranslate(current_language, description, description_en): 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) return mark_safe(description_en)
elif(current_language == "fr" and not description): elif current_language == "fr" and not description:
return mark_safe(description_en) return mark_safe(description_en)
else: else:
return mark_safe(description) return mark_safe(description)

View file

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

View file

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

View file

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

View file

@ -1,115 +1,200 @@
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 random 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.shortcuts import redirect, render
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView
from calendrier.forms import ChangeDoodleName
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
InscriptionMembreForm, RegistrationFormUser)
from gestion.mixins import ChefRequiredMixin
from gestion.models import ErnestoUser, Photo, VideoGallery
from partitions.models import Category
def generer(*args): def generer(*args):
caracteres = string.ascii_letters + string.digits caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)] aleatoire = [random.choice(caracteres) for i in range(6)]
return ''.join(aleatoire) return "".join(aleatoire)
def home(request): class Home(TemplateView):
if request.user.is_authenticated : template_name = "gestion/index.html"
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):
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()
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 class MyLoginView(LoginView):
def changename(request):
if request.method == 'POST': 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(ChefRequiredMixin, TemplateView):
template_name = "gestion/chef.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() requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user) form = self.form_class(requbis, instance=request.user)
if form.is_valid(): if form.is_valid():
form.save() form.save()
success = True return redirect("change_membre")
return redirect('change_membre')
else: context = self.get_context_data()
form = ChangeDoodleName(instance=request.user) context["form"] = form
return render(request, 'gestion/changename.html', locals()) 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 get_context_data(self, **kwargs):
def change_membre(request): context = super().get_context_data(**kwargs)
if request.method == 'POST': comp_form = self.comp_form_class(instance=self.request.user.profile)
comp_form = ChangeMembreForm(request.POST, instance=request.user.profile) user_form = self.user_form_class(instance=self.request.user)
user_form = ChangeFormUser(request.POST, instance=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(): if user_form.is_valid() and comp_form.is_valid():
user_form.save() user_form.save()
comp_form.save() comp_form.save()
success = True 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 context = self.get_context_data()
def change_password(request): context["success"] = success
if request.method == 'POST': 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() requbis = request.POST.copy()
form = PasswordChangeForm(request.user, data=requbis) success = False
form = self.form_class(request.user, data=requbis)
if form.is_valid(): if form.is_valid():
request.user.profile.photo.delete()
form.save() form.save()
success = True success = True
context = self.get_context_data()
else: context["success"] = success
form = PasswordChangeForm(request.user) context["form"] = form
return render(request, 'gestion/changepasswd.html', locals()) 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): def get_context_data(self, **kwargs):
if request.method == 'POST': 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) def post(self, request, *args, **kwargs):
comp_form = InscriptionMembreForm(request.POST) 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(): if user_form.is_valid() and comp_form.is_valid():
pseudo = user_form.cleaned_data['username']
if not (comp_form.cleaned_data['validation'] if not (
== settings.ACCOUNT_CREATION_PASS): 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()) 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) member = user_form.save(commit=False)
temp = True temp = True
while temp: while temp:
code = generer() code = generer()
try: try:
ErnestoUser.objects.get(slug=code) ErnestoUser.objects.get(slug=code)
except: except ErnestoUser.DoesNotExist:
temp = False temp = False
member.save() member.save()
(profile, _) = ErnestoUser.objects.get_or_create(user=member, (profile, k) = ErnestoUser.objects.get_or_create(user=member, slug=code)
slug=code) comp_form = self.comp_form_class(request.POST, instance=profile)
comp_form = InscriptionMembreForm(request.POST, instance=profile)
obj = comp_form.save(commit=False) obj = comp_form.save(commit=False)
obj.slug = code obj.slug = code
obj.save() obj.save()
envoi = True return redirect("thanks")
return redirect('thanks') else:
else: context = self.get_context_data()
comp_form = InscriptionMembreForm() context["user_form"] = user_form
user_form = RegistrationFormUser() context["comp_form"] = comp_form
return render(request, 'gestion/registration.html', locals()) return render(request, self.template_name, context)

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"

27
instruments/forms.py Normal file
View file

@ -0,0 +1,27 @@
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",
"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.

After

Width:  |  Height:  |  Size: 341 KiB

View file

@ -0,0 +1,19 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{%block titre %}{% trans "Ajout d'une instrument" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<p><a href="{% url "instruments:liste" %}" class="button alt">{% trans "Retour à la liste" %}</a></p>
{% if envoi %}<p>{% trans "Cet instrument a été enregistré" %}.{% 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,19 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{%block titre %}{% trans "Ajout d'une réparation" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<p><a href="{% url "instruments:fiche_instru" pk %}" class="button alt">{% trans "Retour à la fiche" %}</a></p>
{% if envoi %}<p>{% trans "Cette réparation a é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'un instrument" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post">
{% csrf_token %}
<p><a href="{% url "instruments:liste" %}" class="button alt">{% trans "Retour aux instruments" %}</a></p>
<p>{% blocktrans with object=object %} Voulez vous vraiment supprimer le.a {{ object }}?{% 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 réparation" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<form action="" method="post">
{% csrf_token %}
<p><a href="{% url "instruments:fiche_instru" id %}" class="button alt">{% trans "Retour à la fiche instrument" %}</a></p>
<p>{% blocktrans with object=object %} Voulez vous vraiment supprimer la réparation {{object}}?{% endblocktrans %}</p>
<input type="submit" value="{% trans "Oui" %}" />
</form>
</div></section>
</div>
{% endblock %}

View file

@ -0,0 +1,101 @@
{% extends "gestion/base.html" %}
{% load static %}
{% load i18n %}
{% block titre %}{% trans "Instruments" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<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/instruments.jpg' %}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
{% endif %}
</span>
{% if user.profile.is_chef %}
<a href="{% url "instruments:ajouter_instru" %}" class="button alt big">{% trans "Ajouter un instrument" %}</a>
{% endif %}
<p></p>
<h4>{% trans "Instruments Disponibles :" %} </h4>
<div class="table-wrapper">
<table class="default">
<thead>
<tr>
<th>{% trans "Intrument" %}</th>
<th>{% trans "Propriétaire" %}</th>
<th>{% trans "Etat" %}</th>
</tr>
</thead>
<tbody>
{% for instrument in instrus_dispo %}
<tr>
<td> <u> <a href="{% url "instruments:fiche_instru" instrument.id %}">{{ instrument.type }} </a></u></td>
<td> {{ instrument.owner }} </td>
<td> {{ instrument.etat }} </td>
<td>
<a href="{% url "instruments:fiche_instru" instrument.id %}" class="button small">{% trans "Consulter" %}<a/>
{% if user.profile.is_chef %}
<a href="{% url "instruments:delete_instru" instrument.id %}" class="button small">{% trans "Supprimer" %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
<section class="wrapper style2">
<div class="inner">
<h4>{% trans "Instruments Prêtés :" %} </h4>
<div class="table-wrapper">
<table class="default">
<thead>
<tr>
<th>{% trans "Intrument" %}</th>
<th>{% trans "Propriétaire" %}</th>
<th>{% trans "Utilisateur" %}</th>
<th>{% trans "Etat" %}</th>
</tr>
</thead>
<tbody>
{% for instrument in instrus_prete %}
<tr>
<td> <u><a href="{% url "instruments:fiche_instru" instrument.id %}">{{ instrument.type }}</a></u></td>
<td> {{ instrument.owner }} </td>
<td> {{ instrument.user }} </td>
<td> {{ instrument.etat}} </td>
<td>
<a href="{% url "instruments:fiche_instru" instrument.id %}" class="button small">{% trans "Consulter" %}<a/>
{% if user.profile.is_chef %}
<a href="{% url "instruments:delete_instru" instrument.id %}" class="button small">{% trans "Supprimer" %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,104 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{% load static %}
{% get_current_language as current_language %}
{% load autotranslate %}
{% block titre %}{{ instru.type }}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<h3>{% blocktrans with type=instru.type etat=instru.etat statut=instru.statut%} {{type}} en {{etat}} : {{statut}} {% endblocktrans%}</h3>
<div class="row">
<div class="7u 12u$(small)">
<p>{% trans "Propriétaire : "%} {% if instru.owner %}{{instru.owner}} {% else %}-{% endif %}<br>
{% trans "Statut : "%} {{instru.statut}} <br>
{% ifequal instru.statut 'Prêté' %}
{% trans "Utilisateur : "%} {% if instru.user %}{{instru.user}} {% else %}-{% endif %}<br>
{% endifequal %}
{% trans "Marque : "%} {% if instru.marque %}{{instru.marque}} {% else %}-{% endif %} <br>
{% trans "Modele : "%} {% if instru.model %}{{instru.model}} {% else %}-{% endif %}<br>
{% trans "Numéro de série : "%} {% if instru.serial %}{{instru.serial}}{% else %}-{% endif %} <br>
{% trans "Prix : "%} {% if instru.prix %}{{instru.prix}} {% else %}-{% endif %}<br>
{% trans "Acheté·e en" %}{% if instru.annee %}{{annee}}{% else %}-{% endif %}
</p>
{% if infos or infos_en %}
<h1>{% trans "Infos utiles :" %}</h1>
<div class="box">{% autotranslate current_language infos infos_en %}</div>
{% endif %}
{% if suppression %}
<p>{{ suppression }}</p>
{% endif %}
{% if not user.profile.is_chef %}
</div>
<div class="5u 12u$(small)">
{% endif %}
<h4>{% blocktrans count counter=reparations|length %}Réparation :{% plural %}Réparations {% endblocktrans %}</h4>
<div class="table-wrapper">
<table class="default">
<thead>
<tr>
<th>{% trans "Date" %}</th>
<th>{% trans "Description" %}</th>
<th>{% trans "Prix" %}</th>
<th>{% trans "lieu" %}</th>
</tr>
</thead>
<tbody>
{% for rep in reparations %}
<tr>
<td> {{ rep.date }} </td>
<td> {% ifequal current_language "fr" %}
{{ rep.description }}
{% else %}
{% if instru.description_en %}
{{ rep.description_en }}
{% else %}
{{ rep.description }}
{% endif %}
{% endifequal %} </td>
<td> {{ rep.prix }} </td>
<td> {{ rep.lieux }} </td>
{% if user.profile.is_chef %}
<td>
<a href="{% url "instruments:update_rep" rep.id %}" class="button small">{% trans "Modifier" %}</a>
<a href="{% url "instruments:delete_rep" rep.id %}" class="button small">{% trans "Supprimer" %}</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<p>
<a class='button ' href="{% url "instruments:liste" %}">Retour aux instruments</a>
{% if user.profile.is_chef %}
<a class='button ' href="{% url "instruments:ajouter_rep" instru.id %}">Ajouter une réparation</a>
{% endif %}
</p>
</div>
{% if user.profile.is_chef %}
<div class="5u 12u$(small)">
<div class="info_part">
<form action="{% url "instruments:fiche_instru" instru.id %}" id="chef-edit-form" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Enregister" />
</form>
{% endif %}
</div>
</section>
</div>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "gestion/base.html" %}
{% load i18n %}
{%block titre %}{% trans "Ajout d'une réparation" %}{% endblock %}
{% block content %}
<div id="main">
<section class="wrapper style1">
<div class="inner">
<p><a href="{% url "instruments:fiche_instru" object.instru.id %}" class="button alt">{% trans "Retour à la fiche" %}</a></p>
{% if envoi %}<p>{% trans "Cette réparation a é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

View file

@ -0,0 +1 @@
do not delete me

View file

@ -0,0 +1,89 @@
from django.contrib.auth import get_user_model
from django.core.files import File
from django.template.defaultfilters import urlencode
from django.test import Client, TestCase
from gestion.models import ErnestoUser
from ..models import Category, Partition, PartitionSet
User = get_user_model()
def new_user(username, ernesto=False, chef=False):
u = User.objects.create_user(username=username)
ErnestoUser.objects.create(user=u, slug=username, is_chef=chef, is_ernesto=ernesto)
return u
class TestViews(TestCase):
# TODO: add tests for upload/deletions
# TODO: test forms
def setUp(self):
# User with different access level and their clients
chef = new_user("chef", ernesto=True, chef=True)
chef_c = Client()
chef_c.force_login(chef)
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())]
# A Partition set with 1 partition
self.pset = PartitionSet.objects.create(
category=Category.objects.first(), nom="My PSet", auteur="PSet author"
)
file = File(open("partitions/tests/test_file.txt"), "test file")
Partition.objects.create(nom="part1", part=file, morceau=self.pset)
def tearDown(self):
"""Remove dummy files from media/partitions/"""
for partition in self.pset.partition_set.all():
partition.delete()
def _get_restricted_page(self, url):
"""
Shorthand for testing wether a page in only accessible by ernesto
members
"""
for user, client in self.client_matrix:
# If user is not None, it is an ernesto member
resp = client.get(url)
if user:
self.assertEqual(200, resp.status_code)
else:
encoded_url = urlencode(urlencode(url))
redirection_url = "/login?next={}".format(encoded_url)
self.assertRedirects(resp, redirection_url)
def test_get_partition_sets(self):
"""The list of all partition sets can be fetched by everyone"""
for _, client in self.client_matrix:
resp = client.get("/partitions/")
self.assertEqual(200, resp.status_code)
def test_get_partitions(self):
"""
Only ernesto members can see the partitions inside of a partition set
"""
url = "/partitions/{}/{}".format(self.pset.nom, self.pset.auteur)
self._get_restricted_page(url)
def test_see(self):
"""Only ernesto members can see partitions"""
part = self.pset.partition_set.first()
url = "/partitions/{}/{}/see/{}".format(
self.pset.nom, self.pset.auteur, part.id
)
self._get_restricted_page(url)
def test_download(self):
"""Only ernesto members can download partitions"""
part = self.pset.partition_set.first()
url = "/partitions/{}/{}/{}".format(self.pset.nom, self.pset.auteur, part.id)
self._get_restricted_page(url)
def test_new(self):
"""Only ernesto members can create partiton sets"""
url = "/partitions/new"
self._get_restricted_page(url)

14
instruments/urls.py Normal file
View file

@ -0,0 +1,14 @@
from django.urls import path
from . import views
app_name = "instruments"
urlpatterns = [
path("", views.ListeInstru.as_view(), name="liste"),
path("delete/<int:pk>", views.DeleteInstru.as_view(), name="delete_instru"),
path("delete_reparation/<int:pk>", views.DeleteRep.as_view(), name="delete_rep"),
path("new", views.CreateInstru.as_view(), name="ajouter_instru"),
path("new_rep/<int:pk>", views.CreateRep.as_view(), name="ajouter_rep"),
path("update_rep/<int:pk>", views.UpdateRep.as_view(), name="update_rep"),
path("fiche/<int:pk>", views.FicheInstru.as_view(), name="fiche_instru"),
]

119
instruments/views.py Normal file
View file

@ -0,0 +1,119 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.utils.safestring import mark_safe
from django.views.generic import (CreateView, DeleteView, TemplateView,
UpdateView)
from gestion.mixins import ChefRequiredMixin
from gestion.models import Photo
from instruments.forms import ChefEditInstrumentForm, ChefReparationForm
from instruments.models import Instrument, Reparation
class ListeInstru(LoginRequiredMixin, TemplateView):
template_name = "instruments/instru_liste.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["photo"] = Photo.objects.filter(cat="instru").order_by("?").first()
context["instrus_dispo"] = (
Instrument.objects.all().order_by("type").filter(statut="Disponible")
)
context["instrus_prete"] = (
Instrument.objects.all().order_by("type").filter(statut="Prêté")
)
return context
class CreateInstru(ChefRequiredMixin, CreateView):
model = Instrument
fields = ["owner", "etat", "type", "marque", "model", "serial", "annee", "prix"]
template_name = "instruments/create_instru.html"
success_url = reverse_lazy("instruments:liste")
class CreateRep(ChefRequiredMixin, TemplateView):
form_class = ChefReparationForm
template_name = "instruments/create_rep.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class()
context["pk"] = self.kwargs["pk"]
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
rep = form.save(commit=False)
rep.instru = get_object_or_404(Instrument, id=self.kwargs["pk"])
rep.save()
return redirect("instruments:fiche_instru", pk=self.kwargs["pk"])
else:
context = self.get_context_data()
context["form"] = form
return render(request, self.template_name, context)
class DeleteRep(ChefRequiredMixin, TemplateView):
model = Reparation
template_name = "instruments/delete_instru.html"
def get(self, request, *args, **kwargs):
rep = get_object_or_404(self.model, id=self.kwargs["pk"])
id_instru = rep.instru.id
rep.delete()
return redirect("instruments:fiche_instru", pk=id_instru)
class FicheInstru(LoginRequiredMixin, TemplateView):
template_name = "instruments/update_instru.html"
model = Instrument
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
instru = get_object_or_404(self.model, id=self.kwargs["pk"])
reparations = Reparation.objects.filter(instru=self.kwargs["pk"]).order_by(
"-date"
)
form = ChefEditInstrumentForm(instance=instru)
infos = mark_safe(instru.infos)
infos_en = mark_safe(instru.infos_en)
context["reparations"] = reparations
context["instru"] = instru
context["form"] = form
context["infos"] = infos
context["infos_en"] = infos_en
return context
def post(self, request, *args, **kwargs):
instru = get_object_or_404(self.model, id=self.kwargs["pk"])
form = ChefEditInstrumentForm(request.POST, instance=instru)
if request.user.profile.is_chef:
if form.is_valid():
form.save()
context = self.get_context_data()
context["form"] = form
return render(request, self.template_name, context)
class UpdateRep(ChefRequiredMixin, UpdateView):
model = Reparation
fields = ["date", "description", "description_en", "prix", "lieux"]
template_name = "instruments/update_rep.html"
def get_success_url(self):
id_instru = get_object_or_404(Reparation, id=self.kwargs["pk"]).instru.id
return reverse_lazy("instruments:fiche_instru", kwargs={"pk": id_instru})
class DeleteInstru(ChefRequiredMixin, DeleteView):
model = Instrument
template_name = "instruments/delete_instru.html"
success_url = reverse_lazy("instruments:liste")

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,7 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault( os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings.local")
"DJANGO_SETTINGS_MODULE",
"Ernestophone.settings.local"
)
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line

View file

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

View file

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

View file

@ -1,8 +1,12 @@
from django import forms from django import forms
from pads.models import Pad from pads.models import Pad
class PadForm(forms.ModelForm): class PadForm(forms.ModelForm):
class Meta: class Meta:
model = Pad model = Pad
fields = ('nom', 'url',) fields = (
"nom",
"url",
)

View file

@ -6,20 +6,27 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Pad', name="Pad",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), (
('nom', models.CharField(max_length=100)), "id",
('url', models.URLField()), models.AutoField(
('date', models.DateField(verbose_name='Créé le')), auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("url", models.URLField()),
("date", models.DateField(verbose_name="Créé le")),
], ],
options={ options={
'verbose_name': 'Pad', "verbose_name": "Pad",
}, },
), ),
] ]

View file

@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('pads', '0001_initial'), ("pads", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='pad', model_name="pad",
name='date', name="date",
field=models.DateField(verbose_name='Cree le'), field=models.DateField(verbose_name="Cree le"),
), ),
] ]

View file

@ -11,4 +11,6 @@ class Pad(models.Model):
class Meta: class Meta:
verbose_name = "Pad" verbose_name = "Pad"
# Create your models here. # Create your models here.

View file

@ -2,7 +2,6 @@ from django.urls import path
from pads import views from pads import views
app_name = "pads" app_name = "pads"
urlpatterns = [ urlpatterns = [
path("", views.PadList.as_view(), name="list"), path("", views.PadList.as_view(), name="list"),

View file

@ -3,6 +3,7 @@ from django.http import HttpResponseRedirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.views.generic import CreateView, DeleteView, ListView, UpdateView from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from gestion.mixins import ChefRequiredMixin from gestion.mixins import ChefRequiredMixin
from pads.models import Pad from pads.models import Pad

View file

@ -1,7 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import Category, PartitionSet
from .models import Category,PartitionSet
admin.site.register(Category) admin.site.register(Category)
admin.site.register(PartitionSet) admin.site.register(PartitionSet)

View file

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

View file

@ -1,11 +0,0 @@
from django.contrib.auth.decorators import user_passes_test
def is_chef(user):
try:
profile = user.profile
return profile.is_chef
except:
return False
chef_required = user_passes_test(lambda u: is_chef(u))

View file

@ -1,5 +1,7 @@
from django import forms from django import forms
from .models import PartitionSet
class UploadFileForm(forms.Form): class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50) title = forms.CharField(max_length=50)
@ -9,3 +11,9 @@ class UploadFileForm(forms.Form):
class UploadMorceauForm(forms.Form): class UploadMorceauForm(forms.Form):
titre = forms.CharField(max_length=100) titre = forms.CharField(max_length=100)
auteur = forms.CharField(max_length=100) auteur = forms.CharField(max_length=100)
class ChefEditMorceauForm(forms.ModelForm):
class Meta:
model = PartitionSet
fields = ("category", "download_unlogged", "infos", "url", "infos_en")

View file

@ -6,31 +6,66 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Partition', name="Partition",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), (
('nom', models.CharField(max_length=100)), "id",
('part', models.FileField(upload_to='partitions/')), models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("part", models.FileField(upload_to="partitions/")),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='PartitionSet', name="PartitionSet",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), (
('nom', models.CharField(max_length=100)), "id",
('auteur', models.CharField(max_length=100)), models.AutoField(
('category', models.CharField(max_length=8, choices=[('active', 'Actif'), ('incoming', 'À venir'), ('old', 'Archive'), ('optional', 'Optionnel')], default='incoming', verbose_name='Types de partitions')), auto_created=True,
('infos', models.TextField(blank=True, verbose_name='Infos utiles', null=True)), primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("auteur", models.CharField(max_length=100)),
(
"category",
models.CharField(
max_length=8,
choices=[
("active", "Actif"),
("incoming", "À venir"),
("old", "Archive"),
("optional", "Optionnel"),
],
default="incoming",
verbose_name="Types de partitions",
),
),
(
"infos",
models.TextField(
blank=True, verbose_name="Infos utiles", null=True
),
),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='partition', model_name="partition",
name='morceau', name="morceau",
field=models.ForeignKey(to='partitions.PartitionSet', on_delete=models.CASCADE), field=models.ForeignKey(
to="partitions.PartitionSet", on_delete=models.CASCADE
),
), ),
] ]

View file

@ -1,19 +1,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
def create_categories(apps, schema_editor): def create_categories(apps, schema_editor):
# Insert the previously hardcoded categories in the database # Insert the previously hardcoded categories in the database
Category = apps.get_model("partitions", "Category") Category = apps.get_model("partitions", "Category")
Category.objects.bulk_create([ Category.objects.bulk_create(
Category(name="Partitions actives", order=1), [
Category(name="Partitions optionnelles", order=2), Category(name="Partitions actives", order=1),
Category(name="Partitions à venir", order=3), Category(name="Partitions optionnelles", order=2),
Category(name="Archives", order=4) Category(name="Partitions à venir", order=3),
]) Category(name="Archives", order=4),
]
)
def set_new_categories(apps, schema_editor): def set_new_categories(apps, schema_editor):
@ -24,7 +26,7 @@ def set_new_categories(apps, schema_editor):
"active": assoc_list[0], "active": assoc_list[0],
"incoming": assoc_list[2], "incoming": assoc_list[2],
"old": assoc_list[3], "old": assoc_list[3],
"optional": assoc_list[1] "optional": assoc_list[1],
} }
for par_set in PartitionSet.objects.all(): for par_set in PartitionSet.objects.all():
par_set.category = mapping[par_set.category_old] par_set.category = mapping[par_set.category_old]
@ -39,7 +41,7 @@ def reset_old_categories(apps, schema_editor):
assoc_list[0][1]: "active", assoc_list[0][1]: "active",
assoc_list[2][1]: "incoming", assoc_list[2][1]: "incoming",
assoc_list[3][1]: "old", assoc_list[3][1]: "old",
assoc_list[1][1]: "optional" assoc_list[1][1]: "optional",
} }
for par_set in PartitionSet.objects.all(): for par_set in PartitionSet.objects.all():
par_set.category_old = mapping[par_set.category] par_set.category_old = mapping[par_set.category]
@ -49,29 +51,39 @@ def reset_old_categories(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('partitions', '0001_initial'), ("partitions", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Category', name="Category",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), (
('name', models.CharField(max_length=127)), "id",
('order', models.IntegerField(verbose_name='order')), models.AutoField(
verbose_name="ID",
primary_key=True,
serialize=False,
auto_created=True,
),
),
("name", models.CharField(max_length=127)),
("order", models.IntegerField(verbose_name="order")),
], ],
options={'verbose_name': 'catégorie', 'verbose_name_plural': 'catégories'}, options={"verbose_name": "catégorie", "verbose_name_plural": "catégories"},
), ),
migrations.RunPython(create_categories, migrations.RunPython.noop), migrations.RunPython(create_categories, migrations.RunPython.noop),
migrations.RenameField(model_name="partitionset", old_name="category", new_name="category_old"), migrations.RenameField(
model_name="partitionset", old_name="category", new_name="category_old"
),
migrations.AddField( migrations.AddField(
model_name='partitionset', model_name="partitionset",
name='category', name="category",
field=models.ForeignKey( field=models.ForeignKey(
verbose_name='Type de partition', verbose_name="Type de partition",
to='partitions.Category', to="partitions.Category",
on_delete=django.db.models.deletion.PROTECT, on_delete=django.db.models.deletion.PROTECT,
default=1 # Dummy, will be set by the RunPython operation default=1, # Dummy, will be set by the RunPython operation
), ),
preserve_default=False, preserve_default=False,
), ),

View file

@ -1,47 +1,78 @@
# Generated by Django 2.2.14 on 2020-07-16 17:49 # Generated by Django 2.2.14 on 2020-07-16 17:49
from django.db import migrations, models
import django.db.models.expressions import django.db.models.expressions
import django.db.models.functions.text import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('partitions', '0002_category'), ("partitions", "0002_category"),
] ]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='category', name="category",
options={'ordering': ('order',), 'verbose_name': 'Categorie', 'verbose_name_plural': 'Categories'}, options={
"ordering": ("order",),
"verbose_name": "Categorie",
"verbose_name_plural": "Categories",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='partition', name="partition",
options={'ordering': (django.db.models.expressions.CombinedExpression(django.db.models.expressions.Value('-'), '+', django.db.models.functions.text.Lower('nom')),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'}, options={
"ordering": (
django.db.models.expressions.CombinedExpression(
django.db.models.expressions.Value("-"),
"+",
django.db.models.functions.text.Lower("nom"),
),
),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='partitionset', name="partitionset",
options={'ordering': (django.db.models.expressions.CombinedExpression(django.db.models.expressions.Value('-'), '+', django.db.models.functions.text.Lower('nom')),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'}, options={
"ordering": (
django.db.models.expressions.CombinedExpression(
django.db.models.expressions.Value("-"),
"+",
django.db.models.functions.text.Lower("nom"),
),
),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
), ),
migrations.AddField( migrations.AddField(
model_name='category', model_name="category",
name='nom_en', name="nom_en",
field=models.CharField(blank=True, max_length=100, null=True), field=models.CharField(blank=True, max_length=100, null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='partitionset', model_name="partitionset",
name='infos_en', name="infos_en",
field=models.TextField(blank=True, null=True, verbose_name='Infos utiles en anglais'), field=models.TextField(
blank=True, null=True, verbose_name="Infos utiles en anglais"
),
), ),
migrations.AddField( migrations.AddField(
model_name='partitionset', model_name="partitionset",
name='url', name="url",
field=models.URLField(blank=True, help_text='Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse', null=True, verbose_name="Url d'une video youtube"), field=models.URLField(
blank=True,
help_text="Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse",
null=True,
verbose_name="Url d'une video youtube",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='category', model_name="category",
name='order', name="order",
field=models.IntegerField(verbose_name='ordre'), field=models.IntegerField(verbose_name="ordre"),
), ),
] ]

View file

@ -0,0 +1,52 @@
# Generated by Django 2.2.17 on 2021-03-31 13:50
import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("partitions", "0003_auto_20200716_1749"),
]
operations = [
migrations.AlterModelOptions(
name="partition",
options={
"ordering": (django.db.models.functions.text.Lower("nom"),),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AlterModelOptions(
name="partitionset",
options={
"ordering": (django.db.models.functions.text.Lower("nom"),),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AddField(
model_name="partitionset",
name="download_unlogged",
field=models.CharField(
choices=[("n", "Non"), ("o", "Oui")],
default="n",
max_length=1,
verbose_name="Téléchargeable non connecté ?",
),
),
migrations.AlterField(
model_name="partitionset",
name="infos",
field=models.TextField(blank=True, default="", verbose_name="Infos utiles"),
),
migrations.AlterField(
model_name="partitionset",
name="infos_en",
field=models.TextField(
blank=True, default="", verbose_name="Infos utiles en anglais"
),
),
]

View file

@ -9,20 +9,21 @@ from django.utils.translation import gettext_lazy as _
class Category(models.Model): class Category(models.Model):
name = models.CharField(max_length=127) name = models.CharField(max_length=127)
order = models.IntegerField(verbose_name=_("ordre")) order = models.IntegerField(verbose_name=_("ordre"))
nom_en = models.CharField(max_length=100,null=True,blank=True) nom_en = models.CharField(max_length=100, null=True, blank=True)
def __str__(self): def __str__(self):
return self.name return self.name
class Meta: class Meta:
verbose_name = _("Categorie") verbose_name = _("Categorie")
verbose_name_plural = _("Categories") verbose_name_plural = _("Categories")
ordering = ('order',) ordering = ("order",)
class Partition(models.Model): class Partition(models.Model):
nom = models.CharField(max_length=100) nom = models.CharField(max_length=100)
part = models.FileField(upload_to="partitions/") part = models.FileField(upload_to="partitions/")
morceau = models.ForeignKey('PartitionSet', on_delete=models.CASCADE) morceau = models.ForeignKey("PartitionSet", on_delete=models.CASCADE)
def __str__(self): def __str__(self):
return self.nom return self.nom
@ -32,26 +33,40 @@ class Partition(models.Model):
super(Partition, self).delete(*args, **kwargs) super(Partition, self).delete(*args, **kwargs)
class Meta: class Meta:
verbose_name = _('Morceau') verbose_name = _("Morceau")
verbose_name_plural = _('Morceaux') verbose_name_plural = _("Morceaux")
ordering = (Lower('nom'),) ordering = (Lower("nom"),)
class PartitionSet(models.Model): class PartitionSet(models.Model):
nom = models.CharField(max_length=100) nom = models.CharField(max_length=100)
auteur = models.CharField(max_length=100) auteur = models.CharField(max_length=100)
category = models.ForeignKey( category = models.ForeignKey(
Category, Category, on_delete=models.PROTECT, verbose_name=_("Type de partition")
on_delete=models.PROTECT, )
verbose_name=_("Type de partition") download_unlogged = models.CharField(
_("Téléchargeable non connecté ?"),
default="n",
choices=[("n", _("Non")), ("o", _("Oui"))],
max_length=1,
)
infos = models.TextField(_("Infos utiles"), null=False, blank=True, default="")
infos_en = models.TextField(
"Infos utiles en anglais", null=False, blank=True, default=""
)
url = models.URLField(
_("Url d'une video youtube"),
null=True,
blank=True,
help_text=_(
"Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse"
),
) )
infos = models.TextField(_("Infos utiles"), null=True, blank=True)
infos_en = models.TextField("Infos utiles en anglais", null=True, blank=True)
url = models.URLField(_("Url d'une video youtube"),null=True,blank=True, help_text= _("Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse"))
def __str__(self): def __str__(self):
return("%s - %s [%s]" % (self.nom, self.auteur, self.category)) return "%s - %s [%s]" % (self.nom, self.auteur, self.category)
class Meta: class Meta:
verbose_name = _('Morceau') verbose_name = _("Morceau")
verbose_name_plural = _('Morceaux') verbose_name_plural = _("Morceaux")
ordering = (Lower('nom'),) ordering = (Lower("nom"),)

View file

@ -7,7 +7,7 @@
<div class="inner"> <div class="inner">
<h4>{% trans "Confirmation de suppression" %}</h4> <h4>{% trans "Confirmation de suppression" %}</h4>
<p>{% trans "Voulez-vous vraiment supprimer cette partition ?" %}"</p> <p>{% trans "Voulez-vous vraiment supprimer cette partition ?" %}</p>
<p><a href="{% url "partitions:delete" nom auteur id %}" class="button " >{% trans "Oui" %}</a></p> <p><a href="{% url "partitions:delete" nom auteur id %}" class="button " >{% trans "Oui" %}</a></p>
<p><a href="{% url "partitions:listepart" nom auteur %}" class="button alt" >{% trans "Retour à la liste des partitions" %}</a></p> <p><a href="{% url "partitions:listepart" nom auteur %}" class="button alt" >{% trans "Retour à la liste des partitions" %}</a></p>

View file

@ -74,7 +74,7 @@
<div class="box">{% autotranslate current_language infos infos_en %}</div> <div class="box">{% autotranslate current_language infos infos_en %}</div>
{% endif %} {% endif %}
{% endif %} {% endif %}

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