models.py 10.4 KB
Newer Older
1
# -*- mode: python; coding: utf-8 -*-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 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.
23 24 25
"""
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
"""
26
from __future__ import unicode_literals
27

28
from django.utils.functional import cached_property
29
from django.db import models
30
from django.db.models.signals import post_save
31
from django.dispatch import receiver
32
from django.core.cache import cache
33

34 35
import cotisations.models
import machines.models
chirac's avatar
chirac committed
36
from re2o.mixins import AclMixin
37

38 39
from .aes_field import AESEncryptedField

Maël Kervella's avatar
Maël Kervella committed
40

Gabriel Detraz's avatar
Gabriel Detraz committed
41
class PreferencesModel(models.Model):
42 43 44
    """ Base object for the Preferences objects
    Defines methods to handle the cache of the settings (they should
    not change a lot) """
Gabriel Detraz's avatar
Gabriel Detraz committed
45 46
    @classmethod
    def set_in_cache(cls):
47
        """ Save the preferences in a server-side cache """
Gabriel Detraz's avatar
Gabriel Detraz committed
48 49 50 51 52 53
        instance, _created = cls.objects.get_or_create()
        cache.set(cls().__class__.__name__.lower(), instance, None)
        return instance

    @classmethod
    def get_cached_value(cls, key):
54
        """ Get the preferences from the server-side cache """
Gabriel Detraz's avatar
Gabriel Detraz committed
55
        instance = cache.get(cls().__class__.__name__.lower())
Maël Kervella's avatar
Maël Kervella committed
56
        if instance is None:
57
            instance = cls.set_in_cache()
Gabriel Detraz's avatar
Gabriel Detraz committed
58 59 60 61 62 63
        return getattr(instance, key)

    class Meta:
        abstract = True


chirac's avatar
chirac committed
64
class OptionalUser(AclMixin, PreferencesModel):
65 66
    """Options pour l'user : obligation ou nom du telephone,
    activation ou non du solde, autorisation du negatif, fingerprint etc"""
67 68
    PRETTY_NAME = "Options utilisateur"

69 70
    is_tel_mandatory = models.BooleanField(default=True)
    user_solde = models.BooleanField(default=False)
71 72 73 74 75
    solde_negatif = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        default=0
    )
76
    max_solde = models.DecimalField(
77 78
        max_digits=5,
        decimal_places=2,
79
        default=50
80
    )
81 82 83 84 85
    min_online_payment = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        default=10
    )
86
    gpg_fingerprint = models.BooleanField(default=True)
87
    all_can_create_club = models.BooleanField(
88
        default=False,
89 90 91 92 93
        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",
94
    )
95 96 97 98
    self_adhesion = models.BooleanField(
        default=False,
        help_text="Un nouvel utilisateur peut se créer son compte sur re2o"
    )
99 100 101 102 103 104
    shell_default = models.OneToOneField(
        'users.ListShell',
        on_delete=models.PROTECT,
        blank=True,
        null=True
    )
105

106 107 108 109 110
    class Meta:
        permissions = (
            ("view_optionaluser", "Peut voir les options de l'user"),
        )

chibrac's avatar
chibrac committed
111
    def clean(self):
112
        """Creation du mode de paiement par solde"""
chibrac's avatar
chibrac committed
113
        if self.user_solde:
114 115 116 117
            p = cotisations.models.Paiement.objects.filter(moyen="Solde")
            if not len(p):
                c = cotisations.models.Paiement(moyen="Solde")
                c.save()
chibrac's avatar
chibrac committed
118

119

120
@receiver(post_save, sender=OptionalUser)
121
def optionaluser_post_save(_sender, **kwargs):
122
    """Ecriture dans le cache"""
123 124 125 126
    user_pref = kwargs['instance']
    user_pref.set_in_cache()


chirac's avatar
chirac committed
127
class OptionalMachine(AclMixin, PreferencesModel):
128 129
    """Options pour les machines : maximum de machines ou d'alias par user
    sans droit, activation de l'ipv6"""
130 131
    PRETTY_NAME = "Options machines"

132 133 134 135 136 137 138 139 140
    SLAAC = 'SLAAC'
    DHCPV6 = 'DHCPV6'
    DISABLED = 'DISABLED'
    CHOICE_IPV6 = (
        (SLAAC, 'Autoconfiguration par RA'),
        (DHCPV6, 'Attribution des ip par dhcpv6'),
        (DISABLED, 'Désactivé'),
    )

141 142 143
    password_machine = models.BooleanField(default=False)
    max_lambdauser_interfaces = models.IntegerField(default=10)
    max_lambdauser_aliases = models.IntegerField(default=10)
144 145 146 147 148
    ipv6_mode = models.CharField(
        max_length=32,
        choices=CHOICE_IPV6,
        default='DISABLED'
    )
149 150 151 152
    create_machine = models.BooleanField(
        default=True,
        help_text="Permet à l'user de créer une machine"
    )
153 154 155

    @cached_property
    def ipv6(self):
156
        """ Check if the IPv6 option is activated """
Maël Kervella's avatar
Maël Kervella committed
157
        return not self.get_cached_value('ipv6_mode') == 'DISABLED'
158

159 160 161 162 163
    class Meta:
        permissions = (
            ("view_optionalmachine", "Peut voir les options de machine"),
        )

164

165
@receiver(post_save, sender=OptionalMachine)
166
def optionalmachine_post_save(_sender, **kwargs):
167
    """Synchronisation ipv6 et ecriture dans le cache"""
168
    machine_pref = kwargs['instance']
169
    machine_pref.set_in_cache()
170 171 172 173 174
    if machine_pref.ipv6_mode != "DISABLED":
        for interface in machines.models.Interface.objects.all():
            interface.sync_ipv6()


chirac's avatar
chirac committed
175
class OptionalTopologie(AclMixin, PreferencesModel):
176 177
    """Reglages pour la topologie : mode d'accès radius, vlan où placer
    les machines en accept ou reject"""
178
    PRETTY_NAME = "Options topologie"
179 180 181
    MACHINE = 'MACHINE'
    DEFINED = 'DEFINED'
    CHOICE_RADIUS = (
182 183 184
        (MACHINE, 'Sur le vlan de la plage ip machine'),
        (DEFINED, 'Prédéfini dans "Vlan où placer les machines\
            après acceptation RADIUS"'),
185
    )
186

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
    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
    )
206

207 208 209 210 211
    class Meta:
        permissions = (
            ("view_optionaltopologie", "Peut voir les options de topologie"),
        )

212

213
@receiver(post_save, sender=OptionalTopologie)
214
def optionaltopologie_post_save(_sender, **kwargs):
215
    """Ecriture dans le cache"""
216 217 218 219
    topologie_pref = kwargs['instance']
    topologie_pref.set_in_cache()


chirac's avatar
chirac committed
220
class GeneralOption(AclMixin, PreferencesModel):
221 222
    """Options générales : nombre de resultats par page, nom du site,
    temps où les liens sont valides"""
223 224
    PRETTY_NAME = "Options générales"

225 226 227 228 229
    general_message = models.TextField(
        default="",
        blank=True,
        help_text="Message général affiché sur le site (maintenance, etc"
    )
230 231 232
    search_display_page = models.IntegerField(default=15)
    pagination_number = models.IntegerField(default=25)
    pagination_large_number = models.IntegerField(default=8)
233 234
    req_expire_hrs = models.IntegerField(default=48)
    site_name = models.CharField(max_length=32, default="Re2o")
235
    email_from = models.EmailField(default="www-data@example.com")
236 237 238 239 240
    GTU_sum_up = models.TextField(
        default="",
        blank=True,
    )
    GTU = models.FileField(
Maël Kervella's avatar
Maël Kervella committed
241
        upload_to='',
242 243 244 245
        default="",
        null=True,
        blank=True,
    )
246

247 248 249 250 251
    class Meta:
        permissions = (
            ("view_generaloption", "Peut voir les options générales"),
        )

252

253
@receiver(post_save, sender=GeneralOption)
254
def generaloption_post_save(_sender, **kwargs):
255
    """Ecriture dans le cache"""
256 257 258 259
    general_pref = kwargs['instance']
    general_pref.set_in_cache()


chirac's avatar
chirac committed
260
class Service(AclMixin, models.Model):
261 262
    """Liste des services affichés sur la page d'accueil : url, description,
    image et nom"""
263 264 265
    name = models.CharField(max_length=32)
    url = models.URLField()
    description = models.TextField()
266
    image = models.ImageField(upload_to='logo', blank=True)
267

268 269 270 271 272
    class Meta:
        permissions = (
            ("view_service", "Peut voir les options de service"),
        )

273 274 275
    def __str__(self):
        return str(self.name)

276

chirac's avatar
chirac committed
277
class AssoOption(AclMixin, PreferencesModel):
278
    """Options générales de l'asso : siret, addresse, nom, etc"""
279 280
    PRETTY_NAME = "Options de l'association"

281 282 283 284
    name = models.CharField(
        default="Association réseau école machin",
        max_length=256
    )
285 286 287 288 289 290
    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)
291 292 293 294 295 296
    utilisateur_asso = models.OneToOneField(
        'users.User',
        on_delete=models.PROTECT,
        blank=True,
        null=True
    )
297 298 299 300
    PAYMENT = (
        ('NONE', 'NONE'),
        ('COMNPAY', 'COMNPAY'),
    )
301 302
    payment = models.CharField(
        max_length=255,
303 304 305
        choices=PAYMENT,
        default='NONE',
    )
306 307 308
    payment_id = models.CharField(
        max_length=255,
        default='',
309
        blank=True
310 311 312
    )
    payment_pass = AESEncryptedField(
        max_length=255,
Gabriel Detraz's avatar
Gabriel Detraz committed
313 314
        null=True,
        blank=True,
315
    )
316 317 318 319
    description = models.TextField(
        null=True,
        blank=True,
    )
320

321 322 323 324 325
    class Meta:
        permissions = (
            ("view_assooption", "Peut voir les options de l'asso"),
        )

326

327
@receiver(post_save, sender=AssoOption)
328
def assooption_post_save(_sender, **kwargs):
329
    """Ecriture dans le cache"""
330 331 332 333
    asso_pref = kwargs['instance']
    asso_pref.set_in_cache()


chirac's avatar
chirac committed
334
class MailMessageOption(AclMixin, models.Model):
335
    """Reglages, mail de bienvenue et autre"""
336 337 338 339
    PRETTY_NAME = "Options de corps de mail"

    welcome_mail_fr = models.TextField(default="")
    welcome_mail_en = models.TextField(default="")
340

341 342 343 344
    class Meta:
        permissions = (
            ("view_mailmessageoption", "Peut voir les options de mail"),
        )