8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-09-12 09:13:08 +00:00

Cleanup for local email accounts

This commit is contained in:
Maël Kervella 2018-07-30 15:00:41 +00:00
parent bd19b27914
commit 43fb83ec12
22 changed files with 587 additions and 599 deletions

46
api/serializers.py Executable file → Normal file
View file

@ -492,12 +492,11 @@ class UserSerializer(NamespacedHMSerializer):
""" """
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
email = serializers.CharField(source='get_mail')
class Meta: class Meta:
model = users.User model = users.User
fields = ('name', 'pseudo', 'email', 'school', 'shell', 'comment', fields = ('surname', 'pseudo', 'email', 'local_email_redirect',
'external_mail', 'redirection', 'internal_address', 'local_email_enabled', 'school', 'shell', 'comment',
'state', 'registered', 'telephone', 'solde', 'access', 'state', 'registered', 'telephone', 'solde', 'access',
'end_access', 'uid', 'class_name', 'api_url') 'end_access', 'uid', 'class_name', 'api_url')
extra_kwargs = { extra_kwargs = {
@ -511,12 +510,11 @@ class ClubSerializer(NamespacedHMSerializer):
name = serializers.CharField(source='surname') name = serializers.CharField(source='surname')
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
email = serializers.CharField(source='get_mail')
class Meta: class Meta:
model = users.Club model = users.Club
fields = ('name', 'pseudo', 'email', 'school', 'shell', 'comment', fields = ('name', 'pseudo', 'email', 'local_email_redirect',
'external_mail', 'redirection', 'internal_address', 'local_email_enabled', 'school', 'shell', 'comment',
'state', 'registered', 'telephone', 'solde', 'room', 'state', 'registered', 'telephone', 'solde', 'room',
'access', 'end_access', 'administrators', 'members', 'access', 'end_access', 'administrators', 'members',
'mailing', 'uid', 'api_url') 'mailing', 'uid', 'api_url')
@ -530,14 +528,13 @@ class AdherentSerializer(NamespacedHMSerializer):
""" """
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
email = serializers.CharField(source='get_mail')
class Meta: class Meta:
model = users.Adherent model = users.Adherent
fields = ('name', 'surname', 'pseudo', 'email', 'redirection', 'internal_address', fields = ('name', 'surname', 'pseudo', 'email', 'local_email_redirect',
'external_mail', 'school', 'shell', 'local_email_enabled', 'school', 'shell', 'comment',
'comment', 'state', 'registered', 'telephone', 'room', 'state', 'registered', 'telephone', 'room', 'solde',
'solde', 'access', 'end_access', 'uid', 'api_url') 'access', 'end_access', 'uid', 'api_url')
extra_kwargs = { extra_kwargs = {
'shell': {'view_name': 'shell-detail'} 'shell': {'view_name': 'shell-detail'}
} }
@ -599,16 +596,13 @@ class WhitelistSerializer(NamespacedHMSerializer):
fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url') fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url')
class MailAliasSerializer(NamespacedHMSerializer): class LocalEmailAccountSerializer(NamespacedHMSerializer):
"""Serialize `users.models.MailAlias` objects. """Serialize `users.models.LocalEmailAccount` objects.
""" """
class Meta: class Meta:
model = users.MailAlias model = users.LocalEmailAccount
fields = ('user', 'valeur', 'complete_mail') fields = ('user', 'local_part', 'complete_email_address', 'api_url')
# SERVICE REGEN # SERVICE REGEN
@ -627,17 +621,21 @@ class ServiceRegenSerializer(NamespacedHMSerializer):
extra_kwargs = { extra_kwargs = {
'api_url': {'view_name': 'serviceregen-detail'} 'api_url': {'view_name': 'serviceregen-detail'}
} }
# Configuration mail
class UserMailAliasSerializer(NamespacedHMSerializer): # LOCAL EMAILS
get_mail_aliases = MailAliasSerializer(read_only=True, many=True)
class LocalEmailUsersSerializer(NamespacedHMSerializer):
local_email_accounts = LocalEmailAccountSerializer(
read_only=True,
many=True
)
class Meta: class Meta:
model = users.User model = users.User
fields = ('pseudo', 'get_mail_aliases') fields = ('local_email_enabled', 'local_email_redirect',
'local_email_accounts')
# DHCP # DHCP

6
api/urls.py Executable file → Normal file
View file

@ -93,13 +93,13 @@ router.register_viewset(r'users/listright', views.ListRightViewSet)
router.register_viewset(r'users/shell', views.ShellViewSet, base_name='shell') router.register_viewset(r'users/shell', views.ShellViewSet, base_name='shell')
router.register_viewset(r'users/ban', views.BanViewSet) router.register_viewset(r'users/ban', views.BanViewSet)
router.register_viewset(r'users/whitelist', views.WhitelistViewSet) router.register_viewset(r'users/whitelist', views.WhitelistViewSet)
router.register_viewset(r'users/mailalias', views.MailAliasViewSet) router.register_viewset(r'users/localemailaccount', views.LocalEmailAccountViewSet)
# SERVICE REGEN # SERVICE REGEN
router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen') router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen')
# DHCP # DHCP
router.register_view(r'dhcp/hostmacip', views.HostMacIpView), router.register_view(r'dhcp/hostmacip', views.HostMacIpView),
# Mail config # LOCAL EMAILS
router.register_view(r'mail/alias', views.UserMailAliasView), router.register_view(r'localemail/users', views.LocalEmailUsersView),
# DNS # DNS
router.register_view(r'dns/zones', views.DNSZonesView), router.register_view(r'dns/zones', views.DNSZonesView),
# MAILING # MAILING

34
api/views.py Executable file → Normal file
View file

@ -469,11 +469,19 @@ class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = serializers.WhitelistSerializer serializer_class = serializers.WhitelistSerializer
class MailAliasViewSet(viewsets.ReadOnlyModelViewSet): class LocalEmailAccountViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.MailAlias` objects. """Exposes list and details of `users.models.LocalEmailAccount` objects.
""" """
queryset = users.MailAlias.objects.all() serializer_class = serializers.LocalEmailAccountSerializer
serializer_class = serializers.MailAliasSerializer queryset = users.LocalEmailAccount.objects.none()
def get_queryset(self):
if preferences.OptionalUser.get_cached_value(
'local_email_accounts_enabled'):
return (users.LocalEmailAccount.objects
.filter(user__local_email_enabled=True))
else:
return users.LocalEmailAccount.objects.none()
# SERVICE REGEN # SERVICE REGEN
@ -496,19 +504,26 @@ class ServiceRegenViewSet(viewsets.ModelViewSet):
return queryset return queryset
# Server mail config # LOCAL EMAILS
class UserMailAliasView(generics.ListAPIView): class LocalEmailUsersView(generics.ListAPIView):
"""Expose all the aliases of the users that activated the internal address """Exposes all the aliases of the users that activated the internal address
""" """
serializer_class = serializers.LocalEmailUsersSerializer
queryset = users.User.objects.filter(internal_address=True) def get_queryset(self):
serializer_class = serializers.UserMailAliasSerializer if preferences.OptionalUser.get_cached_value(
'local_email_accounts_enabled'):
return (users.User.objects
.filter(local_email_enabled=True))
else:
return users.User.objects.none()
# DHCP # DHCP
class HostMacIpView(generics.ListAPIView): class HostMacIpView(generics.ListAPIView):
"""Exposes the associations between hostname, mac address and IPv4 in """Exposes the associations between hostname, mac address and IPv4 in
order to build the DHCP lease files. order to build the DHCP lease files.
@ -519,6 +534,7 @@ class HostMacIpView(generics.ListAPIView):
# DNS # DNS
class DNSZonesView(generics.ListAPIView): class DNSZonesView(generics.ListAPIView):
"""Exposes the detailed information about each extension (hostnames, """Exposes the detailed information about each extension (hostnames,
IPs, DNS records, etc.) in order to build the DNS zone files. IPs, DNS records, etc.) in order to build the DNS zone files.

View file

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-26 19:31
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0034_auto_20180416_1120'),
]
operations = [
migrations.AddField(
model_name='optionaluser',
name='mail_extension',
field=models.CharField(default='@example.org', help_text='Main extension for internal address', max_length=32),
),
]

View file

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-29 16:01
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0035_optionaluser_mail_extension'),
]
operations = [
migrations.AddField(
model_name='optionaluser',
name='mail_accounts',
field=models.BooleanField(default=False, help_text='Enable mail accounts for users'),
),
]

View file

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-30 12:32
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0036_optionaluser_mail_accounts'),
]
operations = [
migrations.AddField(
model_name='optionaluser',
name='max_mail_alias',
field=models.IntegerField(default=15, help_text="Max alias mail for a lambda user"),
),
]

View file

@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-23 12:13
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('preferences', '0037_optionaluser_max_mail_alias'),
('preferences', '0045_remove_unused_payment_fields'),
]
operations = [
]

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-26 19:31
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0045_remove_unused_payment_fields'),
]
operations = [
migrations.AddField(
model_name='optionaluser',
name='local_email_accounts_enabled',
field=models.BooleanField(default=False, help_text='Enable local email accounts for users'),
),
migrations.AddField(
model_name='optionaluser',
name='local_email_domain',
field=models.CharField(default='@example.org', help_text='Domain to use for local email accounts', max_length=32),
),
migrations.AddField(
model_name='optionaluser',
name='max_local_email_accounts',
field=models.IntegerField(default=15, help_text='Maximum number of local email accounts for a standard user'),
),
]

View file

@ -30,9 +30,8 @@ from django.db import models
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.core.cache import cache from django.core.cache import cache
from django.forms import ValidationError from django.forms import ValidationError
import cotisations.models
import machines.models import machines.models
from re2o.mixins import AclMixin from re2o.mixins import AclMixin
@ -85,18 +84,18 @@ class OptionalUser(AclMixin, PreferencesModel):
blank=True, blank=True,
null=True null=True
) )
mail_accounts = models.BooleanField( local_email_accounts_enabled = models.BooleanField(
default=False, default=False,
help_text="Enable mail accounts for users" help_text="Enable local email accounts for users"
) )
mail_extension = models.CharField( local_email_domain = models.CharField(
max_length = 32, max_length = 32,
default = "@example.org", default = "@example.org",
help_text="Main extension for internal address", help_text="Domain to use for local email accounts",
) )
max_mail_alias = models.IntegerField( max_local_email_accounts = models.IntegerField(
default = 15, default = 15,
help_text = "Max alias mail for a lambda user" help_text = "Maximum number of local email accounts for a standard user"
) )
class Meta: class Meta:
@ -108,9 +107,9 @@ class OptionalUser(AclMixin, PreferencesModel):
"""Clean model: """Clean model:
Check the mail_extension Check the mail_extension
""" """
if self.mail_extension[0] != "@": if self.local_email_domain[0] != "@":
raise ValidationError("Mail extension must begin with @") raise ValidationError("Mail domain must begin with @")
@receiver(post_save, sender=OptionalUser) @receiver(post_save, sender=OptionalUser)
def optionaluser_post_save(**kwargs): def optionaluser_post_save(**kwargs):

View file

@ -32,206 +32,204 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %} {% block content %}
<h4>Préférences utilisateur</h4> <h4>Préférences utilisateur</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalUser' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalUser' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer </a>
</a>
<p>
</p>
<h5>Généralités</h5>
<table class="table table-striped">
<tr>
<th>Téléphone obligatoirement requis</th>
<td>{{ useroptions.is_tel_mandatory|tick }}</td>
<th>Auto inscription</th>
<td>{{ useroptions.self_adhesion|tick }}</td>
</tr>
<tr>
<th>Champ gpg fingerprint</th>
<td>{{ useroptions.gpg_fingerprint|tick }}</td>
<th>Shell par défaut des utilisateurs</th>
<td>{{ useroptions.shell_default }}</td>
</tr>
<tr>
<th>Creations d'adhérents par tous</th>
<td>{{ useroptions.all_can_create_adherent|tick }}</td>
<th>Creations de clubs par tous</th>
<td>{{ useroptions.all_can_create_club|tick }}</td>
</tr>
<h5>{% if useroptions.mail_accounts %}<span class="label label-success">Comptes mails{% else %}<span class="label label-danger">Comptes mails{% endif%}</span></h5>
<table class="table table-striped">
<tr>
<th>Gestion des comptes mails</th>
<td>{{ useroptions.mail_accounts }}</td>
<th>Extension mail interne</th>
<td>{{ useroptions.mail_extension }}</td>
</tr>
<tr>
<th>Nombre d'alias maximum</th>
<td>{{ useroption.max_mail_alias }}<td>
</tr>
</table>
<h4>Préférences machines</h4> <h5>Généralités</h5>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalMachine' %}"> <table class="table table-striped">
<i class="fa fa-edit"></i> <tr>
Editer <th>Téléphone obligatoirement requis</th>
</a> <td>{{ useroptions.is_tel_mandatory|tick }}</td>
<p> <th>Auto inscription</th>
</p> <td>{{ useroptions.self_adhesion|tick }}</td>
<table class="table table-striped"> </tr>
<tr> <tr>
<th>Mot de passe par machine</th> <th>Champ gpg fingerprint</th>
<td>{{ machineoptions.password_machine|tick }}</td> <td>{{ useroptions.gpg_fingerprint|tick }}</td>
<th>Machines/interfaces autorisées par utilisateurs</th> <th>Shell par défaut des utilisateurs</th>
<td>{{ machineoptions.max_lambdauser_interfaces }}</td> <td>{{ useroptions.shell_default }}</td>
</tr> </tr>
<tr> <tr>
<th>Alias dns autorisé par utilisateur</th> <th>Creations d'adhérents par tous</th>
<td>{{ machineoptions.max_lambdauser_aliases }}</td> <td>{{ useroptions.all_can_create_adherent|tick }}</td>
<th>Support de l'ipv6</th> <th>Creations de clubs par tous</th>
<td>{{ machineoptions.ipv6_mode }}</td> <td>{{ useroptions.all_can_create_club|tick }}</td>
</tr> </tr>
<tr>
<th>Creation de machines</th>
<td>{{ machineoptions.create_machine|tick }}</td>
</tr>
</table> </table>
<h5>Comptes mails</h5>
<table class="table table-striped">
<tr>
<th>Gestion des comptes mails</th>
<td>{{ useroptions.local_email_accounts_enabled | tick }}</td>
<th>Extension mail interne</th>
<td>{{ useroptions.local_email_domain }}</td>
</tr>
<tr>
<th>Nombre de comptes maximum</th>
<td>{{ useroptions.max_local_email_accounts }}</td>
</tr>
</table>
<h4>Préférences machines</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalMachine' %}">
<i class="fa fa-edit"></i> Editer
</a>
<table class="table table-striped">
<tr>
<th>Mot de passe par machine</th>
<td>{{ machineoptions.password_machine|tick }}</td>
<th>Machines/interfaces autorisées par utilisateurs</th>
<td>{{ machineoptions.max_lambdauser_interfaces }}</td>
</tr>
<tr>
<th>Alias dns autorisé par utilisateur</th>
<td>{{ machineoptions.max_lambdauser_aliases }}</td>
<th>Support de l'ipv6</th>
<td>{{ machineoptions.ipv6_mode }}</td>
</tr>
<tr>
<th>Creation de machines</th>
<td>{{ machineoptions.create_machine|tick }}</td>
</tr>
</table>
<h4>Préférences topologie</h4> <h4>Préférences topologie</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalTopologie' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'OptionalTopologie' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer
</a> </a>
<p>
</p>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Politique générale de placement de vlan</th> <th>Politique générale de placement de vlan</th>
<td>{{ topologieoptions.radius_general_policy }}</td> <td>{{ topologieoptions.radius_general_policy }}</td>
<th> Ce réglage défini la politique vlan après acceptation radius : soit sur le vlan de la plage d'ip de la machine, soit sur un vlan prédéfini dans "Vlan où placer les machines après acceptation RADIUS"</th> <th>
<td></td> Ce réglage défini la politique vlan après acceptation radius :
</tr> soit sur le vlan de la plage d'ip de la machine, soit sur un
<tr> vlan prédéfini dans "Vlan où placer les machines après acceptation
<th>Vlan où placer les machines après acceptation RADIUS</th> RADIUS"
<td>{{ topologieoptions.vlan_decision_ok }}</td> </th>
<th>Vlan où placer les machines après rejet RADIUS</th> <td></td>
<td>{{ topologieoptions.vlan_decision_nok }}</td> </tr>
</tr> <tr>
<th>Vlan où placer les machines après acceptation RADIUS</th>
<td>{{ topologieoptions.vlan_decision_ok }}</td>
<th>Vlan où placer les machines après rejet RADIUS</th>
<td>{{ topologieoptions.vlan_decision_nok }}</td>
</tr>
</table> </table>
<h4>Préférences generales</h4> <h4>Préférences generales</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer
</a> </a>
<p>
</p>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Nom du site web</th> <th>Nom du site web</th>
<td>{{ generaloptions.site_name }}</td> <td>{{ generaloptions.site_name }}</td>
<th>Adresse mail d'expedition automatique</th> <th>Adresse mail d'expedition automatique</th>
<td>{{ generaloptions.email_from }}</td> <td>{{ generaloptions.email_from }}</td>
</tr> </tr>
<tr> <tr>
<th>Affichage de résultats dans le champ de recherche</th> <th>Affichage de résultats dans le champ de recherche</th>
<td>{{ generaloptions.search_display_page }}</td> <td>{{ generaloptions.search_display_page }}</td>
<th>Nombre d'items affichés en liste (taille normale)</th> <th>Nombre d'items affichés en liste (taille normale)</th>
<td>{{ generaloptions.pagination_number }}</td> <td>{{ generaloptions.pagination_number }}</td>
</tr> </tr>
<tr> <tr>
<th>Nombre d'items affichés en liste (taille élevée)</th> <th>Nombre d'items affichés en liste (taille élevée)</th>
<td>{{ generaloptions.pagination_large_number }}</td> <td>{{ generaloptions.pagination_large_number }}</td>
<th>Temps avant expiration du lien de reinitialisation de mot de passe (en heures)</th> <th>Temps avant expiration du lien de reinitialisation de mot de passe (en heures)</th>
<td>{{ generaloptions.req_expire_hrs }}</td> <td>{{ generaloptions.req_expire_hrs }}</td>
</tr> </tr>
<tr> <tr>
<th>Message global affiché sur le site</th> <th>Message global affiché sur le site</th>
<td>{{ generaloptions.general_message }}</td> <td>{{ generaloptions.general_message }}</td>
<th>Résumé des CGU</th> <th>Résumé des CGU</th>
<td>{{ generaloptions.GTU_sum_up }}</td> <td>{{ generaloptions.GTU_sum_up }}</td>
<tr> <tr>
<tr> <tr>
<th>CGU</th> <th>CGU</th>
<td>{{generaloptions.GTU}}</th> <td>{{generaloptions.GTU}}</th>
</tr> </tr>
</table> </table>
<h4>Données de l'association</h4> <h4>Données de l'association</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'AssoOption' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'AssoOption' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer
</a> </a>
<p>
</p>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Nom</th> <th>Nom</th>
<td>{{ assooptions.name }}</td> <td>{{ assooptions.name }}</td>
<th>SIRET</th> <th>SIRET</th>
<td>{{ assooptions.siret }}</td> <td>{{ assooptions.siret }}</td>
</tr> </tr>
<tr> <tr>
<th>Adresse</th> <th>Adresse</th>
<td>{{ assooptions.adresse1 }}<br> <td>{{ assooptions.adresse1 }}<br>
{{ assooptions.adresse2 }}</td> {{ assooptions.adresse2 }}</td>
<th>Contact mail</th> <th>Contact mail</th>
<td>{{ assooptions.contact }}</td> <td>{{ assooptions.contact }}</td>
</tr> </tr>
<tr> <tr>
<th>Telephone</th> <th>Telephone</th>
<td>{{ assooptions.telephone }}</td> <td>{{ assooptions.telephone }}</td>
<th>Pseudo d'usage</th> <th>Pseudo d'usage</th>
<td>{{ assooptions.pseudo }}</td> <td>{{ assooptions.pseudo }}</td>
</tr> </tr>
<tr> <tr>
<th>Objet utilisateur de l'association</th> <th>Objet utilisateur de l'association</th>
<td>{{ assooptions.utilisateur_asso }}</td> <td>{{ assooptions.utilisateur_asso }}</td>
<th>Description de l'association</th> <th>Description de l'association</th>
<td>{{ assooptions.description | safe }}</td> <td>{{ assooptions.description | safe }}</td>
</tr> </tr>
</table> </table>
<h4>Messages personalisé dans les mails</h4> <h4>Messages personalisé dans les mails</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'MailMessageOption' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'MailMessageOption' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer
</a> </a>
<p>
</p>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Mail de bienvenue (Français)</th> <th>Mail de bienvenue (Français)</th>
<td>{{ mailmessageoptions.welcome_mail_fr | safe }}</td> <td>{{ mailmessageoptions.welcome_mail_fr | safe }}</td>
</tr> </tr>
<tr> <tr>
<th>Mail de bienvenue (Anglais)</th> <th>Mail de bienvenue (Anglais)</th>
<td>{{ mailmessageoptions.welcome_mail_en | safe }}</td> <td>{{ mailmessageoptions.welcome_mail_en | safe }}</td>
</tr> </tr>
</table> </table>
<h2>Liste des services et préférences page d'accueil</h2>
<h4>Liste des services et préférences page d'accueil</h4>
{% can_create preferences.Service%} {% can_create preferences.Service%}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-service' %}"><i class="fa fa-plus"></i> Ajouter un service</a> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-service' %}"><i class="fa fa-plus">
</i> Ajouter un service
</a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'preferences:del-services' %}"><i class="fa fa-trash"></i> Supprimer un ou plusieurs service</a> <a class="btn btn-danger btn-sm" role="button" href="{% url 'preferences:del-services' %}"><i class="fa fa-trash">
</i> Supprimer un ou plusieurs service
</a>
{% include "preferences/aff_service.html" with service_list=service_list %} {% include "preferences/aff_service.html" with service_list=service_list %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'HomeOption' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'HomeOption' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i> Editer
Editer
</a> </a>
<p>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>Url du compte twitter</th> <th>Url du compte twitter</th>
<td>{{ homeoptions.twitter_url }}</td> <td>{{ homeoptions.twitter_url }}</td>
<th>Nom utilisé pour afficher le compte</th> <th>Nom utilisé pour afficher le compte</th>
<td>{{ homeoptions.twitter_account_name }}</td> <td>{{ homeoptions.twitter_account_name }}</td>
</tr> </tr>
<tr> <tr>
<th>Url du compte facebook</th> <th>Url du compte facebook</th>
<td>{{ homeoptions.facebook_url }}</td> <td>{{ homeoptions.facebook_url }}</td>
</tr> </tr>
</table> </table>
<br />
<br />
<br />
{% endblock %} {% endblock %}

View file

@ -29,6 +29,7 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url( url(
r'^edit_options/(?P<section>OptionalUser)$', r'^edit_options/(?P<section>OptionalUser)$',

View file

@ -79,6 +79,7 @@ from django.contrib.contenttypes.models import ContentType
register = template.Library() register = template.Library()
def get_model(model_name): def get_model(model_name):
"""Retrieve the model object from its name""" """Retrieve the model object from its name"""
splitted = model_name.split('.') splitted = model_name.split('.')

View file

@ -34,7 +34,7 @@ from reversion.admin import VersionAdmin
from .models import ( from .models import (
User, User,
MailAlias, LocalEmailAccount,
ServiceUser, ServiceUser,
School, School,
ListRight, ListRight,
@ -109,7 +109,7 @@ class BanAdmin(VersionAdmin):
pass pass
class MailAliasAdmin(VersionAdmin): class LocalEmailAccountAdmin(VersionAdmin):
"""Gestion des alias mail""" """Gestion des alias mail"""
pass pass
@ -131,7 +131,9 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
list_display = ( list_display = (
'pseudo', 'pseudo',
'surname', 'surname',
'external_mail', 'email',
'local_email_redirect',
'local_email_enabled',
'school', 'school',
'is_admin', 'is_admin',
'shell' 'shell'
@ -145,7 +147,7 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
'Personal info', 'Personal info',
{ {
'fields': 'fields':
('surname', 'external_mail', 'school', 'shell', 'uid_number') ('surname', 'email', 'school', 'shell', 'uid_number')
} }
), ),
('Permissions', {'fields': ('is_admin', )}), ('Permissions', {'fields': ('is_admin', )}),
@ -160,7 +162,7 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
'fields': ( 'fields': (
'pseudo', 'pseudo',
'surname', 'surname',
'external_mail', 'email',
'school', 'school',
'is_admin', 'is_admin',
'password1', 'password1',
@ -217,7 +219,7 @@ admin.site.register(School, SchoolAdmin)
admin.site.register(ListRight, ListRightAdmin) admin.site.register(ListRight, ListRightAdmin)
admin.site.register(ListShell, ListShellAdmin) admin.site.register(ListShell, ListShellAdmin)
admin.site.register(Ban, BanAdmin) admin.site.register(Ban, BanAdmin)
admin.site.register(MailAlias, MailAliasAdmin) admin.site.register(LocalEmailAccount, LocalEmailAccountAdmin)
admin.site.register(Whitelist, WhitelistAdmin) admin.site.register(Whitelist, WhitelistAdmin)
admin.site.register(Request, RequestAdmin) admin.site.register(Request, RequestAdmin)
# Now register the new UserAdmin... # Now register the new UserAdmin...

View file

@ -53,7 +53,7 @@ from .models import (
School, School,
ListRight, ListRight,
Whitelist, Whitelist,
MailAlias, LocalEmailAccount,
ListShell, ListShell,
Ban, Ban,
Adherent, Adherent,
@ -140,7 +140,7 @@ class UserCreationForm(FormRevMixin, forms.ModelForm):
class Meta: class Meta:
model = Adherent model = Adherent
fields = ('pseudo', 'surname') fields = ('pseudo', 'surname', 'email')
def clean_password2(self): def clean_password2(self):
"""Verifie que password1 et 2 sont identiques""" """Verifie que password1 et 2 sont identiques"""
@ -306,6 +306,7 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
self.fields['room'].label = 'Chambre' self.fields['room'].label = 'Chambre'
self.fields['room'].empty_label = "Pas de chambre" self.fields['room'].empty_label = "Pas de chambre"
self.fields['school'].empty_label = "Séléctionner un établissement" self.fields['school'].empty_label = "Séléctionner un établissement"
class Meta: class Meta:
model = Adherent model = Adherent
fields = [ fields = [
@ -590,28 +591,37 @@ class WhitelistForm(FormRevMixin, ModelForm):
widgets = {'date_end':DateTimePicker} widgets = {'date_end':DateTimePicker}
class MailAliasForm(FormRevMixin, ModelForm): class LocalEmailAccountForm(FormRevMixin, ModelForm):
"""Create and edit a mailalias""" """Create and edit a local email account"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(MailAliasForm, self).__init__(*args, prefix=prefix, **kwargs) super(LocalEmailAccountForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['valeur'].label = "Prefix of mailalias. Can't contain @" self.fields['local_part'].label = "Local part of the email"
self.fields['local_part'].help_text = "Can't contain @"
class Meta: class Meta:
model = MailAlias model = LocalEmailAccount
exclude = ['user'] exclude = ['user']
class MailForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Edit mail settings""" class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Edit email-related settings"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(MailForm, self).__init__(*args, prefix=prefix, **kwargs) super(EmailSettingsForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['external_mail'].label = 'External mail address' self.fields['email'].label = "Contact email address"
if 'redirection' in self.fields: if 'local_email_redirect' in self.fields:
self.fields['redirection'].label = 'Enable redirect to external address' self.fields['local_email_redirect'].label = "Redirect local emails"
if 'internal_address' in self.fields: self.fields['local_email_redirect'].help_text = (
self.fields['internal_address'].label = 'Internal mail address' "Enable the automated redirection of the local email address "
"to the contact email address"
)
if 'local_email_enabled' in self.fields:
self.fields['local_email_enabled'].label = "Use local emails"
self.fields['local_email_enabled'].help_text = (
"Enable the use of the local email account"
)
class Meta: class Meta:
model = User model = User
fields = ['external_mail', 'redirection', 'internal_address'] fields = ['email', 'local_email_redirect', 'local_email_enabled']

View file

@ -10,37 +10,49 @@ import re2o.mixins
class Migration(migrations.Migration): class Migration(migrations.Migration):
def create_initial_local_email_account(apps, schema_editor):
db_alias = schema_editor.connection.alias
User = apps.get_model("users", "User")
LocalEmailAccount = apps.get_model("users", "LocalEmailAccount")
users = User.objects.using(db_alias).all()
for user in users:
LocalEmailAccount.objects.using(db_alias).create(
local_part=user.pseudo,
user=user
)
def delete_all_local_email_accounts(apps, schema_editor):
db_alias = schema_editor.connection.alias
LocalEmailAccount = apps.get_model("users", "LocalEmailAccount")
LocalEmailAccount.objects.using(db_alias).delete()
dependencies = [ dependencies = [
('users', '0072_auto_20180426_2021'), ('users', '0072_auto_20180426_2021'),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='MailAlias', name='LocalEmailAccount',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('valeur', models.CharField(help_text="username de l'adresse mail", max_length=64, unique=True)), ('local_part', models.CharField(help_text="Local part of the email address", max_length=128, unique=True)),
('user', models.ForeignKey(help_text='User of the local email', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model),
), options={'permissions': (('view_localemailaccount', 'Can see a local email account object'),), 'verbose_name': 'Local email account', 'verbose_name_plural': 'Local email accounts'},
migrations.RenameField(
model_name='user',
old_name='email',
new_name='external_mail',
), ),
migrations.AddField( migrations.AddField(
model_name='user', model_name='user',
name='internal_address', name='local_email_enabled',
field=models.BooleanField(default=False, help_text="Activer ou non l'utilisation de l'adresse mail interne"), field=models.BooleanField(default=False, help_text="Wether or not to enable the local email account."),
), ),
migrations.AddField( migrations.AddField(
model_name='user', model_name='user',
name='redirection', name='local_email_redirect',
field=models.BooleanField(default=False, help_text='Activer ou non la redirection du mail interne vers le mail externe'), field=models.BooleanField(default=False, help_text='Whether or not to redirect the local email messages to the main email.'),
), ),
migrations.AddField( migrations.RunPython(create_initial_local_email_account,
model_name='mailalias', delete_all_local_email_accounts),
name='user',
field=models.ForeignKey(blank=True, help_text='Utilisateur associé', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
), ),
] ]

View file

@ -1,42 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-29 15:17
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 = [
('users', '0073_auto_20180629_1614'),
]
def transfer_pseudo(apps, schema_editor):
db_alias = schema_editor.connection.alias
users = apps.get_model("users", "User")
mailalias = apps.get_model("users", "MailAlias")
users_list = users.objects.using(db_alias).all()
for user in users_list:
mailalias.objects.using(db_alias).create(valeur=user.pseudo, user=user)
def untransfer_pseudo(apps, schema_editor):
db_alias = schema_editor.connection.alias
mailalias = apps.get_model("users", "MailAlias")
mailalias.objects.using(db_alias).delete()
operations = [
migrations.AlterField(
model_name='mailalias',
name='user',
field=models.ForeignKey(help_text='Utilisateur associé', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='mailalias',
name='valeur',
field=models.CharField(help_text="Valeur de l'alias mail", max_length=128, unique=True),
),
migrations.RunPython(transfer_pseudo, untransfer_pseudo),
]

View file

@ -53,7 +53,6 @@ from django.db import models
from django.db.models import Q from django.db.models import Q
from django import forms from django import forms
from django.db.models.signals import post_save, post_delete, m2m_changed from django.db.models.signals import post_save, post_delete, m2m_changed
from django.forms import ValidationError
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.template import Context, loader from django.template import Context, loader
@ -98,7 +97,7 @@ def linux_user_validator(login):
""" Retourne une erreur de validation si le login ne respecte """ Retourne une erreur de validation si le login ne respecte
pas les contraintes unix (maj, min, chiffres ou tiret)""" pas les contraintes unix (maj, min, chiffres ou tiret)"""
if not linux_user_check(login): if not linux_user_check(login):
raise ValidationError( raise forms.ValidationError(
", ce pseudo ('%(label)s') contient des carractères interdits", ", ce pseudo ('%(label)s') contient des carractères interdits",
params={'label': login}, params={'label': login},
) )
@ -135,7 +134,7 @@ class UserManager(BaseUserManager):
self, self,
pseudo, pseudo,
surname, surname,
external_mail, email,
password=None, password=None,
su=False su=False
): ):
@ -149,7 +148,7 @@ class UserManager(BaseUserManager):
pseudo=pseudo, pseudo=pseudo,
surname=surname, surname=surname,
name=surname, name=surname,
external_mail=external_mail, email=self.normalize_email(mail),
) )
user.set_password(password) user.set_password(password)
@ -158,19 +157,19 @@ class UserManager(BaseUserManager):
user.save(using=self._db) user.save(using=self._db)
return user return user
def create_user(self, pseudo, surname, external_mail, password=None): def create_user(self, pseudo, surname, email, password=None):
""" """
Creates and saves a User with the given pseudo, name, surname, email, Creates and saves a User with the given pseudo, name, surname, email,
and password. and password.
""" """
return self._create_user(pseudo, surname, external_mail, password, False) return self._create_user(pseudo, surname, email, password, False)
def create_superuser(self, pseudo, surname, external_mail, password): def create_superuser(self, pseudo, surname, email, password):
""" """
Creates and saves a superuser with the given pseudo, name, surname, Creates and saves a superuser with the given pseudo, name, surname,
email, and password. email, and password.
""" """
return self._create_user(pseudo, surname, external_mail, password, True) return self._create_user(pseudo, surname, email, password, True)
class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
@ -195,14 +194,14 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", help_text="Doit contenir uniquement des lettres, chiffres, ou tirets",
validators=[linux_user_validator] validators=[linux_user_validator]
) )
external_mail = models.EmailField() email = models.EmailField()
redirection = models.BooleanField( local_email_redirect = models.BooleanField(
default=False, default=False,
help_text='Activer ou non la redirection du mail interne vers le mail externe' help_text="Whether or not to redirect the local email messages to the main email."
) )
internal_address = models.BooleanField( local_email_enabled = models.BooleanField(
default=False, default=False,
help_text='Activer ou non l\'utilisation de l\'adresse mail interne' help_text="Wether or not to enable the local email account."
) )
school = models.ForeignKey( school = models.ForeignKey(
'School', 'School',
@ -236,7 +235,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
) )
USERNAME_FIELD = 'pseudo' USERNAME_FIELD = 'pseudo'
REQUIRED_FIELDS = ['surname', 'external_mail'] REQUIRED_FIELDS = ['surname', 'email']
objects = UserManager() objects = UserManager()
@ -255,9 +254,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
("view_user", ("view_user",
"Peut voir un objet user quelquonque"), "Peut voir un objet user quelquonque"),
) )
@cached_property @cached_property
def name(self): def name(self):
"""Si il s'agit d'un adhérent, on renvoie le prénom""" """Si il s'agit d'un adhérent, on renvoie le prénom"""
@ -536,7 +533,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
user_ldap.sn = self.pseudo user_ldap.sn = self.pseudo
user_ldap.dialupAccess = str(self.has_access()) user_ldap.dialupAccess = str(self.has_access())
user_ldap.home_directory = '/home/' + self.pseudo user_ldap.home_directory = '/home/' + self.pseudo
user_ldap.mail = self.get_mail() user_ldap.mail = self.email
user_ldap.given_name = self.surname.lower() + '_'\ user_ldap.given_name = self.surname.lower() + '_'\
+ self.name.lower()[:3] + self.name.lower()[:3]
user_ldap.gid = LDAP['user_gid'] user_ldap.gid = LDAP['user_gid']
@ -685,20 +682,12 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
self.pwd_ntlm = hashNT(password) self.pwd_ntlm = hashNT(password)
return return
def get_mail(self):
"""
Return the mail address choosen by the user
"""
if not OptionalUser.get_cached_value('mail_accounts') or not self.internal_address or self.redirection:
return str(self.external_mail)
else:
return str(self.mailalias_set.get(valeur=self.pseudo))
@cached_property @cached_property
def get_mail_aliases(self): def local_email_accounts(self):
if self.internal_address: if (OptionalUser.get_cached_value('local_email_accounts_enabled')
return self.mailalias_set.all() and self.local_email_enabled):
return None return self.localemailaccount_set.all()
return LocalEmailAccount.objects.none()
def get_next_domain_name(self): def get_next_domain_name(self):
"""Look for an available name for a new interface for """Look for an available name for a new interface for
@ -819,20 +808,20 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
) )
@staticmethod @staticmethod
def can_change_redirection(user_request, *_args, **_kwargs): def can_change_local_email_redirect(user_request, *_args, **_kwargs):
""" Check if a user can change redirection. """ Check if a user can change local_email_redirect.
:param user_request: The user who request :param user_request: The user who request
:returns: a message and a boolean which is True if the user has :returns: a message and a boolean which is True if the user has
the right to change a redirection the right to change a redirection
""" """
return ( return (
OptionalUser.get_cached_value('mail_accounts'), OptionalUser.get_cached_value('local_email_accounts_enabled'),
"La gestion des comptes mails doit être activée" "La gestion des comptes mails doit être activée"
) )
@staticmethod @staticmethod
def can_change_internal_address(user_request, *_args, **_kwargs): def can_change_local_email_enabled(user_request, *_args, **_kwargs):
""" Check if a user can change internal address . """ Check if a user can change internal address .
:param user_request: The user who request :param user_request: The user who request
@ -840,9 +829,9 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
the right to change internal address the right to change internal address
""" """
return ( return (
OptionalUser.get_cached_value('mail_accounts'), OptionalUser.get_cached_value('local_email_accounts_enabled'),
"La gestion des comptes mails doit être activée" "La gestion des comptes mails doit être activée"
) )
@staticmethod @staticmethod
def can_change_force(user_request, *_args, **_kwargs): def can_change_force(user_request, *_args, **_kwargs):
@ -938,20 +927,23 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
'shell': self.can_change_shell, 'shell': self.can_change_shell,
'force': self.can_change_force, 'force': self.can_change_force,
'selfpasswd': self.check_selfpasswd, 'selfpasswd': self.check_selfpasswd,
'redirection': self.can_change_redirection, 'local_email_redirect': self.can_change_local_email_redirect,
'internal_address' : self.can_change_internal_address, 'local_email_enabled' : self.can_change_local_email_enabled,
} }
self.__original_state = self.state self.__original_state = self.state
def clean(self, *args, **kwargs): def clean(self, *args, **kwargs):
"""Check if this pseudo is already used by any mailalias. """Check if this pseudo is already used by any mailalias.
Better than raising an error in post-save and catching it""" Better than raising an error in post-save and catching it"""
if MailAlias.objects.filter(valeur=self.pseudo).exclude(user=self): if (LocalEmailAccount.objects
raise ValidationError("Ce pseudo est déjà utilisé") .filter(local_part=self.pseudo)
.exclude(user=self)):
raise ValidationError("This pseudo is already in use.")
def __str__(self): def __str__(self):
return self.pseudo return self.pseudo
class Adherent(User): class Adherent(User):
""" A class representing a member (it's a user with special """ A class representing a member (it's a user with special
informations) """ informations) """
@ -1074,7 +1066,7 @@ def user_post_save(**kwargs):
Synchronise le ldap""" Synchronise le ldap"""
is_created = kwargs['created'] is_created = kwargs['created']
user = kwargs['instance'] user = kwargs['instance']
mail_alias, created = MailAlias.objects.get_or_create(valeur=user.pseudo, user=user) LocalEmailAccount.objects.get_or_create(local_part=user.pseudo, user=user)
if is_created: if is_created:
user.notif_inscription() user.notif_inscription()
user.state_sync() user.state_sync()
@ -1656,87 +1648,122 @@ class LdapServiceUserGroup(ldapdb.models.Model):
return self.name return self.name
class MailAlias(RevMixin, AclMixin, models.Model): class LocalEmailAccount(RevMixin, AclMixin, models.Model):
""" """Defines a local email account for a user
Define a alias for a user Mail
Définit un alias pour un Mail d'utilisateur
""" """
user = models.ForeignKey( user = models.ForeignKey(
User, User,
on_delete=models.CASCADE, on_delete=models.CASCADE,
help_text="Utilisateur associé", help_text="User of the local email",
) )
valeur = models.CharField( local_part = models.CharField(
unique=True, unique=True,
max_length=128, max_length=128,
help_text="Valeur de l'alias mail" help_text="Local part of the email address"
) )
class Meta:
permissions = (
("view_localemailaccount", "Can see a local email account object"),
)
verbose_name = "Local email account"
verbose_name_plural = "Local email accounts"
def __str__(self): def __str__(self):
return self.valeur + OptionalUser.get_cached_value('mail_extension') return self.local_part + OptionalUser.get_cached_value('local_email_domain')
@cached_property
def complete_email_address(self):
return self.local_part + OptionalUser.get_cached_value('local_email_domain')
@staticmethod @staticmethod
def can_create(user_request, userid, *_args, **_kwargs): def can_create(user_request, userid, *_args, **_kwargs):
"""Check if an user can create an mailalias object. """Check if a user can create a `LocalEmailAccount` object.
:param user_request: The user who wants to create a mailalias object. Args:
:return: a message and a boolean which is True if the user can create user_request: The user who wants to create the object.
an user or if the `options.all_can_create` is set. userid: The id of the user to whom the account is to be created
Returns:
a message and a boolean which is True if the user can create
a local email account.
""" """
if not user_request.has_perm('users.add_mailalias'): if user_request.has_perm('users.add_localemailaccount'):
if int(user_request.id) != int(userid): return True, None
return False, 'Vous n\'avez pas le droit d\'ajouter un alias à une autre personne' if not OptionalUser.get_cached_value('local_email_accounts_enabled'):
elif user_request.mailalias_set.all().count() >= OptionalUser.get_cached_value('max_mail_alias'): return False, "The local email accounts are not enabled."
return False, "Vous avez atteint la limite de {} alias".format(OptionalUser.get_cached_value('max_mail_alias')) if int(user_request.id) != int(userid):
else: return False, "You don't have the right to add a local email account to another user."
return True, None elif user_request.local_email_accounts.count() >= OptionalUser.get_cached_value('max_local_email_accounts'):
return False, "You have reached the limit of {} local email account.".format(
OptionalUser.get_cached_value('max_local_email_accounts')
)
return True, None return True, None
def can_view(self, user_request, *_args, **_kwargs): def can_view(self, user_request, *_args, **_kwargs):
""" """Check if a user can view the local email account
Check if the user can view the alias
"""
if user_request.has_perm('users.view_mailalias') or user.request == self.user: Args:
user_request: The user who wants to view the object.
Returns:
a message and a boolean which is True if the user can see
the local email account.
"""
if user_request.has_perm('users.view_localemailaccount'):
return True, None return True, None
else: if not OptionalUser.get_cached_value('local_email_accounts_enabled'):
return False, "Vous n'avais pas les droits suffisants et n'êtes pas propriétaire de ces alias" return False, "The local email accounts are not enabled."
if user_request == self.user:
return True, None
return False, "You don't have the right to edit someone else's local email account."
def can_delete(self, user_request, *_args, **_kwargs): def can_delete(self, user_request, *_args, **_kwargs):
""" """Check if a user can delete the alias
Check if the user can delete the alias
"""
if user_request.has_perm('users.delete_mailalias'): Args:
user_request: The user who wants to delete the object.
Returns:
a message and a boolean which is True if the user can delete
the local email account.
"""
if self.local_part == self.user.pseudo:
return False, ("You cannot delete a local email account whose "
"local part is the same as the username.")
if user_request.has_perm('users.delete_localemailaccount'):
return True, None return True, None
else: if not OptionalUser.get_cached_value('local_email_accounts_enabled'):
if user_request == self.user: return False, "The local email accounts are not enabled."
if self.valeur != self.user.pseudo: if user_request == self.user:
return True, None return True, None
else: return False, ("You don't have the right to delete someone else's "
return False, "Vous ne pouvez pas supprimer l'alias lié à votre pseudo" "local email account")
else:
return False, "Vous n'avez pas les droits suffisants et n'êtes pas propriétairs de ces alias"
def can_edit(self, user_request, *_args, **_kwargs): def can_edit(self, user_request, *_args, **_kwargs):
""" """Check if a user can edit the alias
Check if the user can edit the alias
"""
if user_request.has_perm('users.change_mailalias'): Args:
user_request: The user who wants to edit the object.
Returns:
a message and a boolean which is True if the user can edit
the local email account.
"""
if self.local_part == self.user.pseudo:
return False, ("You cannot edit a local email account whose "
"local part is the same as the username.")
if user_request.has_perm('users.change_localemailaccount'):
return True, None return True, None
else: if not OptionalUser.get_cached_value('local_email_accounts_enabled'):
if user_request == self.user: return False, "The local email accounts are not enabled."
if self.valeur != self.user.pseudo: if user_request == self.user:
return True, None return True, None
else: return False, ("You don't have the right to edit someone else's "
return False, "Vous ne pouvez pas modifier l'alias lié à votre pseudo" "local email account")
else:
return False, "Vous n'avez pas les droits suffisants et n'êtes pas propriétairs de cet alias"
def clean(self, *args, **kwargs): def clean(self, *args, **kwargs):
if "@" in self.valeur: if "@" in self.local_part:
raise ValidationError("Cet alias ne peut contenir un @") raise ValidationError("The local part cannot contain a @")
super(MailAlias, self).clean(*args, **kwargs) super(LocalEmailAccount, self).clean(*args, **kwargs)

View file

@ -21,32 +21,36 @@ 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., with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %} {% endcomment %}
{% load acl %} {% load acl %}
{% if alias_list.paginator %} {% load logs_extra %}
{% if localemailaccount_list.paginator %}
{% include "pagination.html" with list=alias_list %} {% include "pagination.html" with list=alias_list %}
{% endif %} {% endif %}
<table class="table table-striped">
<thead> <table class="table table-striped">
<tr> <thead>
<th>Alias</th> <tr>
<th></th> <th>Local email address</th>
</tr> <th></th>
</thead> </tr>
{% for alias in alias_list %} </thead>
<td>{{ alias }}</td> {% for localemailaccount in localemailaccount_list %}
<td class="text-right"> <td>{{ localemailaccount.complete_email_address }}</td>
{% can_delete alias %} <td class="text-right">
{% include 'buttons/suppr.html' with href='users:del-mailalias' id=alias.id %} {% can_delete localemailaccount %}
{% acl_end %} {% include 'buttons/suppr.html' with href='users:del-localemailaccount' id=localemailaccount.id %}
{% can_edit alias %}
{% include 'buttons/edit.html' with href='users:edit-mailalias' id=alias.id %}
{% acl_end %} {% acl_end %}
{% include 'buttons/history.html' with href='users:history' name='mailalias' id=alias.id %} {% can_edit localemailaccount %}
{% include 'buttons/edit.html' with href='users:edit-localemailaccount' id=localemailaccount.id %}
{% acl_end %}
{% history_button localemailaccount %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
{% if alias_list.paginator %} {% if localemailaccount_list.paginator %}
{% include "pagination.html" with list=alias_list %} {% include "pagination.html" with list=alias_list %}
{% endif %} {% endif %}

View file

@ -25,13 +25,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %} {% load bootstrap3 %}
{% block title %}Users{% endblock %} {% block title %}Local email accounts{% endblock %}
{% block content %} {% block content %}
<h2>Alias</h2> <h2>Local email accounts</h2>
{% include "users/aff_alias.html" with alias_list=alias_list %} {% include "users/aff_localemailaccounts.html" with localemailaccount_list=localemailaccount_list %}
<br />
<br />
<br />
{% endblock %} {% endblock %}

View file

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %} {% load bootstrap3 %}
{% load acl %} {% load acl %}
{% load logs_extra %} {% load logs_extra %}
{% load design %}
{% block title %}Profil{% endblock %} {% block title %}Profil{% endblock %}
@ -408,65 +409,56 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div> </div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading clearfix" data-parent="#accordion" data-toggle="collapse" data-target="#collapse7"> <div class="panel-heading clearfix" data-parent="#accordion" data-toggle="collapse" data-target="#collapse7">
<h3 class="panel-title pull-left"> <h3 class="panel-title pull-left">
<i class="fa fa-envelope"></i> <i class="fa fa-envelope"></i> Email settings
Paramètres mail </h3>
</h3>
</div> </div>
<div id="collapse7" class="panel-collapse collapse"> <div id="collapse7" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
{% can_edit users %} {% can_edit users %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-mail' users.id %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-email-settings' users.id %}">
<i class="fa fa-plus-square"></i> <i class="fa fa-pencil-alt"></i> Edit email settings
Modifier les options mail </a>
</a>
{% acl_end %} {% acl_end %}
{% if mail_accounts %} </div>
<div class="table-responsive"> <div class="panel-body">
<table class="table"> {% if local_email_accounts_enabled %}
<tr> <div class="table-responsive">
<th>Adresse mail externe</th> <table class="table">
<th>Compte mail {{ asso_name }}</th> <tr>
<th>Adresse mail de contact</th> <th colspan="2">Contact email address</th>
</tr> <td colspan="2">{{ users.email }}</td>
<tr> </tr>
<td>{{ users.external_mail }}</td> <tr>
<td>{{ users.internal_address|yesno:"Activé,Désactivé" }}</td> <th>Enable the local email account</th>
<td>{{ users.get_mail }}</td> <td>{{ users.local_email_enabled | tick }}</td>
</table> <th>Enable the local email redirection</th>
<div class="alert alert-info" role="alert"> <td>{{ users.local_email_redirect | tick }}</td>
Vous pouvez bénéficier d'une adresse mail {{ asso_name }}. </tr>
Vous pouvez également la rediriger vers une adresse externe en modifiant les options mail. </table>
</div> </div>
</div> {% if users.local_email_enabled %}
{% if users.internal_address %} {% can_create LocalEmailAccount users.id %}
{% can_create MailAlias users.id %} <a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-localemailaccount' users.id %}">
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-mailalias' users.id %}"> <i class="fa fa-plus-square"></i> Add a local email account
<i class="fa fa-plus-square"></i> </a>
Ajouter un alias mail
</a>
{% acl_end %} {% acl_end %}
{% if alias_list %} {% if localemailaccount_list %}
{% include "users/aff_mailalias.html" with alias_list=alias_list %} {% include "users/aff_localemailaccounts.html" with localemailaccount_list=localemailaccount_list %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% else %} {% else %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table"> <table class="table">
<tr> <tr>
<th>Adresse mail</th> <th>Contact email address</th>
</tr> <td>{{ users.email }}</td>
<tr> </tr>
<td>{{ users.external_mail }}</td> </table>
</tr> </div>
</table> {% endif %}
</div> </div>
{% endif %}
</div>
</div> </div>
</div> </div>
</div> </div>
<br />
<br />
<br />
{% endblock %} {% endblock %}

View file

@ -64,10 +64,18 @@ urlpatterns = [
url(r'^del_whitelist/(?P<whitelistid>[0-9]+)$', url(r'^del_whitelist/(?P<whitelistid>[0-9]+)$',
views.del_whitelist, views.del_whitelist,
name='del-whitelist'), name='del-whitelist'),
url(r'^add_mailalias/(?P<userid>[0-9]+)$', views.add_mailalias, name='add-mailalias'), url(r'^add_localemailaccount/(?P<userid>[0-9]+)$',
url(r'^edit_mailalias/(?P<mailaliasid>[0-9]+)$', views.edit_mailalias, name='edit-mailalias'), views.add_localemailaccount,
url(r'^del-mailalias/(?P<mailaliasid>[0-9]+)$', views.del_mailalias, name='del-mailalias'), name='add-localemailaccount'),
url(r'^edit_mail/(?P<userid>[0-9]+)$', views.edit_mail, name='edit-mail'), url(r'^edit_localemailaccount/(?P<localemailaccountid>[0-9]+)$',
views.edit_localemailaccount,
name='edit-localemailaccount'),
url(r'^del_localemailaccount/(?P<localemailaccountid>[0-9]+)$',
views.del_localemailaccount,
name='del-localemailaccount'),
url(r'^edit_email_settings/(?P<userid>[0-9]+)$',
views.edit_email_settings,
name='edit-email-settings'),
url(r'^add_school/$', views.add_school, name='add-school'), url(r'^add_school/$', views.add_school, name='add-school'),
url(r'^edit_school/(?P<schoolid>[0-9]+)$', url(r'^edit_school/(?P<schoolid>[0-9]+)$',
views.edit_school, views.edit_school,

View file

@ -81,13 +81,13 @@ from .models import (
Adherent, Adherent,
Club, Club,
ListShell, ListShell,
MailAlias, LocalEmailAccount,
) )
from .forms import ( from .forms import (
BanForm, BanForm,
WhitelistForm, WhitelistForm,
MailAliasForm, LocalEmailAccountForm,
MailForm, EmailSettingsForm,
DelSchoolForm, DelSchoolForm,
DelListRightForm, DelListRightForm,
NewListRightForm, NewListRightForm,
@ -496,90 +496,100 @@ def del_whitelist(request, whitelist, **_kwargs):
@login_required @login_required
@can_create(MailAlias) @can_create(LocalEmailAccount)
@can_edit(User) @can_edit(User)
def add_mailalias(request, user, userid): def add_localemailaccount(request, user, userid):
""" Create a new alias""" """ Create a new local email account"""
mailalias_instance = MailAlias(user=user) localemailaccount_instance = LocalEmailAccount(user=user)
mailalias = MailAliasForm( localemailaccount = LocalEmailAccountForm(
request.POST or None, request.POST or None,
instance=mailalias_instance instance=localemailaccount_instance
) )
if mailalias.is_valid(): if localemailaccount.is_valid():
mailalias.save() localemailaccount.save()
messages.success(request, "Alias created") messages.success(request, "Local email account created")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': str(userid)} kwargs={'userid': str(userid)}
)) ))
return form( return form(
{'userform': mailalias, 'action_name': 'Add an alias mail'}, {'userform': localemailaccount,
'showCGU': False,
'action_name': 'Add a local email account'},
'users/user.html', 'users/user.html',
request request
) )
@login_required @login_required
@can_edit(MailAlias) @can_edit(LocalEmailAccount)
def edit_mailalias(request, mailalias_instance, **_kwargs): def edit_localemailaccount(request, localemailaccount_instance, **_kwargs):
""" Edit a mailalias""" """ Edit a local email account"""
mailalias = MailAliasForm( localemailaccount = LocalEmailAccountForm(
request.POST or None, request.POST or None,
instance=mailalias_instance instance=localemailaccount_instance
) )
if mailalias.is_valid(): if localemailaccount.is_valid():
if mailalias.changed_data: if localemailaccount.changed_data:
mailalias.save() localemailaccount.save()
messages.success(request, "Alias modified") messages.success(request, "Local email account modified")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': str(mailalias_instance.user.id)} kwargs={'userid': str(localemailaccount_instance.user.id)}
)) ))
return form( return form(
{'userform': mailalias, 'action_name': 'Edit a mailalias'}, {'userform': localemailaccount,
'showCGU': False,
'action_name': 'Edit a local email account'},
'users/user.html', 'users/user.html',
request request
) )
@login_required @login_required
@can_delete(MailAlias) @can_delete(LocalEmailAccount)
def del_mailalias(request, mailalias, **_kwargs): def del_localemailaccount(request, localemailaccount, **_kwargs):
"""Delete a mail alias""" """Delete a local email account"""
if request.method == "POST": if request.method == "POST":
mailalias.delete() localemailaccount.delete()
messages.success(request, "Alias deleted") messages.success(request, "Local email account deleted")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': str(mailalias.user.id)} kwargs={'userid': str(localemailaccount.user.id)}
)) ))
return form( return form(
{'objet': mailalias, 'objet_name': 'mailalias'}, {'objet': localemailaccount, 'objet_name': 'localemailaccount'},
'users/delete.html', 'users/delete.html',
request request
) )
@login_required @login_required
@can_edit(User) @can_edit(User)
def edit_mail(request, user_instance, **_kwargs): def edit_email_settings(request, user_instance, **_kwargs):
""" Editer un compte mail""" """Edit the email settings of a user"""
mail = MailForm( email_settings = EmailSettingsForm(
request.POST or None, request.POST or None,
instance=user_instance, instance=user_instance,
user=request.user user=request.user
) )
if mail.is_valid(): if email_settings.is_valid():
if mail.changed_data: if email_settings.changed_data:
mail.save() email_settings.save()
messages.success(request, "Option mail modifiée") messages.success(request, "Email settings updated")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': str(user_instance.id)} kwargs={'userid': str(user_instance.id)}
)) ))
return form( return form(
{'userform': mail, 'action_name': 'Editer les options mail'}, {'userform': email_settings,
'showCGU': False,
'action_name': 'Edit the email settings'},
'users/user.html', 'users/user.html',
request request
) )
@login_required @login_required
@can_create(School) @can_create(School)
def add_school(request): def add_school(request):
@ -1002,10 +1012,11 @@ def profil(request, users, **_kwargs):
'white_list': whitelists, 'white_list': whitelists,
'user_solde': user_solde, 'user_solde': user_solde,
'solde_activated': Paiement.objects.filter(is_balance=True).exists(), 'solde_activated': Paiement.objects.filter(is_balance=True).exists(),
'allow_online_payment': allow_online_payment,
'asso_name': AssoOption.objects.first().name, 'asso_name': AssoOption.objects.first().name,
'alias_list': users.mailalias_set.all(), 'localemailaccount_list': users.local_email_accounts,
'mail_accounts': OptionalUser.objects.first().mail_accounts 'local_email_accounts_enabled': (
OptionalUser.objects.first().local_email_accounts_enabled
)
} }
) )