Commit 54d1172e authored by klafyvel's avatar klafyvel
Browse files

Merge branch 'optimisations' into 'master'

Optimisations

See merge request federez/re2o!71
parents 02acb7a6 a53f69c4
......@@ -296,9 +296,8 @@ class RechargeForm(Form):
def clean_value(self):
value = self.cleaned_data['value']
options, _created = OptionalUser.objects.get_or_create()
if value < options.min_online_payment:
raise forms.ValidationError("Montant inférieur au montant minimal de paiement en ligne (%s) €" % options.min_online_payment)
if value + self.user.solde > options.max_solde:
raise forms.ValidationError("Le solde ne peux excéder %s " % options.max_solde)
if value < OptionalUser.get_cached_value('min_online_payment'):
raise forms.ValidationError("Montant inférieur au montant minimal de paiement en ligne (%s) €" % OptionalUser.get_cached_value('min_online_payment'))
if value + self.user.solde > OptionalUser.get_cached_value('max_solde'):
raise forms.ValidationError("Le solde ne peux excéder %s " % OptionalUser.get_cached_value('max_solde'))
return value
......@@ -38,7 +38,6 @@ def refuse_payment(request):
@csrf_exempt
def ipn(request):
option, _created = AssoOption.objects.get_or_create()
p = ComnpayPayment()
order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', )
try:
......@@ -46,7 +45,7 @@ def ipn(request):
except MultiValueDictKeyError:
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
if not p.validSec(data, option.payment_pass):
if not p.validSec(data, AssoOption.get_cached_value('payment_pass')):
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
result = True if (request.POST['result'] == 'OK') else False
......@@ -54,7 +53,7 @@ def ipn(request):
idTransaction = request.POST['idTransaction']
# On vérifie que le paiement nous est destiné
if not idTpe == option.payment_id:
if not idTpe == AssoOption.get_cached_value('payment_id'):
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
try:
......@@ -81,10 +80,9 @@ def ipn(request):
def comnpay(facture, request):
host = request.get_host()
option, _created = AssoOption.objects.get_or_create()
p = ComnpayPayment(
str(option.payment_id),
str(option.payment_pass),
str(AssoOption.get_cached_value('payment_id')),
str(AssoOption.get_cached_value('payment_pass')),
'https://' + host + reverse(
'cotisations:accept_payment',
kwargs={'factureid':facture.id}
......
......@@ -106,9 +106,8 @@ def new_facture(request, user, userid):
articles = article_formset
# Si au moins un article est rempli
if any(art.cleaned_data for art in articles):
options, _created = OptionalUser.objects.get_or_create()
user_solde = options.user_solde
solde_negatif = options.solde_negatif
user_solde = OptionalUser.get_cached_value('user_solde')
solde_negatif = OptionalUser.get_cached_value('solde_negatif')
# Si on paye par solde, que l'option est activée,
# on vérifie que le négatif n'est pas atteint
if user_solde:
......@@ -181,7 +180,6 @@ def new_facture_pdf(request):
Vente ou Facture correspondant en bdd"""
facture_form = NewFactureFormPdf(request.POST or None)
if facture_form.is_valid():
options, _created = AssoOption.objects.get_or_create()
tbl = []
article = facture_form.cleaned_data['article']
quantite = facture_form.cleaned_data['number']
......@@ -200,12 +198,12 @@ def new_facture_pdf(request):
'article': tbl,
'total': prix_total,
'paid': paid,
'asso_name': options.name,
'line1': options.adresse1,
'line2': options.adresse2,
'siret': options.siret,
'email': options.contact,
'phone': options.telephone,
'asso_name': AssoOption.get_cached_value('name'),
'line1': AssoOption.get_cached_value('adresse1'),
'line2': AssoOption.get_cached_value('adresse2'),
'siret': AssoOption.get_cached_value('siret'),
'email': AssoOption.get_cached_value('contact'),
'phone': AssoOption.get_cached_value('telephone'),
'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
})
return form({
......@@ -223,7 +221,6 @@ def facture_pdf(request, facture, factureid):
ventes_objects = Vente.objects.all().filter(facture=facture)
ventes = []
options, _created = AssoOption.objects.get_or_create()
for vente in ventes_objects:
ventes.append([vente, vente.number, vente.prix_total])
return render_invoice(request, {
......@@ -233,12 +230,12 @@ def facture_pdf(request, facture, factureid):
'dest': facture.user,
'article': ventes,
'total': facture.prix_total(),
'asso_name': options.name,
'line1': options.adresse1,
'line2': options.adresse2,
'siret': options.siret,
'email': options.contact,
'phone': options.telephone,
'asso_name': AssoOption.get_cached_value('name'),
'line1': AssoOption.get_cached_value('adresse1'),
'line2': AssoOption.get_cached_value('adresse2'),
'siret': AssoOption.get_cached_value('siret'),
'email': AssoOption.get_cached_value('contact'),
'phone': AssoOption.get_cached_value('telephone'),
'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
})
......@@ -498,8 +495,7 @@ def del_banque(request, instances):
def control(request):
"""Pour le trésorier, vue pour controler en masse les
factures.Case à cocher, pratique"""
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
facture_list = Facture.objects.select_related('user').select_related('paiement')
facture_list = SortTable.sort(
facture_list,
......@@ -567,8 +563,7 @@ def index_banque(request):
@can_view_all(Facture)
def index(request):
"""Affiche l'ensemble des factures, pour les cableurs et +"""
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
facture_list = Facture.objects.select_related('user')\
.select_related('paiement').prefetch_related('vente_set')
facture_list = SortTable.sort(
......@@ -617,9 +612,8 @@ def new_facture_solde(request, userid):
articles = article_formset
# Si au moins un article est rempli
if any(art.cleaned_data for art in articles):
options, _created = OptionalUser.objects.get_or_create()
user_solde = options.user_solde
solde_negatif = options.solde_negatif
user_solde = OptionalUser.get_cached_value('user_solde')
solde_negatif = OptionalUser.get_cached_value('solde_negatif')
# Si on paye par solde, que l'option est activée,
# on vérifie que le négatif n'est pas atteint
if user_solde:
......@@ -687,8 +681,7 @@ def new_facture_solde(request, userid):
@login_required
def recharge(request):
options, _created = AssoOption.objects.get_or_create()
if options.payment == 'NONE':
if AssoOption.get_cached_value('payment') == 'NONE':
messages.error(
request,
"Le paiement en ligne est désactivé."
......@@ -711,6 +704,6 @@ def recharge(request):
number=1,
)
v.save()
content = payment.PAYMENT_SYSTEM[options.payment](facture, request)
content = payment.PAYMENT_SYSTEM[AssoOption.get_cached_value('payment')](facture, request)
return render(request, 'cotisations/payment.html', content)
return form({'rechargeform':f}, 'cotisations/recharge.html', request)
......@@ -121,8 +121,7 @@ STATS_DICT = {
def index(request):
"""Affiche les logs affinés, date reformatées, selectionne
les event importants (ajout de droits, ajout de ban/whitelist)"""
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
# The types of content kept for display
content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user']
# Select only wanted versions
......@@ -180,8 +179,7 @@ def index(request):
def stats_logs(request):
"""Affiche l'ensemble des logs et des modifications sur les objets,
classés par date croissante, en vrac"""
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
revisions = Revision.objects.all().select_related('user')\
.prefetch_related('version_set__object')
revisions = SortTable.sort(
......
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-01-30 15:23
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('machines', '0075_auto_20180130_0052'),
]
operations = [
migrations.AlterField(
model_name='ipv6list',
name='interface',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ipv6list', to='machines.Interface'),
),
]
......@@ -94,8 +94,7 @@ class Machine(FieldPermissionModelMixin, models.Model):
user = users.models.User.objects.get(pk=userid)
except users.models.User.DoesNotExist:
return False, u"Utilisateur inexistant"
options, created = preferences.models.OptionalMachine.objects.get_or_create()
max_lambdauser_interfaces = options.max_lambdauser_interfaces
max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value('max_lambdauser_interfaces')
if not user_request.has_perm('machines.add_machine'):
if user != user_request:
return False, u"Vous ne pouvez pas ajouter une machine à un\
......@@ -1244,10 +1243,9 @@ class Interface(FieldPermissionModelMixin,models.Model):
def sync_ipv6(self):
"""Cree et met à jour l'ensemble des ipv6 en fonction du mode choisi"""
machine_options, _created = preferences.models.OptionalMachine.objects.get_or_create()
if machine_options.ipv6_mode == 'SLAAC':
if preferences.models.OptionalMachine.get_cached_value('ipv6_mode') == 'SLAAC':
self.sync_ipv6_slaac()
elif machine_options.ipv6_mode == 'DHCPV6':
elif preferences.models.OptionalMachine.get_cached_value('ipv6_mode') == 'DHCPV6':
self.sync_ipv6_dhcpv6()
else:
return
......@@ -1255,11 +1253,10 @@ class Interface(FieldPermissionModelMixin,models.Model):
def ipv6(self):
""" Renvoie le queryset de la liste des ipv6
On renvoie l'ipv6 slaac que si le mode slaac est activé (et non dhcpv6)"""
machine_options, _created = preferences.models.OptionalMachine.objects.get_or_create()
if machine_options.ipv6_mode == 'SLAAC':
return Ipv6List.objects.filter(interface=self)
elif machine_options.ipv6_mode == 'DHCPV6':
return Ipv6List.objects.filter(interface=self, slaac_ip=False)
if preferences.models.OptionalMachine.get_cached_value('ipv6_mode') == 'SLAAC':
return self.ipv6list.all()
elif preferences.models.OptionalMachine.get_cached_value('ipv6_mode') == 'DHCPV6':
return self.ipv6list.filter(slaac_ip=False)
else:
return None
......@@ -1338,8 +1335,7 @@ class Interface(FieldPermissionModelMixin,models.Model):
except Machine.DoesNotExist:
return False, u"Machine inexistante"
if not user_request.has_perm('machines.add_interface'):
options, created = preferences.models.OptionalMachine.objects.get_or_create()
max_lambdauser_interfaces = options.max_lambdauser_interfaces
max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value('max_lambdauser_interfaces')
if machine.user != user_request:
return False, u"Vous ne pouvez pas ajouter une interface à une\
machine d'un autre user que vous sans droit"
......@@ -1432,7 +1428,7 @@ class Ipv6List(FieldPermissionModelMixin, models.Model):
protocol='IPv6',
unique=True
)
interface = models.ForeignKey('Interface', on_delete=models.CASCADE)
interface = models.ForeignKey('Interface', on_delete=models.CASCADE, related_name='ipv6list')
slaac_ip = models.BooleanField(default=False)
class Meta:
......@@ -1655,8 +1651,7 @@ class Domain(models.Model):
except Interface.DoesNotExist:
return False, u"Interface inexistante"
if not user_request.has_perm('machines.add_domain'):
options, created = preferences.models.OptionalMachine.objects.get_or_create()
max_lambdauser_aliases = options.max_lambdauser_aliases
max_lambdauser_aliases = preferences.models.OptionalMachine.get_cached_value('max_lambdauser_aliases')
if interface.machine.user != user_request:
return False, u"Vous ne pouvez pas ajouter un alias à une\
machine d'un autre user que vous sans droit"
......
......@@ -981,9 +981,8 @@ def del_nas(request, instances):
@login_required
@can_view_all(Machine)
def index(request):
options, created = GeneralOption.objects.get_or_create()
pagination_large_number = options.pagination_large_number
machines_list = Machine.objects.select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type').prefetch_related('interface_set__type__ip_type__extension').prefetch_related('interface_set__domain__related_domain__extension')
pagination_large_number = GeneralOption.get_cached_value('pagination_large_number')
machines_list = Machine.objects.select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type').prefetch_related('interface_set__type__ip_type__extension').prefetch_related('interface_set__domain__related_domain__extension').prefetch_related('interface_set__ipv6list')
machines_list = SortTable.sort(
machines_list,
request.GET.get('col'),
......@@ -1166,7 +1165,7 @@ def mac_ip_list(request):
@login_required
@permission_required('machines.serveur')
def full_mac_ip_list(request):
interfaces = all_active_assigned_interfaces()
interfaces = all_active_assigned_interfaces(full=True)
seria = FullInterfaceSerializer(interfaces, many=True)
return seria.data
......
......@@ -31,6 +31,7 @@ import cotisations.models
import machines.models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.cache import cache
from .aes_field import AESEncryptedField
......@@ -67,6 +68,19 @@ class OptionalUser(models.Model):
help_text="Un nouvel utilisateur peut se créer son compte sur re2o"
)
@classmethod
def set_in_cache(cls):
optionaluser, _created = cls.objects.get_or_create()
cache.set('optionaluser', optionaluser, None)
return optionaluser
@classmethod
def get_cached_value(cls, key):
optionaluser = cache.get('optionaluser')
if optionaluser == None:
optionaluser = cls.set_in_cache()
return getattr(optionaluser, key)
class Meta:
permissions = (
("view_optionaluser", "Peut voir les options de l'user"),
......@@ -133,6 +147,13 @@ class OptionalUser(models.Model):
c.save()
@receiver(post_save, sender=OptionalUser)
def optionaluser_post_save(sender, **kwargs):
"""Ecriture dans le cache"""
user_pref = kwargs['instance']
user_pref.set_in_cache()
class OptionalMachine(models.Model):
"""Options pour les machines : maximum de machines ou d'alias par user
sans droit, activation de l'ipv6"""
......@@ -158,7 +179,20 @@ class OptionalMachine(models.Model):
@cached_property
def ipv6(self):
return not self.ipv6_mode == 'DISABLED'
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
@classmethod
def set_in_cache(cls):
optionalmachine, _created = cls.objects.get_or_create()
cache.set('optionalmachine', optionalmachine, None)
return optionalmachine
@classmethod
def get_cached_value(cls, key):
optionalmachine = cache.get('optionalmachine')
if optionalmachine == None:
optionalmachine = cls.set_in_cache()
return getattr(optionalmachine, key)
class Meta:
permissions = (
......@@ -220,9 +254,10 @@ class OptionalMachine(models.Model):
@receiver(post_save, sender=OptionalMachine)
def interface_post_save(sender, **kwargs):
"""Synchronisation ipv6"""
def optionalmachine_post_save(sender, **kwargs):
"""Synchronisation ipv6 et ecriture dans le cache"""
machine_pref = kwargs['instance']
machine_pref.set_in_cache()
if machine_pref.ipv6_mode != "DISABLED":
for interface in machines.models.Interface.objects.all():
interface.sync_ipv6()
......@@ -260,6 +295,19 @@ class OptionalTopologie(models.Model):
null=True
)
@classmethod
def set_in_cache(cls):
optionaltopologie, _created = cls.objects.get_or_create()
cache.set('optionaltopologie', optionaltopologie, None)
return optionaltopologie
@classmethod
def get_cached_value(cls, key):
optionaltopologie = cache.get('optionaltopologie')
if optionaltopologie == None:
optionaltopologie = cls.set_in_cache()
return getattr(optionaltopologie, key)
class Meta:
permissions = (
("view_optionaltopologie", "Peut voir les options de topologie"),
......@@ -318,6 +366,13 @@ class OptionalTopologie(models.Model):
de voir les préférences concernant la topologie"
@receiver(post_save, sender=OptionalTopologie)
def optionaltopologie_post_save(sender, **kwargs):
"""Ecriture dans le cache"""
topologie_pref = kwargs['instance']
topologie_pref.set_in_cache()
class GeneralOption(models.Model):
"""Options générales : nombre de resultats par page, nom du site,
temps où les liens sont valides"""
......@@ -345,6 +400,19 @@ class GeneralOption(models.Model):
blank=True,
)
@classmethod
def set_in_cache(cls):
generaloption, _created = cls.objects.get_or_create()
cache.set('generaloption', generaloption, None)
return generaloption
@classmethod
def get_cached_value(cls, key):
generaloption = cache.get('generaloption')
if generaloption == None:
generaloption = cls.set_in_cache()
return getattr(generaloption, key)
class Meta:
permissions = (
("view_generaloption", "Peut voir les options générales"),
......@@ -404,6 +472,13 @@ class GeneralOption(models.Model):
de voir les préférences générales"
@receiver(post_save, sender=GeneralOption)
def generaloption_post_save(sender, **kwargs):
"""Ecriture dans le cache"""
general_pref = kwargs['instance']
general_pref.set_in_cache()
class Service(models.Model):
"""Liste des services affichés sur la page d'accueil : url, description,
image et nom"""
......@@ -513,6 +588,18 @@ class AssoOption(models.Model):
blank=True,
)
@classmethod
def set_in_cache(cls):
assooption, _created = cls.objects.get_or_create()
cache.set('assooption', assooption, None)
return assooption
@classmethod
def get_cached_value(cls, key):
assooption = cache.get('assooption')
if assooption == None:
assooption = cls.set_in_cache()
return getattr(assooption, key)
class Meta:
permissions = (
......@@ -572,6 +659,13 @@ class AssoOption(models.Model):
de voir les préférences concernant l'association"
@receiver(post_save, sender=AssoOption)
def assooption_post_save(sender, **kwargs):
"""Ecriture dans le cache"""
asso_pref = kwargs['instance']
asso_pref.set_in_cache()
class MailMessageOption(models.Model):
"""Reglages, mail de bienvenue et autre"""
PRETTY_NAME = "Options de corps de mail"
......
......@@ -45,7 +45,6 @@ def can_create(model):
def decorator(view):
def wrapper(request, *args, **kwargs):
can, msg = model.can_create(request.user, *args, **kwargs)
#options, _created = OptionalUser.objects.get_or_create()
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('index'))
......
......@@ -31,10 +31,8 @@ from preferences.models import GeneralOption, OptionalMachine
def context_user(request):
"""Fonction de context lorsqu'un user est logué (ou non),
renvoie les infos sur l'user, la liste de ses droits, ses machines"""
general_options, _created = GeneralOption.objects.get_or_create()
machine_options, _created = OptionalMachine.objects.get_or_create()
user = request.user
global_message = general_options.general_message
global_message = GeneralOption.get_cached_value('general_message')
if global_message:
messages.warning(request, global_message)
if user.is_authenticated():
......@@ -44,6 +42,6 @@ def context_user(request):
return {
'request_user': user,
'interfaces': interfaces,
'site_name': general_options.site_name,
'ipv6_enabled': machine_options.ipv6,
'site_name': GeneralOption.get_cached_value('site_name'),
'ipv6_enabled': OptionalMachine.get_cached_value('ipv6'),
}
......@@ -121,15 +121,23 @@ def filter_active_interfaces(interface_set):
.distinct()
def all_active_interfaces():
def filter_complete_interfaces(interface_set):
"""Appel la fonction précédente avec un prefetch_related ipv6 en plus"""
return filter_active_interfaces(interface_set).prefetch_related('ipv6list')
def all_active_interfaces(full=False):
"""Renvoie l'ensemble des machines autorisées à sortir sur internet """
return filter_active_interfaces(Interface.objects)
if full:
return filter_complete_interfaces(Interface.objects)
else:
return filter_active_interfaces(Interface.objects)
def all_active_assigned_interfaces():
def all_active_assigned_interfaces(full=False):
""" Renvoie l'ensemble des machines qui ont une ipv4 assignées et
disposant de l'accès internet"""
return all_active_interfaces().filter(ipv4__isnull=False)
return all_active_interfaces(full=full).filter(ipv4__isnull=False)
def all_active_interfaces_count():
......
......@@ -136,8 +136,7 @@ def history(request, application, object_name, object_id):
'users:profil',
kwargs={'userid':str(request.user.id)}
))
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
reversions = Version.objects.get_for_object(instance)
paginator = Paginator(reversions, pagination_number)
page = request.GET.get('page')
......
......@@ -111,8 +111,7 @@ def finish_results(results, col, order):
SortTable.TOPOLOGIE_INDEX
)
options, _ = GeneralOption.objects.get_or_create()
max_result = options.search_display_page
max_result = GeneralOption.get_cached_value('search_display_page')
for name, val in results.items():
results[name] = val.distinct()[:max_result]
results.update({'max_result': max_result})
......
......@@ -99,8 +99,7 @@ def index(request):
request.GET.get('order'),
SortTable.TOPOLOGIE_INDEX
)
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
paginator = Paginator(switch_list, pagination_number)
page = request.GET.get('page')
try:
......@@ -153,8 +152,7 @@ def index_room(request):
request.GET.get('order'),
SortTable.TOPOLOGIE_INDEX_ROOM
)
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
pagination_number = GeneralOption.get_cached_value('pagination_number')
paginator = Paginator(room_list, pagination_number)
page = request.GET.get('page')
try:
......@@ -192,7 +190,7 @@ def index_stack(request):
@can_view_all(ConstructorSwitch)
def index_model_switch(request):
""" Affichage de l'ensemble des modèles de switches"""
model_switch_list = ModelSwitch.objects
model_switch_list = ModelSwitch.objects.select_related('constructor')
constructor_switch_list = ConstructorSwitch.objects
model_switch_list = SortTable.sort(
model_switch_list,
......@@ -366,8 +364,7 @@ def new_switch(request):
request.POST or None,
)
if switch.is_valid() and machine.is_valid() and interface.is_valid():
options, _created = AssoOption.objects.get_or_create()
user = options.utilisateur_asso
user = AssoOption.get_cached_value('utilisateur_asso')
if not user:
messages.error(request, "L'user association n'existe pas encore,\
veuillez le créer ou le linker dans preferences")
......
......@@ -289,8 +289,7 @@ class AdherentForm(FieldPermissionFormMixin, ModelForm):
"""Verifie que le tel est présent si 'option est validée
dans preferences"""
telephone = self.cleaned_data['telephone']
preferences, _created = OptionalUser.objects.get_or_create()
if not telephone and preferences.is_tel_mandatory:
if not telephone and OptionalUser.get_cached_value('is_tel_mandatory'):
raise forms.ValidationError(
"Un numéro de téléphone valide est requis"
)
......@@ -341,8 +340,7 @@ class ClubForm(FieldPermissionFormMixin, ModelForm):
"""Verifie que le tel est présent si 'option est validée
dans preferences"""