diff --git a/attributs.py b/attributs.py index 3dd03eb..36a7665 100644 --- a/attributs.py +++ b/attributs.py @@ -69,6 +69,7 @@ class Attr(object): ldif: objet contenant l'attribut (permet de faire les validations sur l'environnement) ctxt_check: effectue les validations """ + self.ctxt_check=ctxt_check self.value = None self.conn = conn assert isinstance(val, unicode) @@ -133,12 +134,14 @@ class objectClass(Attr): singlevalue = False optional = False legend = "entité" + def parse_value(self, val, ldif): if val not in [ 'top', 'posixAccount', 'shadowAccount', 'proprio', 'adherent', 'club', 'machine', 'machineCrans', 'borneWifi', 'machineWifi', 'machineFixe', 'cransAccount', 'service', 'facture', 'freeMid' ]: + print(val) raise ValueError("Pourquoi insérer un objectClass=%s ?" % val) else: self.value = unicode(val) @@ -254,22 +257,23 @@ class chbre(Attr): can_modify = ["self", "Cableur", "Nounou"] def parse_value(self, val, ldif): - if u'club' in ldif['objectClass']: - if val in annuaires_pg.locaux_clubs(): + if self.ctxt_check: # Si ce n'est pas la peine de vérifier, on ne vérifie pas + if u'club' in ldif['objectClass']: + if val in annuaires_pg.locaux_clubs(): + self.value = val + return + else: + raise ValueError("Club devrait etre en XclN, pas en %s" % val) + + if val in (u"EXT", u"????"): self.value = val return - else: - raise ValueError("Club devrait etre en XclN, pas en %s" % val) - if val in (u"EXT", u"????"): - self.value = val - return - - try: - annuaires_pg.chbre_prises(val[0], val[1:]) - except NameError: - import annuaires_pg_test - annuaires_pg_test.chbre_prises(val[0], val[1:]) + try: + annuaires_pg.chbre_prises(val[0], val[1:]) + except NameError: + import annuaires_pg_test + annuaires_pg_test.chbre_prises(val[0], val[1:]) self.value = val @@ -295,8 +299,8 @@ class solde(Attr): can_modify = ["imprimeur", "Nounou", "Tresorier"] def parse_value(self, solde, ldif): - # on évite les dépassements - if not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.): + # on évite les dépassements, sauf si on nous dit de ne pas vérifier + if self.ctxt_check and not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.): raise ValueError("Solde invalide: %s" % solde) self.value = solde @@ -304,7 +308,7 @@ class dnsAttr(Attr): def parse_value(self, dns, ldif): dns = dns.lower() name, net = dns.split('.', 1) - if (net not in ['crans.org', 'wifi.crans.org'] or + if self.ctxt_check and (net not in ['crans.org', 'wifi.crans.org'] or not re.match('[a-z][-_a-z0-9]+', name)): raise ValueError("Nom d'hote invalide '%s'" % dns) self.value = dns @@ -544,8 +548,12 @@ class loginShell(Attr): '/usr/bin/rssh', '/usr/local/bin/disconnect_shell', '/usr/scripts/surveillance/disconnect_shell', + '/usr/local/bin/badPassSh', + '/usr/bin/passwd', + '/bin/false', + '/bin//zsh' ''] - if (shell not in shells): + if self.ctxt_check and (shell not in shells): raise ValueError("Shell %s invalide" % shell) self.value = shell diff --git a/lc_ldap.py b/lc_ldap.py index 2480204..5037c88 100644 --- a/lc_ldap.py +++ b/lc_ldap.py @@ -121,32 +121,53 @@ class lc_ldap(ldap.ldapobject.LDAPObject): res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit) return [ new_cransldapobject(self, r[0], mode=mode) for r in res ] + def allMachinesAdherents(self): + """Renvoie la liste de toutes les machines et de tous les adherents + (club et Association Crans compris). Conçue pour s'éxécuter le plus + rapidement possible. On dumpe malgré tout toute la base.""" + res = {} + parent = {} + machines = {} + # (proxying de la base ldap) + for dn, attrs in self.search_s(base_dn, scope=2): + # On crée les listes des machines et propriétaires + if dn.startswith('mid='): # les machines + m = new_cransldapobject(self, dn, ldif = attrs) + parent_dn = dn.split(',', 1)[1] + if not machines.has_key(parent_dn): + machines[parent_dn]=[] + machines[parent_dn].append(m) + elif (dn.startswith('aid=') or dn.startswith('cid=') or dn==base_dn) and not parent.has_key(dn): + # Hélas on refait une recherche ldap dans attributs.py pour trouver les responsables des club + # ce qui prends un temps non négligeable mais est toujours mieux que de le faire pour tous les adherents + parent[dn]=new_cransldapobject(self, dn, ldif = attrs) + allmachines=[] + for dn,mlist in machines.items(): # on associe propriétaires et machines + parent[dn]._machines=mlist + for m in mlist: + m._proprio=parent[dn] + allmachines.append(m) + return allmachines,parent.values() # on renvoie la liste des machines et des adherents (dont club et crans) + def allMachines(self): """Renvoie la liste de toutes les machines, Conçue pour s'éxécuter le plus rapidement possible. On dumpe malgré tout toute la base, c'est pour pouvoir aussi rajouter à moindre coût les propriétaires.""" - res = {} - parent = {} - machines = [] - # On récupère tous les objets ldap et on les met dans un dico - # (proxying de la base ldap) - for dn, attrs in self.search_s(base_dn, scope=2): #on fait tout dans une seule boucle - #~ res[dn] = attrs - # On crée la liste des machines - #~ for dn, attrs in res.items(): - if dn.startswith('mid='): - m = new_cransldapobject(self, dn, ldif = attrs) - parent_dn = dn.split(',', 1)[1] - if not parent.has_key(parent_dn): - parent[parent_dn]=adherent(self, dn,machines= [ new_cransldapobject(self, dn,ldif=attrs)]) # on utilise pas new_cransldapobject pour optimiser les appel ldap (on passe la liste des machines) - else: - parent[parent_dn]._machines.append(new_cransldapobject(self, dn,ldif=attrs)) - #~ m._proprio = new_cransldapobject(self, parent_dn, res[parent_dn],opt=machine_proprio[parent_dn]) - m._proprio = parent[parent_dn] - machines.append(m) + machines,_=self.allMachinesAdherents() return machines + def allAdherents(self): + """Renvoie la liste de toutes les adherents, Conçue pour + s'éxécuter le plus rapidement possible. On dumpe malgré tout + toute la base, c'est pour pouvoir aussi rajouter à moindre coût + les machines.""" + _,adherents=self.allMachinesAdherents() + return adherents + + + + def newMachine(self, parent, realm, uldif): """Crée une nouvelle machine: realm peut être: fil, fil-v6, wifi, wifi-v6, adm, gratuit, personnel-ens, special""" @@ -241,10 +262,10 @@ def new_cransldapobject(conn, dn, mode='ro', ldif = None): classe = None - if ldif: - classe = globals()[ldif['objectClass'][0]] - elif dn == base_dn: + if dn == base_dn: classe = AssociationCrans + elif ldif: + classe = globals()[ldif['objectClass'][0]] else: res = conn.search_s(dn, 0) if not res: @@ -265,7 +286,7 @@ class CransLdapObject(object): self.mode = mode - self.attrs = None # Contient un dico uldif qui doit représenter ce qui + self.attrs = {} # Contient un dico uldif qui doit représenter ce qui # est dans la base self._modifs = None # C'est là qu'on met les modifications @@ -279,6 +300,9 @@ class CransLdapObject(object): # Vous précisez un ldif, l'objet est 'ro' self.mode = 'ro' self.attrs = ldif + if dn != base_dn: # new_cransldapobject ne donne pas de ldif formaté et utilise un ldif non formaté, donc on formate + self.attrs = ldif_to_uldif(self.attrs) + self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False) # on est en read only, donc pas la peine de vérifier la validité elif dn != base_dn: res = conn.search_s(dn, 0) if not res: @@ -395,7 +419,7 @@ class CransLdapObject(object): # XXX - Proposer de filtrer les blacklistes avec un arg supplémentaire ? # XXX - Vérifier les blacklistes des machines pour les adhérents ? attrs = (self.attrs if self.mode not in ["w", "rw"] else self._modifs) - return filter((lambda bl: bl.is_actif()), attrs.get("blacklist")) + return filter((lambda bl: bl.is_actif()), attrs.get("blacklist",[])) def blacklist(self, sanction, commentaire, debut="now", fin = '-'): u""" @@ -424,6 +448,20 @@ class proprio(CransLdapObject): def __init__(self, conn, dn, mode='ro', ldif = None, machines=[]): super(proprio, self).__init__(conn, dn, mode, ldif) self._machines = machines + + def paiement_ok(self): + """Renvoie si le propriétaire à payé pour l'année en cours""" + if self.dn == base_dn: + return True + try: + for paiement in self['paiement']: + if paiement.value == config.ann_scol: + return True + except KeyError: + pass + return False + + def machines(self): if not self._machines: