diff --git a/attributs.py b/attributs.py index 8293259..dd3903c 100644 --- a/attributs.py +++ b/attributs.py @@ -40,6 +40,30 @@ sys.path.append("/usr/scripts/gestion") import config, annuaires_pg from midtools import Mid +### Les droits +# en cas de typo, l'appel d'une variable plante, on préfèrera donc les utiliser en lieu et place +# des chaînes de caractères +nounou = "Nounou" +cableur = "Cableur" +apprenti = "Apprenti" +tresorier = "Tresorier" +bureau = "Bureau" +imprimeur = "Imprimeur" +moderateur = "Moderateur" +multimachines = "Multimachines" +parent = "parent" +soi = "soi" +responsable = "responsable" + +TOUS_DROITS = [nounou, apprenti, bureau, tresorier, imprimeur, moderateur, multimachines, cableur] +DROITS_ELEVES = [nounou, bureau] +DROITS_MOYEN = [apprenti, moderateur] +DROITS_FAIBLES = [cableur, imprimeur, multimachines] + +DROITS_SUPERVISEUR = { nounou : TOUS_DROITS, + bureau : DROITS_FAIBLES + [bureau, tresorier], +} + def attrify(val, attr, ldif, conn, ctxt_check = True): """Transforme un n'importe quoi en Attr. @@ -61,11 +85,12 @@ class Attr(object): singlevalue = None optional = None conn = None + unique = False - can_modify = ['Nounou'] + can_modify = [nounou] - can_view = ['Nounou', 'apprenti', 'self', 'parent', 'owner'] - """Qui peut voir l'attribut. Par défaut, les nounous et les apprentis + can_view = [nounou, apprenti, soi, parent, responsable] + """Qui peut voir l'attribut. Par défaut, les Nounous et les Apprentis peuvent tout voir. Par transparence, et par utilité, on autorise par défaut l'adhérent à voir les données le concernant.""" @@ -121,18 +146,10 @@ class Attr(object): """Vérifie l'unicité dans la base de la valeur (mailAlias, chbre, etc...)""" attr = self.__class__.__name__ - if attr in ["mid", "uid", "cid", "fid", "aid", "ipHostNumber", "uidNumber"]: + if self.unique: res = self.conn.search('%s=%s' % (attr, str(self))) if res: raise ValueError("%s déjà existant" % attr, [r.dn for r in res]) - if attr in ["mailAlias", "canonicalAlias", 'mail', 'uid']: - res = self.conn.search('(|(mail=%s)(mailAlias=%s)(canonicalAlias=%s))' % ((str(self),)*3)) - if res: - raise ValueError("Mail déjà existant", [r.dn for r in res]) - if attr in ["host", "hostAlias"]: - res = self.conn.search('(|(host=%s)(hostAlias=%s))' % ((str(self),)*2)) - if res: - raise ValueError("Hôte déjà existant", [r.dn for r in res]) def _check_users_restrictions(self, values): """Vérifie les restrictions supplémentaires imposées selon les @@ -141,6 +158,11 @@ class Attr(object): ### On l'implémente dans les classes filles ! pass + def is_modifiable(self, liste_droits): + """ + Le droit est-il modifiable par un des droits dans liste_droits ? + """ + return set(liste_droits).isdisjoint(can_modify) class objectClass(Attr): singlevalue = False @@ -150,7 +172,7 @@ class objectClass(Attr): can_modify = [] """ Personne ne doit modifier de classe """ - can_view = ['Nounou', 'apprenti'] + can_view = [nounou, apprenti] """ Internal purpose (et à fin pédagogique) """ def parse_value(self, val, ldif): @@ -177,24 +199,26 @@ class aid(intAttr): optional = True legend = u"Identifiant de l'adhérent" category = 'id' + unique = True can_modify = [] """ Personne ne devrait modifier un attribut d'identification """ - can_view = ['Nounou', 'apprenti', 'cableurs'] + can_view = [nounou, apprenti, 'Cableurs'] class uid(Attr): singlevalue = True option = False legend = u"L'identifiant canonique de l'adhérent" category = 'perso' + unique = True class nom(Attr): singlevalue = True optional = False legend = "Nom" category = 'perso' - can_modify = ["Nounou", "Cableur"] + can_modify = [nounou, cableur] def parse_value(self, val, ldif): if u'club' in ldif['objectClass']: @@ -207,7 +231,7 @@ class prenom(Attr): optional = False legend = u"Prénom" category = 'perso' - can_modify = ["Nounou", "Cableur"] + can_modify = [nounou, cableur] def parse_value(self, val, ldif): self.value = validate_name(val) @@ -218,7 +242,7 @@ class tel(Attr): optional = False legend = u"Téléphone" category = 'perso' - can_modify = ["self", "Nounou", "Cableur"] + can_modify = [soi, nounou, cableur] def parse_value(self, val, ldif): self.value = format_tel(val) @@ -235,36 +259,39 @@ class yearAttr(intAttr): raise ValueError("Année invalide (%r)" % val) self.value = int(val) - class paiement(yearAttr): legend = u"Paiement" - can_modify = ["Cableur", "Nounou", "tresorier"] + can_modify = [cableur, nounou, tresorier] category = 'perso' class carteEtudiant(yearAttr): legend = u"Carte d'étudiant" category = 'perso' - can_modify = ["Cableur", "Nounou", "tresorier"] + can_modify = [cableur, nounou, tresorier] - - -class mailAlias(Attr): - singlevalue = False - optional = True - legend = u"Alias mail" - can_modify = ["self", "Cableur", "Nounou"] - category = 'mail' - - def parse_value(self, val, ldif): - val = val.lower() - if not re.match('[a-z][-_.0-9a-z]+', val): - raise ValueError("Alias mail invalide (%r)" % val) - self.value = val - - -class canonicalAlias(Attr): +class mail(Attr): singlevalue = True optional = False + unique = True + legend = "Le mail de l'adhérent" + can_modify = [soi, nounou, cableur] + category = 'mail' + + def _check_uniqueness(self): + attr = self.__class__.__name__ + if attr in ["mailAlias", "canonicalAlias", 'mail']: + res = self.conn.search('(|(mail=%s)(mailAlias=%s)(canonicalAlias=%s))' % ((str(self),)*3)) + if res: + raise ValueError("Mail déjà existant", [r.dn for r in res]) + + # XXX - to be implemented + #def parse_value(self, mail, ldif): + # pass + +class canonicalAlias(mail): + singlevalue = True + optional = False + unique = True legend = u"Alias mail canonique" category = 'mail' @@ -274,11 +301,25 @@ class canonicalAlias(Attr): raise ValueError("Alias mail invalide (%s)" % val) self.value = val +class mailAlias(mail): + singlevalue = False + optional = True + unique = True + legend = u"Alias mail" + can_modify = [soi, cableur, nounou] + category = 'mail' + + def parse_value(self, val, ldif): + val = val.lower() + if not re.match('[a-z][-_.0-9a-z]+', val): + raise ValueError("Alias mail invalide (%r)" % val) + self.value = val + class etudes(Attr): singlevalue = False optional = False legend = u"Études" - can_modify = ["self", "Cableur", "Nounou"] + can_modify = [soi, cableur, nounou] category = 'perso' def parse_value(self, val, ldif): @@ -289,8 +330,9 @@ class etudes(Attr): class chbre(Attr): singlevalue = True optional = False + unique = True legend = u"Chambre sur le campus" - can_modify = ["self", "Cableur", "Nounou"] + can_modify = [soi, cableur, nounou] category = 'perso' def parse_value(self, val, ldif): @@ -318,23 +360,30 @@ class droits(Attr): singlevalue = False optional = True legend = u"Droits sur les serveurs" - can_modify = ["Nounou", "Bureau"] + can_modify = [nounou, bureau] #ne sert à rien ici, mais c'est tout à fait exceptionnel category = 'perso' def parse_value(self, val, ldif): - if val.lower() not in ['apprenti', 'nounou', 'cableur', 'tresorier', 'bureau', - 'webmaster', 'webradio', 'imprimeur', 'multimachines', 'victime', 'moderateur', 'nounours']: + if val.lower() not in [i.lower() for i in TOUS_DROITS]: raise ValueError("Ces droits n'existent pas (%r)" % val) - if val.lower() == 'webmaster': - self.value = u'WebMaster' - else: - self.value = val.capitalize() + self.value = val.capitalize() + + def is_modifiable(self, liste_droits): + """ + Le droit est-il modifiable par un des droits dans liste_droits ? + """ + modifiables = set() + for i in liste_droits: + modifiables.append(DROITS_SUPERVISEUR.get(i, [])) + modifiables = list(modifiables) + + return self.value in modifiables class solde(Attr): singlevalue = True optional = True legend = u"Solde d'impression" - can_modify = ["imprimeur", "Nounou", "Tresorier"] + can_modify = [imprimeur, nounou, tresorier] def parse_value(self, solde, ldif): # on évite les dépassements, sauf si on nous dit de ne pas vérifier @@ -352,14 +401,25 @@ class dnsAttr(Attr): raise ValueError("Nom d'hote invalide %r" % dns) self.value = dns - class host(dnsAttr): singlevalue = True optional = False hname = legend = u"Nom d'hôte" - can_modify = ["parent", "Nounou", "Cableur"] + can_modify = [parent, nounou, cableur] category = 'base_tech' + def _check_uniqueness(self): + attr = self.__class__.__name__ + if attr in ["host", "hostAlias"]: + res = self.conn.search('(|(host=%s)(hostAlias=%s))' % ((str(self),)*2)) + if res: + raise ValueError("Hôte déjà existant", [r.dn for r in res]) + +class hostAlias(host): + singlevalue = False + unique = True + optional = True + legend = u'Alias de nom de machine' class macAddress(Attr): singlevalue = True @@ -367,7 +427,7 @@ class macAddress(Attr): legend = u"Adresse physique de la carte réseau" hname = "Adresse MAC" category = 'base_tech' - can_modify = ["parent", "Nounou", "Cableur"] + can_modify = [parent, nounou, cableur] def parse_value(self, mac, ldif): self.value = format_mac(mac) @@ -379,6 +439,7 @@ class macAddress(Attr): class ipHostNumber(Attr): singlevalue = True optional = False + unique = True legend = u"Adresse IPv4 de la machine" hname = "IPv4" category = 'base_tech' @@ -395,6 +456,7 @@ class ipHostNumber(Attr): class mid(Attr): singlevalue = True optional = False + unique = True legend = "Identifiant de machine" category = 'id' @@ -405,11 +467,6 @@ class mid(Attr): return unicode(int(self.value)) -class hostAlias(dnsAttr): - singlevalue = False - optional = True - legend = u'Alias de nom de machine' - class ipsec(Attr): singlevalue = False optional = True @@ -488,6 +545,7 @@ class prise(Attr): class cid(intAttr): singlevalue = True optional = True + unique = True legend = u"Identifiant du club" category = 'id' @@ -546,20 +604,20 @@ class info(Attr): optional = True legend = u"Quelques informations" category = 'info' - can_modify = ["Nounou", "Cableur", "Bureau"] + can_modify = [nounou, cableur, bureau] class homepageAlias(Attr): singlevalue = True optional = True legend = u'Un alias pour la page personnelle' - can_modify = ["Nounou", "Cableur"] + can_modify = [nounou, cableur] category = 'webpage' class charteMA(Attr): singlevalue = True optional = True legend= "Signale si l'adhérent a signé la charte de membres actifs" - can_modify = ["Nounou", "Bureau"] + can_modify = [nounou, bureau] category = 'perso' def parse_value(self, signed, ldif): @@ -570,6 +628,7 @@ class charteMA(Attr): class homeDirectory(Attr): singlevalue=True optional = True + unique = True legend="Le chemin du home de l'adhérent" def parse_value(self, home, ldif): @@ -585,7 +644,7 @@ class loginShell(Attr): singlevalue = True optional = True legend = "Le shell de l'adherent" - can_modify = ["self", "Nounou", "Cableur"] + can_modify = [soi, nounou, cableur] def parse_value(self, shell, ldif): #with open('/etc/shells') as f: @@ -620,6 +679,7 @@ class loginShell(Attr): class uidNumber(intAttr): singlevalue = True optional = True + unique = True legend = "L'uid du compte de l'adherent" category = 'id' @@ -639,28 +699,19 @@ class gecos(Attr): a, b, c, d = gecos.split(',') self.value = gecos -class mail(Attr): - singlevalue = True - optional = False - legend = "Le mail de l'adhérent" - can_modify = ["self", "Nounou", "Cableur"] - category = 'mail' - - # XXX - to be implemented - #def parse_value(self, mail, ldif): - # pass class sshFingerprint(Attr): singlevalue = False optional = True legend = "Clef ssh de la machine" - can_modify = ["parent", "Nounou"] + can_modify = [parent, nounou] class gpgFingerprint(Attr): singlevalue = False optional = True + unique = True legend = "Clef gpg d'un adhérent" - can_modify = ["self", "Nounou"] + can_modify = [soi, nounou] class cn(Attr): singlevalue = True @@ -670,12 +721,13 @@ class cn(Attr): class dn(Attr): singlevalue = True optional = False + unique = True category = 'id' class postalAddress(Attr): singlevalue = False optional = True - can_modify = ["self", "Cableur", "Nounou", "Bureau"] + can_modify = [soi, cableur, nounou, bureau] legend = u"Adresse" category = 'perso' @@ -683,7 +735,7 @@ class controle(Attr): singlevalue = True optional = False legend = u"Contrôle" - can_modify = ["Tresorier", "Nounou"] + can_modify = [tresorier, nounou] category = 'perso' def parse_value(self, ctrl, ldif): @@ -694,6 +746,16 @@ class controle(Attr): else: self.value = ctrl + +### Les classes +ADHERENT_ATTRS = [ nom, prenom, tel, chbre, postalAddress, mail, uid, + canonicalAlias, mailAlias, etudes, paiement, + solde, carteEtudiant, droits, loginShell, blacklist ] + +MACHINE_ATTRS = [ host, macAddress, hostAlias, ipHostNumber, portTCPout, + portTCPin, portUDPout, portUDPin ] + + CRANS_ATTRIBUTES= { 'objectClass' : objectClass, 'cn' : cn, @@ -745,11 +807,3 @@ CRANS_ATTRIBUTES= { 'gecos': gecos, 'gidNumber': gidNumber } - -ADHERENT_ATTRS = [ nom, prenom, tel, chbre, postalAddress, mail, uid, - canonicalAlias, mailAlias, etudes, paiement, - solde, carteEtudiant, droits, loginShell, blacklist ] - -MACHINE_ATTRS = [ host, macAddress, hostAlias, ipHostNumber, portTCPout, - portTCPin, portUDPout, portUDPin ] -