Statistiques sur les membres (préparation pour la déréservation des IPs). Début du système de déconnexion globale pour les AGs (ne fonctionne pas pour le moment). Amélioration du calcul de fin d'adhésion. Ce code a été insuffisamment testé pour le moment : NE PAS DÉPLOYER EN PRODUCTION.
This commit is contained in:
parent
2661a73ae7
commit
93362f4f3c
@ -792,3 +792,71 @@ class RoomChangeMemberController(AuthenticatedRestController):
|
||||
redirect("/edit/room/index/" + residence + "/" + room_uid)
|
||||
#end def
|
||||
#end def
|
||||
|
||||
# TODO :
|
||||
""" Controller REST de gestion de la deconnexion globale. """
|
||||
class AllMembersDisableController(AuthenticatedRestController):
|
||||
require_group = groups_enum.admin
|
||||
|
||||
""" Gestion des requêtes post sur ce controller """
|
||||
@expose()
|
||||
def post(self, residence):
|
||||
residence_dn = Residences.get_dn_by_name(self.user, residence)
|
||||
|
||||
# Récupération du membre et de la machine
|
||||
# Note : on cherche la machine seulement sur le membre (member.dn)
|
||||
members = Member.get_all(self.user, residence_dn)
|
||||
for member in members:
|
||||
member = Member.get_by_uid(self.user, residence_dn, member_uid)
|
||||
if member is None:
|
||||
raise Exception('membre inconnu')
|
||||
#end if
|
||||
|
||||
dhcps = Machine.get_dhcps(self.user, member.dn)
|
||||
|
||||
machine_membre_tag = "machine_membre" # FIXME move to config
|
||||
|
||||
for dhcp_item in dhcps:
|
||||
if dhcp_item.uid.first() == machine_membre_tag:
|
||||
dhcp_item.uid.replace(machine_membre_tag, machine_membre_tag + "_disabled")
|
||||
self.user.ldap_bind.save(dhcp_item)
|
||||
#end if
|
||||
#end for
|
||||
|
||||
# On redirige sur la page d'édition du membre
|
||||
redirect("/edit/member/" + residence + "/" + member_uid)
|
||||
#end def
|
||||
|
||||
# TODO :
|
||||
""" Controller REST de gestion de la reconnexion globale. """
|
||||
class AllMembersEnableController(AuthenticatedRestController):
|
||||
require_group = groups_enum.admin
|
||||
|
||||
""" Gestion des requêtes post sur ce controller """
|
||||
@expose()
|
||||
def post(self, residence):
|
||||
residence_dn = Residences.get_dn_by_name(self.user, residence)
|
||||
|
||||
# Récupération du membre et de la machine
|
||||
# Note : on cherche la machine seulement sur le membre (member.dn)
|
||||
member = Member.get_by_uid(self.user, residence_dn, member_uid)
|
||||
if member is None:
|
||||
raise Exception('membre inconnu')
|
||||
#end if
|
||||
|
||||
dhcps = Machine.get_dhcps(self.user, member.dn)
|
||||
|
||||
machine_membre_tag = "machine_membre" # FIXME move to config
|
||||
machine_membre_disabled = machine_membre_tag + "_disabled" # FIXME move to config
|
||||
|
||||
for dhcp_item in dhcps:
|
||||
if dhcp_item.uid.first() == machine_membre_disabled:
|
||||
dhcp_item.uid.replace(machine_membre_disabled, machine_membre_tag)
|
||||
self.user.ldap_bind.save(dhcp_item)
|
||||
#end if
|
||||
#end for
|
||||
|
||||
# On redirige sur la page d'édition du membre
|
||||
redirect("/edit/member/" + residence + "/" + member_uid)
|
||||
#end def
|
||||
|
||||
|
@ -49,7 +49,7 @@ class RoomsController(AuthenticatedBaseController):
|
||||
if residence_dn is None:
|
||||
raise Exception("unknown residence")
|
||||
#end if
|
||||
|
||||
status = CotisationComputes.members_status_from_residence(self.user, residence_dn)
|
||||
for area in Room.get_areas(self.user, residence_dn):
|
||||
areas[area] = dict()
|
||||
|
||||
@ -78,6 +78,7 @@ class RoomsController(AuthenticatedBaseController):
|
||||
"reverse_sorted_name" : self.reverse_sort_name,
|
||||
"sorted_name" : self.sort_name,
|
||||
"stats" : stats,
|
||||
"status" : status,
|
||||
"residence" : residence_name
|
||||
}
|
||||
#end def
|
||||
|
@ -22,24 +22,16 @@ def admin_user():
|
||||
|
||||
sched = Scheduler()
|
||||
|
||||
|
||||
def disconnect_members_from_residence(admin_user, residence_dn):
|
||||
current_year = CotisationComputes.current_year()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
members = Member.get_all(admin_user, residence_dn)
|
||||
|
||||
for member in members:
|
||||
|
||||
machines_tuples = Machine.get_machine_tuples_of_member(admin_user, member.dn)
|
||||
if machines_tuples != []:
|
||||
cotisations = Cotisation.cotisations_of_member(admin_user, member.dn, current_year)
|
||||
months_list, anniversary = CotisationComputes.ldap_items_to_months_list(cotisations)
|
||||
|
||||
if not (now.month in months_list
|
||||
or ((now.month - 1) in months_list and now.day <= (anniversary + 7))):
|
||||
if not CotisationComputes.is_cotisation_paid(member, admin_user, residence_dn):
|
||||
dhcps = Machine.get_dhcps(admin_user, member.dn)
|
||||
|
||||
machine_membre_tag = "machine_membre" # FIXME move to config
|
||||
|
||||
for dhcp_item in dhcps:
|
||||
|
@ -1,4 +1,5 @@
|
||||
from brie.config import ldap_config
|
||||
from brie.model.ldap import *
|
||||
import datetime
|
||||
|
||||
class Residences:
|
||||
@ -96,29 +97,116 @@ class CotisationComputes:
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def ldap_items_to_months_list(ldap_cotisations):
|
||||
def anniversary_from_ldap_items(ldap_cotisations):
|
||||
result = []
|
||||
|
||||
for cotisation in ldap_cotisations:
|
||||
anniversary_data = cotisation.get("x-time").first()
|
||||
anniversary_datetime = datetime.datetime.strptime(anniversary_data,
|
||||
"%Y-%m-%d %H:%M:%S.%f")
|
||||
months = []
|
||||
for month in cotisation.get("x-validMonth").all():
|
||||
result.append((anniversary_datetime, int(month)))
|
||||
months.append(int(month))
|
||||
#end for
|
||||
result.append((anniversary_datetime, months))
|
||||
#end for
|
||||
|
||||
first_anniversary_day = 0
|
||||
# tri par ordre d'inscription et pas ordre de mois
|
||||
anniversary = 0
|
||||
# tri par ordre d'inscription
|
||||
result = sorted(result)
|
||||
|
||||
if result != []:
|
||||
# premier anniversaire
|
||||
first_anniversary_day = result[0][0].day
|
||||
anniversary_day = result[0][0].day
|
||||
months = result[0][1]
|
||||
SORT_ORDER = {9: 0, 10: 1, 11: 2, 12: 3, 1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9, 7: 10, 8: 11}
|
||||
months.sort(key=lambda val: SORT_ORDER[val])
|
||||
anniversary_month = months[-1] + 1
|
||||
if anniversary_month == 13:
|
||||
anniversary_month = 1
|
||||
if anniversary_month > 9:
|
||||
anniversary_year = result[0][0].year
|
||||
else :
|
||||
anniversary_year = result[0][0].year + 1
|
||||
anniversary = datetime.datetime.strptime(str(anniversary_year) + "-" + str(anniversary_month) + "-1 0:0", "%Y-%m-%d %H:%M") + datetime.timedelta(days=(anniversary_day - 1))
|
||||
#end if
|
||||
|
||||
months_without_anniversary = [item[1] for item in result]
|
||||
|
||||
return months_without_anniversary, first_anniversary_day
|
||||
return anniversary
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
# old = SDF or no cotisation this year
|
||||
def is_old_member(member, user_session, residence_dn):
|
||||
current_year = CotisationComputes.current_year()
|
||||
cotisations = Cotisation.cotisations_of_member(user_session, member.dn, current_year)
|
||||
return Room.get_by_member_dn(user_session, residence_dn, member.dn) == None or cotisations == []
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
# 7 days grace period
|
||||
def is_cotisation_paid(member, user_session, residence_dn):
|
||||
if CotisationComputes.is_old_member(member, user_session, residence_dn):
|
||||
return False
|
||||
current_year = CotisationComputes.current_year()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
cotisations = Cotisation.cotisations_of_member(user_session, member.dn, current_year)
|
||||
anniversary = CotisationComputes.anniversary_from_ldap_items(cotisations)
|
||||
delta = (now - anniversary)
|
||||
return delta.days <= 7
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
# less than a month late but more than a week
|
||||
def is_cotisation_late(member, user_session, residence_dn):
|
||||
if CotisationComputes.is_old_member(member, user_session, residence_dn):
|
||||
return False
|
||||
current_year = CotisationComputes.current_year()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
cotisations = Cotisation.cotisations_of_member(user_session, member.dn, current_year)
|
||||
anniversary = CotisationComputes.anniversary_from_ldap_items(cotisations)
|
||||
delta = (now - anniversary)
|
||||
#print("[DEBUG] cotisation en retard pour l'utilisateur "+ member.dn +" now="+ str(now) +" anniversary="+ str(anniversary) +" delta="+ str(delta))
|
||||
return delta.days <= 30 and delta.days > 7
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
# more than a month late
|
||||
def is_no_cotisation(member, user_session, residence_dn):
|
||||
if CotisationComputes.is_old_member(member, user_session, residence_dn):
|
||||
return False
|
||||
current_year = CotisationComputes.current_year()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
cotisations = Cotisation.cotisations_of_member(user_session, member.dn, current_year)
|
||||
anniversary = CotisationComputes.anniversary_from_ldap_items(cotisations)
|
||||
delta = (now - anniversary)
|
||||
return delta.days > 30
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def members_status_from_residence(user_session, residence_dn):
|
||||
members = Member.get_all(user_session, residence_dn)
|
||||
|
||||
old_members = []
|
||||
cotisation_paid_members = []
|
||||
cotisation_late_members = []
|
||||
no_cotisation_members = []
|
||||
WTF_members = []
|
||||
for member in members:
|
||||
if CotisationComputes.is_old_member(member, user_session, residence_dn):
|
||||
old_members.append(member)
|
||||
elif CotisationComputes.is_cotisation_paid(member, user_session, residence_dn):
|
||||
cotisation_paid_members.append(member)
|
||||
elif CotisationComputes.is_cotisation_late(member, user_session, residence_dn):
|
||||
cotisation_late_members.append(member)
|
||||
#print("[DEBUG] cotisation en retard pour l'utilisateur "+ member.dn)
|
||||
elif CotisationComputes.is_no_cotisation(member, user_session, residence_dn):
|
||||
no_cotisation_members.append(member)
|
||||
else:
|
||||
WTF_members.append(member)
|
||||
#end if
|
||||
|
||||
#end for
|
||||
return dict(old_members=old_members, cotisation_paid_members=cotisation_paid_members, cotisation_late_members=cotisation_late_members, no_cotisation_members=no_cotisation_members, WTF_members=WTF_members)
|
||||
#end def
|
||||
|
||||
#end class
|
||||
|
@ -6,7 +6,7 @@
|
||||
<meta name="description" content=""/>
|
||||
<meta name="author" content=""/>
|
||||
|
||||
<!-- Le styles -->
|
||||
<!-- Le style -->
|
||||
<xi:include href="common-css-header.html" />
|
||||
</head>
|
||||
<body>
|
||||
@ -37,6 +37,13 @@
|
||||
<input type="submit" value="Search" class="button"/>
|
||||
</form>
|
||||
</div>
|
||||
<!-- Ne fonctionne pas encore : -->
|
||||
<div class="section">
|
||||
<form action="/disconnectall/" method="post" class="inline_block">
|
||||
<input type="hidden" name="residence" value="${residence}"/>
|
||||
<input type="submit" value="Déconnexion globale" class="button"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -8,30 +8,37 @@
|
||||
<xi:include href="common-css-header.html" />
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
|
||||
<xi:include href="navbar.html" />
|
||||
<div class="rooms_legend">
|
||||
<py:def function="display_stat(name)">
|
||||
<div class="room_number ${name}">${"%03d" % stats[name]}</div>
|
||||
<div class="room_number ok_color">${"%03d" % stats[name]}</div>
|
||||
</py:def>
|
||||
<div>
|
||||
${display_stat("ok_color")}
|
||||
<span>ordinateurs connectés</span>
|
||||
<div class="room_number ok_color">${"%03d" % len(status['cotisation_paid_members'])}</div>
|
||||
<span>Cotisations à jour</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("non_certif_color")}
|
||||
<span>certifs manquants</span>
|
||||
<div class="room_number non_certif_color">${"%03d" % len(status['cotisation_late_members'])}</div>
|
||||
<span>Cotisations en retard</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("non_paye_color")}
|
||||
<span>fins de connexions passées</span>
|
||||
<div class="room_number non_paye_color">${"%03d" % len(status['no_cotisation_members'])}</div>
|
||||
<span>Sans cotisations</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("vide_color")}
|
||||
<span>chambres vides</span>
|
||||
<div class="room_number vide_color">${"%03d" % len(status['old_members'])}</div>
|
||||
<span>Anciens membres</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="room_number vide_color">${"%03d" % len(status['WTF_members'])}</div>
|
||||
<span>Membres WTF</span>
|
||||
</div>
|
||||
<div>
|
||||
<!--${display_stat("vide_color")}-->
|
||||
<span>Chambres vides</span>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<xi:include href="navbar.html" />
|
||||
<div class="area section">
|
||||
<span class="section_name">PREVIEW</span>
|
||||
<div py:if="defined('preview')">
|
||||
|
Loading…
Reference in New Issue
Block a user