mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-09-12 01:03:09 +00:00
Pylint compliance on preferences
This commit is contained in:
parent
e88141db56
commit
332e8a3413
7 changed files with 113 additions and 28 deletions
|
@ -1,2 +1,28 @@
|
||||||
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||||
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||||
|
# quelques clics.
|
||||||
|
#
|
||||||
|
# Copyright © 2017 Gabriel Détraz
|
||||||
|
# Copyright © 2017 Goulven Kermarec
|
||||||
|
# Copyright © 2017 Augustin Lemesle
|
||||||
|
# Copyright © 2018 Maël Kervella
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
"""preferences
|
||||||
|
The app in charge of storing all the preferences for the local installation
|
||||||
|
"""
|
||||||
|
|
||||||
from .acl import *
|
from .acl import *
|
||||||
|
|
|
@ -1,3 +1,34 @@
|
||||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||||
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||||
|
# quelques clics.
|
||||||
|
#
|
||||||
|
# Copyright © 2017 Gabriel Détraz
|
||||||
|
# Copyright © 2017 Goulven Kermarec
|
||||||
|
# Copyright © 2017 Augustin Lemesle
|
||||||
|
# Copyright © 2018 Maël Kervella
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# App de gestion des machines pour re2o
|
||||||
|
# Gabriel Détraz, Augustin Lemesle
|
||||||
|
# Gplv2
|
||||||
|
"""preferences.aes_field
|
||||||
|
Module defining a AESEncryptedField object that can be used in forms
|
||||||
|
to handle the use of properly encrypting and decrypting AES keys
|
||||||
|
"""
|
||||||
|
|
||||||
import string
|
import string
|
||||||
import binascii
|
import binascii
|
||||||
from random import choice
|
from random import choice
|
||||||
|
@ -10,10 +41,13 @@ EOD = '`%EofD%`' # This should be something that will not occur in strings
|
||||||
|
|
||||||
|
|
||||||
def genstring(length=16, chars=string.printable):
|
def genstring(length=16, chars=string.printable):
|
||||||
|
""" Generate a random string of length `length` and composed of
|
||||||
|
the characters in `chars` """
|
||||||
return ''.join([choice(chars) for i in range(length)])
|
return ''.join([choice(chars) for i in range(length)])
|
||||||
|
|
||||||
|
|
||||||
def encrypt(key, s):
|
def encrypt(key, s):
|
||||||
|
""" AES Encrypt a secret `s` with the key `key` """
|
||||||
obj = AES.new(key)
|
obj = AES.new(key)
|
||||||
datalength = len(s) + len(EOD)
|
datalength = len(s) + len(EOD)
|
||||||
if datalength < 16:
|
if datalength < 16:
|
||||||
|
@ -25,12 +59,15 @@ def encrypt(key, s):
|
||||||
|
|
||||||
|
|
||||||
def decrypt(key, s):
|
def decrypt(key, s):
|
||||||
|
""" AES Decrypt a secret `s` with the key `key` """
|
||||||
obj = AES.new(key)
|
obj = AES.new(key)
|
||||||
ss = obj.decrypt(s)
|
ss = obj.decrypt(s)
|
||||||
return ss.split(bytes(EOD, 'utf-8'))[0]
|
return ss.split(bytes(EOD, 'utf-8'))[0]
|
||||||
|
|
||||||
|
|
||||||
class AESEncryptedField(models.CharField):
|
class AESEncryptedField(models.CharField):
|
||||||
|
""" A Field that can be used in forms for adding the support
|
||||||
|
of AES ecnrypted fields """
|
||||||
def save_form_data(self, instance, data):
|
def save_form_data(self, instance, data):
|
||||||
setattr(instance, self.name,
|
setattr(instance, self.name,
|
||||||
binascii.b2a_base64(encrypt(settings.AES_KEY, data)))
|
binascii.b2a_base64(encrypt(settings.AES_KEY, data)))
|
||||||
|
@ -41,16 +78,10 @@ class AESEncryptedField(models.CharField):
|
||||||
return decrypt(settings.AES_KEY,
|
return decrypt(settings.AES_KEY,
|
||||||
binascii.a2b_base64(value)).decode('utf-8')
|
binascii.a2b_base64(value)).decode('utf-8')
|
||||||
|
|
||||||
def from_db_value(self, value, expression, connection, *args):
|
|
||||||
if value is None:
|
|
||||||
return value
|
|
||||||
return decrypt(settings.AES_KEY,
|
|
||||||
binascii.a2b_base64(value)).decode('utf-8')
|
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return value
|
return value
|
||||||
return binascii.b2a_base64(encrypt(
|
return binascii.b2a_base64(encrypt(
|
||||||
settings.AES_KEY,
|
settings.AES_KEY,
|
||||||
value
|
value
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PreferencesConfig(AppConfig):
|
|
||||||
name = 'preferences'
|
|
|
@ -27,25 +27,31 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.db import models
|
from django.db import models
|
||||||
import cotisations.models
|
from django.db.models.signals import post_save
|
||||||
import machines.models
|
|
||||||
from django.db.models.signals import post_save, post_delete
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from .aes_field import AESEncryptedField
|
import cotisations.models
|
||||||
|
import machines.models
|
||||||
from re2o.mixins import AclMixin
|
from re2o.mixins import AclMixin
|
||||||
|
|
||||||
|
from .aes_field import AESEncryptedField
|
||||||
|
|
||||||
|
|
||||||
class PreferencesModel(models.Model):
|
class PreferencesModel(models.Model):
|
||||||
|
""" Base object for the Preferences objects
|
||||||
|
Defines methods to handle the cache of the settings (they should
|
||||||
|
not change a lot) """
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_in_cache(cls):
|
def set_in_cache(cls):
|
||||||
|
""" Save the preferences in a server-side cache """
|
||||||
instance, _created = cls.objects.get_or_create()
|
instance, _created = cls.objects.get_or_create()
|
||||||
cache.set(cls().__class__.__name__.lower(), instance, None)
|
cache.set(cls().__class__.__name__.lower(), instance, None)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_cached_value(cls, key):
|
def get_cached_value(cls, key):
|
||||||
|
""" Get the preferences from the server-side cache """
|
||||||
instance = cache.get(cls().__class__.__name__.lower())
|
instance = cache.get(cls().__class__.__name__.lower())
|
||||||
if instance is None:
|
if instance is None:
|
||||||
instance = cls.set_in_cache()
|
instance = cls.set_in_cache()
|
||||||
|
@ -112,7 +118,7 @@ class OptionalUser(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=OptionalUser)
|
@receiver(post_save, sender=OptionalUser)
|
||||||
def optionaluser_post_save(sender, **kwargs):
|
def optionaluser_post_save(_sender, **kwargs):
|
||||||
"""Ecriture dans le cache"""
|
"""Ecriture dans le cache"""
|
||||||
user_pref = kwargs['instance']
|
user_pref = kwargs['instance']
|
||||||
user_pref.set_in_cache()
|
user_pref.set_in_cache()
|
||||||
|
@ -147,6 +153,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def ipv6(self):
|
def ipv6(self):
|
||||||
|
""" Check if the IPv6 option is activated """
|
||||||
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
|
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -156,7 +163,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=OptionalMachine)
|
@receiver(post_save, sender=OptionalMachine)
|
||||||
def optionalmachine_post_save(sender, **kwargs):
|
def optionalmachine_post_save(_sender, **kwargs):
|
||||||
"""Synchronisation ipv6 et ecriture dans le cache"""
|
"""Synchronisation ipv6 et ecriture dans le cache"""
|
||||||
machine_pref = kwargs['instance']
|
machine_pref = kwargs['instance']
|
||||||
machine_pref.set_in_cache()
|
machine_pref.set_in_cache()
|
||||||
|
@ -204,7 +211,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=OptionalTopologie)
|
@receiver(post_save, sender=OptionalTopologie)
|
||||||
def optionaltopologie_post_save(sender, **kwargs):
|
def optionaltopologie_post_save(_sender, **kwargs):
|
||||||
"""Ecriture dans le cache"""
|
"""Ecriture dans le cache"""
|
||||||
topologie_pref = kwargs['instance']
|
topologie_pref = kwargs['instance']
|
||||||
topologie_pref.set_in_cache()
|
topologie_pref.set_in_cache()
|
||||||
|
@ -244,7 +251,7 @@ class GeneralOption(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=GeneralOption)
|
@receiver(post_save, sender=GeneralOption)
|
||||||
def generaloption_post_save(sender, **kwargs):
|
def generaloption_post_save(_sender, **kwargs):
|
||||||
"""Ecriture dans le cache"""
|
"""Ecriture dans le cache"""
|
||||||
general_pref = kwargs['instance']
|
general_pref = kwargs['instance']
|
||||||
general_pref.set_in_cache()
|
general_pref.set_in_cache()
|
||||||
|
@ -318,7 +325,7 @@ class AssoOption(AclMixin, PreferencesModel):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=AssoOption)
|
@receiver(post_save, sender=AssoOption)
|
||||||
def assooption_post_save(sender, **kwargs):
|
def assooption_post_save(_sender, **kwargs):
|
||||||
"""Ecriture dans le cache"""
|
"""Ecriture dans le cache"""
|
||||||
asso_pref = kwargs['instance']
|
asso_pref = kwargs['instance']
|
||||||
asso_pref.set_in_cache()
|
asso_pref.set_in_cache()
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
from django.test import TestCase
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||||
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||||
|
# quelques clics.
|
||||||
|
#
|
||||||
|
# Copyright © 2017 Gabriel Détraz
|
||||||
|
# Copyright © 2017 Goulven Kermarec
|
||||||
|
# Copyright © 2017 Augustin Lemesle
|
||||||
|
# Copyright © 2018 Maël Kervella
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
"""preferences.tests
|
||||||
|
The tests for the Preferences module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# from django.test import TestCase
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
|
|
|
@ -27,8 +27,8 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from . import views
|
|
||||||
import re2o
|
import re2o
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
@ -31,17 +31,17 @@ topologie, users, service...)
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models import ProtectedError
|
from django.db.models import ProtectedError
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from reversion.models import Version
|
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
from re2o.views import form
|
from re2o.views import form
|
||||||
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all
|
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all
|
||||||
|
|
||||||
from .forms import ServiceForm, DelServiceForm
|
from .forms import ServiceForm, DelServiceForm
|
||||||
from .models import Service, OptionalUser, OptionalMachine, AssoOption
|
from .models import Service, OptionalUser, OptionalMachine, AssoOption
|
||||||
from .models import MailMessageOption, GeneralOption, OptionalTopologie
|
from .models import MailMessageOption, GeneralOption, OptionalTopologie
|
||||||
|
@ -136,7 +136,7 @@ def add_service(request):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@can_edit(Service)
|
@can_edit(Service)
|
||||||
def edit_service(request, service_instance, serviceid):
|
def edit_service(request, service_instance, _serviceid):
|
||||||
"""Edition des services affichés sur la page d'accueil"""
|
"""Edition des services affichés sur la page d'accueil"""
|
||||||
service = ServiceForm(request.POST or None, instance=service_instance)
|
service = ServiceForm(request.POST or None, instance=service_instance)
|
||||||
if service.is_valid():
|
if service.is_valid():
|
||||||
|
|
Loading…
Reference in a new issue