2017-09-10 14:53:02 +00:00
|
|
|
# -*- mode: python; coding: utf-8 -*-
|
2017-06-25 22:50:55 +00:00
|
|
|
# Re2o 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.
|
2017-10-14 04:03:53 +00:00
|
|
|
"""
|
|
|
|
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
|
|
|
|
"""
|
2017-09-10 23:29:24 +00:00
|
|
|
from __future__ import unicode_literals
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2018-01-29 02:53:49 +00:00
|
|
|
from django.utils.functional import cached_property
|
2017-06-25 22:50:55 +00:00
|
|
|
from django.db import models
|
2018-04-14 18:55:24 +00:00
|
|
|
from django.db.models.signals import post_save
|
2018-01-30 05:33:56 +00:00
|
|
|
from django.dispatch import receiver
|
2018-01-30 22:07:43 +00:00
|
|
|
from django.core.cache import cache
|
2017-10-14 04:03:53 +00:00
|
|
|
|
2018-04-14 18:55:24 +00:00
|
|
|
import cotisations.models
|
|
|
|
import machines.models
|
2018-03-28 15:39:23 +00:00
|
|
|
from re2o.mixins import AclMixin
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2018-04-14 18:55:24 +00:00
|
|
|
from .aes_field import AESEncryptedField
|
|
|
|
|
2018-04-13 23:42:22 +00:00
|
|
|
|
2018-01-31 19:43:36 +00:00
|
|
|
class PreferencesModel(models.Model):
|
2018-04-14 18:55:24 +00:00
|
|
|
""" Base object for the Preferences objects
|
|
|
|
Defines methods to handle the cache of the settings (they should
|
|
|
|
not change a lot) """
|
2018-01-31 19:43:36 +00:00
|
|
|
@classmethod
|
|
|
|
def set_in_cache(cls):
|
2018-04-14 18:55:24 +00:00
|
|
|
""" Save the preferences in a server-side cache """
|
2018-01-31 19:43:36 +00:00
|
|
|
instance, _created = cls.objects.get_or_create()
|
|
|
|
cache.set(cls().__class__.__name__.lower(), instance, None)
|
|
|
|
return instance
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_cached_value(cls, key):
|
2018-04-14 18:55:24 +00:00
|
|
|
""" Get the preferences from the server-side cache """
|
2018-01-31 19:43:36 +00:00
|
|
|
instance = cache.get(cls().__class__.__name__.lower())
|
2018-04-13 23:42:22 +00:00
|
|
|
if instance is None:
|
2018-03-18 09:10:56 +00:00
|
|
|
instance = cls.set_in_cache()
|
2018-01-31 19:43:36 +00:00
|
|
|
return getattr(instance, key)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
abstract = True
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class OptionalUser(AclMixin, PreferencesModel):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Options pour l'user : obligation ou nom du telephone,
|
|
|
|
activation ou non du solde, autorisation du negatif, fingerprint etc"""
|
2017-08-24 19:36:59 +00:00
|
|
|
PRETTY_NAME = "Options utilisateur"
|
|
|
|
|
2017-06-25 22:50:55 +00:00
|
|
|
is_tel_mandatory = models.BooleanField(default=True)
|
|
|
|
user_solde = models.BooleanField(default=False)
|
2017-10-14 04:03:53 +00:00
|
|
|
solde_negatif = models.DecimalField(
|
|
|
|
max_digits=5,
|
|
|
|
decimal_places=2,
|
|
|
|
default=0
|
|
|
|
)
|
2018-01-12 00:07:25 +00:00
|
|
|
max_solde = models.DecimalField(
|
2018-01-11 18:25:41 +00:00
|
|
|
max_digits=5,
|
|
|
|
decimal_places=2,
|
2018-01-12 00:07:25 +00:00
|
|
|
default=50
|
2018-01-11 18:25:41 +00:00
|
|
|
)
|
2018-01-14 19:15:21 +00:00
|
|
|
min_online_payment = models.DecimalField(
|
|
|
|
max_digits=5,
|
|
|
|
decimal_places=2,
|
|
|
|
default=10
|
|
|
|
)
|
2017-06-25 22:50:55 +00:00
|
|
|
gpg_fingerprint = models.BooleanField(default=True)
|
2018-02-22 17:14:20 +00:00
|
|
|
all_can_create_club = models.BooleanField(
|
2017-11-21 04:47:05 +00:00
|
|
|
default=False,
|
2018-02-22 17:14:20 +00:00
|
|
|
help_text="Les users peuvent créer un club"
|
|
|
|
)
|
|
|
|
all_can_create_adherent = models.BooleanField(
|
|
|
|
default=False,
|
|
|
|
help_text="Les users peuvent créer d'autres adhérents",
|
2017-11-21 04:47:05 +00:00
|
|
|
)
|
2018-01-14 19:15:21 +00:00
|
|
|
self_adhesion = models.BooleanField(
|
|
|
|
default=False,
|
|
|
|
help_text="Un nouvel utilisateur peut se créer son compte sur re2o"
|
|
|
|
)
|
2018-03-24 20:19:52 +00:00
|
|
|
shell_default = models.OneToOneField(
|
|
|
|
'users.ListShell',
|
|
|
|
on_delete=models.PROTECT,
|
|
|
|
blank=True,
|
|
|
|
null=True
|
|
|
|
)
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_optionaluser", "Peut voir les options de l'user"),
|
|
|
|
)
|
|
|
|
|
2017-06-26 17:23:01 +00:00
|
|
|
def clean(self):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Creation du mode de paiement par solde"""
|
2017-06-26 17:23:01 +00:00
|
|
|
if self.user_solde:
|
2018-01-11 18:25:41 +00:00
|
|
|
p = cotisations.models.Paiement.objects.filter(moyen="Solde")
|
|
|
|
if not len(p):
|
|
|
|
c = cotisations.models.Paiement(moyen="Solde")
|
|
|
|
c.save()
|
2017-06-26 17:23:01 +00:00
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
|
2018-01-31 03:10:10 +00:00
|
|
|
@receiver(post_save, sender=OptionalUser)
|
2018-04-15 01:00:05 +00:00
|
|
|
def optionaluser_post_save(**kwargs):
|
2018-03-18 09:10:56 +00:00
|
|
|
"""Ecriture dans le cache"""
|
2018-01-31 03:10:10 +00:00
|
|
|
user_pref = kwargs['instance']
|
|
|
|
user_pref.set_in_cache()
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class OptionalMachine(AclMixin, PreferencesModel):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Options pour les machines : maximum de machines ou d'alias par user
|
|
|
|
sans droit, activation de l'ipv6"""
|
2017-08-24 19:36:59 +00:00
|
|
|
PRETTY_NAME = "Options machines"
|
|
|
|
|
2018-01-29 02:53:49 +00:00
|
|
|
SLAAC = 'SLAAC'
|
|
|
|
DHCPV6 = 'DHCPV6'
|
|
|
|
DISABLED = 'DISABLED'
|
|
|
|
CHOICE_IPV6 = (
|
|
|
|
(SLAAC, 'Autoconfiguration par RA'),
|
|
|
|
(DHCPV6, 'Attribution des ip par dhcpv6'),
|
|
|
|
(DISABLED, 'Désactivé'),
|
|
|
|
)
|
|
|
|
|
2017-06-25 22:50:55 +00:00
|
|
|
password_machine = models.BooleanField(default=False)
|
|
|
|
max_lambdauser_interfaces = models.IntegerField(default=10)
|
|
|
|
max_lambdauser_aliases = models.IntegerField(default=10)
|
2018-01-29 02:53:49 +00:00
|
|
|
ipv6_mode = models.CharField(
|
|
|
|
max_length=32,
|
|
|
|
choices=CHOICE_IPV6,
|
|
|
|
default='DISABLED'
|
|
|
|
)
|
2018-02-28 15:36:59 +00:00
|
|
|
create_machine = models.BooleanField(
|
|
|
|
default=True,
|
|
|
|
help_text="Permet à l'user de créer une machine"
|
|
|
|
)
|
2018-01-29 02:53:49 +00:00
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def ipv6(self):
|
2018-04-14 18:55:24 +00:00
|
|
|
""" Check if the IPv6 option is activated """
|
2018-04-13 23:42:22 +00:00
|
|
|
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
|
2018-01-30 22:07:43 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_optionalmachine", "Peut voir les options de machine"),
|
|
|
|
)
|
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
|
2018-01-30 05:33:56 +00:00
|
|
|
@receiver(post_save, sender=OptionalMachine)
|
2018-04-15 01:00:05 +00:00
|
|
|
def optionalmachine_post_save(**kwargs):
|
2018-03-18 09:10:56 +00:00
|
|
|
"""Synchronisation ipv6 et ecriture dans le cache"""
|
2018-01-30 05:33:56 +00:00
|
|
|
machine_pref = kwargs['instance']
|
2018-01-31 03:10:10 +00:00
|
|
|
machine_pref.set_in_cache()
|
2018-01-30 05:33:56 +00:00
|
|
|
if machine_pref.ipv6_mode != "DISABLED":
|
|
|
|
for interface in machines.models.Interface.objects.all():
|
|
|
|
interface.sync_ipv6()
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class OptionalTopologie(AclMixin, PreferencesModel):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Reglages pour la topologie : mode d'accès radius, vlan où placer
|
|
|
|
les machines en accept ou reject"""
|
2017-08-26 13:10:18 +00:00
|
|
|
PRETTY_NAME = "Options topologie"
|
2017-09-02 13:20:44 +00:00
|
|
|
MACHINE = 'MACHINE'
|
|
|
|
DEFINED = 'DEFINED'
|
|
|
|
CHOICE_RADIUS = (
|
2017-10-14 04:03:53 +00:00
|
|
|
(MACHINE, 'Sur le vlan de la plage ip machine'),
|
|
|
|
(DEFINED, 'Prédéfini dans "Vlan où placer les machines\
|
|
|
|
après acceptation RADIUS"'),
|
2017-09-02 13:20:44 +00:00
|
|
|
)
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
radius_general_policy = models.CharField(
|
|
|
|
max_length=32,
|
|
|
|
choices=CHOICE_RADIUS,
|
|
|
|
default='DEFINED'
|
|
|
|
)
|
|
|
|
vlan_decision_ok = models.OneToOneField(
|
|
|
|
'machines.Vlan',
|
|
|
|
on_delete=models.PROTECT,
|
|
|
|
related_name='decision_ok',
|
|
|
|
blank=True,
|
|
|
|
null=True
|
|
|
|
)
|
|
|
|
vlan_decision_nok = models.OneToOneField(
|
|
|
|
'machines.Vlan',
|
|
|
|
on_delete=models.PROTECT,
|
|
|
|
related_name='decision_nok',
|
|
|
|
blank=True,
|
|
|
|
null=True
|
|
|
|
)
|
2017-09-10 16:16:59 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_optionaltopologie", "Peut voir les options de topologie"),
|
|
|
|
)
|
|
|
|
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2018-01-31 03:10:10 +00:00
|
|
|
@receiver(post_save, sender=OptionalTopologie)
|
2018-04-15 01:00:05 +00:00
|
|
|
def optionaltopologie_post_save(**kwargs):
|
2018-03-18 09:10:56 +00:00
|
|
|
"""Ecriture dans le cache"""
|
2018-01-31 03:10:10 +00:00
|
|
|
topologie_pref = kwargs['instance']
|
|
|
|
topologie_pref.set_in_cache()
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class GeneralOption(AclMixin, PreferencesModel):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Options générales : nombre de resultats par page, nom du site,
|
|
|
|
temps où les liens sont valides"""
|
2017-08-24 19:36:59 +00:00
|
|
|
PRETTY_NAME = "Options générales"
|
|
|
|
|
2017-12-16 03:01:39 +00:00
|
|
|
general_message = models.TextField(
|
|
|
|
default="",
|
|
|
|
blank=True,
|
|
|
|
help_text="Message général affiché sur le site (maintenance, etc"
|
|
|
|
)
|
2017-06-25 22:50:55 +00:00
|
|
|
search_display_page = models.IntegerField(default=15)
|
|
|
|
pagination_number = models.IntegerField(default=25)
|
|
|
|
pagination_large_number = models.IntegerField(default=8)
|
2017-08-26 14:04:51 +00:00
|
|
|
req_expire_hrs = models.IntegerField(default=48)
|
|
|
|
site_name = models.CharField(max_length=32, default="Re2o")
|
2018-03-21 21:58:31 +00:00
|
|
|
email_from = models.EmailField(default="www-data@example.com")
|
2018-01-14 22:47:44 +00:00
|
|
|
GTU_sum_up = models.TextField(
|
|
|
|
default="",
|
|
|
|
blank=True,
|
|
|
|
)
|
|
|
|
GTU = models.FileField(
|
2018-04-13 23:42:22 +00:00
|
|
|
upload_to='',
|
2018-01-14 22:47:44 +00:00
|
|
|
default="",
|
|
|
|
null=True,
|
|
|
|
blank=True,
|
|
|
|
)
|
2017-06-25 22:50:55 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_generaloption", "Peut voir les options générales"),
|
|
|
|
)
|
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
|
2018-01-31 03:10:10 +00:00
|
|
|
@receiver(post_save, sender=GeneralOption)
|
2018-04-15 01:00:05 +00:00
|
|
|
def generaloption_post_save(**kwargs):
|
2018-03-18 09:10:56 +00:00
|
|
|
"""Ecriture dans le cache"""
|
2018-01-31 03:10:10 +00:00
|
|
|
general_pref = kwargs['instance']
|
|
|
|
general_pref.set_in_cache()
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class Service(AclMixin, models.Model):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Liste des services affichés sur la page d'accueil : url, description,
|
|
|
|
image et nom"""
|
2017-08-24 19:36:59 +00:00
|
|
|
name = models.CharField(max_length=32)
|
|
|
|
url = models.URLField()
|
|
|
|
description = models.TextField()
|
2017-10-14 04:03:53 +00:00
|
|
|
image = models.ImageField(upload_to='logo', blank=True)
|
2017-08-24 19:36:59 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_service", "Peut voir les options de service"),
|
|
|
|
)
|
|
|
|
|
2017-08-25 02:35:49 +00:00
|
|
|
def __str__(self):
|
|
|
|
return str(self.name)
|
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class AssoOption(AclMixin, PreferencesModel):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Options générales de l'asso : siret, addresse, nom, etc"""
|
2017-08-24 19:36:59 +00:00
|
|
|
PRETTY_NAME = "Options de l'association"
|
|
|
|
|
2017-10-14 04:03:53 +00:00
|
|
|
name = models.CharField(
|
|
|
|
default="Association réseau école machin",
|
|
|
|
max_length=256
|
|
|
|
)
|
2017-08-24 19:36:59 +00:00
|
|
|
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)
|
2017-10-14 04:03:53 +00:00
|
|
|
utilisateur_asso = models.OneToOneField(
|
|
|
|
'users.User',
|
|
|
|
on_delete=models.PROTECT,
|
|
|
|
blank=True,
|
|
|
|
null=True
|
|
|
|
)
|
2018-01-11 18:25:41 +00:00
|
|
|
PAYMENT = (
|
|
|
|
('NONE', 'NONE'),
|
|
|
|
('COMNPAY', 'COMNPAY'),
|
|
|
|
)
|
2018-03-18 09:10:56 +00:00
|
|
|
payment = models.CharField(
|
|
|
|
max_length=255,
|
2018-01-11 18:25:41 +00:00
|
|
|
choices=PAYMENT,
|
|
|
|
default='NONE',
|
|
|
|
)
|
2018-01-15 00:06:54 +00:00
|
|
|
payment_id = models.CharField(
|
|
|
|
max_length=255,
|
|
|
|
default='',
|
2018-03-18 09:10:56 +00:00
|
|
|
blank=True
|
2018-01-15 00:06:54 +00:00
|
|
|
)
|
|
|
|
payment_pass = AESEncryptedField(
|
|
|
|
max_length=255,
|
2018-01-29 16:46:46 +00:00
|
|
|
null=True,
|
|
|
|
blank=True,
|
2018-01-15 00:06:54 +00:00
|
|
|
)
|
2018-03-18 01:14:45 +00:00
|
|
|
description = models.TextField(
|
|
|
|
null=True,
|
|
|
|
blank=True,
|
|
|
|
)
|
2018-01-15 00:06:54 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_assooption", "Peut voir les options de l'asso"),
|
|
|
|
)
|
|
|
|
|
2017-09-08 20:53:13 +00:00
|
|
|
|
2018-01-31 03:10:10 +00:00
|
|
|
@receiver(post_save, sender=AssoOption)
|
2018-04-15 01:00:05 +00:00
|
|
|
def assooption_post_save(**kwargs):
|
2018-03-18 09:10:56 +00:00
|
|
|
"""Ecriture dans le cache"""
|
2018-01-31 03:10:10 +00:00
|
|
|
asso_pref = kwargs['instance']
|
|
|
|
asso_pref.set_in_cache()
|
|
|
|
|
|
|
|
|
2018-03-28 15:39:23 +00:00
|
|
|
class MailMessageOption(AclMixin, models.Model):
|
2017-10-14 04:03:53 +00:00
|
|
|
"""Reglages, mail de bienvenue et autre"""
|
2017-09-08 20:53:13 +00:00
|
|
|
PRETTY_NAME = "Options de corps de mail"
|
|
|
|
|
|
|
|
welcome_mail_fr = models.TextField(default="")
|
|
|
|
welcome_mail_en = models.TextField(default="")
|
2017-12-08 23:41:16 +00:00
|
|
|
|
2017-12-31 20:43:59 +00:00
|
|
|
class Meta:
|
|
|
|
permissions = (
|
|
|
|
("view_mailmessageoption", "Peut voir les options de mail"),
|
|
|
|
)
|