mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-08-19 21:53:41 +00:00
Mise en cache des attributs user (@proprety) + reecriture de methodes directes SQl pour la collecte des set users (has_access, etc)
This commit is contained in:
parent
787e048a2a
commit
c9131d591d
11 changed files with 131 additions and 30 deletions
|
@ -58,7 +58,7 @@ def create_cotis(vente, user, duration, date_start=False):
|
|||
if date_start:
|
||||
end_adhesion = Cotisation.objects.filter(vente__in=Vente.objects.filter(facture__in=Facture.objects.filter(user=user).exclude(valid=False))).filter(date_start__lt=date_start).aggregate(Max('date_end'))['date_end__max']
|
||||
else:
|
||||
end_adhesion = user.end_adhesion()
|
||||
end_adhesion = user.end_adhesion
|
||||
date_start = date_start or timezone.now()
|
||||
end_adhesion = end_adhesion or date_start
|
||||
date_max = max(end_adhesion, date_start)
|
||||
|
@ -102,7 +102,7 @@ def new_facture(request, userid):
|
|||
if art_item.cleaned_data['article'].iscotisation:
|
||||
create_cotis(new_vente, user, art_item.cleaned_data['article'].duration*art_item.cleaned_data['quantity'])
|
||||
if any(art_item.cleaned_data['article'].iscotisation for art_item in articles if art_item.cleaned_data):
|
||||
messages.success(request, "La cotisation a été prolongée pour l'adhérent %s jusqu'au %s" % (user.name, user.end_adhesion()) )
|
||||
messages.success(request, "La cotisation a été prolongée pour l'adhérent %s jusqu'au %s" % (user.name, user.end_adhesion) )
|
||||
else:
|
||||
messages.success(request, "La facture a été crée")
|
||||
return redirect("/users/profil/" + userid)
|
||||
|
|
|
@ -73,7 +73,7 @@ def decide_vlan(switch_id, port_number, mac_address):
|
|||
room_user = User.objects.filter(room=Room.objects.filter(name=port.room))
|
||||
if not room_user:
|
||||
return (sw_name, 'Chambre non cotisante', VLAN_NOK)
|
||||
elif not room_user[0].has_access():
|
||||
elif not room_user[0].has_access:
|
||||
return (sw_name, 'Chambre resident desactive', VLAN_NOK)
|
||||
# else: user OK, on passe à la verif MAC
|
||||
|
||||
|
@ -82,7 +82,7 @@ def decide_vlan(switch_id, port_number, mac_address):
|
|||
interface = Interface.objects.filter(mac_address=mac_address)
|
||||
if not interface:
|
||||
return (sw_name, 'Machine inconnue', VLAN_NOK)
|
||||
elif not interface[0].is_active():
|
||||
elif not interface[0].is_active:
|
||||
return (sw_name, 'Machine non active / adherent non cotisant', VLAN_NOK)
|
||||
else:
|
||||
return (sw_name, 'Machine OK', VLAN_OK)
|
||||
|
|
42
logs/templates/logs/aff_stats_general.html
Normal file
42
logs/templates/logs/aff_stats_general.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% comment %}
|
||||
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
|
||||
|
||||
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.
|
||||
{% endcomment %}
|
||||
|
||||
{% for stats in stats_list %}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for element in stats.0 %}
|
||||
<th>{{ element }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% for key, stat in stats.1.items %}
|
||||
<tr>
|
||||
{% for item in stat %}
|
||||
<td>{{ item }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endfor %}
|
36
logs/templates/logs/stats_general.html
Normal file
36
logs/templates/logs/stats_general.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "logs/sidebar.html" %}
|
||||
{% comment %}
|
||||
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
|
||||
|
||||
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.
|
||||
{% endcomment %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Statistiques générales{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Statistiques générales</h2>
|
||||
{% include "logs/aff_stats_general.html" with stats_list=stats_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
|
@ -40,6 +40,7 @@ from reversion.models import Revision
|
|||
from reversion.models import Version
|
||||
|
||||
from users.models import User, ServiceUser, Right, School, ListRight, ListShell, Ban, Whitelist
|
||||
from users.models import all_has_access, all_whitelisted, all_baned, all_adherent
|
||||
from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation
|
||||
from machines.models import Machine, MachineType, IpType, Extension, Interface, Domain, IpList
|
||||
from topologie.models import Switch, Port, Room
|
||||
|
@ -107,10 +108,10 @@ def stats_general(request):
|
|||
'active_users' : ["Users actifs", User.objects.filter(state=User.STATE_ACTIVE).count()],
|
||||
'inactive_users' : ["Users désactivés", User.objects.filter(state=User.STATE_DISABLED).count()],
|
||||
'archive_users' : ["Users archivés", User.objects.filter(state=User.STATE_ARCHIVE).count()],
|
||||
'adherent_users' : ["Adhérents à l'association", len([user for user in all_active_users if user.is_adherent()])],
|
||||
'connexion_users' : ["Utilisateurs bénéficiant d'une connexion", len([user for user in all_active_users if user.has_access()])],
|
||||
'ban_users' : ["Utilisateurs bannis", len([user for user in all_active_users if user.is_ban()])],
|
||||
'whitelisted_user' : ["Utilisateurs bénéficiant d'une connexion gracieuse", len([user for user in all_active_users if user.is_whitelisted()])],
|
||||
'adherent_users' : ["Adhérents à l'association", all_adherent().count()],
|
||||
'connexion_users' : ["Utilisateurs bénéficiant d'une connexion", all_has_access().count()],
|
||||
'ban_users' : ["Utilisateurs bannis", all_baned().count()],
|
||||
'whitelisted_user' : ["Utilisateurs bénéficiant d'une connexion gracieuse", all_whitelisted().count()],
|
||||
}],
|
||||
[["Range d'ip", "Nombre d'ip totales", "Nombre d'ip utilisées", "Nombre d'ip libres"] ,ip]
|
||||
]
|
||||
|
|
|
@ -27,6 +27,7 @@ from django.forms import ValidationError
|
|||
from macaddress.fields import MACAddressField
|
||||
from netaddr import mac_bare, EUI
|
||||
from django.core.validators import MinValueValidator,MaxValueValidator
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from re2o.settings import MAIN_EXTENSION
|
||||
|
||||
|
@ -101,11 +102,12 @@ class Interface(models.Model):
|
|||
type = models.ForeignKey('MachineType', on_delete=models.PROTECT)
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
|
||||
@cached_property
|
||||
def is_active(self):
|
||||
""" Renvoie si une interface doit avoir accès ou non """
|
||||
machine = self.machine
|
||||
user = self.machine.user
|
||||
return machine.active and user.has_access()
|
||||
return machine.active and user.has_access
|
||||
|
||||
def mac_bare(self):
|
||||
return str(EUI(self.mac_address, dialect=mac_bare)).lower()
|
||||
|
|
|
@ -728,7 +728,7 @@ class JSONResponse(HttpResponse):
|
|||
def mac_ip_list(request):
|
||||
interf = Interface.objects.select_related('ipv4').select_related('domain__extension').all()
|
||||
interfaces = list(filter(
|
||||
lambda interface: interface.ipv4 and interface.is_active(),
|
||||
lambda interface: interface.ipv4 and interface.is_active,
|
||||
interf
|
||||
))
|
||||
seria = InterfaceSerializer(interfaces, many=True)
|
||||
|
|
|
@ -30,11 +30,11 @@ class PortForm(ModelForm):
|
|||
|
||||
class EditPortForm(ModelForm):
|
||||
class Meta(PortForm.Meta):
|
||||
fields = ['room', 'machine_interface', 'related', 'radius', 'details']
|
||||
fields = ['room', 'related', 'radius', 'details']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EditPortForm, self).__init__(*args, **kwargs)
|
||||
self.fields['related'].queryset = Port.objects.all().order_by('switch', 'port')
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super(EditPortForm, self).__init__(*args, **kwargs)
|
||||
# self.fields['related'].queryset = Port.objects.all().order_by('switch', 'port')
|
||||
|
||||
class AddPortForm(ModelForm):
|
||||
class Meta(PortForm.Meta):
|
||||
|
|
|
@ -126,7 +126,7 @@ def new_port(request, switch_id):
|
|||
@permission_required('infra')
|
||||
def edit_port(request, port_id):
|
||||
try:
|
||||
port_object = Port.objects.get(pk=port_id)
|
||||
port_object = Port.objects.select_related('switch__switch_interface__domain__extension').select_related('machine_interface').select_related('room').select_related('related').get(pk=port_id)
|
||||
except Port.DoesNotExist:
|
||||
messages.error(request, u"Port inexistant")
|
||||
return redirect("/topologie/")
|
||||
|
|
|
@ -26,6 +26,7 @@ from django.forms import ModelForm, Form
|
|||
from django import forms
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
import ldapdb.models
|
||||
import ldapdb.models.fields
|
||||
|
@ -88,6 +89,17 @@ def get_admin_right():
|
|||
admin_right.save()
|
||||
return admin_right
|
||||
|
||||
def all_adherent():
|
||||
return User.objects.filter(facture__in=Facture.objects.filter(vente__in=Vente.objects.filter(cotisation__in=Cotisation.objects.filter(vente__in=Vente.objects.filter(facture__in=Facture.objects.all().exclude(valid=False))).filter(date_end__gt=timezone.now())))).distinct()
|
||||
|
||||
def all_baned():
|
||||
return User.objects.filter(ban__in=Ban.objects.filter(date_end__gt=timezone.now())).distinct()
|
||||
|
||||
def all_whitelisted():
|
||||
return User.objects.filter(whitelist__in=Whitelist.objects.filter(date_end__gt=timezone.now())).distinct()
|
||||
|
||||
def all_has_access():
|
||||
return User.objects.filter(Q(state=User.STATE_ACTIVE) & ~Q(ban__in=Ban.objects.filter(date_end__gt=timezone.now())) & (Q(whitelist__in=Whitelist.objects.filter(date_end__gt=timezone.now())) | Q(facture__in=Facture.objects.filter(vente__in=Vente.objects.filter(cotisation__in=Cotisation.objects.filter(vente__in=Vente.objects.filter(facture__in=Facture.objects.all().exclude(valid=False))).filter(date_end__gt=timezone.now())))))).distinct()
|
||||
|
||||
class UserManager(BaseUserManager):
|
||||
def _create_user(self, pseudo, name, surname, email, password=None, su=False):
|
||||
|
@ -204,12 +216,14 @@ class User(AbstractBaseUser):
|
|||
def has_perm(self, perm, obj=None):
|
||||
return True
|
||||
|
||||
@cached_property
|
||||
def end_adhesion(self):
|
||||
date_max = Cotisation.objects.filter(vente__in=Vente.objects.filter(facture__in=Facture.objects.filter(user=self).exclude(valid=False))).aggregate(models.Max('date_end'))['date_end__max']
|
||||
return date_max
|
||||
|
||||
@cached_property
|
||||
def is_adherent(self):
|
||||
end = self.end_adhesion()
|
||||
end = self.end_adhesion
|
||||
if not end:
|
||||
return False
|
||||
elif end < timezone.now():
|
||||
|
@ -217,19 +231,22 @@ class User(AbstractBaseUser):
|
|||
else:
|
||||
return True
|
||||
|
||||
@cached_property
|
||||
def end_ban(self):
|
||||
""" Renvoie la date de fin de ban d'un user, False sinon """
|
||||
date_max = Ban.objects.filter(user=self).aggregate(models.Max('date_end'))['date_end__max']
|
||||
return date_max
|
||||
|
||||
@cached_property
|
||||
def end_whitelist(self):
|
||||
""" Renvoie la date de fin de whitelist d'un user, False sinon """
|
||||
date_max = Whitelist.objects.filter(user=self).aggregate(models.Max('date_end'))['date_end__max']
|
||||
return date_max
|
||||
|
||||
@cached_property
|
||||
def is_ban(self):
|
||||
""" Renvoie si un user est banni ou non """
|
||||
end = self.end_ban()
|
||||
end = self.end_ban
|
||||
if not end:
|
||||
return False
|
||||
elif end < timezone.now():
|
||||
|
@ -237,9 +254,10 @@ class User(AbstractBaseUser):
|
|||
else:
|
||||
return True
|
||||
|
||||
@cached_property
|
||||
def is_whitelisted(self):
|
||||
""" Renvoie si un user est whitelisté ou non """
|
||||
end = self.end_whitelist()
|
||||
end = self.end_whitelist
|
||||
if not end:
|
||||
return False
|
||||
elif end < timezone.now():
|
||||
|
@ -247,23 +265,25 @@ class User(AbstractBaseUser):
|
|||
else:
|
||||
return True
|
||||
|
||||
@cached_property
|
||||
def has_access(self):
|
||||
""" Renvoie si un utilisateur a accès à internet """
|
||||
return self.state == User.STATE_ACTIVE \
|
||||
and not self.is_ban() and (self.is_adherent() or self.is_whitelisted())
|
||||
and not self.is_ban and (self.is_adherent or self.is_whitelisted)
|
||||
|
||||
@cached_property
|
||||
def end_access(self):
|
||||
""" Renvoie la date de fin normale d'accès (adhésion ou whiteliste)"""
|
||||
if not self.end_adhesion():
|
||||
if not self.end_whitelist():
|
||||
if not self.end_adhesion:
|
||||
if not self.end_whitelist:
|
||||
return None
|
||||
else:
|
||||
return self.end_whitelist()
|
||||
return self.end_whitelist
|
||||
else:
|
||||
if not self.end_whitelist():
|
||||
return self.end_adhesion()
|
||||
if not self.end_whitelist:
|
||||
return self.end_adhesion
|
||||
else:
|
||||
return max(self.end_adhesion(), self.end_whitelist())
|
||||
return max(self.end_adhesion, self.end_whitelist)
|
||||
|
||||
def user_interfaces(self):
|
||||
return Interface.objects.filter(machine__in=Machine.objects.filter(user=self, active=True))
|
||||
|
@ -293,7 +313,7 @@ class User(AbstractBaseUser):
|
|||
if base:
|
||||
user_ldap.name = 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.mail = self.email
|
||||
user_ldap.given_name = str(self.surname).lower() + '_' + str(self.name).lower()[:3]
|
||||
|
@ -303,7 +323,7 @@ class User(AbstractBaseUser):
|
|||
if self.shell:
|
||||
user_ldap.login_shell = self.shell.shell
|
||||
if access_refresh:
|
||||
user_ldap.dialupAccess = str(self.has_access())
|
||||
user_ldap.dialupAccess = str(self.has_access)
|
||||
if mac_refresh:
|
||||
user_ldap.macs = [inter.mac_bare() for inter in Interface.objects.filter(machine__in=Machine.objects.filter(user=self))]
|
||||
user_ldap.save()
|
||||
|
|
|
@ -272,7 +272,7 @@ def add_ban(request, userid):
|
|||
reversion.set_comment("Création")
|
||||
messages.success(request, "Bannissement ajouté")
|
||||
return redirect("/users/profil/" + userid)
|
||||
if user.is_ban():
|
||||
if user.is_ban:
|
||||
messages.error(
|
||||
request,
|
||||
"Attention, cet utilisateur a deja un bannissement actif"
|
||||
|
@ -318,7 +318,7 @@ def add_whitelist(request, userid):
|
|||
reversion.set_comment("Création")
|
||||
messages.success(request, "Accès à titre gracieux accordé")
|
||||
return redirect("/users/profil/" + userid)
|
||||
if user.is_whitelisted():
|
||||
if user.is_whitelisted:
|
||||
messages.error(
|
||||
request,
|
||||
"Attention, cet utilisateur a deja un accès gracieux actif"
|
||||
|
@ -463,7 +463,7 @@ def mass_archive(request):
|
|||
to_archive_list = []
|
||||
if to_archive_date.is_valid():
|
||||
date = to_archive_date.cleaned_data['date']
|
||||
to_archive_list = [user for user in User.objects.exclude(state=User.STATE_ARCHIVE) if not user.end_access() or user.end_access() < date]
|
||||
to_archive_list = [user for user in User.objects.exclude(state=User.STATE_ARCHIVE) if not user.end_access or user.end_access < date]
|
||||
if "valider" in request.POST:
|
||||
for user in to_archive_list:
|
||||
archive(user)
|
||||
|
|
Loading…
Reference in a new issue