Compare commits

..

No commits in common. "master" and "peb_dev" have entirely different histories.

12 changed files with 301 additions and 660 deletions

View file

@ -47,8 +47,7 @@ import random
import string import string
from unicodedata import normalize from unicodedata import normalize
from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac, fetch_cert_info from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac, fetch_cert_info
from crans_utils import to_generalized_time_format, from_generalized_time_format, datetime_from_generalized_time_format from crans_utils import to_generalized_time_format, from_generalized_time_format
from crans_utils import datetime_to_generalized_time_format
import itertools import itertools
if '/usr/scripts' not in sys.path: if '/usr/scripts' not in sys.path:
@ -243,7 +242,7 @@ class AttrsDict(dict):
""" """
ldif = {} ldif = {}
for attr, vals in self.items(): for attr, vals in self.items():
ldif[attr] = [unicode(val).encode(config.ldap_encoding) for val in vals] ldif[attr] = [ str(val) for val in vals ]
return ldif return ldif
class Attr(object): class Attr(object):
@ -351,7 +350,9 @@ class Attr(object):
raise UniquenessError("%s déjà existant" % attr, [r.dn for r in res]) raise UniquenessError("%s déjà existant" % attr, [r.dn for r in res])
def is_modifiable(self, liste_droits): def is_modifiable(self, liste_droits):
"""L'attribut est-il modifiable par un des droits dans liste_droits ?""" """
L'attribut est-il modifiable par un des droits dans liste_droits ?
"""
return not set(liste_droits).isdisjoint(self.can_modify) return not set(liste_droits).isdisjoint(self.can_modify)
class AttributeFactory(object): class AttributeFactory(object):
@ -392,26 +393,13 @@ class rightProtectedAttr(Attr):
""" """
On permet la modification à un utilisateur On permet la modification à un utilisateur
""" """
# Si on est soi-même, on peut changer son mot de passe sans condition
if not soi in liste_droits: if not soi in liste_droits:
modifiables = set() modifiables = set()
# On regarde la liste des droits qu'a la connexion courante, ce sont a priori
# les droits de l'utilisateur qui modifie le mot de passe, ajoutés de soi/parent
# les cas échéants.
for i in liste_droits: for i in liste_droits:
# Si le droit est un droit "superviseur" (ie ayant le droit de modifier certains
# utilisateurs ayant un des droits "supervisés", on ajoute la liste des droits
# supervisés aux droits modifiables
if i in DROITS_SUPERVISEUR: if i in DROITS_SUPERVISEUR:
modifiables = modifiables.union(DROITS_SUPERVISEUR[i]) modifiables = modifiables.union(DROITS_SUPERVISEUR[i])
modifiables = list(modifiables) modifiables = list(modifiables)
# On prend les droits de l'utilisateur dont on cherche à modifier le mot de passe
# et on les compare à la liste des droits que l'utilisateur qui modifie a le droit
# de modifier. S'il y en a un qui n'est pas dans la liste des droits modifiables, on jette.
for droit in self.parent.get('droits', []): for droit in self.parent.get('droits', []):
if droit not in modifiables and droit in TOUS_DROITS: if droit not in modifiables and droit in TOUS_DROITS:
return False return False
@ -525,14 +513,14 @@ class aid(intAttr):
self.value = int(aid) self.value = int(aid)
@crans_attribute @crans_attribute
class uid(rightProtectedAttr): class uid(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
option = False option = False
legend = u"L'identifiant canonique de l'adhérent" legend = u"L'identifiant canonique de l'adhérent"
category = 'perso' category = 'perso'
unique = True unique = True
can_modify = [cableur, nounou] can_modify = [nounou]
ldap_name = "uid" ldap_name = "uid"
@crans_attribute @crans_attribute
@ -648,31 +636,25 @@ class generalizedTimeFormat(Attr):
une donnée de temps suivant la RFC 4517 une donnée de temps suivant la RFC 4517
""" """
__slots__ = ("datetime",) __slots__ = ("_stamp",)
python_type = datetime.datetime default = "19700101000000Z"
default = datetime_from_generalized_time_format("19700101000000Z")
def __unicode__(self):
return unicode(datetime_to_generalized_time_format(self.value))
def __float__(self): def __float__(self):
return from_generalized_time_format(unicode(self)) return self._stamp
def __int__(self): def __int__(self):
return int(float(self)) return int(self._stamp)
def __eq__(self, othertime): def __eq__(self, othertime):
if isinstance(othertime, generalizedTimeFormat): if isinstance(othertime, generalizedTimeFormat):
return self.value == othertime.value return self._stamp == othertime._stamp
elif isinstance(othertime, float): elif isinstance(othertime, float):
return float(self) == othertime return self._stamp == othertime
elif isinstance(othertime, int): elif isinstance(othertime, int):
return int(self) == othertime return self._stamp == othertime
elif isinstance(othertime, unicode) or isinstance(othertime, str): elif isinstance(othertime, unicode) or isinstance(othertime, str):
resource = generalizedTimeFormat(othertime, conn=None, Parent=None) resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
return self == resource return self._stamp == resource._stamp
elif isinstance(othertime, datetime.datetime):
return self.value == othertime
else: else:
return False return False
@ -681,16 +663,14 @@ class generalizedTimeFormat(Attr):
def __lt__(self, othertime): def __lt__(self, othertime):
if isinstance(othertime, generalizedTimeFormat): if isinstance(othertime, generalizedTimeFormat):
return self.value < othertime.value return self._stamp < othertime._stamp
elif isinstance(othertime, float): elif isinstance(othertime, float):
return float(self) < othertime return self._stamp < othertime
elif isinstance(othertime, int): elif isinstance(othertime, int):
return int(self) < othertime return self._stamp < othertime
elif isinstance(othertime, unicode) or isinstance(othertime, str): elif isinstance(othertime, unicode) or isinstance(othertime, str):
resource = generalizedTimeFormat(othertime, conn=None, Parent=None) resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
return self < resource return self._stamp < resource._stamp
elif isinstance(othertime, datetime.datetime):
return self.value < othertime
else: else:
return False return False
@ -705,9 +685,15 @@ class generalizedTimeFormat(Attr):
def parse_value(self, gtf): def parse_value(self, gtf):
if isinstance(gtf, str) or isinstance(gtf, unicode): if isinstance(gtf, str) or isinstance(gtf, unicode):
self.value = datetime_from_generalized_time_format(gtf) if not ('Z' in gtf or '+' in gtf or '-' in gtf):
elif isinstance(gtf, datetime.datetime): self._stamp = gtf
self.value = to_generalized_time_format(float(gtf))
else:
self._stamp = from_generalized_time_format(gtf)
self.value = gtf self.value = gtf
elif isinstance(gtf, float):
self._stamp = gtf
self.value = to_generalized_time_format(gtf)
@crans_attribute @crans_attribute
class debutAdhesion(generalizedTimeFormat): class debutAdhesion(generalizedTimeFormat):
@ -754,43 +740,28 @@ class mail(rightProtectedAttr):
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
attr = self.__class__.__name__ attr = self.__class__.__name__
if str(self) in liste_exclue: if str(self) in liste_exclue:
return return
if attr in ["mailAlias", "canonicalAlias", 'mail']:
# On initialise le résultat, s'il vaut true en fin de course, le mail mail, end = str(self).split('@', 1)
# est déjà pris. if end.startswith('crans'):
res = False
mail = str(self)
_, domain = mail.split('@')
if domain in config.dns.mail_crans:
# On commence par vérifier auprès du serveur SMTP
# si l'adresse email est prise sur le réseau. Cela permet
# de tester aussi les adresses statiquement écrites dans
# aliases.db.
try: try:
smtp = smtplib.SMTP(smtpserv) smtp = smtplib.SMTP(smtpserv)
smtp.putcmd("vrfy", mail) smtp.putcmd("vrfy", mail)
res = smtp.getreply()[0] in [250, 252] res = smtp.getreply()[0] in [250, 252]
smtp.close() smtp.close()
except: except:
print 'Serveur de mail injoignable' raise ValueError('Serveur de mail injoignable')
check = self.conn.search(
u'(|(mail=%(mail)s)(mailAlias=%(mail)s)(canonicalAlias=%(mail)s)(mailExt=%(mail)s))' % {
'mail': mail,
}
)
if len(check) >= 1:
res = True
if res: if res:
raise ValueError("Le mail %s est déjà pris." % (str(self))) raise ValueError("Le mail %s est déjà pris." % (str(self)))
else:
check = self.conn.search(u'mail=%s' % mail)
if len(check) >= 1:
raise ValueError("Le mail %s est déjà pris." % (str(self)))
def parse_value(self, mail): def parse_value(self, mail):
if not re.match(u'^[-+_.0-9A-Za-z]+@([A-Za-z0-9]{1}[A-Za-z0-9-_]+[.])+[a-z]{2,20}$', mail): if not re.match(u'^[-_.0-9A-Za-z]+@([A-Za-z0-9]{1}[A-Za-z0-9-_]+[.])+[a-z]{2,6}$', mail):
raise ValueError("%s invalide %r" % (self.legend, mail)) raise ValueError("%s invalide %r" % (self.legend, mail))
self.value = mail self.value = mail
@ -816,6 +787,7 @@ class mailAlias(mail):
optional = True optional = True
unique = True unique = True
legend = u"Alias mail" legend = u"Alias mail"
can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailAlias" ldap_name = "mailAlias"
@ -835,7 +807,8 @@ class mailExt(mail):
singlevalue = False singlevalue = False
optional = True optional = True
unique = True unique = True
legend = u"Mail de redirection ou de secours" legend = u"Mail de secours"
can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailExt" ldap_name = "mailExt"
@ -890,7 +863,7 @@ class chbre(Attr):
def parse_value(self, chambre): def parse_value(self, chambre):
if self.parent != None and u'club' in [str(o) for o in self.parent['objectClass']]: if self.parent != None and u'club' in [str(o) for o in self.parent['objectClass']]:
if chambre in annuaires_pg.locaux_clubs() or chambre in (u"EXT", u"????"): if chambre in annuaires_pg.locaux_clubs():
self.value = chambre self.value = chambre
else: else:
raise ValueError("Club devrait etre en XclN, pas en %r" % chambre) raise ValueError("Club devrait etre en XclN, pas en %r" % chambre)
@ -1082,6 +1055,7 @@ class rid(intAttr):
unique = True unique = True
legend = u"Identifiant réseau de machine" legend = u"Identifiant réseau de machine"
category = 'id' category = 'id'
can_modify = [nounou]
ldap_name = "rid" ldap_name = "rid"
def parse_value(self, rid): def parse_value(self, rid):
@ -1113,7 +1087,7 @@ class ipsec(Attr):
legend = u'Clef wifi' legend = u'Clef wifi'
category = 'wifi' category = 'wifi'
ldap_name = "ipsec" ldap_name = "ipsec"
can_modify = [nounou, cableur, parent] can_modify = [nounou, parent]
historique = "info" historique = "info"
default = u'auto' default = u'auto'
@ -1132,8 +1106,8 @@ class puissance(Attr):
optional = True optional = True
legend = u"puissance d'émission pour les bornes wifi" legend = u"puissance d'émission pour les bornes wifi"
category = 'wifi' category = 'wifi'
can_modify = [nounou]
ldap_name = "puissance" ldap_name = "puissance"
default = '60'
@crans_attribute @crans_attribute
class canal(intAttr): class canal(intAttr):
@ -1142,8 +1116,8 @@ class canal(intAttr):
optional = True optional = True
legend = u'Canal d\'émission de la borne' legend = u'Canal d\'émission de la borne'
category = 'wifi' category = 'wifi'
can_modify = [nounou]
ldap_name = "canal" ldap_name = "canal"
default = "11"
@crans_attribute @crans_attribute
class hotspot(boolAttr): class hotspot(boolAttr):
@ -1152,24 +1126,25 @@ class hotspot(boolAttr):
optional = True optional = True
legend = u'Hotspot' legend = u'Hotspot'
category = 'wifi' category = 'wifi'
can_modify = [nounou]
ldap_name = "hotspot" ldap_name = "hotspot"
default = "FALSE"
@crans_attribute @crans_attribute
class positionBorne(Attr): class positionBorne(Attr):
__slots__ = () __slots__ = ()
legend = u"Position de la borne" legend = u"Position de la borne"
category = "wifi" category = "wifi"
can_modify = [nounou]
singlevalue = True singlevalue = True
optional = True optional = True
ldap_name = "positionBorne" ldap_name = "positionBorne"
default = "0 0"
@crans_attribute @crans_attribute
class nvram(Attr): class nvram(Attr):
__slots__ = () __slots__ = ()
legend = u"Configuration speciale" legend = u"Configuration speciale"
optional = True optional = True
can_modify = [nounou]
ldap_name = "nvram" ldap_name = "nvram"
class portAttr(Attr): class portAttr(Attr):
@ -1178,6 +1153,7 @@ class portAttr(Attr):
optional = True optional = True
legend = u'Ouverture de port' legend = u'Ouverture de port'
category = 'firewall' category = 'firewall'
can_modify = [nounou]
def parse_value(self, port): def parse_value(self, port):
if ":" in port: if ":" in port:
@ -1251,6 +1227,7 @@ class nombrePrises(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
categoriy = 'base_tech' categoriy = 'base_tech'
can_modify = [nounou]
ldap_name = "nombrePrises" ldap_name = "nombrePrises"
@crans_attribute @crans_attribute
@ -1260,6 +1237,7 @@ class prise(Attr):
optional = True optional = True
legend = u"Prise sur laquelle est branchée la machine" legend = u"Prise sur laquelle est branchée la machine"
category = 'base_tech' category = 'base_tech'
can_modify = [nounou]
ldap_name = "prise" ldap_name = "prise"
@crans_attribute @crans_attribute
@ -1369,7 +1347,7 @@ class blacklist(Attr):
optional = True optional = True
legend = u"Blackliste" legend = u"Blackliste"
category = 'info' category = 'info'
can_modify = [nounou, bureau] can_modify = [nounou]
ldap_name = "blacklist" ldap_name = "blacklist"
python_type = dict python_type = dict
@ -1482,7 +1460,7 @@ class homeDirectory(rightProtectedAttr):
ldap_name = "homeDirectory" ldap_name = "homeDirectory"
@crans_attribute @crans_attribute
class loginShell(rightProtectedAttr): class loginShell(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
@ -1499,7 +1477,7 @@ class loginShell(rightProtectedAttr):
self.value = shell self.value = shell
@crans_attribute @crans_attribute
class uidNumber(intAttr, rightProtectedAttr): class uidNumber(intAttr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
@ -1507,17 +1485,15 @@ class uidNumber(intAttr, rightProtectedAttr):
legend = "L'uid du compte de l'adherent" legend = "L'uid du compte de l'adherent"
category = 'id' category = 'id'
ldap_name = "uidNumber" ldap_name = "uidNumber"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class gidNumber(intAttr, rightProtectedAttr): class gidNumber(intAttr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
legend = "Le gid du compte de l'adhérent" legend = "Le gid du compte de l'adhérent"
category = 'id' category = 'id'
ldap_name = "gidNumber" ldap_name = "gidNumber"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class gecos(Attr): class gecos(Attr):
@ -1527,7 +1503,6 @@ class gecos(Attr):
legend = "Le gecos" legend = "Le gecos"
category = 'id' category = 'id'
ldap_name = "gecos" ldap_name = "gecos"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class userPassword(rightProtectedAttr): class userPassword(rightProtectedAttr):
@ -1620,7 +1595,6 @@ class gpgMail(mail):
legend = "Mail associé à une clef gpg" legend = "Mail associé à une clef gpg"
can_modify = [soi, nounou] can_modify = [soi, nounou]
ldap_name = "gpgMail" ldap_name = "gpgMail"
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
super(mail, self).check_uniqueness(liste_exclue) super(mail, self).check_uniqueness(liste_exclue)
@ -1633,7 +1607,6 @@ class cn(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = False optional = False
can_modify = [cableur, nounou]
category = 'id' category = 'id'
ldap_name = "cn" ldap_name = "cn"
@ -1696,7 +1669,7 @@ class modePaiement(Attr):
self.value = mode self.value = mode
@crans_attribute @crans_attribute
class recuPaiement(generalizedTimeFormat): class recuPaiement(Attr):
__slots__ = () __slots__ = ()
ldap_name = "recuPaiement" ldap_name = "recuPaiement"
can_modify = [cableur, nounou] can_modify = [cableur, nounou]
@ -1766,6 +1739,7 @@ class machineAlias(boolAttr):
class issuerCN(Attr): class issuerCN(Attr):
__slots__ = () __slots__ = ()
ldap_name = "issuerCN" ldap_name = "issuerCN"
can_modify = [nounou]
legend = "Common Name de l'éméteur du certificat" legend = "Common Name de l'éméteur du certificat"
@crans_attribute @crans_attribute
@ -1773,18 +1747,21 @@ class serialNumber(Attr):
__slots__ = () __slots__ = ()
ldap_name = "serialNumber" ldap_name = "serialNumber"
python_type = int python_type = int
can_modify = [nounou]
legend = "Numéro de série du certificat" legend = "Numéro de série du certificat"
@crans_attribute @crans_attribute
class start(intAttr): class start(intAttr):
__slots__ = () __slots__ = ()
ldap_name = "start" ldap_name = "start"
can_modify = [nounou]
legend = "Date de début" legend = "Date de début"
@crans_attribute @crans_attribute
class end(intAttr): class end(intAttr):
__slots__ = () __slots__ = ()
ldap_name = "end" ldap_name = "end"
can_modify = [nounou]
legend = "Date de fin" legend = "Date de fin"
@crans_attribute @crans_attribute
@ -1801,6 +1778,7 @@ class revocked(boolAttr):
ldap_name = "revocked" ldap_name = "revocked"
singlevalue = True singlevalue = True
optional = True optional = True
can_modify = [nounou]
legend = "Détermine si le certificat est révoqué" legend = "Détermine si le certificat est révoqué"
@crans_attribute @crans_attribute

View file

@ -47,6 +47,7 @@ if '/usr/scripts' not in sys.path:
sys.path.append('/usr/scripts') sys.path.append('/usr/scripts')
from gestion import config from gestion import config
from unicodedata import normalize from unicodedata import normalize
import subprocess
from netifaces import interfaces, ifaddresses, AF_INET from netifaces import interfaces, ifaddresses, AF_INET
try: try:
@ -54,11 +55,6 @@ try:
except: except:
pytz = None pytz = None
try:
import dateutil.tz
except:
dateutil = None
DEVNULL = open(os.devnull, 'w') DEVNULL = open(os.devnull, 'w')
def find_rid_plage(rid): def find_rid_plage(rid):
@ -249,6 +245,7 @@ def escape(chaine):
dans une requête ldap.""" dans une requête ldap."""
return ldap.filter.escape_filter_chars(chaine) return ldap.filter.escape_filter_chars(chaine)
def hash_password(password, salt=None, longueur=4): def hash_password(password, salt=None, longueur=4):
if longueur < 4: if longueur < 4:
raise ValueError("salt devrait faire au moins 4 octets") raise ValueError("salt devrait faire au moins 4 octets")
@ -344,57 +341,21 @@ def from_generalized_time_format(gtf):
""" """
return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S")) return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S"))
def localized_datetime(date=None, tz=None):
"""Builds a datetime object based on a date string formatted as
%Y%m%d%H%M%S, and a tz timezone looking like +0200"""
if tz is None:
if date is not None:
if "+" in date or '-' in date or 'Z' in date:
if date.endswith("Z"):
date = date[:-1] + "+0000"
date, tz = date[:-5], date[-5:]
_notz = (tz is None)
# Shit may happen
if tz == "Z":
tz = "+0000"
if date is not None:
the_date = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
else:
the_date = datetime.datetime.now()
# No timezone means we try to get from the system
# if we have dateutil, else, UTC.
if tz is None:
if dateutil is not None:
tz = datetime.datetime.now(dateutil.tz.tzlocal()).strftime("%z")
else:
tz = "+0000"
# No pytz means no timezoned datetime
if pytz is not None:
the_timezone = pytz.FixedOffset(int(tz[0:-2])*60 + int(tz[-2:]))
the_date = the_timezone.localize(the_date)
the_date = the_timezone.normalize(the_date)
else:
# Maybe we can do something
if dateutil is not None:
if _notz:
the_date.replace(tzinfo=dateutil.tz.tzlocal())
return the_date
def datetime_from_generalized_time_format(gtf): def datetime_from_generalized_time_format(gtf):
"""Returns a datetime from generalized time format""" """Returns a datetime from generalized time format
"""
if '-' in gtf or '+' in gtf: if '-' in gtf or '+' in gtf:
date, tz = gtf[0:14], gtf[14:] date, tz = gtf[0:14], gtf[14:]
else: else:
date = gtf.replace("Z", '') date = gtf.replace("Z", '')
tz = '+0000' tz = '+0000'
return localized_datetime(date, tz) the_date = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
if pytz is not None:
the_timezone = pytz.FixedOffset(int(tz[0:-2])*60 + int(tz[-2:]))
the_date = the_timezone.localize(the_date)
the_date = the_timezone.normalize(the_date)
return the_date
def datetime_to_generalized_time_format(datetime_obj): def datetime_to_generalized_time_format(datetime_obj):
"""Transforms a datetime to a GTF""" """Transforms a datetime to a GTF"""

View file

@ -1,3 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# LC_LDAP.PY-- LightWeight CransLdap # LC_LDAP.PY-- LightWeight CransLdap
@ -38,7 +39,6 @@
import os import os
import sys import sys
import re import re
import time
from contextlib import contextmanager from contextlib import contextmanager
import ldap import ldap
@ -53,12 +53,11 @@ import variables
import copy import copy
import itertools import itertools
## import de /usr/scripts ## import de /usr/scripts/
if "/usr/scripts" not in sys.path: if not "/usr/scripts/" in sys.path:
sys.path.append('/usr/scripts') sys.path.append('/usr/scripts/')
import gestion.config as config import gestion.config as config
from gestion import secrets_new as secrets
import cranslib.deprecated import cranslib.deprecated
# A priori, ldif_to_uldif et ldif_to_cldif sont obsolètes, # A priori, ldif_to_uldif et ldif_to_cldif sont obsolètes,
@ -106,10 +105,6 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
# Si un username, on récupère le dn associé… # Si un username, on récupère le dn associé…
if user and not dn: if user and not dn:
if readonly_dn is None:
readonly_dn = secrets.get('ldap_readonly_auth_dn')
if readonly_password is None:
readonly_password = secrets.get('ldap_readonly_password')
dn = self.user_to_dn(user, readonly_dn, readonly_password) dn = self.user_to_dn(user, readonly_dn, readonly_password)
# Si on a un dn, on se connecte avec à la base ldap sinon on s'y # Si on a un dn, on se connecte avec à la base ldap sinon on s'y
@ -117,7 +112,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
if dn: if dn:
self.conn = self.bind_s(dn, cred) self.conn = self.bind_s(dn, cred)
self.dn = dn self.dn = dn
self.droits = [droit.decode(config.ldap_encoding) for droit in self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])] self.droits = self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])
if dn == variables.admin_dn: if dn == variables.admin_dn:
self.droits += [attributs.nounou] self.droits += [attributs.nounou]
# Il faut peupler current_login, qui sera utilisé pour écrire dans l'historique qui fait des modifications # Il faut peupler current_login, qui sera utilisé pour écrire dans l'historique qui fait des modifications
@ -252,7 +247,6 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
res = {} res = {}
parent = {} parent = {}
machines = {} machines = {}
factures = {}
# (proxying de la base ldap) # (proxying de la base ldap)
for dn, attrs in self.search_s(variables.base_dn, scope=2): for dn, attrs in self.search_s(variables.base_dn, scope=2):
# On crée les listes des machines et propriétaires # On crée les listes des machines et propriétaires
@ -262,26 +256,14 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
if not machines.has_key(parent_dn): if not machines.has_key(parent_dn):
machines[parent_dn] = [] machines[parent_dn] = []
machines[parent_dn].append(m) machines[parent_dn].append(m)
if dn.startswith('fid='): # les factures
f = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs))
parent_dn = dn.split(',', 1)[1]
if not factures.has_key(parent_dn):
factures[parent_dn] = []
factures[parent_dn].append(f)
elif (dn.startswith('aid=') or dn.startswith('cid=') or dn == variables.base_dn) and not parent.has_key(dn): elif (dn.startswith('aid=') or dn.startswith('cid=') or dn == variables.base_dn) and not parent.has_key(dn):
parent[dn] = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs)) parent[dn] = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs))
allmachines = [] allmachines = []
for dn in parent: # on associe propriétaires et factures, machines for dn, mlist in machines.iteritems(): # on associe propriétaires et machines
mlist = machines.get(dn, [])
flist = factures.get(dn, [])
parent[dn]._machines = mlist parent[dn]._machines = mlist
parent[dn]._factures = flist
parent[dn]._factures_last_update = time.time()
for m in mlist: for m in mlist:
m._proprio = parent[dn] m._proprio = parent[dn]
allmachines.append(m) allmachines.append(m)
for f in flist:
f._proprio = parent[dn]
return allmachines, parent.values() # on renvoie la liste des machines et des adherents (dont club et crans) return allmachines, parent.values() # on renvoie la liste des machines et des adherents (dont club et crans)
def allMachines(self, mode='ro'): def allMachines(self, mode='ro'):
@ -329,7 +311,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
uldif['objectClass'] = [u'machineCrans'] uldif['objectClass'] = [u'machineCrans']
assert isinstance(owner, objets.AssociationCrans) assert isinstance(owner, objets.AssociationCrans)
elif realm in ["bornes", "bornes-v6"]: elif realm == "bornes":
uldif['objectClass'] = [u'borneWifi'] uldif['objectClass'] = [u'borneWifi']
assert isinstance(owner, objets.AssociationCrans) assert isinstance(owner, objets.AssociationCrans)

View file

@ -179,7 +179,7 @@ class LdapLockHolder:
host, pid, begin = self.getlock(item, value) host, pid, begin = self.getlock(item, value)
time_left = self.timeout - (time.time() - begin) time_left = self.timeout - (time.time() - begin)
if time_left <= delai: if time_left <= delai:
raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value)) raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value, time_left))
def removelock(self, item, value, Id='default', force=False): def removelock(self, item, value, Id='default', force=False):
""" """
@ -214,3 +214,6 @@ class LdapLockHolder:
except ldap.INVALID_DN_SYNTAX: except ldap.INVALID_DN_SYNTAX:
print '%s=%s,%s' % (item, value, LOCKS_DN) print '%s=%s,%s' % (item, value, LOCKS_DN)
raise raise
except ValueError as e:
self.removelock(item, value, Id, force=True)
raise LockNotFound()

530
objets.py
View file

@ -56,9 +56,9 @@ import ldap_locks
import variables import variables
import printing import printing
## import de /usr/scripts ## import de /usr/scripts/
if "/usr/scripts" not in sys.path: if not "/usr/scripts/" in sys.path:
sys.path.append('/usr/scripts') sys.path.append('/usr/scripts/')
import gestion.config as config import gestion.config as config
import gestion.config.impression import gestion.config.impression
@ -66,7 +66,6 @@ import cranslib.deprecated
#: Champs à ignorer dans l'historique #: Champs à ignorer dans l'historique
HIST_IGNORE_FIELDS = ["modifiersName", "entryCSN", "modifyTimestamp", "historique"] HIST_IGNORE_FIELDS = ["modifiersName", "entryCSN", "modifyTimestamp", "historique"]
FACTURES_REFRESH_PERIOD = 60
def new_cransldapobject(conn, dn, mode='ro', uldif=None, lockId=None): def new_cransldapobject(conn, dn, mode='ro', uldif=None, lockId=None):
"""Crée un objet :py:class:`CransLdapObject` en utilisant la classe correspondant à """Crée un objet :py:class:`CransLdapObject` en utilisant la classe correspondant à
@ -84,7 +83,7 @@ def new_cransldapobject(conn, dn, mode='ro', uldif=None, lockId=None):
else: else:
res = conn.search_s(dn, 0) res = conn.search_s(dn, 0)
if not res: if not res:
raise ValueError('objet inexistant: %s' % dn) raise ValueError ('objet inexistant: %s' % dn)
_, attrs = res[0] _, attrs = res[0]
classe = ObjectFactory.get(attrs['objectClass'][0]) classe = ObjectFactory.get(attrs['objectClass'][0])
@ -101,8 +100,7 @@ class CransLdapObject(object):
""" Qui peut faire quoi ? """ """ Qui peut faire quoi ? """
__slots__ = ("in_context", "conn", "lockId", "attrs", "_modifs", "dn", "parent_dn", "mode") __slots__ = ("in_context", "conn", "lockId", "attrs", "_modifs", "dn", "parent_dn", "mode")
can_be_by = { can_be_by = { variables.created: [attributs.nounou],
variables.created: [attributs.nounou],
variables.modified: [attributs.nounou], variables.modified: [attributs.nounou],
variables.deleted: [attributs.nounou], variables.deleted: [attributs.nounou],
} }
@ -171,7 +169,7 @@ class CransLdapObject(object):
else: else:
res = self.conn.search_s(dn, 0) res = self.conn.search_s(dn, 0)
if not res: if not res:
raise ValueError('objet inexistant: %s' % dn) raise ValueError ('objet inexistant: %s' % dn)
self.dn, ldif = res[0] self.dn, ldif = res[0]
# L'objet sortant de la base ldap, on ne fait pas de vérifications sur # L'objet sortant de la base ldap, on ne fait pas de vérifications sur
@ -204,12 +202,21 @@ class CransLdapObject(object):
for v in nldif[attr]: for v in nldif[attr]:
if v in vals: if v in vals:
vals.remove(v) vals.remove(v)
nvals = [nldif[attr][vals.index(v)] for v in vals] nvals = [nldif[attr][vals.index(v)] for v in vals ]
raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals) raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals)
def oid(self): def _id(self):
"""Retourne l'id de l'objet courant""" """Retourne l'id de l'objet courant"""
return [self.dn.split(",")[0].split("=")[1]] if isinstance(self, adherent):
return self['aid']
elif isinstance(self, machine):
return self['mid']
elif isinstance(self, club):
return self['cid']
elif isinstance(self, facture):
return self['fid']
else:
return [self.dn]
def _out_of_context(self, *args, **kwargs): def _out_of_context(self, *args, **kwargs):
raise EnvironmentError("Hors du context, impossible de faire des écritures") raise EnvironmentError("Hors du context, impossible de faire des écritures")
@ -221,6 +228,8 @@ class CransLdapObject(object):
#self.save = self._out_of_context #self.save = self._out_of_context
#self.create = self._out_of_context #self.create = self._out_of_context
#self.delete = self._out_of_context #self.delete = self._out_of_context
# On retombe en read only
self.mode = 'ro'
# On purge les lock de l'objet # On purge les lock de l'objet
self.conn.lockholder.purge(self.lockId) self.conn.lockholder.purge(self.lockId)
@ -250,11 +259,11 @@ class CransLdapObject(object):
def c_mul(a, b): def c_mul(a, b):
return eval(hex((long(a) * b) & 0xFFFFFFFFL)[:-1]) return eval(hex((long(a) * b) & 0xFFFFFFFFL)[:-1])
value = 0x345678 value = 0x345678
l = 0 l=0
keys = self.keys() keys = self.keys()
keys.sort() keys.sort()
for key in keys: for key in keys:
l += len(self.attrs[key]) l+=len(self.attrs[key])
for item in self.attrs[key]: for item in self.attrs[key]:
value = c_mul(1000003, value) ^ hash(item) value = c_mul(1000003, value) ^ hash(item)
value = value ^ l value = value ^ l
@ -263,31 +272,31 @@ class CransLdapObject(object):
return value return value
def __iter__(self): def __iter__(self):
if self.mode in ['w', 'rw']: if self.mode in [ 'w', 'rw' ]:
return self._modifs.__iter__() return self._modifs.__iter__()
else: else:
return self.attrs.__iter__() return self.attrs.__iter__()
def keys(self): def keys(self):
if self.mode in ['w', 'rw']: if self.mode in [ 'w', 'rw' ]:
return self._modifs.keys() return self._modifs.keys()
else: else:
return self.attrs.keys() return self.attrs.keys()
def values(self): def values(self):
if self.mode in ['w', 'rw']: if self.mode in [ 'w', 'rw' ]:
return self._modifs.values() return self._modifs.values()
else: else:
return self.attrs.values() return self.attrs.values()
def items(self): def items(self):
if self.mode in ['w', 'rw']: if self.mode in [ 'w', 'rw' ]:
return self._modifs.items() return self._modifs.items()
else: else:
return self.attrs.items() return self.attrs.items()
def display(self, *args, **kwargs): def display(self, historique=5, blacklist=5):
print printing.sprint(self, *args, **kwargs) print printing.sprint(self, historique=historique, blacklist=blacklist)
def history_add(self, login, chain): def history_add(self, login, chain):
"""Ajoute une ligne à l'historique de l'objet. """Ajoute une ligne à l'historique de l'objet.
@ -303,8 +312,7 @@ class CransLdapObject(object):
"Génère une ligne d'historique pour l'arribut attr ou une ligne par attributs pour l'objet courant" "Génère une ligne d'historique pour l'arribut attr ou une ligne par attributs pour l'objet courant"
if attr is None: if attr is None:
for attr in self.keys(): for attr in self.keys():
self.history_gen(attr, login=login) self.history_gen(attr)
return
def partial_name(name, max_len=14, start=7, end=7): def partial_name(name, max_len=14, start=7, end=7):
if len(name) > max_len: if len(name) > max_len:
return "%s%s" % (name[:start], name[-end:]) return "%s%s" % (name[:start], name[-end:])
@ -335,8 +343,8 @@ class CransLdapObject(object):
if attr.historique == "full": if attr.historique == "full":
comm = u"%s (%s -> %s)" % (attr.ldap_name, old_values[0], new_values[0]) comm = u"%s (%s -> %s)" % (attr.ldap_name, old_values[0], new_values[0])
elif attr.historique == "partial": elif attr.historique == "partial":
old = partial_name(unicode(old_values[0])) old = partial_name(str(old_values[0]))
new = partial_name(unicode(new_values[0])) new = partial_name(str(new_values[0]))
comm = u"%s (%s -> %s)" % (attr.ldap_name, old, new) comm = u"%s (%s -> %s)" % (attr.ldap_name, old, new)
elif attr.historique == "info": elif attr.historique == "info":
comm = u"%s" % attr.ldap_name comm = u"%s" % attr.ldap_name
@ -345,7 +353,7 @@ class CransLdapObject(object):
if attr.historique == "info": if attr.historique == "info":
comm = u"+%s" % attr.ldap_name comm = u"+%s" % attr.ldap_name
elif attr.historique in ["full", "partial"]: elif attr.historique in ["full", "partial"]:
new = unicode(new_values[0]) new = str(new_values[0])
if attr.historique == "partial": if attr.historique == "partial":
new = partial_name(new) new = partial_name(new)
comm = u"%s+%s" % (attr.ldap_name, new) comm = u"%s+%s" % (attr.ldap_name, new)
@ -354,7 +362,7 @@ class CransLdapObject(object):
if attr.historique == "info": if attr.historique == "info":
comm = u"-%s" % attr.ldap_name comm = u"-%s" % attr.ldap_name
elif attr.historique in ["full", "partial"]: elif attr.historique in ["full", "partial"]:
old = unicode(old_values[0]) old = str(old_values[0])
if attr.historique == "partial": if attr.historique == "partial":
old = partial_name(old) old = partial_name(old)
comm = u"%s-%s" % (attr.ldap_name, old) comm = u"%s-%s" % (attr.ldap_name, old)
@ -362,9 +370,9 @@ class CransLdapObject(object):
added = [] added = []
deleted = [] deleted = []
if attr.historique == "partial": if attr.historique == "partial":
append = lambda x: partial_name(unicode(x)) append = lambda x: partial_name(str(x))
else: else:
append = lambda x: unicode(x) append = lambda x: str(x)
for a in new_values: for a in new_values:
if not a in old_values: if not a in old_values:
added.append(append(a)) added.append(append(a))
@ -429,7 +437,7 @@ class CransLdapObject(object):
try: try:
if self.conn.search(dn=self.dn): if self.conn.search(dn=self.dn):
raise ValueError('objet existant: %s' % self.dn) raise ValueError ('objet existant: %s' % self.dn)
except ldap.NO_SUCH_OBJECT: except ldap.NO_SUCH_OBJECT:
pass pass
@ -444,8 +452,8 @@ class CransLdapObject(object):
ldif = self._modifs.to_ldif() ldif = self._modifs.to_ldif()
for attr in binary: for attr in binary:
ldif['%s;binary' % attr] = ldif[attr] ldif['%s;binary' % attr]=ldif[attr]
del ldif[attr] del(ldif[attr])
# Création de la requête LDAP # Création de la requête LDAP
modlist = addModlist(ldif) modlist = addModlist(ldif)
# Requête LDAP de création de l'objet # Requête LDAP de création de l'objet
@ -584,11 +592,11 @@ class CransLdapObject(object):
ldif = self._modifs.to_ldif() ldif = self._modifs.to_ldif()
orig_ldif = self.attrs.to_ldif() orig_ldif = self.attrs.to_ldif()
for attr in binary: for attr in binary:
ldif['%s;binary' % (attr,)] = ldif[attr] ldif['%s;binary' % attr]=ldif[attr]
orig_ldif['%s;binary' % (attr,)] = orig_ldif.get(attr, []) orig_ldif['%s;binary' % attr]=orig_ldif.get(attr, [])
del ldif[attr] del(ldif[attr])
try: try:
del orig_ldif[attr] del(orig_ldif[attr])
except KeyError: except KeyError:
pass pass
@ -602,10 +610,10 @@ class CransLdapObject(object):
return default return default
def __getitem__(self, attr, default=None): def __getitem__(self, attr, default=None):
if self._modifs.has_key(attr) and self.mode in ['w', 'rw']: if self._modifs.has_key(attr) and self.mode in [ 'w', 'rw' ]:
return attributs.AttrsList(self, attr, [v for v in self._modifs[attr]]) return attributs.AttrsList(self, attr, [ v for v in self._modifs[attr] ])
elif self.attrs.has_key(attr): elif self.attrs.has_key(attr):
return attributs.AttrsList(self, attr, [v for v in self.attrs[attr]]) return attributs.AttrsList(self, attr, [ v for v in self.attrs[attr] ])
elif self.has_key(attr): elif self.has_key(attr):
return attributs.AttrsList(self, attr, []) if default is None else default return attributs.AttrsList(self, attr, []) if default is None else default
else: else:
@ -670,11 +678,8 @@ class CransLdapObject(object):
try: try:
for attribut in attrs_before_verif: for attribut in attrs_before_verif:
# Vérification que (attr, value) est localement unique # Vérification que (attr, value) est localement unique
# Il vaut mieux le vérifier ici, car l'erreur que LDAP
# lève n'est pas très claire. (mais il est clair qu'il ne
# tolère pas les doublons dans un objet)
if attrs_before_verif.count(attribut) > 1: if attrs_before_verif.count(attribut) > 1:
raise ValueError("%r en double\n(%r)" % (attribut.legend if attribut.legend else attr, attribut)) raise ValueError("%s en double\n(%s)" % (attribut.legend if attribut.legend else attr, attribut))
# On lock les nouvelles valeurs globalement unique # On lock les nouvelles valeurs globalement unique
if not no_uniq_lock and attribut.unique and not attribut in self._modifs.get(attr, []) and not attribut in attribut.unique_exclue: if not no_uniq_lock and attribut.unique and not attribut in self._modifs.get(attr, []) and not attribut in attribut.unique_exclue:
@ -694,8 +699,8 @@ class CransLdapObject(object):
if not no_concurrent_lock and not attributs.AttributeFactory.get(attr).concurrent and self._modifs.get(attr, []) == self.attrs.get(attr, []) and attrs_before_verif != self.attrs.get(attr, []): if not no_concurrent_lock and not attributs.AttributeFactory.get(attr).concurrent and self._modifs.get(attr, []) == self.attrs.get(attr, []) and attrs_before_verif != self.attrs.get(attr, []):
if not self.in_context: if not self.in_context:
cranslib.deprecated.usage("Des locks ne devrait être ajoutés que dans un context manager", level=2) cranslib.deprecated.usage("Des locks ne devrait être ajoutés que dans un context manager", level=2)
self.conn.lockholder.addlock("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',', '_'), attr), self.lockId) self.conn.lockholder.addlock("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',','_'), attr), self.lockId)
locked.append(("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',', '_'), attr), self.lockId)) locked.append(("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',','_'), attr), self.lockId))
try: try:
# une fois le lock acquit, on vérifie que l'attribut n'a pas été édité entre temps # une fois le lock acquit, on vérifie que l'attribut n'a pas été édité entre temps
if self.conn.search(dn=self.dn, scope=0)[0].get(attr, []) != self.attrs.get(attr, []): if self.conn.search(dn=self.dn, scope=0)[0].get(attr, []) != self.attrs.get(attr, []):
@ -717,7 +722,7 @@ class CransLdapObject(object):
self.conn.lockholder.removelock(attr, str(attribut), self.lockId) self.conn.lockholder.removelock(attr, str(attribut), self.lockId)
# Si on remet la valeur antérieure au lock, on le libère # Si on remet la valeur antérieure au lock, on le libère
if not attributs.AttributeFactory.get(attr).concurrent and self._modifs.get(attr, []) != self.attrs.get(attr, []) and attrs_before_verif == self.attrs.get(attr, []): if not attributs.AttributeFactory.get(attr).concurrent and self._modifs.get(attr, []) != self.attrs.get(attr, []) and attrs_before_verif == self.attrs.get(attr, []):
self.conn.lockholder.removelock("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',', '_'), attr), self.lockId) self.conn.lockholder.removelock("dn", "%s_%s" % (self.dn.replace('=', '-').replace(',','_'), attr), self.lockId)
# On met à jour self._modifs avec les nouvelles valeurs # On met à jour self._modifs avec les nouvelles valeurs
self._modifs[attr] = attrs_before_verif self._modifs[attr] = attrs_before_verif
@ -774,7 +779,7 @@ class CransLdapObject(object):
Améliorations possibles: Améliorations possibles:
- Vérifier les blacklistes des machines pour les adhérents ? - Vérifier les blacklistes des machines pour les adhérents ?
""" """
blacklist_liste = [] blacklist_liste=[]
# blacklistes virtuelle si on est un adhérent pour carte étudiant et chambre invalides # blacklistes virtuelle si on est un adhérent pour carte étudiant et chambre invalides
if isinstance(self, adherent): if isinstance(self, adherent):
if self['chbre'][0] == '????': if self['chbre'][0] == '????':
@ -786,11 +791,11 @@ class CransLdapObject(object):
blacklist_liste.append(bl) blacklist_liste.append(bl)
blacklist_liste.extend(bl for bl in self.get("blacklist", []) if bl.is_actif()) blacklist_liste.extend(bl for bl in self.get("blacklist", []) if bl.is_actif())
if excepts: if excepts:
return [b for b in blacklist_liste if b['type'] not in excepts] return [ b for b in blacklist_liste if b['type'] not in excepts ]
else: else:
return blacklist_liste return blacklist_liste
def blacklist(self, sanction, commentaire, debut="now", fin='-'): def blacklist(self, sanction, commentaire, debut="now", fin = '-'):
""" """
Blacklistage de la ou de toutes la machines du propriétaire Blacklistage de la ou de toutes la machines du propriétaire
* debut et fin sont le nombre de secondes depuis epoch * debut et fin sont le nombre de secondes depuis epoch
@ -842,51 +847,31 @@ def crans_object(classe):
class InetOrgPerson(CransLdapObject): class InetOrgPerson(CransLdapObject):
__slots__ = () __slots__ = ()
ldap_name = "inetOrgPerson" ldap_name = "inetOrgPerson"
def __unicode__(self):
return u"%s : cn=%s" % (self.__class__.__name__, self['cn'][0])
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__) + " : cn=" + str(self['cn'][0])
pass pass
class proprio(CransLdapObject): class proprio(CransLdapObject):
u""" Un propriétaire de machine (adhérent, club…) """ u""" Un propriétaire de machine (adhérent, club…) """
__slots__ = ("_machines", "_factures", "full", '_factures_last_update') __slots__ = ("_machines", "_factures", "full")
can_be_by = { can_be_by = { variables.created: [attributs.nounou, attributs.bureau, attributs.cableur],
variables.created: [ variables.modified: [attributs.nounou, attributs.bureau, attributs.soi, attributs.cableur],
attributs.nounou, variables.deleted: [attributs.nounou, attributs.bureau,],
attributs.bureau,
attributs.cableur,
],
variables.modified: [
attributs.nounou,
attributs.bureau,
attributs.soi,
attributs.cableur,
],
variables.deleted: [
attributs.nounou,
attributs.bureau,
],
} }
crans_account_attribs = [ crans_account_attribs = [attributs.uid, attributs.canonicalAlias, attributs.solde,
attributs.uid, attributs.canonicalAlias, attributs.solde,
attributs.contourneGreylist, attributs.derniereConnexion, attributs.contourneGreylist, attributs.derniereConnexion,
attributs.homepageAlias, attributs.loginShell, attributs.gecos, attributs.homepageAlias, attributs.loginShell, attributs.gecos,
attributs.uidNumber, attributs.homeDirectory, attributs.uidNumber, attributs.homeDirectory,
attributs.gidNumber, attributs.userPassword, attributs.gidNumber, attributs.userPassword,
attributs.mailAlias, attributs.cn, attributs.rewriteMailHeaders, attributs.mailAlias, attributs.cn, attributs.rewriteMailHeaders,
attributs.mailExt, attributs.compteWiki, attributs.droits, attributs.mailExt, attributs.compteWiki, attributs.droits,
attributs.shadowExpire, attributs.shadowExpire]
] default_attribs = [attributs.nom, attributs.chbre, attributs.paiement, attributs.info,
default_attribs = [
attributs.nom, attributs.chbre, attributs.paiement, attributs.info,
attributs.blacklist, attributs.controle, attributs.historique, attributs.blacklist, attributs.controle, attributs.historique,
attributs.debutAdhesion, attributs.finAdhesion, attributs.debutConnexion, attributs.debutAdhesion, attributs.finAdhesion, attributs.debutConnexion,
attributs.finConnexion, attributs.finConnexion]
]
@property @property
def attribs(self): def attribs(self):
@ -903,17 +888,13 @@ class proprio(CransLdapObject):
"""Renvoie la liste des clubs dont l'adherent est imprimeur (surchargée dans les objets adherent)""" """Renvoie la liste des clubs dont l'adherent est imprimeur (surchargée dans les objets adherent)"""
return [] return []
def __unicode__(self):
return u"%s : nom=%s" % (self.__class__.__name__, self['nom'][0])
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__) + " : nom=" + str(self['nom'][0])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(proprio, self).__init__(*args, **kwargs) super(proprio, self).__init__(*args, **kwargs)
self._machines = None self._machines = None
self._factures = None self._factures = None
self._factures_last_update = 0
def delete_compte(self, mail): def delete_compte(self, mail):
# Je pense qu'en pratique cette vérification ne sert à rien puisqu'on se fera jetter à la tentative de modification # Je pense qu'en pratique cette vérification ne sert à rien puisqu'on se fera jetter à la tentative de modification
@ -932,15 +913,15 @@ class proprio(CransLdapObject):
self['uidNumber'] = [] self['uidNumber'] = []
self['gidNumber'] = [] self['gidNumber'] = []
self['gecos'] = [] self['gecos'] = []
self['shadowExpire'] = [] self['shadowExpire']=[]
self['derniereConnexion'] = [] self['derniereConnexion']=[]
self['mailExt'] = [] self['mailExt']=[]
self['uid'] = [] self['uid' ]=[]
self._modifs['objectClass'] = [u'adherent'] self._modifs['objectClass'] = [u'adherent']
self.full = False self.full = False
def compte(self, login=None, uidNumber=0, hash_pass='', shell=config.login_shell): def compte(self, login = None, uidNumber=0, hash_pass = '', shell=config.login_shell):
u"""Renvoie le nom du compte crans. S'il n'existe pas, et que login u"""Renvoie le nom du compte crans. S'il n'existe pas, et que login
est précisé, le crée.""" est précisé, le crée."""
@ -948,6 +929,7 @@ class proprio(CransLdapObject):
return self['uid'][0] return self['uid'][0]
elif login: elif login:
fn = crans_utils.strip_accents(unicode(self['prenom'][0]).capitalize())
ln = crans_utils.strip_accents(unicode(self['nom'][0]).capitalize()) ln = crans_utils.strip_accents(unicode(self['nom'][0]).capitalize())
login = crans_utils.strip_spaces(crans_utils.strip_accents(login), by=u'-').lower() login = crans_utils.strip_spaces(crans_utils.strip_accents(login), by=u'-').lower()
if not re.match('^[a-z][-a-z]{1,15}$', login): if not re.match('^[a-z][-a-z]{1,15}$', login):
@ -955,43 +937,25 @@ class proprio(CransLdapObject):
if crans_utils.mailexist(login): if crans_utils.mailexist(login):
raise ValueError("Login existant ou correspondant à un alias mail.") raise ValueError("Login existant ou correspondant à un alias mail.")
if self.ldap_name == u'adherent': home = u'/home/' + login
home = u'/home/' + login[0] + '/' + login
if os.path.exists(home): if os.path.exists(home):
raise ValueError('Création du compte impossible : home existant') raise ValueError('Création du compte impossible : home existant')
if os.path.exists("/home/mail/" + login): if os.path.exists("/var/mail/" + login):
raise ValueError('Création du compte impossible : /home/mail/%s existant' % str(login)) raise ValueError('Création du compte impossible : /var/mail/%s existant' % str(login))
fn = crans_utils.strip_accents(unicode(self['prenom'][0]).capitalize())
self._modifs['objectClass'] = [u'adherent', u'cransAccount', u'posixAccount', u'shadowAccount'] self._modifs['objectClass'] = [u'adherent', u'cransAccount', u'posixAccount', u'shadowAccount']
self['uid' ] = [login]
self['homeDirectory'] = [home] self['homeDirectory'] = [home]
self['cn'] = [fn + u' ' + ln]
self['mail'] = [login + u"@crans.org"] self['mail'] = [login + u"@crans.org"]
calias = crans_utils.strip_spaces(fn) + u'.' + crans_utils.strip_spaces(ln) + '@crans.org' calias = crans_utils.strip_spaces(fn) + u'.' + crans_utils.strip_spaces(ln) + '@crans.org'
if crans_utils.mailexist(calias): if crans_utils.mailexist(calias):
calias = login + u'@crans.org' calias = login
if crans_utils.mailexist(calias):
raise ValueError('Creation impossible, Alias canonique déjà pris, merci de choisir un autre login')
self['canonicalAlias'] = [calias] self['canonicalAlias'] = [calias]
self['cn'] = [ fn + u' ' + ln ]
else:
# C'est un club
home = u'/home/c/club/' + login.split('-', 1)[-1]
if os.path.exists(home):
raise ValueError('Création du compte impossible : home existant')
if os.path.exists("/home/mail/" + login):
raise ValueError('Création du compte impossible : /home/mail/%s existant' % str(login))
self._modifs['objectClass'] = [u'club', u'cransAccount', u'posixAccount', u'shadowAccount']
self['homeDirectory'] = [home]
self['cn'] = [ln]
# Les attributs communs
self['uid'] = [login]
self['loginShell'] = [unicode(shell)] self['loginShell'] = [unicode(shell)]
if hash_pass:
self['userPassword'] = [unicode(hash_pass)] self['userPassword'] = [unicode(hash_pass)]
self["solde"] = 0.0
if uidNumber: if uidNumber:
if self.conn.search(u'(uidNumber=%s)' % uidNumber): if self.conn.search(u'(uidNumber=%s)' % uidNumber):
@ -1045,45 +1009,11 @@ class proprio(CransLdapObject):
def fin_adhesion(self): def fin_adhesion(self):
"""Retourne la date de fin d'adhésion""" """Retourne la date de fin d'adhésion"""
return max([ return max([float(facture.get('finAdhesion', [crans_utils.from_generalized_time_format(attributs.finAdhesion.default)])[0]) for facture in self.factures(refresh=True, mode="ro") if facture.get('controle', [''])[0] != u"FALSE" and facture.get('recuPaiement', [''])[0] != ''] + [0.0])
facture.get('finAdhesion', [attributs.finAdhesion.default])[0]
for facture in self.factures(refresh=(time.time() - self._factures_last_update > FACTURES_REFRESH_PERIOD))
if facture.get('controle', [''])[0] != u"FALSE" and facture.get('recuPaiement', [])
] + [attributs.finAdhesion.default])
def fin_connexion(self): def fin_connexion(self):
"""Retourne la date de fin de connexion""" """Retourne la date de fin de connexion"""
return max([ return max([float(facture.get('finConnexion', [crans_utils.from_generalized_time_format(attributs.finConnexion.default)])[0]) for facture in self.factures(refresh=True, mode="ro") if facture.get('controle', [''])[0] != u"FALSE" and facture.get('recuPaiement', [''])[0] != ''] + [0.0])
facture.get('finConnexion', [attributs.finConnexion.default])[0]
for facture in self.factures(refresh=(time.time() - self._factures_last_update > FACTURES_REFRESH_PERIOD))
if facture.get('controle', [''])[0] != u"FALSE" and facture.get('recuPaiement', [])
] + [attributs.finConnexion.default])
def adhesion_ok(self, no_bl=False):
"""Renvoie si le propriétaire a une adhésion en cours."""
if self.dn == variables.base_dn:
return True
_now = crans_utils.localized_datetime()
fin_paiement = self.fin_adhesion()
paiement = (
_now < fin_paiement
or
(
config.periode_transitoire
and
(
crans_utils.datetime_from_generalized_time_format(config.gtf_debut_periode_transitoire)
<= fin_paiement
<= crans_utils.datetime_from_generalized_time_format(config.gtf_fin_periode_transitoire)
)
)
)
return paiement
def paiement_ok(self, no_bl=False): def paiement_ok(self, no_bl=False):
u""" u"""
@ -1092,33 +1022,15 @@ class proprio(CransLdapObject):
""" """
if self.dn == variables.base_dn: if self.dn == variables.base_dn:
return True return True
if not no_bl: if not no_bl:
for bl in self.blacklist_actif(): for bl in self.blacklist_actif():
if bl['type'] == 'paiement': if bl['type'] == 'paiement':
return False return False
_now = crans_utils.localized_datetime()
if isinstance(self, adherent): if isinstance(self, adherent):
fin_paiement = min(self.fin_adhesion(), self.fin_connexion()) fin_paiement = min(self.fin_adhesion(), self.fin_connexion())
else: else:
fin_paiement = self.fin_adhesion() fin_paiement = self.fin_adhesion()
paiement = time.time() < fin_paiement or (config.periode_transitoire and config.debut_periode_transitoire <= fin_paiement <= config.fin_periode_transitoire)
paiement = (
_now < fin_paiement
or
(
config.periode_transitoire
and
(
crans_utils.datetime_from_generalized_time_format(config.gtf_debut_periode_transitoire)
<= fin_paiement
<= crans_utils.datetime_from_generalized_time_format(config.gtf_fin_periode_transitoire)
)
)
)
return paiement return paiement
def carte_ok(self): def carte_ok(self):
@ -1144,7 +1056,7 @@ class proprio(CransLdapObject):
if new_solde < config.impression.decouvert: if new_solde < config.impression.decouvert:
raise ValueError(u"Solde minimal atteint, opération non effectuée.") raise ValueError(u"Solde minimal atteint, opération non effectuée.")
transaction = u"credit" if diff >= 0 else u"debit" transaction = u"credit" if diff >=0 else u"debit"
new_solde = u"%.2f" % new_solde new_solde = u"%.2f" % new_solde
self.history_add(login, u"%s %.2f Euros [%s]" % (transaction, abs(diff), comment)) self.history_add(login, u"%s %.2f Euros [%s]" % (transaction, abs(diff), comment))
self["solde"] = new_solde self["solde"] = new_solde
@ -1157,7 +1069,7 @@ class proprio(CransLdapObject):
"""Renvoie la liste des machines""" """Renvoie la liste des machines"""
if self._machines is None or refresh: if self._machines is None or refresh:
try: try:
self._machines = self.conn.search(u'mid=*', dn=self.dn, scope=1, mode=self.mode if mode is None else mode) self._machines = self.conn.search(u'mid=*', dn = self.dn, scope = 1, mode=self.mode if mode is None else mode)
for m in self._machines: for m in self._machines:
m._proprio = self m._proprio = self
except ldap.NO_SUCH_OBJECT: except ldap.NO_SUCH_OBJECT:
@ -1173,10 +1085,9 @@ class proprio(CransLdapObject):
refresh = True refresh = True
if self._factures is None or refresh: if self._factures is None or refresh:
try: try:
self._factures = self.conn.search(u'fid=*', dn=self.dn, scope=1, mode=mode) self._factures = self.conn.search(u'fid=*', dn = self.dn, scope = 1, mode=mode)
for m in self._factures: for m in self._factures:
m._proprio = self m._proprio = self
self._factures_last_update = time.time()
# Si on manipule un objet pas encore enregistré dans la la bdd # Si on manipule un objet pas encore enregistré dans la la bdd
except ldap.NO_SUCH_OBJECT: except ldap.NO_SUCH_OBJECT:
self._factures = [] self._factures = []
@ -1236,44 +1147,20 @@ class proprio(CransLdapObject):
class machine(CransLdapObject): class machine(CransLdapObject):
u""" Une machine """ u""" Une machine """
__slots__ = ("_proprio", "_certificats") __slots__ = ("_proprio", "_certificats")
can_be_by = { can_be_by = { variables.created: [attributs.nounou, attributs.bureau, attributs.cableur, attributs.parent, attributs.respo],
variables.created: [ variables.modified: [attributs.nounou, attributs.bureau, attributs.cableur, attributs.parent, attributs.respo],
attributs.nounou, variables.deleted: [attributs.nounou, attributs.bureau, attributs.cableur, attributs.parent, attributs.respo],
attributs.bureau,
attributs.cableur,
attributs.parent,
attributs.respo,
],
variables.modified: [
attributs.nounou,
attributs.bureau,
attributs.cableur,
attributs.parent,
attributs.respo,
],
variables.deleted: [
attributs.nounou,
attributs.bureau,
attributs.cableur,
attributs.parent,
attributs.respo,
],
} }
attribs = [ attribs = [attributs.mid, attributs.macAddress, attributs.host,
attributs.mid, attributs.macAddress, attributs.host,
attributs.rid, attributs.info, attributs.blacklist, attributs.hostAlias, attributs.rid, attributs.info, attributs.blacklist, attributs.hostAlias,
attributs.exempt, attributs.portTCPout, attributs.portTCPin, attributs.exempt, attributs.portTCPout, attributs.portTCPin,
attributs.portUDPout, attributs.portUDPin, attributs.sshFingerprint, attributs.portUDPout, attributs.portUDPin, attributs.sshFingerprint,
attributs.ipHostNumber, attributs.ip6HostNumber, attributs.historique, attributs.ipHostNumber, attributs.ip6HostNumber, attributs.historique,
attributs.dnsIpv6, attributs.machineAlias, attributs.dnsIpv6, attributs.machineAlias]
]
def __unicode__(self):
return u"%s : host=%s" % (self.__class__.__name__, self['host'][0])
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__) + " : host=" + str(self['host'][0])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(machine, self).__init__(*args, **kwargs) super(machine, self).__init__(*args, **kwargs)
@ -1288,16 +1175,12 @@ class machine(CransLdapObject):
qu'un de ses certificats l'utilise. qu'un de ses certificats l'utilise.
""" """
if attr in ['host', 'hostAlias']: if attr in ['host', 'hostAlias']:
deleted = [value for value in self[attr] if value not in values] deleted = [ value for value in self[attr] if value not in values ]
for domain in deleted: for domain in deleted:
for certificat in self.certificats(): for certificat in self.certificats():
if domain in certificat['hostCert']: if domain in certificat['hostCert']:
raise EnvironmentError("Vous devez d'abord supprimer ou éditer les certificats utilisant le nom de domaine %s avant de le retirer de la machine" % domain) raise EnvironmentError("Vous devez d'abord supprimer ou éditer les certificats utilisant le nom de domaine %s avant de le retirer de la machine" % domain)
def oid(self):
"""Retourne l'id de l'objet courant"""
return self['mid']
def proprio(self, mode=None, refresh=False): def proprio(self, mode=None, refresh=False):
u"""Renvoie le propriétaire de la machine""" u"""Renvoie le propriétaire de la machine"""
if not hasattr(self, '_proprio') or not self._proprio or refresh: if not hasattr(self, '_proprio') or not self._proprio or refresh:
@ -1308,7 +1191,7 @@ class machine(CransLdapObject):
"""Renvoie la liste des certificats de la machine""" """Renvoie la liste des certificats de la machine"""
if refresh or self._certificats is None: if refresh or self._certificats is None:
try: try:
self._certificats = self.conn.search(u'xid=*', dn=self.dn, scope=1, mode=self.mode) self._certificats = self.conn.search(u'xid=*', dn = self.dn, scope = 1, mode=self.mode)
for m in self._certificats: for m in self._certificats:
m._machine = self m._machine = self
except ldap.NO_SUCH_OBJECT: except ldap.NO_SUCH_OBJECT:
@ -1317,7 +1200,7 @@ class machine(CransLdapObject):
def blacklist_actif(self, excepts=[]): def blacklist_actif(self, excepts=[]):
u"""Renvoie la liste des blacklistes actives sur la machine et le proprio""" u"""Renvoie la liste des blacklistes actives sur la machine et le proprio"""
black = self.proprio().blacklist_actif(excepts) black=self.proprio().blacklist_actif(excepts)
black.extend(super(machine, self).blacklist_actif(excepts)) black.extend(super(machine, self).blacklist_actif(excepts))
return black return black
@ -1384,7 +1267,7 @@ class machine(CransLdapObject):
sbm['rid'] = (orid, nrid) sbm['rid'] = (orid, nrid)
# Les macAddress sont déjà des unicodes. # Les macAddress sont déjà des unicodes.
# On change l'ip6 # On change l'ip6
if old['macAddress'] != new['macAddress']: elif old['macAddress'] != new['macAddress']:
nip6 = unicode(crans_utils.ip6_of_mac(new['macAddress'], new['rid'])) nip6 = unicode(crans_utils.ip6_of_mac(new['macAddress'], new['rid']))
try: try:
oip6 = unicode(self._modifs['ip6HostNumber'][0]) oip6 = unicode(self._modifs['ip6HostNumber'][0])
@ -1418,7 +1301,6 @@ class machine(CransLdapObject):
if unicode(self['ipHostNumber'][0]) != unicode(crans_utils.ip4_of_rid(sbm['rid'][1])): if unicode(self['ipHostNumber'][0]) != unicode(crans_utils.ip4_of_rid(sbm['rid'][1])):
raise ValueError("L'ipv4 et le rid ne concordent pas !") raise ValueError("L'ipv4 et le rid ne concordent pas !")
self['ip6HostNumber'] = [unicode(crans_utils.ip6_of_mac(self['macAddress'][0].value, self['rid'][0].value))] self['ip6HostNumber'] = [unicode(crans_utils.ip6_of_mac(self['macAddress'][0].value, self['rid'][0].value))]
self['rid'] = [sbm['rid'][1]]
if sbm['ipHostNumber']: if sbm['ipHostNumber']:
if sbm['ipHostNumber'][1] == u"": if sbm['ipHostNumber'][1] == u"":
ip4 = [] ip4 = []
@ -1455,21 +1337,14 @@ class AssociationCrans(proprio):
def delete(self, comm, login): def delete(self, comm, login):
pass pass
def __unicode__(self):
return u"Le Crans"
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__) + " : Le Crans"
class BaseInvites(proprio): class BaseInvites(proprio):
u"""Un artefact de la base ldap""" u"""Un artefact de la base ldap"""
__slots__ = () __slots__ = ()
def __unicode__(self):
return u"%s" % (self.__class__.__name__,)
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__)
def delete(self, comm, login): def delete(self, comm, login):
raise EnvironmentError("Les pauvres invites") raise EnvironmentError("Les pauvres invites")
@ -1481,8 +1356,7 @@ class adherent(proprio):
@property @property
def attribs(self): def attribs(self):
return super(adherent, self).attribs + [ return super(adherent, self).attribs + [attributs.aid, attributs.prenom, attributs.tel,
attributs.aid, attributs.prenom, attributs.tel,
attributs.mail, attributs.mailInvalide, attributs.charteMA, attributs.mail, attributs.mailInvalide, attributs.charteMA,
attributs.derniereConnexion, attributs.gpgFingerprint, attributs.derniereConnexion, attributs.gpgFingerprint,
attributs.carteEtudiant, attributs.etudes, attributs.carteEtudiant, attributs.etudes,
@ -1490,11 +1364,8 @@ class adherent(proprio):
] ]
ldap_name = "adherent" ldap_name = "adherent"
def __unicode__(self):
return u"Adhérent : %s %s" % (self['prenom'][0], self['nom'][0])
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return "Adhérent : " + str(self['prenom'][0]) + " " + str(self['nom'][0])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(adherent, self).__init__(*args, **kwargs) super(adherent, self).__init__(*args, **kwargs)
@ -1505,13 +1376,13 @@ class adherent(proprio):
def clubs(self): def clubs(self):
"""Renvoie la liste des clubs dont l'adherent est responsable""" """Renvoie la liste des clubs dont l'adherent est responsable"""
if self._clubs is None: if self._clubs is None:
self._clubs = self.conn.search(u'responsable=%s' % self['aid'][0], scope=1, mode=self.mode) self._clubs = self.conn.search(u'responsable=%s' % self['aid'][0], scope = 1, mode=self.mode)
return self._clubs return self._clubs
def imprimeur_clubs(self): def imprimeur_clubs(self):
"""Renvoie la liste des clubs dont l'adherent est imprimeur""" """Renvoie la liste des clubs dont l'adherent est imprimeur"""
if self._imprimeur_clubs is None: if self._imprimeur_clubs is None:
self._imprimeur_clubs = self.conn.search(u'imprimeurClub=%s' % self['aid'][0], scope=1, mode=self.mode) self._imprimeur_clubs = self.conn.search(u'imprimeurClub=%s' % self['aid'][0], scope = 1, mode=self.mode)
return self._imprimeur_clubs return self._imprimeur_clubs
def delete(self, comm="", login=None): def delete(self, comm="", login=None):
@ -1520,31 +1391,13 @@ class adherent(proprio):
raise EnvironmentError("L'adhérent est responsable ou imprimeur pour les clubs %s, suppression impossible" % ", ".join(str(c["cid"][0]) for c in clubs)) raise EnvironmentError("L'adhérent est responsable ou imprimeur pour les clubs %s, suppression impossible" % ", ".join(str(c["cid"][0]) for c in clubs))
super(adherent, self).delete(comm, login) super(adherent, self).delete(comm, login)
def oid(self):
"""Retourne l'id de l'objet courant"""
return self['aid']
@crans_object @crans_object
class club(proprio): class club(proprio):
u"""Club crans""" u"""Club crans"""
__slots__ = () __slots__ = ()
can_be_by = { can_be_by = { variables.created: [attributs.nounou, attributs.bureau, attributs.cableur],
variables.created: [ variables.modified: [attributs.nounou, attributs.bureau, attributs.respo, attributs.cableur, attributs.soi],
attributs.nounou, variables.deleted: [attributs.nounou, attributs.bureau],
attributs.bureau,
attributs.cableur,
],
variables.modified: [
attributs.nounou,
attributs.bureau,
attributs.respo,
attributs.cableur,
attributs.soi,
],
variables.deleted: [
attributs.nounou,
attributs.bureau,
],
} }
ldap_name = "club" ldap_name = "club"
@ -1555,15 +1408,8 @@ class club(proprio):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(club, self).__init__(*args, **kwargs) super(club, self).__init__(*args, **kwargs)
def __unicode__(self):
return u"Club : %s" % (self['nom'][0],)
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return "Club : " + str(self['nom'][0])
def oid(self):
"""Retourne l'id de l'objet courant"""
return self['cid']
@crans_object @crans_object
class machineFixe(machine): class machineFixe(machine):
@ -1613,95 +1459,50 @@ class machineWifi(machine):
@crans_object @crans_object
class machineCrans(machine): class machineCrans(machine):
__slots__ = () __slots__ = ()
can_be_by = { can_be_by = { variables.created: [attributs.nounou],
variables.created: [ variables.modified: [attributs.nounou],
attributs.nounou, variables.deleted: [attributs.nounou],
],
variables.modified: [
attributs.nounou,
],
variables.deleted: [
attributs.nounou,
],
} }
attribs = machine.attribs + [ attribs = machine.attribs + [attributs.prise, attributs.nombrePrises]
attributs.prise, attributs.nombrePrises,
]
ldap_name = "machineCrans" ldap_name = "machineCrans"
@crans_object @crans_object
class borneWifi(machine): class borneWifi(machine):
__slots__ = () __slots__ = ()
can_be_by = { can_be_by = { variables.created: [attributs.nounou],
variables.created: [ variables.modified: [attributs.nounou],
attributs.nounou, variables.deleted: [attributs.nounou],
],
variables.modified: [
attributs.nounou,
],
variables.deleted: [
attributs.nounou,
],
} }
attribs = machine.attribs + [ attribs = machine.attribs + [attributs.canal, attributs.puissance, attributs.hotspot,
attributs.canal, attributs.puissance, attributs.hotspot, attributs.prise, attributs.positionBorne, attributs.nvram]
attributs.prise, attributs.positionBorne, attributs.nvram,
]
ldap_name = "borneWifi" ldap_name = "borneWifi"
@crans_object @crans_object
class switchCrans(machine): class switchCrans(machine):
__slots__ = () __slots__ = ()
can_be_by = { can_be_by = { variables.created: [attributs.nounou],
variables.created: [ variables.modified: [attributs.nounou],
attributs.nounou, variables.deleted: [attributs.nounou],
],
variables.modified: [
attributs.nounou,
],
variables.deleted: [
attributs.nounou,
],
} }
attribs = machine.attribs + [ attribs = machine.attribs + [attributs.nombrePrises]
attributs.nombrePrises,
]
ldap_name = "switchCrans" ldap_name = "switchCrans"
@crans_object @crans_object
class facture(CransLdapObject): class facture(CransLdapObject):
__slots__ = ("_proprio", "_recuPaiement") __slots__ = ("_proprio", "_recuPaiement")
can_be_by = { can_be_by = { variables.created: [attributs.nounou, attributs.bureau, attributs.cableur],
variables.created: [ variables.modified: [attributs.nounou, attributs.bureau, attributs.cableur],
attributs.nounou, variables.deleted: [attributs.nounou, attributs.bureau, attributs.cableur],
attributs.bureau,
attributs.cableur,
],
variables.modified: [
attributs.nounou,
attributs.bureau,
attributs.cableur,
],
variables.deleted: [
attributs.nounou,
attributs.bureau,
attributs.cableur,
],
} }
attribs = [ attribs = [attributs.fid, attributs.modePaiement, attributs.recuPaiement,
attributs.fid, attributs.modePaiement, attributs.recuPaiement,
attributs.historique, attributs.article, attributs.info, attributs.historique, attributs.article, attributs.info,
attributs.debutAdhesion, attributs.finAdhesion, attributs.debutConnexion, attributs.debutAdhesion, attributs.finAdhesion, attributs.debutConnexion,
attributs.finConnexion, attributs.controle, attributs.finConnexion, attributs.controle ]
]
ldap_name = "facture" ldap_name = "facture"
def __unicode__(self):
return u"Facture : fid=%s" % (self['fid'][0],)
def __repr__(self): def __repr__(self):
return repr(self.__unicode__()) return str(self.__class__.__name__) + " : fid=" + str(self['fid'][0])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._proprio = None self._proprio = None
@ -1713,14 +1514,10 @@ class facture(CransLdapObject):
raise EnvironmentError("Paiement déjà effectué pour cette facture, impossible de modifier son contenu") raise EnvironmentError("Paiement déjà effectué pour cette facture, impossible de modifier son contenu")
return super(facture, self).__setitem__(attr, value) return super(facture, self).__setitem__(attr, value)
def oid(self):
"""Retourne l'id de l'objet courant"""
return self['fid']
def total(self): def total(self):
total = 0 total=0
for article in self["article"]: for article in self["article"]:
total += int(article['nombre'])*float(article['pu']) total+=int(article['nombre'])*float(article['pu'])
return total return total
def crediter(self): def crediter(self):
@ -1742,12 +1539,11 @@ class facture(CransLdapObject):
proprio_save = True proprio_save = True
return proprio_save return proprio_save
if not self._recuPaiement: if not self._recuPaiement:
with self.proprio() as proprio: with self.proprio() as proprio:
proprio_save = credite_arts(proprio) proprio_save = credite_arts(proprio)
# On vient de créditer, le paiement a été reçu # On vient de créditer, le paiement a été reçu
self['recuPaiement'] = crans_utils.datetime_to_generalized_time_format(crans_utils.localized_datetime()) self['recuPaiement']=unicode(time.strftime("%Y-%m-%d %H:%M:%S"))
self._recuPaiement = True self._recuPaiement = True
# Il faudrait faire quelquechose pour que si l'enregistrement suivant de la facture crash, # Il faudrait faire quelquechose pour que si l'enregistrement suivant de la facture crash,
@ -1767,30 +1563,6 @@ class facture(CransLdapObject):
proprio.save() proprio.save()
raise raise
def adhesion_connexion(self):
u"""Effectue l'adhésion ou la connexion, rempli les attribus ldap correspondants"""
def do_adh_conn(proprio):
u"""Rempli les attribus qu'il faut sur les factures d'adhésion et de connexion"""
# On parse les art et on update les attribus
_now = crans_utils.localized_datetime()
for art in self['article']:
if 'ADH' in art['code']:
self['debutAdhesion'] = max(proprio.fin_adhesion(), _now)
self['finAdhesion'] = max(proprio.fin_adhesion(), _now).replace(year=max(proprio.fin_adhesion(), _now).year + 1)
if 'CAI' in art['code']:
nbr_mois = int(art['code'].replace('CAI',''))
self['debutConnexion'] = max(proprio.fin_connexion(), _now)
con_month = max(proprio.fin_connexion(), _now).month
con_year = max(proprio.fin_connexion(), _now).year
self['finConnexion'] = max(proprio.fin_connexion(), _now).replace(year=con_year + ((con_month + nbr_mois) // 12), month= (con_month + nbr_mois - 1 ) % 12 + 1)
return
# On effectue les opérations
do_adh_conn(self.proprio())
self.crediter()
def proprio(self, refresh=False): def proprio(self, refresh=False):
u"""Renvoie le propriétaire de la facture""" u"""Renvoie le propriétaire de la facture"""
if refresh or not self._proprio: if refresh or not self._proprio:
@ -1800,41 +1572,19 @@ class facture(CransLdapObject):
@crans_object @crans_object
class baseCert(CransLdapObject): class baseCert(CransLdapObject):
__slots__ = ("_machine",) __slots__ = ("_machine",)
can_be_by = { can_be_by = { variables.created: [attributs.nounou, attributs.bureau, attributs.parent],
variables.created: [ variables.modified: [attributs.nounou, attributs.bureau, attributs.parent],
attributs.nounou, variables.deleted: [attributs.nounou, attributs.bureau, attributs.parent],
attributs.bureau,
attributs.parent,
],
variables.modified: [
attributs.nounou,
attributs.bureau,
attributs.parent,
],
variables.deleted: [
attributs.nounou,
attributs.bureau,
attributs.parent,
],
} }
default_attribs = [ default_attribs = [ attributs.xid, attributs.certificat, attributs.hostCert, attributs.historique,
attributs.xid, attributs.certificat, attributs.hostCert, attributs.historique, attributs.info, attributs.csr ]
attributs.info, attributs.csr,
]
tlsa_attribs = [ tlsa_attribs = [ attributs.certificatUsage, attributs.selector, attributs.matchingType,
attributs.certificatUsage, attributs.selector, attributs.matchingType, attributs.portTCPin, attributs.portUDPin]
attributs.portTCPin, attributs.portUDPin, x509_attribs = [ attributs.issuerCN, attributs.start, attributs.end,
] attributs.crlUrl, attributs.revocked, attributs.serialNumber ]
x509_attribs = [ private_attribs = [ attributs.privatekey, attributs.encrypted ]
attributs.issuerCN, attributs.start, attributs.end,
attributs.crlUrl, attributs.revocked, attributs.serialNumber,
]
private_attribs = [
attributs.privatekey, attributs.encrypted,
]
@property @property
def attribs(self): def attribs(self):
@ -1869,9 +1619,9 @@ class baseCert(CransLdapObject):
s'il est réèlement présent dans les données du certificat. s'il est réèlement présent dans les données du certificat.
""" """
if attr in ['hostCert']: if attr in ['hostCert']:
deleted = [value for value in self[attr] if value not in values] deleted = [ value for value in self[attr] if value not in values ]
for domain in deleted: for domain in deleted:
if domain in [self['certificat'][0]['subject']['CN']] + self['certificat'][0]['extensions'].get('subjectAltName', []): if domain in [self['certificat'][0]['subject']['CN']] + self['certificat'][0]['extensions'].get('subjectAltName',[]):
raise EnvironmentError("Vous ne pouvez pas retirer le domaine %s alors qu'il est déclaré dans le certificat" % domain) raise EnvironmentError("Vous ne pouvez pas retirer le domaine %s alors qu'il est déclaré dans le certificat" % domain)
def private(self, privatekey, encrypted): def private(self, privatekey, encrypted):
@ -1881,8 +1631,8 @@ class baseCert(CransLdapObject):
return return
self._modifs['objectClass'].append(u"privateKey") self._modifs['objectClass'].append(u"privateKey")
#self.attribs.extend(self.private_attribs) #self.attribs.extend(self.private_attribs)
self['encrypted'] = encrypted self['encrypted']=encrypted
self['privatekey'] = privatekey self['privatekey']=privatekey
def tlsa(self, certificatUsage, matchingType): def tlsa(self, certificatUsage, matchingType):
if not self.mode in ['w', 'rw']: if not self.mode in ['w', 'rw']:
@ -1891,9 +1641,9 @@ class baseCert(CransLdapObject):
return return
self._modifs['objectClass'].append(u"TLSACert") self._modifs['objectClass'].append(u"TLSACert")
#self.attribs.extend(self.tlsa_attribs) #self.attribs.extend(self.tlsa_attribs)
self['certificatUsage'] = certificatUsage self['certificatUsage']=certificatUsage
self['matchingType'] = matchingType self['matchingType']=matchingType
self['selector'] = 0 self['selector']=0
def x509(self, issuerCN, start, end, serialNumber, crlUrl=None): def x509(self, issuerCN, start, end, serialNumber, crlUrl=None):
if not self.mode in ['w', 'rw']: if not self.mode in ['w', 'rw']:

View file

@ -3,17 +3,13 @@
{{["aid=",o.aid.0]|join|coul('bleu')}} {{"Nom : "|coul('gras')}}{{o.prenom|join(' ')}} {{o.nom|join(' ')}} {{["aid=",o.aid.0]|join|coul('bleu')}} {{"Nom : "|coul('gras')}}{{o.prenom|join(' ')}} {{o.nom|join(' ')}}
{% endblock%} {% endblock%}
{% block proprio %} {% block proprio %}
{% if disp_telephone %}
{{"Numéro de téléphone : "|coul('gras')}}{{o.tel|telephone|join(', ')}} {{"Numéro de téléphone : "|coul('gras')}}{{o.tel|telephone|join(', ')}}
{% endif %}
{% if disp_adresse %}
{% if o.chbre.0 == 'EXT' and o.postalAddress %} {% if o.chbre.0 == 'EXT' and o.postalAddress %}
{{"Adresse : "|coul('gras')}}{{o.postalAddress.0}} {{o.postalAddress.1}} {{"Adresse : "|coul('gras')}}{{o.postalAddress.0}} {{o.postalAddress.1}}
{{o.postalAddress.2}} {{o.postalAddress.3}} {{o.postalAddress.2}} {{o.postalAddress.3}}
{% else %} {% else %}
{{"Chambre : "|coul('gras')}}{{o.chbre.0}} ({{o.chbre.0|string|prise_etat}}) {{"Chambre : "|coul('gras')}}{{o.chbre.0}} ({{o.chbre.0|string|prise_etat}})
{% endif %} {% endif %}
{% endif %}
{{"Études : "|coul('gras')}}{{o.etudes|join(' ')}} {{"Études : "|coul('gras')}}{{o.etudes|join(' ')}}
{{adh}} {% if o.get('controle', []) and 'p' in o.controle.0.value %}{{"(OK)"|coul('vert')}}{% endif %} {{adh}} {% if o.get('controle', []) and 'p' in o.controle.0.value %}{{"(OK)"|coul('vert')}}{% endif %}

View file

@ -1,4 +1,4 @@
{{["fid=",o.oid().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio().oid().0}}) {{["fid=",o._id().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio()._id().0}})
{% if o.article %} {% if o.article %}
{{"Article : "|coul('gras')}} Prix N° Total Commentaire {{"Article : "|coul('gras')}} Prix N° Total Commentaire
{% set total = [] %}{% for a in o.article %} {% set total = [] %}{% for a in o.article %}

View file

@ -6,9 +6,6 @@
{{"IPv4 : "|coul('gras')}}{{o.ipHostNumber|join(', ')}} {{"IPv4 : "|coul('gras')}}{{o.ipHostNumber|join(', ')}}
{% if o.ip6HostNumber %}{{"IPv6 : "|coul('gras')}}{{o.ip6HostNumber|join(', ')}} {% if o.ip6HostNumber %}{{"IPv6 : "|coul('gras')}}{{o.ip6HostNumber|join(', ')}}
{% endif %} {% endif %}
{% if sshfp and o.sshFingerprint %}
{{"Fingerprints SSH : "|coul('gras')}}{{o.sshFingerprint|join('\n ')}}
{% endif %}
{{"DnsIpv6 : "|coul('gras')}}{% if not o.dnsIpv6 or o.dnsIpv6.0.value %} {{"DnsIpv6 : "|coul('gras')}}{% if not o.dnsIpv6 or o.dnsIpv6.0.value %}
{{"TRUE"|coul('vert')}} {{"TRUE"|coul('vert')}}
{% else %} {% else %}

View file

@ -16,7 +16,6 @@ import gestion.annuaires_pg
import gestion.hptools2 as hptools2 import gestion.hptools2 as hptools2
import lc_ldap.attributs as attributs import lc_ldap.attributs as attributs
import lc_ldap.crans_utils as crans_utils
def try_import(lib): def try_import(lib):
""" """
@ -202,21 +201,16 @@ def list_factures(factures, width=None):
data = [] data = []
for facture in factures: for facture in factures:
controle = facture.get('controle', [""])[0] controle = facture.get('controle', [""])[0]
if controle == u"TRUE": if controle == "TRUE":
controle = style(u"Validée", "vert") controle = style(u"Validée", "vert")
elif controle == u"FALSE": elif controle == "FALSE":
controle = style(u"Invalide", "rouge") controle = style(u"Invalide", "rouge")
else: else:
controle = u"N/A" controle = u"N/A"
if facture.get('recuPaiement', []):
_dtime = crans_utils.datetime_from_generalized_time_format(unicode(facture.get('recuPaiement', [attributs.recuPaiement.default])[0]))
_recu = _dtime.strftime("%d/%m/%Y %H:%M:%S")
else:
_recu = False
data.append([ data.append([
facture['fid'][0], facture['fid'][0],
facture['modePaiement'][0], facture['modePaiement'][0],
style(_recu, 'vert') if _recu else style(u"NON", 'rouge'), style(facture.get('recuPaiement', [])[0], "vert") if facture.get('recuPaiement', []) else style("NON", "rouge"),
controle, controle,
' '.join(attr['code'] for attr in facture.get('article',[])), ' '.join(attr['code'] for attr in facture.get('article',[])),
u"%s €" % sum([float(a['pu'])*int(a['nombre']) for a in facture.get('article',[])]) u"%s €" % sum([float(a['pu'])*int(a['nombre']) for a in facture.get('article',[])])
@ -229,69 +223,49 @@ def list_factures(factures, width=None):
width=width) width=width)
def list_adherents(adherents, width=None): def list_adherents(adherents, width=None):
return tableau( return tableau([
[ [a['aid'][0],
[
a['aid'][0],
u' '.join(unicode(i) for i in a['prenom'] + a['nom']), u' '.join(unicode(i) for i in a['prenom'] + a['nom']),
a['chbre'][0], a['chbre'][0], style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'),
style('o', 'vert') if a.adhesion_ok() else style('n', 'rouge'), u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines())
style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'), ] for a in adherents ],
u', '.join(unicode(m['host'][0]).split('.', 1)[0] for m in a.machines()) titre = [u'aid', u'Prénom Nom', u'Chbre', u'P', u'Machines'],
] largeur = [5, 35, 5, 1, '*'],
for a in adherents alignement = ['d', 'c', 'c', 'c', 'g'],
], width=width)
titre=[u'aid', u'Prénom Nom', u'Chbre', u'A', u'C', u'Machines'],
largeur=[5, 35, 5, 1, 1, '*'],
alignement=['d', 'c', 'c', 'c', 'c', 'g'],
width=width
)
def list_clubs(clubs, width=None): def list_clubs(clubs, width=None):
return tableau( return tableau([
[ [a['cid'][0],
[
a['cid'][0],
u' '.join(unicode(i) for i in a['nom']), u' '.join(unicode(i) for i in a['nom']),
a['chbre'][0], a['chbre'][0], style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'),
style('o', 'vert') if a.adhesion_ok() else style('n', 'rouge'),
style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'),
u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines()) u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines())
] ] for a in clubs ],
for a in clubs titre = [u'cid', u'Nom', u'Chbre', u'P', u'Machines'],
], largeur = [5, 35, 5, 1, '*'],
titre = [u'cid', u'Nom', u'Chbre', u'A', u'C', u'Machines'], alignement = ['d', 'c', 'c', 'c', 'g'],
largeur = [5, 35, 5, 1, 1, '*'], width=width)
alignement = ['d', 'c', 'c', 'c', 'c', 'g'],
width=width
)
def proprio(proprio, params): def proprio(proprio, params):
_now = crans_utils.localized_datetime() params['o']=proprio
params['o'] = proprio etat_administratif=[]
etat_administratif = []
if proprio.paiement_ok(): if proprio.paiement_ok():
etat_administratif.append(style(u"à jour", "vert")) etat_administratif.append(style(u"à jour", "vert"))
if not proprio.paiement_ok(): if not proprio.paiement_ok():
etat_administratif.append(style(u"cotisation non réglée", "violet")) etat_administratif.append(style(u"cotisation non réglée", "violet"))
if proprio.fin_adhesion() >= time.time():
if proprio.fin_adhesion() >= _now:
adh = style(u"Adhésion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_adhesion())),), "vert") adh = style(u"Adhésion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_adhesion())),), "vert")
elif proprio.paiement_ok(): elif proprio.paiement_ok():
adh = style(u"Adhésion terminée, mais il y a un sursis.", 'orange') adh = style(u"Adhésion terminée, mais il y a un sursis.", 'orange')
else: else:
adh = style(u"Pas adhérent actuellement.", 'rouge') adh = style(u"Pas adhérent actuellement.", 'rouge')
params["adh"] = adh params["adh"] = adh
if proprio.fin_connexion() >= _now: if proprio.fin_connexion() >= time.time():
conn = style(u"Connexion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_connexion())),), "vert") conn = style(u"Connexion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_connexion())),), "vert")
elif proprio.paiement_ok(): elif proprio.paiement_ok():
conn = style(u"Connexion terminée, mais il y a un sursis.", 'orange') conn = style(u"Connexion terminée, mais il y a un sursis.", 'orange')
else: else:
conn = style(u"Pas connecté actuellement.", 'rouge') conn = style(u"Pas connecté actuellement.", 'rouge')
params["conn"] = conn params["conn"] = conn
params['etat_administratif'] = etat_administratif params['etat_administratif'] = etat_administratif
@ -324,10 +298,7 @@ def blacklist(blacklist, params):
def sprint(object, historique=5, blacklist_len=5, **params): def sprint(object, historique=5, blacklist_len=5, **params):
from lc_ldap import objets, attributs from lc_ldap import objets, attributs
params.update({ params.update({'historique':historique, "blacklist":blacklist_len})
'historique': historique,
'blacklist': blacklist_len,
})
if isinstance(object, objets.machine): if isinstance(object, objets.machine):
return machine(object, params) return machine(object, params)
elif isinstance(object, objets.adherent): elif isinstance(object, objets.adherent):

View file

@ -32,6 +32,7 @@ services_to_attrs['mail_modif'] = [ attributs.droits, attributs.exempt ] + servi
services_to_objects={} services_to_objects={}
services_to_objects['delete']={} services_to_objects['delete']={}
services_to_objects['create']={} services_to_objects['create']={}
services_to_objects['create']['home'] = [objets.adherent, objets.club]
services_to_objects['delete']['del_user'] = [objets.adherent, objets.club] services_to_objects['delete']['del_user'] = [objets.adherent, objets.club]
NOW = time.time() NOW = time.time()

View file

@ -15,7 +15,7 @@ try:
from gestion import secrets_new as secrets from gestion import secrets_new as secrets
except ImportError: except ImportError:
sys.stderr.write("lc_ldap shortcuts: shaa, cannot import secrets_new. " + sys.stderr.write("lc_ldap shortcuts: shaa, cannot import secrets_new. " +
"try again with /usr/scripts in PYTHONPATH " + "try again with /usr/scripts/ in PYTHONPATH " +
"(argv: %s)\n" % " ".join(getattr(sys, 'argv', []))) "(argv: %s)\n" % " ".join(getattr(sys, 'argv', [])))
sys.path.append("/usr/scripts") sys.path.append("/usr/scripts")
from gestion import secrets_new as secrets from gestion import secrets_new as secrets
@ -51,7 +51,7 @@ def lc_ldap_test(*args, **kwargs):
except OSError: except OSError:
pass pass
# On impose le serveur # On impose le serveur
kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'vo.adm.crans.org') kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'localhost')
kwargs.setdefault("dn", 'cn=admin,dc=crans,dc=org') kwargs.setdefault("dn", 'cn=admin,dc=crans,dc=org')
# Le mot de passe de la base de test # Le mot de passe de la base de test
kwargs.setdefault("cred", variables.ldap_test_password) kwargs.setdefault("cred", variables.ldap_test_password)

View file

@ -14,6 +14,8 @@ import lc_ldap
import shortcuts import shortcuts
import variables import variables
## import dans /usr/scripts/
sys.path.append("/usr/scripts/")
from gestion.affich_tools import anim, OK, cprint, ERREUR from gestion.affich_tools import anim, OK, cprint, ERREUR
mail_format = False mail_format = False