8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 14:42:25 +00:00

Deplace dans preferences les reglages concernant l'associtation (partie 1)

This commit is contained in:
Gabriel Detraz 2017-08-24 21:36:59 +02:00 committed by chirac
parent 63a5fb41b9
commit 8fda3b1ac7
19 changed files with 378 additions and 55 deletions

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-18 23:04
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cotisations', '0020_auto_20170819_0057'),
]
operations = [
migrations.AlterField(
model_name='paiement',
name='type_paiement',
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-23 23:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cotisations', '0021_auto_20170819_0104'),
]
operations = [
migrations.AlterField(
model_name='paiement',
name='type_paiement',
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255),
),
]

View file

@ -41,9 +41,9 @@ from .models import Facture, Article, Vente, Cotisation, Paiement, Banque
from .forms import NewFactureForm, TrezEditFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm, NewFactureFormPdf, CreditSoldeForm, SelectArticleForm
from users.models import User
from .tex import render_tex
from re2o.settings import ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH
from re2o.settings import LOGO_PATH
from re2o import settings
from preferences.models import OptionalUser, GeneralOption
from preferences.models import OptionalUser, AssoOption, GeneralOption
from dateutil.relativedelta import relativedelta
from django.utils import timezone
@ -111,6 +111,7 @@ def new_facture(request, userid):
def new_facture_pdf(request):
facture_form = NewFactureFormPdf(request.POST or None)
if facture_form.is_valid():
options, created = AssoOption.objects.get_or_create()
tbl = []
article = facture_form.cleaned_data['article']
quantite = facture_form.cleaned_data['number']
@ -122,7 +123,7 @@ def new_facture_pdf(request):
tbl.append([a, quantite, a.prix * quantite])
prix_total = sum(a[2] for a in tbl)
user = {'name':destinataire, 'room':chambre}
return render_tex(request, 'cotisations/factures.tex', {'DATE' : timezone.now(),'dest':user,'fid':fid, 'article':tbl, 'total':prix_total, 'paid':paid, 'asso_name':ASSO_NAME, 'line1':ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)})
return render_tex(request, 'cotisations/factures.tex', {'DATE' : timezone.now(),'dest':user,'fid':fid, 'article':tbl, 'total':prix_total, 'paid':paid, 'asso_name':options.name, 'line1':options.adresse1, 'line2':options.adresse2, 'siret':options.siret, 'email':options.contact, 'phone':options.telephone, 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)})
return form({'factureform': facture_form}, 'cotisations/facture.html', request)
@login_required
@ -140,9 +141,10 @@ def facture_pdf(request, factureid):
return redirect("/users/profil/" + str(request.user.id))
vente = Vente.objects.all().filter(facture=facture)
ventes = []
options, created = AssoOption.objects.get_or_create()
for v in vente:
ventes.append([v, v.number, v.prix_total])
return render_tex(request, 'cotisations/factures.tex', {'paid':True, 'fid':facture.id, 'DATE':facture.date,'dest':facture.user, 'article':ventes, 'total': facture.prix_total(), 'asso_name':ASSO_NAME, 'line1': ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path':os.path.join(settings.BASE_DIR, LOGO_PATH)})
return render_tex(request, 'cotisations/factures.tex', {'paid':True, 'fid':facture.id, 'DATE':facture.date,'dest':facture.user, 'article':ventes, 'total': facture.prix_total(), 'asso_name':options.name, 'line1': options.adresse1, 'line2':options.adresse2, 'siret':options.siret, 'email':options.contact, 'phone':options.telephone, 'tpl_path':os.path.join(settings.BASE_DIR, LOGO_PATH)})
@login_required
@permission_required('cableur')

View file

@ -334,6 +334,7 @@ def machine_post_save(sender, **kwargs):
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
regen('dhcp')
regen('dns')
regen('mac_ip_list')
@receiver(post_delete, sender=Machine)
def machine_post_delete(sender, **kwargs):
@ -348,6 +349,7 @@ def interface_post_save(sender, **kwargs):
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
regen('dhcp')
regen('dns')
regen('mac_ip_list')
@receiver(post_delete, sender=Interface)
def interface_post_delete(sender, **kwargs):

View file

@ -1,3 +1,47 @@
from django.contrib import admin
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Register your models here.
from django.contrib import admin
from reversion.admin import VersionAdmin
from .models import OptionalUser, OptionalMachine, GeneralOption, Service, AssoOption
class OptionalUserAdmin(VersionAdmin):
pass
class OptionalMachineAdmin(VersionAdmin):
pass
class GeneralOptionAdmin(VersionAdmin):
pass
class ServiceAdmin(VersionAdmin):
pass
class AssoOptionAdmin(VersionAdmin):
pass
admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin)
admin.site.register(GeneralOption, GeneralOptionAdmin)
admin.site.register(Service, ServiceAdmin)
admin.site.register(AssoOption, AssoOptionAdmin)

View file

@ -22,38 +22,48 @@
from django.forms import ModelForm, Form, ValidationError
from django import forms
from .models import OptionalUser, OptionalMachine, GeneralOption
from .models import OptionalUser, OptionalMachine, GeneralOption, AssoOption, Service
from django.db.models import Q
class EditUserOptionsForm(ModelForm):
class EditOptionalUserForm(ModelForm):
class Meta:
model = OptionalUser
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EditUserOptionsForm, self).__init__(*args, **kwargs)
super(EditOptionalUserForm, self).__init__(*args, **kwargs)
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de téléphone'
self.fields['user_solde'].label = 'Activation du solde pour les utilisateurs'
class EditMachineOptionsForm(ModelForm):
class EditOptionalMachineForm(ModelForm):
class Meta:
model = OptionalMachine
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EditMachineOptionsForm, self).__init__(*args, **kwargs)
super(EditOptionalMachineForm, self).__init__(*args, **kwargs)
self.fields['password_machine'].label = "Possibilité d'attribuer un mot de passe par interface"
self.fields['max_lambdauser_interfaces'].label = "Maximum d'interfaces autorisées pour un user normal"
self.fields['max_lambdauser_aliases'].label = "Maximum d'alias dns autorisés pour un user normal"
class EditGeneralOptionsForm(ModelForm):
class EditGeneralOptionForm(ModelForm):
class Meta:
model = GeneralOption
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EditGeneralOptionsForm, self).__init__(*args, **kwargs)
super(EditGeneralOptionForm, self).__init__(*args, **kwargs)
self.fields['search_display_page'].label = 'Resultats affichés dans une recherche'
self.fields['pagination_number'].label = 'Items par page, taille normale (ex users)'
self.fields['pagination_large_number'].label = 'Items par page, taille élevée (machines)'
class EditAssoOptionForm(ModelForm):
class Meta:
model = AssoOption
fields = '__all__'
class Service(ModelForm):
class Meta:
model = Service
fields = '__all__'

View file

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-23 23:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0003_optionaluser_solde_negatif'),
]
operations = [
migrations.CreateModel(
name='AssoOption',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default="Association réseau de l'école machin", max_length=32)),
('siret', models.CharField(default='00000000000000', max_length=32)),
('adresse', models.CharField(default="1 Rue de l'exemple, 94230 Cachan", max_length=128)),
('contact', models.EmailField(default='contact@example.org', max_length=254)),
('telephone', models.CharField(default='0000000000', max_length=15)),
('pseudo', models.CharField(default='Asso', max_length=32)),
],
),
migrations.CreateModel(
name='Services',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=32)),
('url', models.URLField()),
('description', models.TextField()),
('image', models.ImageField(upload_to='logo')),
],
),
]

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-23 23:39
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('preferences', '0004_assooption_services'),
]
operations = [
migrations.RenameModel(
old_name='Services',
new_name='Service',
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-23 23:43
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0005_auto_20170824_0139'),
]
operations = [
migrations.AlterField(
model_name='service',
name='image',
field=models.ImageField(blank=True, upload_to='logo'),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-24 18:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0006_auto_20170824_0143'),
]
operations = [
migrations.AlterField(
model_name='assooption',
name='name',
field=models.CharField(default="Association réseau de l'école machin", max_length=256),
),
]

View file

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-24 19:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0007_auto_20170824_2056'),
]
operations = [
migrations.RemoveField(
model_name='assooption',
name='adresse',
),
migrations.AddField(
model_name='assooption',
name='adresse1',
field=models.CharField(default='1 Rue de exemple', max_length=128),
),
migrations.AddField(
model_name='assooption',
name='adresse2',
field=models.CharField(default='94230 Cachan', max_length=128),
),
migrations.AlterField(
model_name='assooption',
name='name',
field=models.CharField(default='Association réseau école machin', max_length=256),
),
]

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-08-24 19:35
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('preferences', '0008_auto_20170824_2122'),
]
operations = [
migrations.AddField(
model_name='assooption',
name='utilisateur_asso',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

View file

@ -25,6 +25,8 @@ from django.db import models
from cotisations.models import Paiement
class OptionalUser(models.Model):
PRETTY_NAME = "Options utilisateur"
is_tel_mandatory = models.BooleanField(default=True)
user_solde = models.BooleanField(default=False)
solde_negatif = models.DecimalField(max_digits=5, decimal_places=2, default=0)
@ -35,6 +37,8 @@ class OptionalUser(models.Model):
Paiement.objects.get_or_create(moyen="Solde")
class OptionalMachine(models.Model):
PRETTY_NAME = "Options machines"
password_machine = models.BooleanField(default=False)
max_lambdauser_interfaces = models.IntegerField(default=10)
max_lambdauser_aliases = models.IntegerField(default=10)
@ -43,7 +47,26 @@ class OptionalMachine(models.Model):
class GeneralOption(models.Model):
PRETTY_NAME = "Options générales"
search_display_page = models.IntegerField(default=15)
pagination_number = models.IntegerField(default=25)
pagination_large_number = models.IntegerField(default=8)
class Service(models.Model):
name = models.CharField(max_length=32)
url = models.URLField()
description = models.TextField()
image = models.ImageField(upload_to='logo', blank=True)
class AssoOption(models.Model):
PRETTY_NAME = "Options de l'association"
name = models.CharField(default="Association réseau école machin", max_length=256)
siret = models.CharField(default="00000000000000", max_length=32)
adresse1 = models.CharField(default="1 Rue de exemple", max_length=128)
adresse2 = models.CharField(default="94230 Cachan", max_length=128)
contact = models.EmailField(default="contact@example.org")
telephone = models.CharField(max_length=15, default="0000000000")
pseudo = models.CharField(default="Asso", max_length=32)
utilisateur_asso = models.OneToOneField('users.User', on_delete=models.PROTECT, blank=True, null=True)

View file

@ -28,13 +28,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}Création et modification des préférences{% endblock %}
{% block content %}
<h4>Préférences utilisateur</h4>
{% if is_bureau %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' %}">
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalUser' %}">
<i class="glyphicon glyphicon-edit"></i>
Editer
</a>
{% endif %}
<h4>Préférences utilisateur</h4>
<p>
</p>
<table class="table table-striped">
<tr>
<th>Téléphone obligatoirement requis</th>
@ -48,6 +50,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</tr>
</table>
<h4>Préférences machines</h4>
{% if is_bureau %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalMachine' %}">
<i class="glyphicon glyphicon-edit"></i>
Editer
</a>
{% endif %}
<p>
</p>
<table class="table table-striped">
<tr>
<th>Mot de passe par machine</th>
@ -61,6 +71,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</tr>
</table>
<h4>Préférences generales</h4>
{% if is_bureau %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}">
<i class="glyphicon glyphicon-edit"></i>
Editer
</a>
{% endif %}
<p>
</p>
<table class="table table-striped">
<tr>
<th>Affichage de résultats dans le champ de recherche</th>
@ -73,6 +91,39 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td>{{ generaloptions.pagination_large_number }}</td>
</tr>
</table>
<h4>Données de l'association</h4>
{% if is_bureau %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'AssoOption' %}">
<i class="glyphicon glyphicon-edit"></i>
Editer
</a>
{% endif %}
<p>
</p>
<table class="table table-striped">
<tr>
<th>Nom</th>
<td>{{ assooptions.name }}</td>
<th>SIRET</th>
<td>{{ assooptions.siret }}</td>
</tr>
<tr>
<th>Adresse</th>
<td>{{ assooptions.adresse1 }} {{ assooptions.adresse2 }}</td>
<th>Contact mail</th>
<td>{{ assooptions.contact }}</td>
</tr>
<tr>
<th>Telephone</th>
<td>{{ assooptions.telephone }}</td>
<th>Pseudo d'usage</th>
<td>{{ assooptions.pseudo }}</td>
</tr>
<tr>
<th>Objet utilisateur de l'association</th>
<td>{{ assooptions.utilisateur_asso }}</td>
</tr>
</table>
<br />
<br />
<br />

View file

@ -28,15 +28,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}Création et modification des préférences{% endblock %}
{% block content %}
{% bootstrap_form_errors useroptions %}
{% bootstrap_form_errors machineoptions %}
{% bootstrap_form_errors generaloptions %}
{% bootstrap_form_errors options %}
<h3>Edition des préférences</h3>
<form class="form" method="post">
{% csrf_token %}
{% bootstrap_form useroptions %}
{% bootstrap_form machineoptions %}
{% bootstrap_form generaloptions %}
{% bootstrap_form options %}
{% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %}
</form>
<br />

View file

@ -26,6 +26,9 @@ from . import views
urlpatterns = [
url(r'^edit_options/$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>OptionalUser)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>OptionalMachine)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>GeneralOption)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>AssoOption)$', views.edit_options, name='edit-options'),
url(r'^$', views.display_options, name='display-options'),
]

View file

@ -42,8 +42,9 @@ from django.db import transaction
from reversion.models import Version
from reversion import revisions as reversion
from .forms import EditUserOptionsForm, EditMachineOptionsForm, EditGeneralOptionsForm
from .models import OptionalUser, OptionalMachine, GeneralOption
from .models import OptionalUser, OptionalMachine, AssoOption, GeneralOption
from . import models
from . import forms
def form(ctx, template, request):
c = ctx
@ -57,35 +58,27 @@ def display_options(request):
useroptions, created = OptionalUser.objects.get_or_create()
machineoptions, created = OptionalMachine.objects.get_or_create()
generaloptions, created = GeneralOption.objects.get_or_create()
return form({'useroptions': useroptions, 'machineoptions': machineoptions, 'generaloptions': generaloptions}, 'preferences/display_preferences.html', request)
assooptions, crated = AssoOption.objects.get_or_create()
return form({'useroptions': useroptions, 'machineoptions': machineoptions, 'generaloptions': generaloptions, 'assooptions' : assooptions}, 'preferences/display_preferences.html', request)
@login_required
@permission_required('admin')
def edit_options(request):
def edit_options(request, section):
""" Edition des préférences générales"""
useroptions_instance, created = OptionalUser.objects.get_or_create()
machineoptions_instance, created = OptionalMachine.objects.get_or_create()
generaloptions_instance, created = GeneralOption.objects.get_or_create()
useroptions = EditUserOptionsForm(request.POST or None, instance=useroptions_instance)
machineoptions = EditMachineOptionsForm(request.POST or None, instance=machineoptions_instance)
generaloptions = EditGeneralOptionsForm(request.POST or None, instance=generaloptions_instance)
if useroptions.is_valid() or machineoptions.is_valid() or generaloptions.is_valid():
if useroptions.is_valid():
model = getattr(models, section, None)
form_instance = getattr(forms, 'Edit' + section + 'Form', None)
if model and form:
options_instance, created = model.objects.get_or_create()
options = form_instance(request.POST or None, instance=options_instance)
if options.is_valid():
with transaction.atomic(), reversion.create_revision():
useroptions.save()
options.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in useroptions.changed_data))
if machineoptions.is_valid():
with transaction.atomic(), reversion.create_revision():
machineoptions.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in machineoptions.changed_data))
if generaloptions.is_valid():
with transaction.atomic(), reversion.create_revision():
generaloptions.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in generaloptions.changed_data))
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in options.changed_data))
messages.success(request, "Préférences modifiées")
return redirect("/preferences/")
return form({'useroptions': useroptions, 'machineoptions': machineoptions, 'generaloptions': generaloptions}, 'preferences/edit_preferences.html', request)
return form({'options': options}, 'preferences/edit_preferences.html', request)
else:
messages.error(request, "Objet inconnu")
return redirect("/preferences/")

View file

@ -147,6 +147,8 @@ STATICFILES_DIRS = (
),
)
MEDIA_ROOT = '/var/www/re2o/static'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')

View file

@ -44,10 +44,10 @@ from users.forms import EditInfoForm, InfoForm, BaseInfoForm, StateForm, RightFo
from cotisations.models import Facture
from machines.models import Machine, Interface
from users.forms import MassArchiveForm, PassForm, ResetPasswordForm
from preferences.models import OptionalUser, GeneralOption
from preferences.models import OptionalUser, AssoOption, GeneralOption
from re2o.login import hashNT
from re2o.settings import REQ_EXPIRE_STR, EMAIL_FROM, ASSO_NAME, ASSO_EMAIL, SITE_NAME
from re2o.settings import REQ_EXPIRE_STR, EMAIL_FROM, SITE_NAME
def form(ctx, template, request):
@ -74,10 +74,11 @@ def password_change_action(u_form, user, request, req=False):
def reset_passwd_mail(req, request):
""" Prend en argument un request, envoie un mail de réinitialisation de mot de pass """
t = loader.get_template('users/email_passwd_request')
options, created = AssoOption.objects.get_or_create()
c = {
'name': str(req.user.name) + ' ' + str(req.user.surname),
'asso': ASSO_NAME,
'asso_mail': ASSO_EMAIL,
'asso': options.name,
'asso_mail': options.contact,
'site_name': SITE_NAME,
'url': request.build_absolute_uri(
reverse('users:process', kwargs={'token': req.token})),
@ -102,10 +103,11 @@ def notif_ban(ban):
def notif_inscription(user):
""" Prend en argument un objet user, envoie un mail de bienvenue """
t = loader.get_template('users/email_welcome')
options, created = AssoOption.objects.get_or_create()
c = Context({
'nom': str(user.name) + ' ' + str(user.surname),
'asso_name': ASSO_NAME,
'asso_email':ASSO_EMAIL,
'asso_name': options.name,
'asso_email': options.contact,
'pseudo':user.pseudo,
})
send_mail('Bienvenue au Rézo / Welcome to Rézo Metz', '',