From 6dfa3af3ec077cf939250e7973abe416dd389b73 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Fri, 28 Oct 2011 18:28:59 +0200 Subject: [PATCH 1/3] =?UTF-8?q?[attributs]=20On=20ne=20fait=20des=20appels?= =?UTF-8?q?=20=C3=A0=20pgsql=20que=20s'il=20faut=20effectivement=20v=C3=A9?= =?UTF-8?q?rifier=20les=20donn=C3=A9es.=20Quand=20on=20est=20en=20red=20on?= =?UTF-8?q?ly,=20en=20plus=20d'=C3=AAtre=20inutile,=20on=20fait=20souvent?= =?UTF-8?q?=20cracher=20le=20binding=20=C3=A0=20cause=20de=20vieux=20enreg?= =?UTF-8?q?istrements.=20Accessoirement,=20on=20rajoute=20quelques=20shell?= =?UTF-8?q?s=20valident.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- attributs.py | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) 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 From 2459e40531ccccb13cba46b352fa6921e39891c0 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Fri, 28 Oct 2011 19:16:25 +0200 Subject: [PATCH 2/3] =?UTF-8?q?[lc=5Fldap]=20Ajoute=20d'une=20methode=20g?= =?UTF-8?q?=C3=A9n=C3=A9rale=20(allMachinesAdherents)=20renvoyant=20la=20l?= =?UTF-8?q?istes=20de=20toutes=20les=20machines=20et=20de=20tous=20les=20a?= =?UTF-8?q?dh=C3=A9rents.=20On=20bind=20allMachines=20dessus=20et=20on=20a?= =?UTF-8?q?joute=20allAdherents=20en=20bindant=20=C3=A9galement.=20On=20aj?= =?UTF-8?q?oute=20aussi=20une=20methode=20paiement=5Fok=20dans=20la=20clas?= =?UTF-8?q?se=20proprio=20car=20pratique.=20Cette=20fois,=20pour=20allMach?= =?UTF-8?q?inesAdherents=20on=20oublie=20pas=20de=20traiter=20les=20club,?= =?UTF-8?q?=20mais=20on=20refait=20un=20appel=20=C3=A0=20l'annuaire=20ldap?= =?UTF-8?q?=20pour=20chaque=20club=20pour=20trouver=20le=20responsable=20c?= =?UTF-8?q?e=20qui=20prends=20un=20temps=20non=20n=C3=A9gligeable=20(c'est?= =?UTF-8?q?=20toujours=20mieux=20que=20de=20refaire=20un=20appel=20pour=20?= =?UTF-8?q?chaque=20machine=20pour=20trouver=20le=20propri=C3=A9taire)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lc_ldap.py | 83 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/lc_ldap.py b/lc_ldap.py index 2480204..246cacb 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,17 @@ 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 + for paiement in self['paiement']: + if paiement.value == config.ann_scol: + return True + return False + + def machines(self): if not self._machines: From b697fdf94f9c02df767fb53c5747bb5ccd390f93 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Fri, 28 Oct 2011 20:23:47 +0200 Subject: [PATCH 3/3] [lc_ldap] On n'oublie pas que 'paiement' est un champs optionnel --- lc_ldap.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lc_ldap.py b/lc_ldap.py index 246cacb..5037c88 100644 --- a/lc_ldap.py +++ b/lc_ldap.py @@ -453,9 +453,12 @@ class proprio(CransLdapObject): """Renvoie si le propriétaire à payé pour l'année en cours""" if self.dn == base_dn: return True - for paiement in self['paiement']: - if paiement.value == config.ann_scol: - return True + try: + for paiement in self['paiement']: + if paiement.value == config.ann_scol: + return True + except KeyError: + pass return False