feat(ernestoprofil): init user managment system
This commit is contained in:
parent
9b1cb51aae
commit
8c2769b0b9
44 changed files with 1461 additions and 22528 deletions
|
@ -40,9 +40,12 @@ INSTALLED_APPS = [
|
|||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"sass_processor",
|
||||
"ernestoprofile",
|
||||
"bulma",
|
||||
"shared",
|
||||
"sass_processor",
|
||||
"authens",
|
||||
"solo",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -103,35 +106,36 @@ DATABASES = {
|
|||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = (
|
||||
[]
|
||||
if DEBUG
|
||||
else [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
)
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
# Authentication backends
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
"authens.backends.ENSCASBackend",
|
||||
"authens.backends.OldCASBackend",
|
||||
]
|
||||
|
||||
LOGIN_URL = reverse_lazy("authens:login")
|
||||
|
||||
AUTHENS_USE_OLDCAS = False
|
||||
LOGIN_REDIRECT_URL = reverse_lazy("home") # TODO change for agenda
|
||||
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy("home")
|
||||
|
||||
# AUTHENS_USE_OLDCAS = True
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
@ -174,3 +178,7 @@ MESSAGE_TAGS = {
|
|||
messages.WARNING: "is-warning",
|
||||
messages.ERROR: "is-danger",
|
||||
}
|
||||
|
||||
# Email
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
|
|
|
@ -22,7 +22,9 @@ from django.views.generic import TemplateView
|
|||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("", TemplateView.as_view(template_name="home.html")),
|
||||
path("authens/", include("authens.urls")),
|
||||
path("", TemplateView.as_view(template_name="home.html"), name="home"),
|
||||
path("account/", include("ernestoprofile.urls")),
|
||||
]
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [
|
||||
|
|
3
ernestoprofile/README.md
Normal file
3
ernestoprofile/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# `ernestouser`
|
||||
|
||||
Application qui gère les profils utilisateurs et l'authentification
|
0
ernestoprofile/__init__.py
Normal file
0
ernestoprofile/__init__.py
Normal file
23
ernestoprofile/admin.py
Normal file
23
ernestoprofile/admin.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
from solo.admin import SingletonModelAdmin
|
||||
|
||||
from .models import AuthConfiguration, Profile
|
||||
|
||||
|
||||
# Register your models here.
|
||||
class ProfileInline(admin.StackedInline):
|
||||
model = Profile
|
||||
can_delete = False
|
||||
|
||||
|
||||
# Define a new User admin
|
||||
class UserAdmin(BaseUserAdmin):
|
||||
inlines = [ProfileInline]
|
||||
|
||||
|
||||
# Re-register UserAdmin
|
||||
admin.site.unregister(User)
|
||||
admin.site.register(User, UserAdmin)
|
||||
admin.site.register(AuthConfiguration, SingletonModelAdmin)
|
6
ernestoprofile/apps.py
Normal file
6
ernestoprofile/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ErnestoprofileConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "ernestoprofile"
|
39
ernestoprofile/forms.py
Normal file
39
ernestoprofile/forms.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from django import forms
|
||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import AuthConfiguration, Profile
|
||||
|
||||
|
||||
class ProfileForm(forms.ModelForm):
|
||||
|
||||
class Meta: # pyright: ignore
|
||||
model = Profile
|
||||
# abstract = True
|
||||
exclude = ["user"]
|
||||
|
||||
|
||||
class UserForm(UserChangeForm):
|
||||
class Meta: # pyright: ignore
|
||||
model = User
|
||||
fields = ["username", "email", "first_name", "last_name"]
|
||||
|
||||
|
||||
class UserCreateForm(UserCreationForm):
|
||||
class Meta: # pyright: ignore
|
||||
model = User
|
||||
fields = ["username", "email", "first_name", "last_name"]
|
||||
|
||||
|
||||
class BecomeErnestoForm(forms.Form):
|
||||
password = forms.CharField(
|
||||
label=_("L'ernesto mot de passe"), widget=forms.PasswordInput
|
||||
)
|
||||
|
||||
def clean_password(self):
|
||||
data = self.cleaned_data["password"]
|
||||
if data != AuthConfiguration.get_solo().password:
|
||||
raise ValidationError(_("Ernesto mot de passe incorrect"))
|
||||
return data
|
84
ernestoprofile/migrations/0001_initial.py
Normal file
84
ernestoprofile/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Generated by Django 4.2.12 on 2024-06-18 05:51
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AuthConfiguration",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"password",
|
||||
models.CharField(
|
||||
default="dummy",
|
||||
max_length=255,
|
||||
verbose_name="Mot de passe pour devenir fanfaron",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Paramètres d'authentification",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Profile",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"phone",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="seulement visible par les chef·fe·s",
|
||||
max_length=20,
|
||||
verbose_name="Numéro de téléphone",
|
||||
),
|
||||
),
|
||||
(
|
||||
"polls_pseudo",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
max_length=30,
|
||||
verbose_name="Pseudo pour les sondages",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ernestoprofil",
|
||||
"verbose_name_plural": "Ernestoprofils",
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,46 @@
|
|||
# Generated by Django 4.2.12 on 2024-06-22 18:58
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("ernestoprofile", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="profile",
|
||||
name="phone",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
help_text="seulement visible par les chef·fe·s",
|
||||
max_length=20,
|
||||
verbose_name="Numéro de téléphone",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="profile",
|
||||
name="polls_pseudo",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
max_length=30,
|
||||
verbose_name="Pseudo pour les sondages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="profile",
|
||||
name="user",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="profile",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
]
|
26
ernestoprofile/migrations/0003_alter_profile_polls_pseudo.py
Normal file
26
ernestoprofile/migrations/0003_alter_profile_polls_pseudo.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 4.2.12 on 2024-06-22 19:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"ernestoprofile",
|
||||
"0002_alter_profile_phone_alter_profile_polls_pseudo_and_more",
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="profile",
|
||||
name="polls_pseudo",
|
||||
field=models.CharField(
|
||||
help_text="Le pseudo qui s'affichera pour tes réponses aux sondages",
|
||||
max_length=30,
|
||||
unique=True,
|
||||
verbose_name="Pseudo pour les sondages",
|
||||
),
|
||||
),
|
||||
]
|
18
ernestoprofile/migrations/0004_add_groups.py
Normal file
18
ernestoprofile/migrations/0004_add_groups.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2.12 on 2024-06-23 04:09
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def create_groups(apps, schema_editor):
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Group.objects.update_or_create(name="Ernestophoniste")
|
||||
Group.objects.update_or_create(name="Chef")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("ernestoprofile", "0003_alter_profile_polls_pseudo"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(create_groups)]
|
0
ernestoprofile/migrations/__init__.py
Normal file
0
ernestoprofile/migrations/__init__.py
Normal file
22
ernestoprofile/mixins.py
Normal file
22
ernestoprofile/mixins.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import AccessMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
class LocalUserOnlyMixin(AccessMixin):
|
||||
"""Verify that the current user is authenticated."""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if hasattr(request.user, "cas_account"):
|
||||
return self.handle_no_permission()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class LocalUserOnlySoftMixin(LocalUserOnlyMixin):
|
||||
|
||||
redirect_url = None
|
||||
reject_message = ""
|
||||
|
||||
def handle_no_permission(self):
|
||||
messages.warning(self.request, self.reject_message)
|
||||
return HttpResponseRedirect(str(self.redirect_url))
|
59
ernestoprofile/models.py
Normal file
59
ernestoprofile/models.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Create your models here.
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from solo.models import SingletonModel
|
||||
|
||||
|
||||
class AuthConfiguration(SingletonModel):
|
||||
password = models.CharField(
|
||||
max_length=255,
|
||||
default="dummy",
|
||||
verbose_name=_("Mot de passe pour devenir fanfaron"),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Auth Configuration"
|
||||
|
||||
class Meta: # pyright: ignore
|
||||
verbose_name = _("Paramètres d'authentification")
|
||||
|
||||
|
||||
class Instrument(models.Model):
|
||||
name = models.CharField(
|
||||
_("Nom de l'instrument"),
|
||||
max_length=50,
|
||||
blank=False,
|
||||
null=False,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
|
||||
class Profile(models.Model):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
|
||||
|
||||
phone = models.CharField(
|
||||
_("Numéro de téléphone"),
|
||||
max_length=20,
|
||||
blank=True,
|
||||
default="",
|
||||
help_text=_("seulement visible par les chef·fe·s"),
|
||||
)
|
||||
|
||||
polls_pseudo = models.CharField(
|
||||
_("Pseudo pour les sondages"),
|
||||
max_length=30,
|
||||
help_text=_("Le pseudo qui s'affichera pour tes réponses aux sondages"),
|
||||
unique=True,
|
||||
blank=False,
|
||||
null=False,
|
||||
)
|
||||
|
||||
instruments = models.ManyToManyField(Instrument)
|
||||
|
||||
class Meta: # pyright: ignore
|
||||
verbose_name = _("Ernestoprofil")
|
||||
verbose_name_plural = _("Ernestoprofils")
|
||||
|
||||
def __str__(self):
|
||||
return self.user.username
|
48
ernestoprofile/templates/authens/login_switch.html
Normal file
48
ernestoprofile/templates/authens/login_switch.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section class="section">
|
||||
<h1 class="title">{% trans "Choisissez la méthode de connexion" %}</h1>
|
||||
|
||||
<div class="buttons">
|
||||
<a class="button signin-button is-primary is-fullwidth"
|
||||
href="{% url "authens:login.cas" %}?next={{ next }}">
|
||||
<span class="icon">
|
||||
<i class="ti ti-school"></i>
|
||||
</span>
|
||||
<span>{% trans "Connexion via clipper" %}</span>
|
||||
</a>
|
||||
<a class="button signin-button is-link is-fullwidth"
|
||||
href="{% url "authens:login.pwd" %}?next={{ next }}">
|
||||
<span class="icon">
|
||||
<i class="ti ti-key"></i>
|
||||
</span>
|
||||
<span>{% trans "Connexion par mot de passe" %}</span>
|
||||
</a>
|
||||
<a class="button signin-button is-secondary is-fullwidth"
|
||||
href="{% url "authens:login.oldcas" %}?next={{ next }}">
|
||||
<span class="icon">🦕</span>
|
||||
<span>{% trans "Connexion dino" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" />
|
||||
{% trans "Se souvenir de mon choix" %}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="content notification">
|
||||
{% url "authens:reset.pwd" as url_reset %}
|
||||
<p class="has-text-centered">
|
||||
{% blocktrans %}Si votre fin de scolarité approche, créez un mot de passe pour votre compte pour bénéficier de la connexion dino: <a href="{{ url_reset }}">créer un mot de passe</a>.
|
||||
<br>
|
||||
<a href="{{ url_reset }}">Mot de passe oublié</a>{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
25
ernestoprofile/templates/authens/oldcas_login.html
Normal file
25
ernestoprofile/templates/authens/oldcas_login.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{# TODO: Add hero #}
|
||||
<section class="section">
|
||||
<h1 class="title">{% trans "Connexion en tant que vieilleux" %}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" type="submit">
|
||||
<span>{% trans "Connection" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
24
ernestoprofile/templates/authens/pwd_login.html
Normal file
24
ernestoprofile/templates/authens/pwd_login.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{# TODO: Add hero #}
|
||||
<section class="section">
|
||||
<h1 class="title">{% trans "Connexion par mot de passe" %}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" type="submit">
|
||||
<span>{% trans "Connection" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
32
ernestoprofile/templates/authens/pwd_reset.html
Normal file
32
ernestoprofile/templates/authens/pwd_reset.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section class="section">
|
||||
|
||||
<h1 class="title">{% trans "Réinitialisation du mot de passe" %}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-fullwidth is-outlined is-primary is-light"
|
||||
type="submit">
|
||||
<span>{% trans "Envoyer un mail" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-primary"
|
||||
href="{% url 'authens:login.pwd' %}?next={{ next }}">
|
||||
<span>{% trans "Retour" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
26
ernestoprofile/templates/authens/pwd_reset_confirm.html
Normal file
26
ernestoprofile/templates/authens/pwd_reset_confirm.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "authens/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<h1 class="title">{% trans "Réinitialisation du mot de passe" %}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True %}
|
||||
|
||||
<div class="field is-grouped is-centered">
|
||||
<div class="control is-expanded">
|
||||
<button class="button is-fullwidth is-outlined is-primary is-light"
|
||||
type="submit">
|
||||
<span class="icon">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>{% trans "Enregistrer" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
15
ernestoprofile/templates/authens/pwd_reset_email.txt
Normal file
15
ernestoprofile/templates/authens/pwd_reset_email.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% load i18n %}{% autoescape off %}
|
||||
{% blocktrans %}Cher·re Ernesto,
|
||||
|
||||
Quelqu'un (probablement vous) a demandé la réinitialisation du mot de passe associé à cette addresse sur l'ernestosite.{% endblocktrans %}
|
||||
|
||||
{% blocktrans %}S'il s'agit bien de vous, vous pouvez vous rendre à l'adresse suivante pour en choisir un nouveau : {% endblocktrans %}
|
||||
{% block reset_link %}
|
||||
{{ protocol }}://{{ domain }}{% url "authens:reset.pwd.confirm" uidb64=uid token=token %}
|
||||
{% endblock %}
|
||||
|
||||
{% blocktrans with username=user.base_username %}Pour information, votre nom d'ernesto est le suivant : {{ username }}{% endblocktrans %}
|
||||
|
||||
{% block signature %}{% blocktrans %}L'Ernestosite team{% endblocktrans %}{% endblock %}
|
||||
|
||||
{% endautoescape %}
|
26
ernestoprofile/templates/ernestoprofile/create-user.html
Normal file
26
ernestoprofile/templates/ernestoprofile/create-user.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{# TODO: Add hero #}
|
||||
<section class="section">
|
||||
<h1 class="title">{% trans "Créer un compte" %}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True form=user_form %}
|
||||
{% include "bulma/form.html" with errors=True form=profile_form %}
|
||||
{% include "bulma/form.html" with errors=True form=ernesto_form %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" type="submit">
|
||||
<span>{% trans "Enregister" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
33
ernestoprofile/templates/ernestoprofile/edit-user.html
Normal file
33
ernestoprofile/templates/ernestoprofile/edit-user.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{# TODO: Add hero #}
|
||||
<section class="section">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h1 class="title level-item">{% trans "Modifier mon ernesto-profil" %}</h1>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<a href="{% url "ernestoprofil:password-change" %}"
|
||||
class="button is-primary is-outlined">{% trans "Modifier mon mot de passe" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True form=user_form %}
|
||||
{% include "bulma/form.html" with errors=True form=profile_form %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" type="submit">
|
||||
<span>{% trans "Enregister" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
1
ernestoprofile/tests.py
Normal file
1
ernestoprofile/tests.py
Normal file
|
@ -0,0 +1 @@
|
|||
# Create your tests here.
|
12
ernestoprofile/urls.py
Normal file
12
ernestoprofile/urls.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.urls import path
|
||||
|
||||
from .views import BecomeErnesto, CreateUser, EditUser, LogoutView, PasswordChange
|
||||
|
||||
app_name = "ernestoprofil"
|
||||
urlpatterns = [
|
||||
path("edit-user", EditUser.as_view(), name="edit-user"),
|
||||
path("create-user", CreateUser.as_view(), name="create-user"),
|
||||
path("password-change", PasswordChange.as_view(), name="password-change"),
|
||||
path("logout", LogoutView.as_view(), name="logout"),
|
||||
path("become-ernesto", BecomeErnesto.as_view(), name="become-ernesto"),
|
||||
]
|
176
ernestoprofile/views.py
Normal file
176
ernestoprofile/views.py
Normal file
|
@ -0,0 +1,176 @@
|
|||
from authens import views as authens_views
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.auth.views import PasswordChangeView
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.forms import ModelForm
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import FormView, TemplateView
|
||||
|
||||
from shared.mixins import LocalUserOnlySoftMixin
|
||||
|
||||
from .forms import BecomeErnestoForm, ProfileForm, UserCreateForm, UserForm
|
||||
from .models import Profile
|
||||
|
||||
|
||||
# Create your views here.
|
||||
class LogoutView(authens_views.LogoutView):
|
||||
def get_success_url(self):
|
||||
messages.success(self.request, _("Déconnecté avec succès"))
|
||||
return super().get_success_url()
|
||||
|
||||
|
||||
class PasswordChange(LocalUserOnlySoftMixin, PasswordChangeView):
|
||||
|
||||
redirect_url = reverse_lazy("ernestoprofil:edit-user")
|
||||
reject_message = _(
|
||||
"Vous ne pouvez pas changer votre mote de pass avec un compte CAS"
|
||||
)
|
||||
|
||||
extra_context = {
|
||||
"title": _("Changer mon mot de passe"),
|
||||
"submit": _("Enregistrer"),
|
||||
}
|
||||
template_name = "simple_form.html"
|
||||
success_url = reverse_lazy("ernestoprofil:edit-user")
|
||||
|
||||
|
||||
class BecomeErnesto(LoginRequiredMixin, FormView):
|
||||
template_name = "simple_form.html"
|
||||
form_class = BecomeErnestoForm
|
||||
success_url = reverse_lazy("home")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx.update(
|
||||
{
|
||||
"title": _("Devenir fanfaron"),
|
||||
"submit": _("Pouêt 🎶"),
|
||||
}
|
||||
)
|
||||
return ctx
|
||||
|
||||
def form_valid(self, form):
|
||||
group, created = Group.objects.get_or_create(name="Ernestophoniste")
|
||||
group.user_set.add(self.request.user)
|
||||
messages.success(
|
||||
self.request, _("Bienvenue à la fanfare jeune ernestophoniste! 🎺")
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class BaseEditUser(TemplateView):
|
||||
|
||||
def get_instance(self, fname):
|
||||
raise ImproperlyConfigured("")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
inst_forms = self.get_forms()
|
||||
for f in self.forms:
|
||||
if f not in kwargs:
|
||||
kwargs[f] = inst_forms[f]
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return str(self.success_url)
|
||||
|
||||
def get_forms(self):
|
||||
kwargs = {}
|
||||
if self.request.method in ("POST", "PUT"):
|
||||
kwargs.update(
|
||||
{
|
||||
"data": self.request.POST,
|
||||
"files": self.request.FILES,
|
||||
}
|
||||
)
|
||||
inst_forms = {}
|
||||
for f, form_class in self.forms.items():
|
||||
if issubclass(form_class, ModelForm):
|
||||
inst_forms[f] = form_class(
|
||||
prefix=f,
|
||||
instance=self.get_instance(f),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
else:
|
||||
inst_forms[f] = form_class(prefix=f, **kwargs)
|
||||
return inst_forms
|
||||
|
||||
def valid(self, forms):
|
||||
pass
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
Handle POST requests: instantiate a form instance with the passed
|
||||
POST variables and then check if it's valid.
|
||||
"""
|
||||
forms = self.get_forms()
|
||||
valid = True
|
||||
for fname, form in forms.items():
|
||||
valid &= form.is_valid()
|
||||
if valid:
|
||||
user = forms["user_form"].save()
|
||||
forms["profile_form"].instance.user = user
|
||||
print(forms["profile_form"].instance.polls_pseudo)
|
||||
for fname, form in forms.items():
|
||||
if isinstance(form, ModelForm):
|
||||
form.save()
|
||||
self.valid(forms)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
else:
|
||||
return self.render_to_response(self.get_context_data(**forms))
|
||||
|
||||
|
||||
class EditUser(LoginRequiredMixin, BaseEditUser):
|
||||
template_name = "ernestoprofile/edit-user.html"
|
||||
forms = {
|
||||
"user_form": UserForm,
|
||||
"profile_form": ProfileForm,
|
||||
}
|
||||
success_url = reverse_lazy("ernestoprofil:edit-user")
|
||||
|
||||
def get_instance(self, fname):
|
||||
match fname:
|
||||
case "user_form":
|
||||
return self.request.user
|
||||
case "profile_form":
|
||||
if not hasattr(self.request.user, "profile"):
|
||||
Profile.objects.create(
|
||||
user=self.request.user, polls_pseudo=self.request.user.username
|
||||
)
|
||||
return self.request.user.profile
|
||||
|
||||
def get_success_url(self):
|
||||
messages.success(self.request, _("Profil mis à jour avec succès"))
|
||||
return super().get_success_url()
|
||||
|
||||
|
||||
class CreateUser(BaseEditUser):
|
||||
|
||||
template_name = "ernestoprofile/create-user.html"
|
||||
forms = {
|
||||
"user_form": UserCreateForm,
|
||||
"profile_form": ProfileForm,
|
||||
"ernesto_form": BecomeErnestoForm,
|
||||
}
|
||||
success_url = reverse_lazy("home")
|
||||
|
||||
def get_instance(self, fname):
|
||||
return None
|
||||
|
||||
def valid(self, forms):
|
||||
user = forms["user_form"].instance
|
||||
group, created = Group.objects.get_or_create(name="Ernestophoniste")
|
||||
group.user_set.add(user)
|
||||
|
||||
def get_success_url(self):
|
||||
messages.success(
|
||||
self.request,
|
||||
_(
|
||||
"Bienvenue chèr.re fanfaron.ne! Tu peux maintenant te connecter pour découvrir ce merveilleux site."
|
||||
),
|
||||
) # TODO middot
|
||||
return super().get_success_url()
|
15
provisioning/authens/01-get-success_url.patch
Normal file
15
provisioning/authens/01-get-success_url.patch
Normal file
|
@ -0,0 +1,15 @@
|
|||
diff --git a/authens/views.py b/authens/views.py
|
||||
index 0478861..b1c93e9 100644
|
||||
--- a/authens/views.py
|
||||
+++ b/authens/views.py
|
||||
@@ -138,8 +138,8 @@ class LogoutView(auth_views.LogoutView):
|
||||
else:
|
||||
self.cas_connected = False
|
||||
|
||||
- def get_next_page(self):
|
||||
- next_page = super().get_next_page()
|
||||
+ def get_success_url(self):
|
||||
+ next_page = super().get_success_url()
|
||||
if self.cas_connected:
|
||||
cas_client = get_cas_client(self.request)
|
||||
|
|
@ -8,6 +8,7 @@ buildPythonPackage rec {
|
|||
pname = "authens";
|
||||
version = "v0.1b5";
|
||||
doCheck = false;
|
||||
patches = [ ./01-get-success_url.patch ];
|
||||
src = builtins.fetchGit {
|
||||
url = "https://git.eleves.ens.fr/klub-dev-ens/authens.git";
|
||||
#rev = "master";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
lib,
|
||||
buildPythonPackage,
|
||||
fetchgit,
|
||||
#fetchgit,
|
||||
setuptools,
|
||||
setuptools-scm,
|
||||
wheel,
|
||||
|
@ -13,11 +13,12 @@ buildPythonPackage rec {
|
|||
version = "0.1.4";
|
||||
pyproject = true;
|
||||
|
||||
src = fetchgit {
|
||||
url = "https://git.hubrecht.ovh/hubrecht/django-bulma-forms";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-4KTMXx3YxDxB4/YH14pJnNYtpOGXeDmD+gcbrUHwD/w=";
|
||||
};
|
||||
src = ../../../django-bulma-forms;
|
||||
#fetchgit {
|
||||
# url = "https://git.hubrecht.ovh/hubrecht/django-bulma-forms";
|
||||
# rev = "v${version}";
|
||||
# hash = "sha256-4KTMXx3YxDxB4/YH14pJnNYtpOGXeDmD+gcbrUHwD/w=";
|
||||
#};
|
||||
|
||||
nativeBuildInputs = [
|
||||
setuptools
|
||||
|
|
38
provisioning/django-solo/default.nix
Normal file
38
provisioning/django-solo/default.nix
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
lib,
|
||||
buildPythonPackage,
|
||||
fetchFromGitHub,
|
||||
setuptools,
|
||||
wheel,
|
||||
django,
|
||||
}:
|
||||
|
||||
buildPythonPackage rec {
|
||||
pname = "django-solo";
|
||||
version = "2.2.0";
|
||||
pyproject = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "lazybird";
|
||||
repo = "django-solo";
|
||||
rev = version;
|
||||
hash = "sha256-utLwELFk5/oiYnfJCnnHQPlVTADSjt9cbMOOUKMtnfM=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
setuptools
|
||||
wheel
|
||||
];
|
||||
|
||||
dependencies = [ django ];
|
||||
|
||||
pythonImportsCheck = [ "solo" ];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Helps working with singletons - things like global settings that you want to edit from the admin site";
|
||||
homepage = "https://github.com/lazybird/django-solo";
|
||||
changelog = "https://github.com/lazybird/django-solo/blob/${src.rev}/CHANGES";
|
||||
license = licenses.cc-by-30;
|
||||
maintainers = with maintainers; [ ];
|
||||
};
|
||||
}
|
|
@ -9,7 +9,7 @@ let
|
|||
|
||||
hooks = {
|
||||
# JS hooks
|
||||
eslint.enable = true;
|
||||
# eslint.enable = true;
|
||||
|
||||
# Python hooks
|
||||
ruff.enable = true;
|
||||
|
@ -36,6 +36,7 @@ let
|
|||
authens = self.callPackage ./authens { };
|
||||
pythoncas = self.callPackage ./python-cas { };
|
||||
django-browser-reload = self.callPackage ./django-browser-reload { };
|
||||
django-solo = self.callPackage ./django-solo { };
|
||||
django-bulma-forms = self.callPackage ./django-bulma-forms { };
|
||||
django-sass-processor = self.callPackage ./django-sass-processor { };
|
||||
django-sass-processor-dart-sass = self.callPackage ./django-sass-processor-dart-sass { };
|
||||
|
@ -51,6 +52,7 @@ pkgs.mkShell {
|
|||
ps.django
|
||||
ps.gunicorn
|
||||
ps.authens
|
||||
ps.django-solo
|
||||
ps.django-browser-reload
|
||||
ps.django-bulma-forms
|
||||
ps.django-sass-processor
|
||||
|
|
30
pyproject.toml
Normal file
30
pyproject.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "ernesto"
|
||||
version = "1.0.0"
|
||||
authors = [{name = "Maurice Debray", email = "sinavir@sinavir.fr"}]
|
||||
description = ""
|
||||
license = {file = "LICENSE"}
|
||||
readme = "README.md"
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
|
||||
"Programming Language :: Python :: 3",
|
||||
]
|
||||
|
||||
|
||||
[tool.djlint]
|
||||
blank_line_after_tag = "load,extends"
|
||||
format_js = true
|
||||
indent = 2
|
||||
max_blank_lines = 1
|
||||
profile = "django"
|
||||
|
||||
[tool.djlint.js]
|
||||
indent_size = 4
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
22
shared/mixins.py
Normal file
22
shared/mixins.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import AccessMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
class LocalUserOnlyMixin(AccessMixin):
|
||||
"""Verify that the current user is authenticated."""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if hasattr(request.user, "cas_account"):
|
||||
return self.handle_no_permission()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class LocalUserOnlySoftMixin(LocalUserOnlyMixin):
|
||||
|
||||
redirect_url = None
|
||||
reject_message = ""
|
||||
|
||||
def handle_no_permission(self):
|
||||
messages.warning(self.request, self.reject_message)
|
||||
return HttpResponseRedirect(str(self.redirect_url))
|
1
shared/static/bulma/.gitignore
vendored
Normal file
1
shared/static/bulma/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.css
|
22451
shared/static/bulma/bulma.css
vendored
22451
shared/static/bulma/bulma.css
vendored
File diff suppressed because it is too large
Load diff
7
shared/static/bulma/bulma.scss
vendored
7
shared/static/bulma/bulma.scss
vendored
|
@ -8,9 +8,10 @@
|
|||
|
||||
/*! bulma.io v1.0.0 | MIT License | github.com/jgthms/bulma */
|
||||
@use "sass" with (
|
||||
$navbar-item-img-max-height: 2rem,
|
||||
$family-sans-serif: '"Signika", sans-serif',
|
||||
$primary: #ff4500,
|
||||
$link: #730000
|
||||
$link: #730000,
|
||||
);
|
||||
|
||||
body {
|
||||
|
@ -20,4 +21,8 @@ body {
|
|||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
@import url("https://fonts.googleapis.com/css?family=Signika:400,700");
|
||||
|
|
379
shared/static/icons/ernesto-white-long-bis.svg
Normal file
379
shared/static/icons/ernesto-white-long-bis.svg
Normal file
|
@ -0,0 +1,379 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="217.9005"
|
||||
height="61.852177"
|
||||
viewBox="0 0 217.9005 61.85218"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
sodipodi:docname="ernesto-white-long-bis.svg"
|
||||
inkscape:export-filename="ernesto_filled-64x64.png"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="2.1575361"
|
||||
inkscape:cx="59.558679"
|
||||
inkscape:cy="33.3714"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1055"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g4"
|
||||
showgrid="false" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath3">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-379.20901,-637.53812)"
|
||||
id="path3" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath5">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-383.65581,-637.53812)"
|
||||
id="path5" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath7">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-371.99561,-633.14062)"
|
||||
id="path7" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath61">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-231.36961,-599.54491)"
|
||||
id="path61" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath63">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-253.05321,-706.59232)"
|
||||
id="path63" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath65">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-305.49411,-694.92041)"
|
||||
id="path65" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath67">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-321.33011,-710.64162)"
|
||||
id="path67" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath69">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-339.27001,-690.53912)"
|
||||
id="path69" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath71">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-258.63231,-619.17772)"
|
||||
id="path71" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath73">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-318.36281,-612.33982)"
|
||||
id="path73" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath75">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-232.2529,-680.92871)"
|
||||
id="path75" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath77">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-337.67291,-618.84521)"
|
||||
id="path77" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath79">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-223.5034,-666.56542)"
|
||||
id="path79" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath81">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-286.82281,-678.06791)"
|
||||
id="path81" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath83">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-256.417,-629.66261)"
|
||||
id="path83" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath85">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-179.78031,-703.79152)"
|
||||
id="path85" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath9">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-659.84861,-589.57762)"
|
||||
id="path9" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath11">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-686.02931,-730.88182)"
|
||||
id="path11" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath13">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-751.05759,-695.40532)"
|
||||
id="path13" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath15">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-767.67872,-718.45802)"
|
||||
id="path15" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath17">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-801.15632,-706.96632)"
|
||||
id="path17" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath19">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-699.35162,-614.75981)"
|
||||
id="path19" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath21">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-779.83014,-605.59672)"
|
||||
id="path21" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath23">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-658.15042,-696.48682)"
|
||||
id="path23" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath25">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-804.58112,-617.13872)"
|
||||
id="path25" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath27">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-646.06642,-677.34962)"
|
||||
id="path27" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath29">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-731.28712,-692.65382)"
|
||||
id="path29" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath31">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-695.64941,-630.91601)"
|
||||
id="path31" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath33">
|
||||
<path
|
||||
d="M 0,841.89 H 1190.551 V 0 H 0 Z"
|
||||
transform="translate(-586.13182,-724.30372)"
|
||||
id="path33" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(55.737102,10.584888)">
|
||||
<g
|
||||
id="g2"
|
||||
transform="matrix(0.33637415,0,0,0.33637531,-22.728233,-7.6664558)">
|
||||
<g
|
||||
id="g4"
|
||||
transform="matrix(1,0.08748836,0,1,0,-13.741963)">
|
||||
<g
|
||||
id="g3"
|
||||
transform="matrix(4.2285533,0.709314,0,3.9031162,-138.7291,-356.0536)">
|
||||
<path
|
||||
id="path8"
|
||||
d="M 0,0 C -2.154,-1.758 -4.411757,-3.6103174 -4.654757,-6.6833174 -5.002757,-11.069317 -5.225,-26.661 -5.278,-28.301 c -0.156,-4.818 -0.91,-11.121 3.449,-11.455 2.497,-0.191 4.896,1.68 5.999,3.152 3.517,4.702 6.271,10.846 6.271,21.331 0,7.837 0,16.945 -7.097,16.945 C 2.318,1.672 0.683,0.556 0,0 m -8.541,14.641 c 1.224,0.128 2.603,-0.596 2.949,-1.627 C -5.16,11.74 -5.24,8.007 -5.388,6.608 -5.474,5.812 -5.386757,5.5585033 -5.366757,4.6026826 -4.911757,4.1026826 -1.422,9.842 7.684,9.842 c 1.785,0 3.602,-0.274 5.331,-1.097 5.65,-2.69 9.289,-9.932 9.289,-23.489 0,-13.451 -7.167,-23.544 -12.711,-27.113 -2.764,-1.781 -6.413,-2.786 -10.506,-2.982 -1.047,-0.052 -3.263,0.838 -4.068,-0.306 -0.808,-1.146 -0.752,-6.098 -0.784,-7.198 -0.636,-23.09 -2.436,-32.515 -8.061,-35.303 -1.462,-0.725 -3.279,-1.094 -3.462,-0.125 -0.119,0.627 0.223,1.005 1.326,2.159 1.936,2.025 1.936,4.089 2.237,8.845 0.394,6.211 -2.1,57.998 -2.745,66.803 -0.089,1.218 0.078,8.212 -1.932,8.337 -0.624,0.039 -2.932,-1.679 -4.981,-3.796 -0.623,-0.647 -2.892,-3.249 -3.318,-1.13 -0.591,2.961 9.664,17.473 15.822,20.483 0.737,0.36 1.523,0.626 2.338,0.711"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.35277776,0,0,-0.35277776,109.0012,80.514293)"
|
||||
clip-path="url(#clipPath9)"
|
||||
sodipodi:nodetypes="cccccsscccccscscccccccccccccc" />
|
||||
<path
|
||||
id="path18"
|
||||
d="m -2.083847,-15.3782 c 1.09699997,-0.567 1.23199997,-2.768 1.35599997,-3.724 C -0.14484703,-23.5652 0.89,-40.161 0.719,-42.935 c -0.028,-0.459 -0.136,-2.855 0.426,-3.02 0.587,-0.174 1.477,1.438 2.047,2.239 1.744,2.46 4.534,6.067 8.753,6.367 5.169,0.367 6.771,-7.318 6.807,-12.595 0.127,-19.937 0.136,-25.568 0.732,-28.546 0.152,-0.75 0.616,-2.093 1.552,-2.246 2.217,-0.362 2.281,3.391 4.202,3.673 3.139,0.461 0.769,-4.914 0.063,-6.256 -1.578,-2.994 -3.399,-4.997 -5.822,-6.055 -2.622,-1.146 -6.428,-0.619 -7.95,1.036 -1.894,2.06 -2.807,6.581 -3.115,10.447 -0.715,8.994 0.133,17.165 -0.523,25.596 -0.127,1.624 -0.476,3.634 -1.259,3.827 -0.709,0.174 -1.691,-0.993 -2.232,-1.65 -3.386,-4.118 -4.613,-7.971 -4.553,-14.743 0.062,-7.55 0.086,-16.816 -0.479,-21.698 -0.266,-2.283 -0.892,-5.289 -2.92,-6.983 -1.235,-1.033 -3.257,-1.667 -3.637,-0.41 -0.252,0.826 1.022,1.665 1.258,3.462 0.314,2.402 0.364,5.293 0.202,8.039 -0.705,11.868 -3.4622748,53.263246 -3.7332748,55.978246 -0.115,1.164 -0.16,3.353 -1.0850002,3.338 -1.649,-0.027 -3.358,-2.846 -4.208,-2.611 -0.163,0.046 -1.549,1.423 -1.561,2.004 -0.017,0.789 6.531428,6.539554 11.652428,8.267554 0.854,0.288 1.842,0.477 2.58,0.096"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.35277776,0,0,-0.35277776,120.10394,58.023656)"
|
||||
clip-path="url(#clipPath19)"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
id="path20"
|
||||
d="m 0,0 c -1.285,0.73 -2.063,-2.027 -3.419,-1.702 -1.206,0.289 -2.184,2.311 -2.261,5.547 -0.077,3.24 1.002,25.38 0.822,28.189 -0.314,4.956 -1.144,10.432 -5.613,9.541 -4.154,-0.829 -6.578,-4.075 -8.277,-7.174 -0.257,-0.464 -1.883,-4.205 -2.394,-4.161 -0.712,0.062 -0.831,1.552 -1.108,3.031 -0.293,1.569 -1.155,6.294 -3.83,6.813 C -35.842,41.98 -39.721803,15.721866 -40.709803,13.085866 -42.393803,8.5938655 -46.956,6.115 -50.109,2.892 c -1.552,-1.584 -4.103,-3.635 -6.301,-4.028 -2.929,-0.525 -6.1,0.741 -7.078,3.184 -2.903,7.235 5.263,11.141 10.071,7.326 2.052,-1.625 2.358556,-4.0246458 3.473556,-3.9396458 0.340399,0.025502 10.394963,7.4891328 7.819686,11.8289718 C -43.640979,20.124256 -45.396,22.592 -48.159,24.016 c -6.18,3.193 -14.641,1.58 -19.561,-3.837 -5.03,-5.541 -7.551,-19.725 3.871,-25.452 3.686,-1.851 8.626,-0.864 11.659,1.023 0.892,0.553 1.33,1.275 1.738,0.941 0.301,-0.246 0.144,-1.6 -0.045,-2.344 -1.936,-7.652 -5.925,-9.79 -9.519,-9.518 -5.771,0.435 -7.216,7.097 -7.772,8.415 -0.340893,0.2877357 -1.088666,0.153623 -2.434814,-0.097743 -1.352263,-0.2476709 -1.865247,-0.3457225 -1.897186,-1.233257 -0.184,-7.493 5.815,-17.814 16.77,-17.506 13.169,0.373 17.482977,19.0828386 16.152328,31.3184574 0.33679,2.5295247 2.181725,6.6436386 2.388869,8.1514086 0.925,3.881 1.274803,11.474134 3.059803,11.212134 1.188,-0.173 1.31,-2.994 1.436,-4.613 0.384,-4.847 1.755,-22.495 1.871,-24.551 0.411,-7.312 0.44,-13.968 -1.758,-19.643 -0.331,-0.855 -1.203,-2.766 -0.967,-3.181 0.656,-1.153 3.729,0.847 4.442,1.426 4.519,3.685 6.726,11.854 6.786,18.841 0.035,4.374 -0.394,14.162 0.303,22.633 0.35,4.24 2.105,9.62 4.342,12.434 0.401,0.503 0.754,1.131 1.602,0.927 0.402,-0.097 0.36,-1.291 0.376,-1.735 0.073,-2.347 -0.575,-23.962 -0.149,-31.126 0.089,-1.466 0.136,-2.773 0.562,-4.029 1.419,-4.188 6.357,-3.863 9.604,-1.672 1.88,1.268 4.968,4.757 5.574,6.775 C 0.748,-0.854 0.477,-0.271 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.35277776,0,0,-0.35277776,153.29405,73.277736)"
|
||||
clip-path="url(#clipPath21)"
|
||||
sodipodi:nodetypes="csscccccccccccccccccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
id="path24"
|
||||
d="m 0,0 c -1.097,0 -1.167,-0.584 -1.46,-1.951 -0.86,-4.029 -4.619,-9.789 -8.922,-9.647 -10.727,0.353 -10.364,26.953 -6.067,27.149 2.329,0.106 3.28,-4.098 3.124,-6.549 C -13.589,4.799 -16.91,0.3 -19.467,-1.146 l 1.011,-3.545 c 6.56,3.72 11.768,9.317 13.001,18.265 1.058,7.697 -2.329,13.892 -7.486,13.626 -11.015,-0.562 -15.465,-23.756 -14.121,-34.773 1.058,-8.686 6.676,-15.554 12.499,-15.781 7.202,-0.284 16.049,8.336 15.991,20.124 C 1.422,-1.986 1.058,0 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
transform="matrix(0.35277776,0,0,-0.35277776,162.2917,71.32908)"
|
||||
clip-path="url(#clipPath25)" />
|
||||
</g>
|
||||
<g
|
||||
id="g1"
|
||||
transform="matrix(3.5025645,0,0,3.5025645,-342.30908,-88.983443)">
|
||||
<path
|
||||
id="path10"
|
||||
d="m 0,0 c 3.925,0.872 3.57,-3.354 3.57,-6.841 0,-1.635 -0.207,-5.524 0.96,-3.111 1.514,3.13 4.049,7.805 7.407,9.203 6.321,2.633 9.019,-2.697 9.073,-8.939 0.029,-3.784 -0.636,-8.132 -1.171,-11.964 -0.337,-2.416 -0.401,-4.539 -0.789,-7.06 -0.39,-2.543 -0.893,-6.621 -0.789,-9.198 0.029,-0.763 0.431,-2.613 1.143,-2.695 0.896,-0.104 1.727,1.684 2.888,1.357 0.999,-0.282 0.783,-2.523 0.481,-3.744 -0.783,-3.177 -3.162,-6.581 -6.137,-8.024 -4.126,-1.999 -7.421,0.581 -7.95,4.513 -0.364,2.725 -0.071,5.917 0,8.753 0.151,6.14 0.842,12.296 0.96,18.572 0.039,2.128 0.098,5.378 -0.106,6.611 -0.612,3.661 -2.412,0.272 -3.544,-1.536 -4.536,-7.246 -2.774,-23.704 -3.454,-31.568 -0.42,-4.839 -1.053,-9.615 -2.946,-13.167 -0.944,-1.77 -2.545,-4.254 -4.526,-5.506 -0.534,-0.337 -1.418,-0.718 -1.808,-0.492 -1.052,0.61 -0.192,1.993 0.065,2.955 2.105,7.91 1.599,18.081 0.57,26.9 -1.376,11.784 -2.337,17.567 -3.372,17.654 -1.808,0.151 -2.284,-2.109 -2.704,-3.18 -0.366,-0.942 -0.407,-2.674 -1.063,-3.308 -1.129,-1.085 -2.838,-0.647 -3,0.98 -0.171,1.74 0.633,4.583 1.244,6.063 0.834,2.015 1.738,4.759 3.328,7.071 C -8.798,-5.532 -5.843,-1.299 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.43319446,0,0,-0.43319446,123.83195,24.587673)"
|
||||
clip-path="url(#clipPath11)" />
|
||||
<path
|
||||
id="path12"
|
||||
d="m 0,0 c 0.021,-3.813 -1.282,-6.979 -4.593,-8.786 -0.916,-0.501 -3.96,-0.944 -4.139,0.475 -0.086,0.655 1.069,1.335 1.241,1.905 0.883,2.926 -1.549,7.341 -3.113,8.546 -4.113,3.172 -3.717,-4.172 -3.2,-6.491 1.936,-8.697 9.983,-13.42 12.696,-21.315 1.146,-3.334 1.383,-8.728 -0.733,-12.606 -2.438,-4.469 -7.202,-8.301 -12.93,-7.417 -3.315,0.511 -5.635,2.602 -7.291,5.136 -0.764,1.169 -1.772,3.593 -2.068,5.15 -0.608,3.218 -1.008,6.621 -0.017,10.545 0.283,1.121 1.385,2.693 2.712,1.326 0.908,-0.935 0.848,-2.884 1.176,-4.025 1.076,-3.76 3.535,-7.992 9.109,-8.007 2.027,-0.004 4.504,1.12 5.148,4.731 0.562,3.152 -1.105,5.334 -4.749,8.528 -4.803,4.208 -11.579,9.774 -12.634,17.418 -1.15,8.33 4.58,13.286 10.352,14.367 C -5.408,10.909 -0.029,5.173 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.48633305,0,0,-0.48633305,154.66817,37.004843)"
|
||||
clip-path="url(#clipPath13)" />
|
||||
<path
|
||||
id="path14"
|
||||
d="M 0,0 C 1.936,0.131 4.997,4.963 7.001,3.663 9.303,2.163 6.288,-1.032 5.124,-1.933 3.685,-3.047 -0.328,-5.33 -0.701,-5.708 c -0.609,-0.615 -0.712,-3.539 -1.023,-5.105 -0.372,-1.899 -0.573,-4.061 -0.709,-5.302 -0.458,-4.194 -0.78,-7.523 -1.111,-10.7 -0.36,-3.428 -0.812,-6.933 -1.022,-10.292 -0.485,-7.701 -0.314,-13.466 1.379,-13.498 0.84,-0.016 1.52,1.099 1.797,1.866 0.553,1.541 1.96,2.617 2.279,-0.049 0.328,-2.763 -0.39,-5.375 -2.831,-7.046 -2.696,-1.849 -7.025,-1.678 -9.129,1.021 -1.23,1.578 -2.075,4.362 -2.328,6.551 -1.363,11.791 -0.057,25.255 0.076,37.936 -1.259,-0.094 -4.793,-1.402 -4.92,0.381 -0.112,1.524 4.288,1.549 4.926,2.533 0.148,0.224 0.422,6.621 0.396,7.67 -0.083,3.513 -1.731,3.905 -4.282,0.629 -0.807,-1.036 -1.809,-3.11 -2.784,-3.208 -2.092,-0.207 -0.695,4.252 -0.405,5.078 1.838,5.275 6.552,10.067 11.756,12.636 C -6.438,16.479 1.657,19.04 1.858,14.274 1.965,11.734 0.188,2.172 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.48633305,0,0,-0.48633305,162.75156,30.886171)"
|
||||
clip-path="url(#clipPath15)" />
|
||||
<path
|
||||
id="path16"
|
||||
d="m 0,0 c 0.907,-3.057 -0.429,-4.106 -2.049,-5.872 -1.587,-1.732 -4.09,-3.366 -5.928,-4.575 -0.961,-0.633 -3.336,-2.313 -4.199,-1.741 -0.65,0.429 -0.603,1.89 -0.727,2.701 -1.454,9.661 -10.61,7.909 -12.147,3.303 -1.308,-3.934 0.305,-6.556 1.992,-7.888 5.598,-4.419 14.422,0.621 18.391,3.492 3.644,2.635 6.342,5.997 8.751,9.881 0.833,1.345 1.584,2.633 2.443,4.312 0.906,1.764 3.1501254,5.648724 4.642451,5.1105435 C 12.827451,8.3985435 11.156,3.583 10.477,1.804 9.202,-1.547 6.173,-5.297 3.874,-8.024 2.99,-9.068 2.216,-9.394 1.894,-10.168 c -0.798,-1.931 -1.09,-5.486 -1.666,-7.587 -1.584,-5.79 -5.43,-11.105 -9.688,-14.504 -3.842,-3.064 -11.771,-4.529 -17.126,-1.44 -3.853,2.223 -5.813,6.126 -7.185,10.803 -0.369,1.249 -1.096,4.241 -0.177,4.7 1.088,0.547 2.252,-1.482 3.63,-1.987 1.483,-0.547 2.345,-0.027 3.035,-1.001 0.236,-0.331 0.351,-0.916 0.472,-1.365 0.447,-1.637 2.131,-6.983 6.233,-7.195 3.094,-0.158 5.91,3.3 7.027,9.265 0.104,0.547 0.311,1.073 0.086,1.277 -0.316,0.282 -3.111,-0.816 -7.335,-0.433 -7.746,0.708 -13.293,6.581 -10.344,15.206 1.374,4.018 4.3,7.195 7.703,9.446 C -12.759,12.087 -2.258,7.568 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.48633305,0,0,-0.48633305,179.03284,40.929077)"
|
||||
clip-path="url(#clipPath17)"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
id="path22"
|
||||
d="m 0,0 c 2.31,5.927 3.634,11.8 9.092,15.11 2.179,1.32 4.935,0.453 6.112,-5.339 0.686,-3.37 0.275,-8.924 -0.405,-11.782 -0.751,-3.165 -3.127,-8.504 -6.195,-9.697 -3.211,-1.247 -6.137,1.67 -4.778,4.874 0.228,0.542 1.112,1.807 1.545,2.163 1.033,0.853 3.296,1.327 3.287,2.814 C 8.649,-0.148 6.37,4.984 5.566,5 4.601,5.02 3.389,0.958 3.124,-0.031 2.127,-3.764 1.606,-8.298 1.521,-12.046 c -0.041,-1.781 -0.003,-3.696 0.112,-4.847 0.423,-4.227 0.884,-9.241 0.4,-13.801 -0.406,-3.833 -2.638,-8.263 -5.002,-9.983 -0.675,-0.49 -2.287,-1.346 -2.774,-0.641 -0.63,0.91 0.671,2.12 0.832,2.647 0.386,1.257 0.141,4.237 0.032,5.703 -0.353,4.775 -3.088,19.774 -3.838,22.974 -0.318,1.357 -1.08,4.493 -1.529,4.674 -1.383,0.56 -2.959,-2.576 -5.046,-7.089 -0.49,-1.064 -1.161,-2.907 -2.111,-3.182 -0.841,-0.243 -1.617,0.522 -1.285,2.004 0.148,0.651 0.38,1.209 0.63,2.091 1.605,5.649 6.118,13.458 10.881,16.508 0.947,0.606 2.344,1.164 3.34,1.478 C 0.446,7.837 -0.542,3.335 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.43319446,0,0,-0.43319446,111.75496,39.487396)"
|
||||
clip-path="url(#clipPath23)" />
|
||||
<path
|
||||
id="path26"
|
||||
d="m 0,0 c -1.37,-0.063 -1.423,-0.796 -1.707,-2.523 -0.839,-5.085 -5.201,-12.506 -10.585,-12.581 -13.434,-0.188 -14.537,33.084 -9.18,33.579 2.906,0.269 4.342,-4.931 4.291,-8.003 -0.086,-5.269 -3.971,-11.088 -7.084,-13.046 l 1.475,-4.371 c 7.979,5.034 14.162,12.337 15.176,23.592 0.875,9.683 -3.727,17.228 -10.155,16.596 -13.733,-1.352 -17.938,-30.601 -15.613,-44.294 1.834,-10.794 9.26,-19.05 16.549,-18.994 9.02,0.068 19.571,11.362 18.809,26.091 C 1.896,-2.399 1.324,0.062 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
transform="matrix(0.43319446,0,0,-0.43319446,106.52025,47.777527)"
|
||||
clip-path="url(#clipPath27)" />
|
||||
<path
|
||||
id="path28"
|
||||
d="m 0,0 c -0.095,0.739 -0.497,2.052 -1.649,1.556 -0.505,-0.217 -0.976,-1.398 -1.28,-2.101 -0.71,-1.645 -2.326,-5.998 -6.2,-6.18 -3.109,-0.146 -6.517,2.627 -7.43,9.194 -1.471,10.57 1.017,18.32 4.945,18.505 2.961,0.139 3.468,-5.242 2.348,-9.432 -0.865,-3.236 -4.027,-9.097 -7.834,-9.593 0,0 -5.886,-5.648 0.934,-3.348 6.821,2.297 12.342,10.015 14.053,16.059 1.865,6.583 -0.406,15.166 -7.583,14.098 -1.8,-0.268 -3.588,-1.426 -4.962,-2.778 -5.888,-5.797 -10.353,-17.034 -8.952,-28.311 0.907,-7.287 4.855,-15.163 12.788,-14.686 6.661,0.402 9.805,9.514 10.577,13.543 C -0.03,-2.339 0.106,-0.842 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
transform="matrix(0.43319446,0,0,-0.43319446,143.43738,41.147831)"
|
||||
clip-path="url(#clipPath29)" />
|
||||
<path
|
||||
id="path30"
|
||||
d="m -8.7450691,0.39360726 c -1.245,-3.24299946 -6.5109999,-6.58699956 -6.9369999,-1.69599946 -0.198,2.28299946 3.104,6.984999 4.957,7.281999 2.0879999,0.337 3.2739999,-2.1989995 1.9799999,-5.58599954 M 1.754931,35.431907 c -0.713,0 -0.98999997,-0.774 -2.41799997,-2.621 -5.93900013,-7.685 -24.08500003,-20.733 -43.02900003,-23.0360002 -10.725,-1.305 -29.499,4.1817002 -46.279,-16.997299 -1.981,-2.4980001 -6.485812,-4.1358138 -9.711812,-5.1498138 -8.022999,-2.521 -8.204869,-2.555763 -14.225119,-2.206094 0.879,9.4250005 6.639,13.2043 9.023,30.1983 6.23,44.389 -3.518,65.259 -20.458,74.016 -3.267,1.689 -7.525,0.328 -10.192,-3.499 -4.341,-6.229 -15.647,-29.199 -14.462,-32.325 0.846,-2.239 2.822,-1.116 3.788,1.38 1.384,3.576 2.537,6.739 4.986,8.493 5.785,4.141 26.651,-3.384 24.812,-41.597 -1.806,-37.519 -14.669,-28.9442335 -34.264,-55.747234 -0.736,-1.008 -2.709,-3.678 -2.566,-5.321 0.09,-1.017 1.894,-2.054 2.926,-1.855 1.50524,0.295166 20.77475,14.471564 27.739,11.214701 3.003,-3.295 5.813,-8.161 7.137,-13.427 0.469,-1.872 1.357,-3.666 3.571,-2.263 0.738,0.469 0.923,2.082 0.873,3.684 -0.74438,20.931327 11.454466,22.107387 27.586223,23.165092 13.212,0.288 36.288708,-9.832952 57.855708,-0.08695 21.1369999,9.5529998 33.454,23.5632988 30.177,46.726299 -0.224,1.583 -1.06,7.253 -2.869,7.254"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.35277776,0.03086395,0,-0.35277776,123.77659,67.893825)"
|
||||
clip-path="url(#clipPath31)"
|
||||
sodipodi:nodetypes="ccccccccccccccscccccccccccsc" />
|
||||
<path
|
||||
id="path32"
|
||||
d="m 0,0 c -2.698,2.946 -3.368,6.526 -0.642,9.179 4.794,4.657 13.982,-0.46 16.613,-8.334 1.477,-4.424 1.858,-13.089 -6.975,-20.765 -1.016,-0.819 -2.53,0.361 -1.537,1.751 1.289,1.796 2.894,6.835 0.36,11.53 C 5.872,-3.035 2.29,-2.505 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
transform="matrix(0.35277776,0,0,-0.35277776,85.003826,32.951646)"
|
||||
clip-path="url(#clipPath33)" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 24 KiB |
|
@ -2,9 +2,9 @@
|
|||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="48.156189"
|
||||
height="19.813145"
|
||||
viewBox="0 0 48.156189 19.813145"
|
||||
width="150"
|
||||
height="62"
|
||||
viewBox="0 0 150 62.000003"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
|
@ -26,15 +26,16 @@
|
|||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="17.146626"
|
||||
inkscape:cx="23.124083"
|
||||
inkscape:cy="15.629897"
|
||||
inkscape:zoom="3.292102"
|
||||
inkscape:cx="-7.290175"
|
||||
inkscape:cy="60.447701"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-height="1055"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g1" />
|
||||
inkscape:current-layer="g4"
|
||||
showgrid="false" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<clipPath
|
||||
|
@ -274,7 +275,7 @@
|
|||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-6.3894695,-9.7672879)">
|
||||
transform="translate(43.610527,10.590344)">
|
||||
<g
|
||||
id="g2"
|
||||
transform="matrix(0.33637415,0,0,0.33637531,-22.728233,-7.6664558)">
|
||||
|
@ -283,7 +284,7 @@
|
|||
transform="matrix(1,0.08748836,0,1,0,-13.741963)">
|
||||
<g
|
||||
id="g3"
|
||||
transform="matrix(0.86859292,0.14570116,0,0.80174446,88.322932,-16.382563)">
|
||||
transform="matrix(2.7055492,0.45383937,0,2.4973253,-56.59998,-220.77782)">
|
||||
<path
|
||||
id="path8"
|
||||
d="m 0,0 c -2.154,-1.758 -4.433,-5.061 -4.676,-8.134 -0.348,-4.386 -0.549,-18.527 -0.602,-20.167 -0.156,-4.818 -0.91,-11.121 3.449,-11.455 2.497,-0.191 4.896,1.68 5.999,3.152 3.517,4.702 6.271,10.846 6.271,21.331 0,7.837 0,16.945 -7.097,16.945 C 2.318,1.672 0.683,0.556 0,0 m -8.541,14.641 c 1.224,0.128 2.603,-0.596 2.949,-1.627 0.432,-1.274 0.352,-5.007 0.204,-6.406 -0.086,-0.796 -0.02,-3.436 0,-3.456 0.455,-0.5 3.966,6.69 13.072,6.69 1.785,0 3.602,-0.274 5.331,-1.097 5.65,-2.69 9.289,-9.932 9.289,-23.489 0,-13.451 -7.167,-23.544 -12.711,-27.113 -2.764,-1.781 -6.413,-2.786 -10.506,-2.982 -1.047,-0.052 -3.263,0.838 -4.068,-0.306 -0.808,-1.146 -0.752,-6.098 -0.784,-7.198 -0.636,-23.09 -2.436,-32.515 -8.061,-35.303 -1.462,-0.725 -3.279,-1.094 -3.462,-0.125 -0.119,0.627 0.223,1.005 1.326,2.159 1.936,2.025 1.936,4.089 2.237,8.845 0.394,6.211 -2.1,57.998 -2.745,66.803 -0.089,1.218 0.078,8.212 -1.932,8.337 -0.624,0.039 -2.932,-1.679 -4.981,-3.796 -0.623,-0.647 -2.892,-3.249 -3.318,-1.13 -0.591,2.961 9.664,17.473 15.822,20.483 0.737,0.36 1.523,0.626 2.338,0.711"
|
||||
|
@ -313,7 +314,7 @@
|
|||
</g>
|
||||
<g
|
||||
id="g1"
|
||||
transform="translate(16.849468,27.462558)">
|
||||
transform="matrix(3.1148646,0,0,3.1148646,-279.23013,-84.206213)">
|
||||
<path
|
||||
id="path10"
|
||||
d="m 0,0 c 3.925,0.872 3.57,-3.354 3.57,-6.841 0,-1.635 -0.207,-5.524 0.96,-3.111 1.514,3.13 4.049,7.805 7.407,9.203 6.321,2.633 9.019,-2.697 9.073,-8.939 0.029,-3.784 -0.636,-8.132 -1.171,-11.964 -0.337,-2.416 -0.401,-4.539 -0.789,-7.06 -0.39,-2.543 -0.893,-6.621 -0.789,-9.198 0.029,-0.763 0.431,-2.613 1.143,-2.695 0.896,-0.104 1.727,1.684 2.888,1.357 0.999,-0.282 0.783,-2.523 0.481,-3.744 -0.783,-3.177 -3.162,-6.581 -6.137,-8.024 -4.126,-1.999 -7.421,0.581 -7.95,4.513 -0.364,2.725 -0.071,5.917 0,8.753 0.151,6.14 0.842,12.296 0.96,18.572 0.039,2.128 0.098,5.378 -0.106,6.611 -0.612,3.661 -2.412,0.272 -3.544,-1.536 -4.536,-7.246 -2.774,-23.704 -3.454,-31.568 -0.42,-4.839 -1.053,-9.615 -2.946,-13.167 -0.944,-1.77 -2.545,-4.254 -4.526,-5.506 -0.534,-0.337 -1.418,-0.718 -1.808,-0.492 -1.052,0.61 -0.192,1.993 0.065,2.955 2.105,7.91 1.599,18.081 0.57,26.9 -1.376,11.784 -2.337,17.567 -3.372,17.654 -1.808,0.151 -2.284,-2.109 -2.704,-3.18 -0.366,-0.942 -0.407,-2.674 -1.063,-3.308 -1.129,-1.085 -2.838,-0.647 -3,0.98 -0.171,1.74 0.633,4.583 1.244,6.063 0.834,2.015 1.738,4.759 3.328,7.071 C -8.798,-5.532 -5.843,-1.299 0,0"
|
||||
|
@ -371,7 +372,7 @@
|
|||
clip-path="url(#clipPath33)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:7.92767px;line-height:1.25;font-family:sans-serif;text-align:end;text-anchor:end;white-space:pre;inline-size:102.756;fill:#ffffff;fill-opacity:1;stroke-width:2.97287"
|
||||
style="font-size:7.92767px;line-height:1.25;font-family:sans-serif;text-align:end;text-anchor:end;white-space:pre;inline-size:102.756;display:inline;fill:#ffffff;fill-opacity:1;stroke-width:2.97287"
|
||||
x="213.26958"
|
||||
y="73.687592"
|
||||
id="logo"
|
||||
|
@ -379,16 +380,16 @@
|
|||
class="logo-subtitle"><tspan
|
||||
x="213.26958"
|
||||
y="73.687592"
|
||||
id="tspan2"><tspan
|
||||
style="font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans'"
|
||||
id="tspan1">La fanfare de l'École</tspan><tspan
|
||||
y="73.687592"
|
||||
id="tspan3"> </tspan></tspan><tspan
|
||||
id="tspan7"><tspan
|
||||
style="font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans'"
|
||||
id="tspan5">La fanfare de l'École</tspan><tspan
|
||||
y="73.687592"
|
||||
id="tspan8"> </tspan></tspan><tspan
|
||||
x="213.26958"
|
||||
y="83.750981"
|
||||
id="tspan6"><tspan
|
||||
id="tspan10"><tspan
|
||||
style="font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans'"
|
||||
id="tspan4">normale supérieure de Paris</tspan></tspan></text>
|
||||
id="tspan9">normale supérieure de Paris</tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
38
shared/static/js/common.js
Normal file
38
shared/static/js/common.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// Get all "navbar-burger" elements
|
||||
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
|
||||
|
||||
// Add a click event on each of them
|
||||
$navbarBurgers.forEach( el => {
|
||||
el.addEventListener('click', () => {
|
||||
|
||||
// Get the target from the "data-target" attribute
|
||||
const target = el.dataset.target;
|
||||
const $target = document.getElementById(target);
|
||||
|
||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||
el.classList.toggle('is-active');
|
||||
$target.classList.toggle('is-active');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const $deleteElems = Array.prototype.slice.call(document.querySelectorAll('.delete'), 0);
|
||||
|
||||
// Add a click event on each of them
|
||||
$deleteElems.forEach( el => {
|
||||
el.addEventListener('click', () => {
|
||||
// Get the target from the "data-target" attribute
|
||||
if ('target' in el.dataset) {
|
||||
const target = el.dataset.target;
|
||||
const $target = document.getElementById(target);
|
||||
$target.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -1,7 +1,5 @@
|
|||
{% load django_browser_reload %}
|
||||
{% load i18n %}
|
||||
|
||||
<footer class="footer has-text-centered">
|
||||
<b>{% translate "Logiciel développé pour et par l'Ernestophone." %}</b>
|
||||
{% django_browser_reload_script %}
|
||||
</footer>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load auth_extra %}
|
||||
<nav class="navbar is-primary" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="https://buma.io">
|
||||
<img src="{% static "icons/ernesto-white-long.svg" %}"/>
|
||||
<a class="navbar-item py-0" href="{% url "home" %}" >
|
||||
{# TODO: Rename #}
|
||||
<img src="{% static "icons/ernesto-white-long-bis.svg" %}"/>
|
||||
</a>
|
||||
|
||||
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="mainNavbar">
|
||||
|
@ -16,28 +18,38 @@
|
|||
|
||||
<div id="mainNavbar" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item">
|
||||
Home
|
||||
<a href="{% url "home" %}" class="navbar-item">
|
||||
{% trans "Accueil" %}
|
||||
</a>
|
||||
|
||||
<a class="navbar-item">
|
||||
Documentation
|
||||
<a href="#{# TODO #}" class="navbar-item">
|
||||
{% trans "Agenda" %}
|
||||
</a>
|
||||
|
||||
<a href="#{# TODO #}" class="navbar-item">
|
||||
{% trans "Répertoire" %}
|
||||
</a>
|
||||
|
||||
<a href="{% url "home" %}#contact" class="navbar-item">
|
||||
{% trans "Contact" %}
|
||||
</a>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<a href="#{# TODO #}" class="navbar-item">
|
||||
{% trans "Le pouvoir des ernestos" %}
|
||||
</a>
|
||||
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link">
|
||||
Le pouvoir des chef·fe·s
|
||||
{% trans "Le pouvoir des chef·fe·s" %}
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown">
|
||||
<a class="navbar-item">
|
||||
Administration
|
||||
<a href="{% url "admin:index" %}" class="navbar-item">
|
||||
{% trans "Administration" %}
|
||||
</a>
|
||||
<a class="navbar-item is-selected">
|
||||
Test
|
||||
</a>
|
||||
<a class="navbar-item">
|
||||
Contact
|
||||
<a href="#{# TODO #}" class="navbar-item">
|
||||
{% trans "TODO" %}
|
||||
</a>
|
||||
<hr class="navbar-divider">
|
||||
<a class="navbar-item">
|
||||
|
@ -45,24 +57,51 @@
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="navbar-end">
|
||||
{% if user.is_authenticated %}
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link button is-link has-text-white">
|
||||
<span class="icon"> <i class="ti ti-user"></i> </span>
|
||||
<span>{{ user.username }}</span>
|
||||
</a>
|
||||
<div class="navbar-dropdown is-right">
|
||||
<div class="dropdown-content">
|
||||
<a href="{% url "ernestoprofil:edit-user" %}" class="navbar-item">{% trans "Modifier mon profil" %}</a>
|
||||
{% if not user|has_group:"Ernestophoniste" %}
|
||||
<a href="{% url "ernestoprofil:become-ernesto" %}" class="navbar-item">{% trans "Devenir fanfaron" %}</a>
|
||||
{% endif %}
|
||||
|
||||
<hr class="navbar-divider" />
|
||||
<form class="navbar-item" action="{% url "ernestoprofil:logout" %}">
|
||||
{% csrf_token %}
|
||||
<button class="button is-link is-size-6" type="submit">
|
||||
<span>{% trans "Se déconnecter" %}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%else%}
|
||||
<div class="navbar-item">
|
||||
<div class="buttons">
|
||||
<a class="button is-link has-text-white">
|
||||
<strong>
|
||||
Créer un compte
|
||||
<span class="icon">
|
||||
<i class="ti ti-door-enter"></i>
|
||||
</span>
|
||||
</strong>
|
||||
<a href="{% url "ernestoprofil:create-user" %}" class="button is-link has-text-white icon-text">
|
||||
<span>{% trans "Créer un compte" %}</span>
|
||||
<span class="icon">
|
||||
<i class="ti ti-user-plus"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-light">
|
||||
Se connecter
|
||||
<a href="{% url "authens:login" %}" class="button is-light">
|
||||
<span>{% trans "Se connecter" %}</span>
|
||||
<span class="icon">
|
||||
<i class="ti ti-door-enter"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load auth_extra %}
|
||||
{% load django_browser_reload %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
|
@ -6,7 +9,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="keywords" content="fanfare,Ernestophone,Brass Band,ENS,École Normale Supérieure" />
|
||||
<meta name="description" content="{% blocktranslate %}Site web de l'Ernestophone, la fanfare de l'École Normale Supérieure de Paris{% endblocktranslate %}" />
|
||||
<title>{% translate "L'Ernestophone" %}</title>
|
||||
<title>{% block title %}{% translate "L'Ernestophone" %}{% endblock %}</title>
|
||||
|
||||
{% include "_links.html" %}
|
||||
</head>
|
||||
|
@ -14,9 +17,34 @@
|
|||
<body>
|
||||
{% include "_nav.html" %}
|
||||
|
||||
<section id="notifications" class="section py-0">
|
||||
{% if user.is_authenticated and not user|has_group:"Ernestophoniste" and request.resolver_match.view_name != "ernestoprofil:become-ernesto" %}
|
||||
<div class="content notification is-warning my-2" id="message-{{ forloop.counter0 }}">
|
||||
<button class="delete" data-target="message-{{ forloop.counter0 }}"></button>
|
||||
{% blocktranslate %}Vous n'êtes pas encore considérés comme fanfaron par le site. Pour le devenir, cliquez sur{% endblocktranslate %}
|
||||
<a href="{% url "ernestoprofil:become-ernesto" %}">{% trans "ce lien" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# TODO add warning for pupitre #}
|
||||
{% for message in messages %}
|
||||
<div class="notification {{ message.level_tag }} my-2" id="message-{{ forloop.counter0 }}">
|
||||
<button class="delete" data-target="message-{{ forloop.counter0 }}"></button>
|
||||
{% if 'safe' in message.tags %}
|
||||
{{ message|safe }}
|
||||
{% else %}
|
||||
{{ message }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
|
||||
{% include "_footer.html" %}
|
||||
<script src="{% static "js/common.js" %}" defer></script>
|
||||
{% block extra_scripts %}
|
||||
{% endblock extra_scripts %}
|
||||
{# TODO: Add analytics #}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -43,10 +43,11 @@
|
|||
<section id="contact" class="section content">
|
||||
<h1 class="has-text-centered">Nous contacter</h1>
|
||||
<p>
|
||||
Vous préparez un évenement et vous recherchez une fanfare dynamique ? N'hésitez pas à nous envoyer un message par mail ou sur Facebook. Nous serons ravis de venir fanfaronner pour vous !!
|
||||
Vous préparez un évenement et vous recherchez une fanfare dynamique ? N'hésitez pas à nous envoyer un message par mail (<span class="tag">fanfare (at) ens.psl.eu</span>) ou sur Facebook. Nous serons ravis de venir fanfaronner pour vous !!
|
||||
</p>
|
||||
<hr/>
|
||||
<div class="level">
|
||||
{# TODO: Fill #}
|
||||
<div class="level-item has-text-centered">
|
||||
<a class="title">
|
||||
<span class="icon">
|
||||
|
@ -68,8 +69,8 @@
|
|||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<a class="title">
|
||||
<div class="level-item has-text-centered" href="mailto:fanfare@ens.psl.eu">
|
||||
<a class="title" href="mailto:fanfare@ens.psl.eu">
|
||||
<span class="icon">
|
||||
<i class="ti ti-mail"></i>
|
||||
</span>
|
||||
|
|
23
shared/templates/simple_form.html
Normal file
23
shared/templates/simple_form.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{# TODO: Add hero #}
|
||||
<section class="section">
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "bulma/form.html" with errors=True %}
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" type="submit">
|
||||
<span>{{ submit }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
8
shared/templatetags/auth_extra.py
Normal file
8
shared/templatetags/auth_extra.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def has_group(user, group_name):
|
||||
return user.groups.filter(name=group_name).exists()
|
Loading…
Add table
Add a link
Reference in a new issue