Compare commits
66 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
20c4c10624 | ||
![]() |
962d052198 | ||
![]() |
9252614cd9 | ||
![]() |
0b93ad0e19 | ||
![]() |
ab13249ef5 | ||
![]() |
c644027d5f | ||
![]() |
37b30c32e5 | ||
![]() |
c4a2f1a717 | ||
![]() |
0733bfd99e | ||
![]() |
4a2a2f7e68 | ||
![]() |
9b73ae0fde | ||
![]() |
440c9040bc | ||
![]() |
bf0de1c5be | ||
![]() |
333ee38724 | ||
![]() |
8b5614214c | ||
![]() |
443876863f | ||
![]() |
00f67697ee | ||
![]() |
c0d2e04cc7 | ||
![]() |
990f791298 | ||
![]() |
2becf821d3 | ||
![]() |
f61aebd21a | ||
![]() |
dba07d8f60 | ||
![]() |
8b9b9dc169 | ||
![]() |
5b57476ab4 | ||
![]() |
2a806bb367 | ||
![]() |
9388e1d217 | ||
![]() |
d7800bbfb1 | ||
![]() |
91fa2974e4 | ||
![]() |
3e71d60304 | ||
![]() |
bbea130179 | ||
![]() |
48de31425d | ||
![]() |
a1f27f9f1a | ||
![]() |
4de62cd0a8 | ||
![]() |
af251f267b | ||
![]() |
8213b919ee | ||
![]() |
c18de85fd2 | ||
![]() |
9610cc6b0b | ||
![]() |
d1eb555599 | ||
![]() |
dae802b057 | ||
![]() |
4858953064 | ||
![]() |
854f774f37 | ||
![]() |
f23644497b | ||
![]() |
930d09b539 | ||
![]() |
c91c89f3df | ||
![]() |
fa7387420a | ||
![]() |
d20fa54614 | ||
![]() |
c35878562a | ||
![]() |
4a0a514986 | ||
![]() |
08cda773b0 | ||
![]() |
54a8d9c4cb | ||
![]() |
e59a468d19 | ||
![]() |
83ca2e7991 | ||
![]() |
55eb87dce9 | ||
![]() |
0fb2cf4416 | ||
![]() |
4a3434847e | ||
![]() |
1353f00e17 | ||
![]() |
8ae5870468 | ||
![]() |
12ba81e272 | ||
![]() |
ad8d9026f0 | ||
![]() |
6142e6ef34 | ||
![]() |
8f871ac166 | ||
![]() |
6c1dc6c587 | ||
![]() |
f988e962c9 | ||
![]() |
e46d1fe338 | ||
![]() |
5b66ae0095 | ||
![]() |
f4318415e8 |
12 changed files with 660 additions and 301 deletions
160
attributs.py
160
attributs.py
|
@ -47,7 +47,8 @@ import random
|
|||
import string
|
||||
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 to_generalized_time_format, from_generalized_time_format
|
||||
from crans_utils import to_generalized_time_format, from_generalized_time_format, datetime_from_generalized_time_format
|
||||
from crans_utils import datetime_to_generalized_time_format
|
||||
import itertools
|
||||
|
||||
if '/usr/scripts' not in sys.path:
|
||||
|
@ -242,7 +243,7 @@ class AttrsDict(dict):
|
|||
"""
|
||||
ldif = {}
|
||||
for attr, vals in self.items():
|
||||
ldif[attr] = [ str(val) for val in vals ]
|
||||
ldif[attr] = [unicode(val).encode(config.ldap_encoding) for val in vals]
|
||||
return ldif
|
||||
|
||||
class Attr(object):
|
||||
|
@ -350,9 +351,7 @@ class Attr(object):
|
|||
raise UniquenessError("%s déjà existant" % attr, [r.dn for r in res])
|
||||
|
||||
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)
|
||||
|
||||
class AttributeFactory(object):
|
||||
|
@ -393,13 +392,26 @@ class rightProtectedAttr(Attr):
|
|||
"""
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
# 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:
|
||||
modifiables = modifiables.union(DROITS_SUPERVISEUR[i])
|
||||
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', []):
|
||||
if droit not in modifiables and droit in TOUS_DROITS:
|
||||
return False
|
||||
|
@ -513,14 +525,14 @@ class aid(intAttr):
|
|||
self.value = int(aid)
|
||||
|
||||
@crans_attribute
|
||||
class uid(Attr):
|
||||
class uid(rightProtectedAttr):
|
||||
__slots__ = ()
|
||||
singlevalue = True
|
||||
option = False
|
||||
legend = u"L'identifiant canonique de l'adhérent"
|
||||
category = 'perso'
|
||||
unique = True
|
||||
can_modify = [nounou]
|
||||
can_modify = [cableur, nounou]
|
||||
ldap_name = "uid"
|
||||
|
||||
@crans_attribute
|
||||
|
@ -636,25 +648,31 @@ class generalizedTimeFormat(Attr):
|
|||
une donnée de temps suivant la RFC 4517
|
||||
|
||||
"""
|
||||
__slots__ = ("_stamp",)
|
||||
default = "19700101000000Z"
|
||||
__slots__ = ("datetime",)
|
||||
python_type = datetime.datetime
|
||||
default = datetime_from_generalized_time_format("19700101000000Z")
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(datetime_to_generalized_time_format(self.value))
|
||||
|
||||
def __float__(self):
|
||||
return self._stamp
|
||||
return from_generalized_time_format(unicode(self))
|
||||
|
||||
def __int__(self):
|
||||
return int(self._stamp)
|
||||
return int(float(self))
|
||||
|
||||
def __eq__(self, othertime):
|
||||
if isinstance(othertime, generalizedTimeFormat):
|
||||
return self._stamp == othertime._stamp
|
||||
return self.value == othertime.value
|
||||
elif isinstance(othertime, float):
|
||||
return self._stamp == othertime
|
||||
return float(self) == othertime
|
||||
elif isinstance(othertime, int):
|
||||
return self._stamp == othertime
|
||||
return int(self) == othertime
|
||||
elif isinstance(othertime, unicode) or isinstance(othertime, str):
|
||||
resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
|
||||
return self._stamp == resource._stamp
|
||||
return self == resource
|
||||
elif isinstance(othertime, datetime.datetime):
|
||||
return self.value == othertime
|
||||
else:
|
||||
return False
|
||||
|
||||
|
@ -663,14 +681,16 @@ class generalizedTimeFormat(Attr):
|
|||
|
||||
def __lt__(self, othertime):
|
||||
if isinstance(othertime, generalizedTimeFormat):
|
||||
return self._stamp < othertime._stamp
|
||||
return self.value < othertime.value
|
||||
elif isinstance(othertime, float):
|
||||
return self._stamp < othertime
|
||||
return float(self) < othertime
|
||||
elif isinstance(othertime, int):
|
||||
return self._stamp < othertime
|
||||
return int(self) < othertime
|
||||
elif isinstance(othertime, unicode) or isinstance(othertime, str):
|
||||
resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
|
||||
return self._stamp < resource._stamp
|
||||
return self < resource
|
||||
elif isinstance(othertime, datetime.datetime):
|
||||
return self.value < othertime
|
||||
else:
|
||||
return False
|
||||
|
||||
|
@ -685,15 +705,9 @@ class generalizedTimeFormat(Attr):
|
|||
|
||||
def parse_value(self, gtf):
|
||||
if isinstance(gtf, str) or isinstance(gtf, unicode):
|
||||
if not ('Z' in gtf or '+' in gtf or '-' in gtf):
|
||||
self._stamp = gtf
|
||||
self.value = to_generalized_time_format(float(gtf))
|
||||
else:
|
||||
self._stamp = from_generalized_time_format(gtf)
|
||||
self.value = gtf
|
||||
elif isinstance(gtf, float):
|
||||
self._stamp = gtf
|
||||
self.value = to_generalized_time_format(gtf)
|
||||
self.value = datetime_from_generalized_time_format(gtf)
|
||||
elif isinstance(gtf, datetime.datetime):
|
||||
self.value = gtf
|
||||
|
||||
@crans_attribute
|
||||
class debutAdhesion(generalizedTimeFormat):
|
||||
|
@ -740,28 +754,43 @@ class mail(rightProtectedAttr):
|
|||
|
||||
def check_uniqueness(self, liste_exclue):
|
||||
attr = self.__class__.__name__
|
||||
|
||||
if str(self) in liste_exclue:
|
||||
return
|
||||
if attr in ["mailAlias", "canonicalAlias", 'mail']:
|
||||
mail, end = str(self).split('@', 1)
|
||||
if end.startswith('crans'):
|
||||
try:
|
||||
smtp = smtplib.SMTP(smtpserv)
|
||||
smtp.putcmd("vrfy", mail)
|
||||
res = smtp.getreply()[0] in [250, 252]
|
||||
smtp.close()
|
||||
except:
|
||||
raise ValueError('Serveur de mail injoignable')
|
||||
|
||||
if res:
|
||||
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)))
|
||||
# On initialise le résultat, s'il vaut true en fin de course, le mail
|
||||
# est déjà pris.
|
||||
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:
|
||||
smtp = smtplib.SMTP(smtpserv)
|
||||
smtp.putcmd("vrfy", mail)
|
||||
res = smtp.getreply()[0] in [250, 252]
|
||||
smtp.close()
|
||||
except:
|
||||
print '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:
|
||||
raise ValueError("Le mail %s est déjà pris." % (str(self)))
|
||||
|
||||
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,6}$', mail):
|
||||
if not re.match(u'^[-+_.0-9A-Za-z]+@([A-Za-z0-9]{1}[A-Za-z0-9-_]+[.])+[a-z]{2,20}$', mail):
|
||||
raise ValueError("%s invalide %r" % (self.legend, mail))
|
||||
self.value = mail
|
||||
|
||||
|
@ -787,7 +816,6 @@ class mailAlias(mail):
|
|||
optional = True
|
||||
unique = True
|
||||
legend = u"Alias mail"
|
||||
can_modify = [soi, cableur, nounou]
|
||||
category = 'mail'
|
||||
ldap_name = "mailAlias"
|
||||
|
||||
|
@ -807,8 +835,7 @@ class mailExt(mail):
|
|||
singlevalue = False
|
||||
optional = True
|
||||
unique = True
|
||||
legend = u"Mail de secours"
|
||||
can_modify = [soi, cableur, nounou]
|
||||
legend = u"Mail de redirection ou de secours"
|
||||
category = 'mail'
|
||||
ldap_name = "mailExt"
|
||||
|
||||
|
@ -863,7 +890,7 @@ class chbre(Attr):
|
|||
|
||||
def parse_value(self, chambre):
|
||||
if self.parent != None and u'club' in [str(o) for o in self.parent['objectClass']]:
|
||||
if chambre in annuaires_pg.locaux_clubs():
|
||||
if chambre in annuaires_pg.locaux_clubs() or chambre in (u"EXT", u"????"):
|
||||
self.value = chambre
|
||||
else:
|
||||
raise ValueError("Club devrait etre en XclN, pas en %r" % chambre)
|
||||
|
@ -1055,7 +1082,6 @@ class rid(intAttr):
|
|||
unique = True
|
||||
legend = u"Identifiant réseau de machine"
|
||||
category = 'id'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "rid"
|
||||
|
||||
def parse_value(self, rid):
|
||||
|
@ -1087,7 +1113,7 @@ class ipsec(Attr):
|
|||
legend = u'Clef wifi'
|
||||
category = 'wifi'
|
||||
ldap_name = "ipsec"
|
||||
can_modify = [nounou, parent]
|
||||
can_modify = [nounou, cableur, parent]
|
||||
historique = "info"
|
||||
default = u'auto'
|
||||
|
||||
|
@ -1106,8 +1132,8 @@ class puissance(Attr):
|
|||
optional = True
|
||||
legend = u"puissance d'émission pour les bornes wifi"
|
||||
category = 'wifi'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "puissance"
|
||||
default = '60'
|
||||
|
||||
@crans_attribute
|
||||
class canal(intAttr):
|
||||
|
@ -1116,8 +1142,8 @@ class canal(intAttr):
|
|||
optional = True
|
||||
legend = u'Canal d\'émission de la borne'
|
||||
category = 'wifi'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "canal"
|
||||
default = "11"
|
||||
|
||||
@crans_attribute
|
||||
class hotspot(boolAttr):
|
||||
|
@ -1126,25 +1152,24 @@ class hotspot(boolAttr):
|
|||
optional = True
|
||||
legend = u'Hotspot'
|
||||
category = 'wifi'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "hotspot"
|
||||
default = "FALSE"
|
||||
|
||||
@crans_attribute
|
||||
class positionBorne(Attr):
|
||||
__slots__ = ()
|
||||
legend = u"Position de la borne"
|
||||
category = "wifi"
|
||||
can_modify = [nounou]
|
||||
singlevalue = True
|
||||
optional = True
|
||||
ldap_name = "positionBorne"
|
||||
default = "0 0"
|
||||
|
||||
@crans_attribute
|
||||
class nvram(Attr):
|
||||
__slots__ = ()
|
||||
legend = u"Configuration speciale"
|
||||
optional = True
|
||||
can_modify = [nounou]
|
||||
ldap_name = "nvram"
|
||||
|
||||
class portAttr(Attr):
|
||||
|
@ -1153,7 +1178,6 @@ class portAttr(Attr):
|
|||
optional = True
|
||||
legend = u'Ouverture de port'
|
||||
category = 'firewall'
|
||||
can_modify = [nounou]
|
||||
|
||||
def parse_value(self, port):
|
||||
if ":" in port:
|
||||
|
@ -1227,7 +1251,6 @@ class nombrePrises(intAttr):
|
|||
singlevalue = True
|
||||
optional = True
|
||||
categoriy = 'base_tech'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "nombrePrises"
|
||||
|
||||
@crans_attribute
|
||||
|
@ -1237,7 +1260,6 @@ class prise(Attr):
|
|||
optional = True
|
||||
legend = u"Prise sur laquelle est branchée la machine"
|
||||
category = 'base_tech'
|
||||
can_modify = [nounou]
|
||||
ldap_name = "prise"
|
||||
|
||||
@crans_attribute
|
||||
|
@ -1347,7 +1369,7 @@ class blacklist(Attr):
|
|||
optional = True
|
||||
legend = u"Blackliste"
|
||||
category = 'info'
|
||||
can_modify = [nounou]
|
||||
can_modify = [nounou, bureau]
|
||||
ldap_name = "blacklist"
|
||||
python_type = dict
|
||||
|
||||
|
@ -1460,7 +1482,7 @@ class homeDirectory(rightProtectedAttr):
|
|||
ldap_name = "homeDirectory"
|
||||
|
||||
@crans_attribute
|
||||
class loginShell(Attr):
|
||||
class loginShell(rightProtectedAttr):
|
||||
__slots__ = ()
|
||||
singlevalue = True
|
||||
optional = True
|
||||
|
@ -1477,7 +1499,7 @@ class loginShell(Attr):
|
|||
self.value = shell
|
||||
|
||||
@crans_attribute
|
||||
class uidNumber(intAttr):
|
||||
class uidNumber(intAttr, rightProtectedAttr):
|
||||
__slots__ = ()
|
||||
singlevalue = True
|
||||
optional = True
|
||||
|
@ -1485,15 +1507,17 @@ class uidNumber(intAttr):
|
|||
legend = "L'uid du compte de l'adherent"
|
||||
category = 'id'
|
||||
ldap_name = "uidNumber"
|
||||
can_modify = [cableur, nounou]
|
||||
|
||||
@crans_attribute
|
||||
class gidNumber(intAttr):
|
||||
class gidNumber(intAttr, rightProtectedAttr):
|
||||
__slots__ = ()
|
||||
singlevalue = True
|
||||
optional = True
|
||||
legend = "Le gid du compte de l'adhérent"
|
||||
category = 'id'
|
||||
ldap_name = "gidNumber"
|
||||
can_modify = [cableur, nounou]
|
||||
|
||||
@crans_attribute
|
||||
class gecos(Attr):
|
||||
|
@ -1503,6 +1527,7 @@ class gecos(Attr):
|
|||
legend = "Le gecos"
|
||||
category = 'id'
|
||||
ldap_name = "gecos"
|
||||
can_modify = [cableur, nounou]
|
||||
|
||||
@crans_attribute
|
||||
class userPassword(rightProtectedAttr):
|
||||
|
@ -1595,6 +1620,7 @@ class gpgMail(mail):
|
|||
legend = "Mail associé à une clef gpg"
|
||||
can_modify = [soi, nounou]
|
||||
ldap_name = "gpgMail"
|
||||
|
||||
def check_uniqueness(self, liste_exclue):
|
||||
super(mail, self).check_uniqueness(liste_exclue)
|
||||
|
||||
|
@ -1607,6 +1633,7 @@ class cn(Attr):
|
|||
__slots__ = ()
|
||||
singlevalue = True
|
||||
optional = False
|
||||
can_modify = [cableur, nounou]
|
||||
category = 'id'
|
||||
ldap_name = "cn"
|
||||
|
||||
|
@ -1669,7 +1696,7 @@ class modePaiement(Attr):
|
|||
self.value = mode
|
||||
|
||||
@crans_attribute
|
||||
class recuPaiement(Attr):
|
||||
class recuPaiement(generalizedTimeFormat):
|
||||
__slots__ = ()
|
||||
ldap_name = "recuPaiement"
|
||||
can_modify = [cableur, nounou]
|
||||
|
@ -1739,7 +1766,6 @@ class machineAlias(boolAttr):
|
|||
class issuerCN(Attr):
|
||||
__slots__ = ()
|
||||
ldap_name = "issuerCN"
|
||||
can_modify = [nounou]
|
||||
legend = "Common Name de l'éméteur du certificat"
|
||||
|
||||
@crans_attribute
|
||||
|
@ -1747,21 +1773,18 @@ class serialNumber(Attr):
|
|||
__slots__ = ()
|
||||
ldap_name = "serialNumber"
|
||||
python_type = int
|
||||
can_modify = [nounou]
|
||||
legend = "Numéro de série du certificat"
|
||||
|
||||
@crans_attribute
|
||||
class start(intAttr):
|
||||
__slots__ = ()
|
||||
ldap_name = "start"
|
||||
can_modify = [nounou]
|
||||
legend = "Date de début"
|
||||
|
||||
@crans_attribute
|
||||
class end(intAttr):
|
||||
__slots__ = ()
|
||||
ldap_name = "end"
|
||||
can_modify = [nounou]
|
||||
legend = "Date de fin"
|
||||
|
||||
@crans_attribute
|
||||
|
@ -1778,7 +1801,6 @@ class revocked(boolAttr):
|
|||
ldap_name = "revocked"
|
||||
singlevalue = True
|
||||
optional = True
|
||||
can_modify = [nounou]
|
||||
legend = "Détermine si le certificat est révoqué"
|
||||
|
||||
@crans_attribute
|
||||
|
|
|
@ -47,7 +47,6 @@ if '/usr/scripts' not in sys.path:
|
|||
sys.path.append('/usr/scripts')
|
||||
from gestion import config
|
||||
from unicodedata import normalize
|
||||
import subprocess
|
||||
from netifaces import interfaces, ifaddresses, AF_INET
|
||||
|
||||
try:
|
||||
|
@ -55,6 +54,11 @@ try:
|
|||
except:
|
||||
pytz = None
|
||||
|
||||
try:
|
||||
import dateutil.tz
|
||||
except:
|
||||
dateutil = None
|
||||
|
||||
DEVNULL = open(os.devnull, 'w')
|
||||
|
||||
def find_rid_plage(rid):
|
||||
|
@ -245,7 +249,6 @@ def escape(chaine):
|
|||
dans une requête ldap."""
|
||||
return ldap.filter.escape_filter_chars(chaine)
|
||||
|
||||
|
||||
def hash_password(password, salt=None, longueur=4):
|
||||
if longueur < 4:
|
||||
raise ValueError("salt devrait faire au moins 4 octets")
|
||||
|
@ -341,21 +344,57 @@ 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"))
|
||||
|
||||
def datetime_from_generalized_time_format(gtf):
|
||||
"""Returns a datetime from generalized time format
|
||||
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):
|
||||
"""Returns a datetime from generalized time format"""
|
||||
if '-' in gtf or '+' in gtf:
|
||||
date, tz = gtf[0:14], gtf[14:]
|
||||
else:
|
||||
date = gtf.replace("Z", '')
|
||||
tz = '+0000'
|
||||
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
|
||||
return localized_datetime(date, tz)
|
||||
|
||||
def datetime_to_generalized_time_format(datetime_obj):
|
||||
"""Transforms a datetime to a GTF"""
|
||||
|
|
32
lc_ldap.py
32
lc_ldap.py
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# LC_LDAP.PY-- LightWeight CransLdap
|
||||
|
@ -39,6 +38,7 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
import ldap
|
||||
|
@ -53,11 +53,12 @@ import variables
|
|||
import copy
|
||||
import itertools
|
||||
|
||||
## import de /usr/scripts/
|
||||
if not "/usr/scripts/" in sys.path:
|
||||
sys.path.append('/usr/scripts/')
|
||||
## import de /usr/scripts
|
||||
if "/usr/scripts" not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
|
||||
import gestion.config as config
|
||||
from gestion import secrets_new as secrets
|
||||
import cranslib.deprecated
|
||||
|
||||
# A priori, ldif_to_uldif et ldif_to_cldif sont obsolètes,
|
||||
|
@ -105,6 +106,10 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
|
|||
|
||||
# Si un username, on récupère le dn associé…
|
||||
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)
|
||||
|
||||
# Si on a un dn, on se connecte avec à la base ldap sinon on s'y
|
||||
|
@ -112,7 +117,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
|
|||
if dn:
|
||||
self.conn = self.bind_s(dn, cred)
|
||||
self.dn = dn
|
||||
self.droits = self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])
|
||||
self.droits = [droit.decode(config.ldap_encoding) for droit in self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])]
|
||||
if dn == variables.admin_dn:
|
||||
self.droits += [attributs.nounou]
|
||||
# Il faut peupler current_login, qui sera utilisé pour écrire dans l'historique qui fait des modifications
|
||||
|
@ -247,6 +252,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
|
|||
res = {}
|
||||
parent = {}
|
||||
machines = {}
|
||||
factures = {}
|
||||
# (proxying de la base ldap)
|
||||
for dn, attrs in self.search_s(variables.base_dn, scope=2):
|
||||
# On crée les listes des machines et propriétaires
|
||||
|
@ -256,14 +262,26 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
|
|||
if not machines.has_key(parent_dn):
|
||||
machines[parent_dn] = []
|
||||
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):
|
||||
parent[dn] = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs))
|
||||
allmachines = []
|
||||
for dn, mlist in machines.iteritems(): # on associe propriétaires et machines
|
||||
for dn in parent: # on associe propriétaires et factures, machines
|
||||
mlist = machines.get(dn, [])
|
||||
flist = factures.get(dn, [])
|
||||
parent[dn]._machines = mlist
|
||||
parent[dn]._factures = flist
|
||||
parent[dn]._factures_last_update = time.time()
|
||||
for m in mlist:
|
||||
m._proprio = parent[dn]
|
||||
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)
|
||||
|
||||
def allMachines(self, mode='ro'):
|
||||
|
@ -311,7 +329,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
|
|||
uldif['objectClass'] = [u'machineCrans']
|
||||
assert isinstance(owner, objets.AssociationCrans)
|
||||
|
||||
elif realm == "bornes":
|
||||
elif realm in ["bornes", "bornes-v6"]:
|
||||
uldif['objectClass'] = [u'borneWifi']
|
||||
assert isinstance(owner, objets.AssociationCrans)
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ class LdapLockHolder:
|
|||
host, pid, begin = self.getlock(item, value)
|
||||
time_left = self.timeout - (time.time() - begin)
|
||||
if time_left <= delai:
|
||||
raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value, time_left))
|
||||
raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value))
|
||||
|
||||
def removelock(self, item, value, Id='default', force=False):
|
||||
"""
|
||||
|
@ -214,6 +214,3 @@ class LdapLockHolder:
|
|||
except ldap.INVALID_DN_SYNTAX:
|
||||
print '%s=%s,%s' % (item, value, LOCKS_DN)
|
||||
raise
|
||||
except ValueError as e:
|
||||
self.removelock(item, value, Id, force=True)
|
||||
raise LockNotFound()
|
||||
|
|
|
@ -3,13 +3,17 @@
|
|||
{{["aid=",o.aid.0]|join|coul('bleu')}} {{"Nom : "|coul('gras')}}{{o.prenom|join(' ')}} {{o.nom|join(' ')}}
|
||||
{% endblock%}
|
||||
{% block proprio %}
|
||||
{% if disp_telephone %}
|
||||
{{"Numéro de téléphone : "|coul('gras')}}{{o.tel|telephone|join(', ')}}
|
||||
{% endif %}
|
||||
{% if disp_adresse %}
|
||||
{% if o.chbre.0 == 'EXT' and o.postalAddress %}
|
||||
{{"Adresse : "|coul('gras')}}{{o.postalAddress.0}} {{o.postalAddress.1}}
|
||||
{{o.postalAddress.2}} {{o.postalAddress.3}}
|
||||
{% else %}
|
||||
{{"Chambre : "|coul('gras')}}{{o.chbre.0}} ({{o.chbre.0|string|prise_etat}})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{"Études : "|coul('gras')}}{{o.etudes|join(' ')}}
|
||||
{{adh}} {% if o.get('controle', []) and 'p' in o.controle.0.value %}{{"(OK)"|coul('vert')}}{% endif %}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{["fid=",o._id().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio()._id().0}})
|
||||
{{["fid=",o.oid().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio().oid().0}})
|
||||
{% if o.article %}
|
||||
{{"Article : "|coul('gras')}} Prix N° Total Commentaire
|
||||
{% set total = [] %}{% for a in o.article %}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
{{"IPv4 : "|coul('gras')}}{{o.ipHostNumber|join(', ')}}
|
||||
{% if o.ip6HostNumber %}{{"IPv6 : "|coul('gras')}}{{o.ip6HostNumber|join(', ')}}
|
||||
{% 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 %}
|
||||
{{"TRUE"|coul('vert')}}
|
||||
{% else %}
|
||||
|
|
|
@ -16,6 +16,7 @@ import gestion.annuaires_pg
|
|||
import gestion.hptools2 as hptools2
|
||||
|
||||
import lc_ldap.attributs as attributs
|
||||
import lc_ldap.crans_utils as crans_utils
|
||||
|
||||
def try_import(lib):
|
||||
"""
|
||||
|
@ -201,16 +202,21 @@ def list_factures(factures, width=None):
|
|||
data = []
|
||||
for facture in factures:
|
||||
controle = facture.get('controle', [""])[0]
|
||||
if controle == "TRUE":
|
||||
if controle == u"TRUE":
|
||||
controle = style(u"Validée", "vert")
|
||||
elif controle == "FALSE":
|
||||
elif controle == u"FALSE":
|
||||
controle = style(u"Invalide", "rouge")
|
||||
else:
|
||||
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([
|
||||
facture['fid'][0],
|
||||
facture['modePaiement'][0],
|
||||
style(facture.get('recuPaiement', [])[0], "vert") if facture.get('recuPaiement', []) else style("NON", "rouge"),
|
||||
style(_recu, 'vert') if _recu else style(u"NON", 'rouge'),
|
||||
controle,
|
||||
' '.join(attr['code'] for attr in facture.get('article',[])),
|
||||
u"%s €" % sum([float(a['pu'])*int(a['nombre']) for a in facture.get('article',[])])
|
||||
|
@ -223,49 +229,69 @@ def list_factures(factures, width=None):
|
|||
width=width)
|
||||
|
||||
def list_adherents(adherents, width=None):
|
||||
return tableau([
|
||||
[a['aid'][0],
|
||||
u' '.join(unicode(i) for i in a['prenom'] + a['nom']),
|
||||
a['chbre'][0], 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())
|
||||
] for a in adherents ],
|
||||
titre = [u'aid', u'Prénom Nom', u'Chbre', u'P', u'Machines'],
|
||||
largeur = [5, 35, 5, 1, '*'],
|
||||
alignement = ['d', 'c', 'c', 'c', 'g'],
|
||||
width=width)
|
||||
return tableau(
|
||||
[
|
||||
[
|
||||
a['aid'][0],
|
||||
u' '.join(unicode(i) for i in a['prenom'] + a['nom']),
|
||||
a['chbre'][0],
|
||||
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())
|
||||
]
|
||||
for a in adherents
|
||||
],
|
||||
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):
|
||||
return tableau([
|
||||
[a['cid'][0],
|
||||
u' '.join(unicode(i) for i in a['nom']),
|
||||
a['chbre'][0], 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())
|
||||
] for a in clubs ],
|
||||
titre = [u'cid', u'Nom', u'Chbre', u'P', u'Machines'],
|
||||
largeur = [5, 35, 5, 1, '*'],
|
||||
alignement = ['d', 'c', 'c', 'c', 'g'],
|
||||
width=width)
|
||||
return tableau(
|
||||
[
|
||||
[
|
||||
a['cid'][0],
|
||||
u' '.join(unicode(i) for i in a['nom']),
|
||||
a['chbre'][0],
|
||||
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())
|
||||
]
|
||||
for a in clubs
|
||||
],
|
||||
titre = [u'cid', u'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 proprio(proprio, params):
|
||||
params['o']=proprio
|
||||
etat_administratif=[]
|
||||
_now = crans_utils.localized_datetime()
|
||||
params['o'] = proprio
|
||||
etat_administratif = []
|
||||
|
||||
if proprio.paiement_ok():
|
||||
etat_administratif.append(style(u"à jour", "vert"))
|
||||
|
||||
if not proprio.paiement_ok():
|
||||
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")
|
||||
elif proprio.paiement_ok():
|
||||
adh = style(u"Adhésion terminée, mais il y a un sursis.", 'orange')
|
||||
else:
|
||||
adh = style(u"Pas adhérent actuellement.", 'rouge')
|
||||
|
||||
params["adh"] = adh
|
||||
if proprio.fin_connexion() >= time.time():
|
||||
if proprio.fin_connexion() >= _now:
|
||||
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():
|
||||
conn = style(u"Connexion terminée, mais il y a un sursis.", 'orange')
|
||||
else:
|
||||
conn = style(u"Pas connecté actuellement.", 'rouge')
|
||||
|
||||
params["conn"] = conn
|
||||
params['etat_administratif'] = etat_administratif
|
||||
|
||||
|
@ -298,7 +324,10 @@ def blacklist(blacklist, params):
|
|||
|
||||
def sprint(object, historique=5, blacklist_len=5, **params):
|
||||
from lc_ldap import objets, attributs
|
||||
params.update({'historique':historique, "blacklist":blacklist_len})
|
||||
params.update({
|
||||
'historique': historique,
|
||||
'blacklist': blacklist_len,
|
||||
})
|
||||
if isinstance(object, objets.machine):
|
||||
return machine(object, params)
|
||||
elif isinstance(object, objets.adherent):
|
||||
|
|
|
@ -32,7 +32,6 @@ services_to_attrs['mail_modif'] = [ attributs.droits, attributs.exempt ] + servi
|
|||
services_to_objects={}
|
||||
services_to_objects['delete']={}
|
||||
services_to_objects['create']={}
|
||||
services_to_objects['create']['home'] = [objets.adherent, objets.club]
|
||||
services_to_objects['delete']['del_user'] = [objets.adherent, objets.club]
|
||||
|
||||
NOW = time.time()
|
||||
|
|
|
@ -15,7 +15,7 @@ try:
|
|||
from gestion import secrets_new as secrets
|
||||
except ImportError:
|
||||
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', [])))
|
||||
sys.path.append("/usr/scripts")
|
||||
from gestion import secrets_new as secrets
|
||||
|
@ -51,7 +51,7 @@ def lc_ldap_test(*args, **kwargs):
|
|||
except OSError:
|
||||
pass
|
||||
# On impose le serveur
|
||||
kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'localhost')
|
||||
kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'vo.adm.crans.org')
|
||||
kwargs.setdefault("dn", 'cn=admin,dc=crans,dc=org')
|
||||
# Le mot de passe de la base de test
|
||||
kwargs.setdefault("cred", variables.ldap_test_password)
|
||||
|
|
2
test.py
2
test.py
|
@ -14,8 +14,6 @@ import lc_ldap
|
|||
import shortcuts
|
||||
import variables
|
||||
|
||||
## import dans /usr/scripts/
|
||||
sys.path.append("/usr/scripts/")
|
||||
from gestion.affich_tools import anim, OK, cprint, ERREUR
|
||||
|
||||
mail_format = False
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue