Quelques améliorations, mise en place de fonctions pour tester parenté,

tester si c'est soi-même qu'on modifie, pour tester si on peut bien
altérer l'objet concerné.
Création des objets en deux temps (on crée l'objet Crans, puis
on l'enregistre dans ldap après test des droits.
Changement de méthode de binding : le binding nominatif va être bien
trop complexe à implémenter, on va donc faire autrement...
This commit is contained in:
Pierre-Elliott Bécue 2013-01-28 00:45:01 +01:00
parent fcafdbff28
commit 42c48f77e8
3 changed files with 190 additions and 61 deletions

View file

@ -425,6 +425,8 @@ class hostAlias(host):
optional = True optional = True
legend = u'Alias de nom de machine' legend = u'Alias de nom de machine'
can_modify = [nounou, cableur]
class macAddress(Attr): class macAddress(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
@ -447,6 +449,7 @@ class ipHostNumber(Attr):
legend = u"Adresse IPv4 de la machine" legend = u"Adresse IPv4 de la machine"
hname = "IPv4" hname = "IPv4"
category = 'base_tech' category = 'base_tech'
can_modify = [nounou]
def parse_value(self, ip, ldif): def parse_value(self, ip, ldif):
if ip == '<automatique>': if ip == '<automatique>':
@ -476,6 +479,7 @@ class rid(Attr):
unique = True unique = True
legend = "Identifiant réseau de machine" legend = "Identifiant réseau de machine"
category = 'id' category = 'id'
can_modify = [nounou]
def parse_value(self, rid, ldif): def parse_value(self, rid, ldif):
self.value = Rid(rid = int(rid)) self.value = Rid(rid = int(rid))
@ -494,18 +498,21 @@ 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]
class canal(intAttr): class canal(intAttr):
singlevalue = True singlevalue = True
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]
class portAttr(Attr): class portAttr(Attr):
singlevalue = False singlevalue = False
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, ldif): def parse_value(self, port, ldif):
if ":" in port: if ":" in port:
@ -553,6 +560,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]
def parse_value(self, prise, ldif): def parse_value(self, prise, ldif):
### Tu es une Nounou, je te fais confiance ### Tu es une Nounou, je te fais confiance
@ -570,6 +578,7 @@ class responsable(Attr):
optional = True optional = True
legend = u"Responsable du club" legend = u"Responsable du club"
category = 'perso' category = 'perso'
can_modify = [nounou]
def get_respo(self): def get_respo(self):
if self.value == None: if self.value == None:
@ -583,12 +592,12 @@ class responsable(Attr):
def __unicode__(self): def __unicode__(self):
return self.__resp return self.__resp
class blacklist(Attr): class blacklist(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Blackliste" legend = u"Blackliste"
category = 'info' category = 'info'
can_modify = [nounou]
def parse_value(self, bl, ldif): def parse_value(self, bl, ldif):
bl_debut, bl_fin, bl_type, bl_comm = bl.split('$') bl_debut, bl_fin, bl_type, bl_comm = bl.split('$')
@ -712,10 +721,8 @@ class gecos(Attr):
category = 'id' category = 'id'
def parse_value(self, gecos, ldif): def parse_value(self, gecos, ldif):
a, b, c, d = gecos.split(',')
self.value = gecos self.value = gecos
class sshFingerprint(Attr): class sshFingerprint(Attr):
singlevalue = False singlevalue = False
optional = True optional = True

View file

@ -77,8 +77,6 @@ def ip6_of_mac(mac, rid):
else: else:
raise ValueError("Rid dans aucune plage: %d" % rid) raise ValueError("Rid dans aucune plage: %d" % rid)
print net
# En théorie, format_mac est inutile, car on ne devrait avoir # En théorie, format_mac est inutile, car on ne devrait avoir
# que des mac formatées. # que des mac formatées.
mac = format_mac(mac).replace(':', '') mac = format_mac(mac).replace(':', '')

View file

@ -36,17 +36,29 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import with_statement from __future__ import with_statement
import os, sys, ldap, re, netaddr, datetime, copy, time, random import os
import sys
import ldap
import ldap.filter import ldap.filter
from ldap.modlist import addModlist, modifyModlist from ldap.modlist import addModlist, modifyModlist
import re
import netaddr
import datetime
import copy
import time
import random
try: try:
from Levenshtein import jaro from Levenshtein import jaro
except ImportError: except ImportError:
def jaro(a, b): return 0 def jaro(a, b): return 0
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
import config, crans_utils import config
from attributs import attrify, blacklist import crans_utils
from attributs import *
from ldap_locks import CransLock from ldap_locks import CransLock
import ridtools import ridtools
@ -54,6 +66,11 @@ uri = 'ldap://ldap.adm.crans.org/'
base_dn = 'ou=data,dc=crans,dc=org' base_dn = 'ou=data,dc=crans,dc=org'
log_dn = "cn=log" log_dn = "cn=log"
# Protection contre les typos
created = 'created'
modified = 'modified'
deleted = 'deleted'
# Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script # Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script
# Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo) # Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo)
# est plus pertinente que USER (qui sera root) # est plus pertinente que USER (qui sera root)
@ -75,6 +92,10 @@ def escape(chaine):
return ldap.filter.escape_filter_chars(chaine) return ldap.filter.escape_filter_chars(chaine)
def ldif_to_uldif(ldif): def ldif_to_uldif(ldif):
"""
Transforme un dictionnaire ldif en un dictionnaire
ldif unicode.
"""
uldif = {} uldif = {}
for attr, vals in ldif.items(): for attr, vals in ldif.items():
uldif[attr] = [ unicode(val, 'utf-8') for val in vals ] uldif[attr] = [ unicode(val, 'utf-8') for val in vals ]
@ -92,6 +113,10 @@ def ldif_to_cldif(ldif, conn, check_ctxt = True):
return cldif return cldif
def cldif_to_ldif(cldif): def cldif_to_ldif(cldif):
"""
Transforme un ldif crans en ldif valide au sens openldap.
Ce ldif est celui qui sera transmis à la base.
"""
ldif = {} ldif = {}
for attr, vals in cldif.items(): for attr, vals in cldif.items():
ldif[attr] = [ str(val) for val in vals ] ldif[attr] = [ str(val) for val in vals ]
@ -108,6 +133,7 @@ def lc_ldap_admin():
secrets = import_secrets() secrets = import_secrets()
return lc_ldap(uri='ldap://ldap.adm.crans.org/', dn=secrets.ldap_auth_dn, cred=secrets.ldap_password) return lc_ldap(uri='ldap://ldap.adm.crans.org/', dn=secrets.ldap_auth_dn, cred=secrets.ldap_password)
class lc_ldap(ldap.ldapobject.LDAPObject): class lc_ldap(ldap.ldapobject.LDAPObject):
"""Connexion à la base ldap crans, chaque instance représente une connexion """Connexion à la base ldap crans, chaque instance représente une connexion
""" """
@ -147,7 +173,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
# 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
# connecte en anonyme # connecte en anonyme
if dn: if dn:
self.conn = self.bind_s(dn, cred) self.conn = self.bind_s(secrets.ldap_auth_dn, secrets.ldap_password)
self.dn = dn self.dn = dn
self.droits = 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', [])
else: else:
@ -155,13 +181,13 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
self.dn = None self.dn = None
self.droits = [] self.droits = []
def search(self, filterstr='(objectClass=*)', mode='ro', dn= base_dn, scope= 2, sizelimit=400): def search(self, filterstr='(objectClass=*)', mode='ro', dn= base_dn, scope=ldap.SCOPE_SUBTREE, sizelimit=1000):
"""La fonction de recherche dans la base ldap qui renvoie un liste de """La fonction de recherche dans la base ldap qui renvoie un liste de
CransLdapObjects. On utilise la feature de sizelimit de python ldap""" CransLdapObjects. On utilise la feature de sizelimit de python ldap"""
ldap_res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit) ldap_res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit)
ret = [] ret = []
for dn, ldif in ldap_res: for dn, ldif in ldap_res:
ret.append(new_cransldapobject(self, dn, mode=mode)) ret.append(new_cransldapobject(self, dn, mode, ldif))
return ret return ret
def allMachinesAdherents(self): def allMachinesAdherents(self):
@ -213,20 +239,17 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
#adm, serveurs, bornes, wifi, adherents, gratuit ou personnel-ens""" #adm, serveurs, bornes, wifi, adherents, gratuit ou personnel-ens"""
owner = self.search('objectClass=*', dn=parent, scope=0)[0] owner = self.search('objectClass=*', dn=parent, scope=0)[0]
if realm in ["adm", "serveurs"]: if realm in ["adm", "serveurs", "serveurs-v6", "adm-v6"]:
uldif['objectClass'] = [u'machineCrans'] uldif['objectClass'] = [u'machineCrans']
assert isinstance(owner, AssociationCrans) assert isinstance(owner, AssociationCrans)
# XXX - Vérifier les droits
elif realm == "bornes": elif realm == "bornes":
uldif['objectClass'] = [u'borneWifi'] uldif['objectClass'] = [u'borneWifi']
assert isinstance(owner, AssociationCrans) assert isinstance(owner, AssociationCrans)
# XXX - Vérifier les droits
elif realm in ["wifi", "wifi-v6"]: elif realm in ["wifi", "wifi-v6"]:
uldif['objectClass'] = [u'machineWifi'] uldif['objectClass'] = [u'machineWifi']
assert isinstance(owner, adherent) or isinstance(owner, club) assert isinstance(owner, adherent) or isinstance(owner, club)
# XXX - Vérifier les droits (owner.type_connexion)
elif realm in ["fil", "fil-v6", "personnel-ens"]: elif realm in ["fil", "fil-v6", "personnel-ens"]:
uldif['objectClass'] = [u'machineFixe'] uldif['objectClass'] = [u'machineFixe']
@ -234,26 +257,43 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
else: raise ValueError("Realm inconnu: %r" % realm) else: raise ValueError("Realm inconnu: %r" % realm)
# On récupère la plage des mids
plage = xrange( *(config.mid[realm]))
# On récupère le premier id libre dans la plages s'il n'est pas # On récupère le premier id libre dans la plages s'il n'est pas
# déjà précisé dans le ldiff # déjà précisé dans le ldiff
mid = uldif.setdefault('mid', [ unicode(self._find_id('mid', plage)) ]) rid = uldif.setdefault('rid', [ unicode(self._find_id('rid', plage)) ])
# La machine peut-elle avoir une ipv4 ?
if 'v6' not in realm: if 'v6' not in realm:
uldif['ipHostNumber'] = [ unicode(crans_utils.ip4_of_mid(int (mid[0]))) ] uldif['ipHostNumber'] = [ unicode(crans_utils.ip4_of_rid(rid[0])) ]
return self._create_entity('mid=%s,%s' % (mid[0], parent), uldif) uldif['ip6HostNumber'] = [ unicode(crans_utils.ip6_of_mac(uldif['macAddress'][0], rid[0])) ]
# On récupère la plage des mids
plage = xrange( *(config.rid[realm]))
# Tout doit disparaître !!
machine = self._create_entity('mid=%s,%s' % (mid[0], parent), uldif)
if machine.may_be(created, self.droits + self._is_parent(machine)):
machine.create()
else:
raise EnvironmentError("Vous n'avez pas le droit de créer cette machine.")
def newAdherent(self, uldif): def newAdherent(self, uldif):
"""Crée un nouvel adhérent""" """Crée un nouvel adhérent"""
aid = uldif.setdefault('aid', [ unicode(self._find_id('aid')) ]) aid = uldif.setdefault('aid', [ unicode(self._find_id('aid')) ])
uldif['objectClass'] = [u'adherent'] uldif['objectClass'] = [u'adherent']
return self._create_entity('aid=%s,%s' % (aid[0], base_dn), uldif) adherent = self._create_entity('aid=%s,%s' % (aid[0], base_dn), uldif)
if adherent.may_be(created, self):
adherent.create()
else:
raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.")
def newClub(self, uldif): def newClub(self, uldif):
"""Crée un nouveau club""" """Crée un nouveau club"""
cid = uldif.setdefault('cid', [ unicode(self._find_id('cid')) ]) cid = uldif.setdefault('cid', [ unicode(self._find_id('cid')) ])
uldif['objectClass'] = [u'club'] uldif['objectClass'] = [u'club']
return self._create_entity('cid=%s,%s' % (cid[0], base_dn), uldif) club = self._create_entity('cid=%s,%s' % (cid[0], base_dn), uldif)
if club.may_be(created, self):
club.create()
else:
raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.")
def newFacture(self, uldif): def newFacture(self, uldif):
"""Crée une nouvelle facture """Crée une nouvelle facture
@ -267,31 +307,53 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
cldif = ldif_to_cldif(uldif, self) cldif = ldif_to_cldif(uldif, self)
# Conversion en ascii # Conversion en ascii
ldif = cldif_to_ldif(cldif) ldif = cldif_to_ldif(cldif)
# Création de la requête LDAP
modlist = addModlist(ldif)
# Requête LDAP de création de l'objet
self.add_s(dn, modlist)
# Renvoi du CransLdapObject # Renvoi du CransLdapObject
return new_cransldapobject(self, dn, mode='w') return new_cransldapobject(self, dn, 'rw', ldif)
def _find_id(self, attr, plage=None):
def _find_id(self, attr, plage = xrange(1, 32000)): '''Trouve un id libre. Si une plage est fournie, cherche
'''Trouve un <attr>id libre dans plage''' l'id dans celle-ci, sinon, prend le plus élevé possible.'''
res = self.search_s(base_dn, 2, '%s=*' % attr, attrlist = [attr]) res = self.search_s(base_dn, ldap.SCOPE_SUBTREE, '%s=*' % attr, attrlist = [attr])
nonfree = [ int(r[1].get(attr)[0]) for r in res if r[1].get(attr) ] nonfree = [ int(r[1].get(attr)[0]) for r in res if r[1].get(attr) ]
nonfree.sort() nonfree.sort()
for i in plage: if plage != None:
if nonfree and nonfree[0] <= i: for i in plage:
while nonfree and nonfree[0] <= i: if i in nonfree:
nonfree = nonfree[1:] continue
else:
break
else: else:
break raise EnvironmentError('Aucun %s libre dans la plage [%d, %d]' %
(attr, plage[0], i))
else: else:
raise EnvironmentError('Aucun %s libre dans la plage [%d, %d]' % i = nonfree[-1]+1
(attr, plage[0], i))
return i return i
def _is_parent(self, obj):
"""
Teste le lien de parenté de l'objet 1 sur l'objet 2.
Retourne une liste qui s'ajoutera à la liste des droits
"""
if obj.dn.endswith(self.dn) and obj.dn != self.dn:
return [parent]
else:
return []
def _is_self(obj1, obj2):
"""
Teste si l'objet qui se binde est celui qui est en cours de modif.
Retourne une liste qui s'ajoutera à la liste des droits
"""
if obj.dn == self.dn:
return [soi]
else:
return []
def new_cransldapobject(conn, dn, mode='ro', ldif = None): def new_cransldapobject(conn, dn, mode='ro', ldif = None):
"""Crée un objet CransLdap en utilisant la classe correspondant à """Crée un objet CransLdap en utilisant la classe correspondant à
@ -317,6 +379,11 @@ class CransLdapObject(object):
"""Classe de base des objets CransLdap. """Classe de base des objets CransLdap.
Cette classe ne devrait pas être utilisée directement.""" Cette classe ne devrait pas être utilisée directement."""
can_be_by = { created: [nounou],
modified: [nounou],
deleted: [nounou],
}
""" Champs uniques et nécessaires """ """ Champs uniques et nécessaires """
ufields = [] ufields = []
@ -348,36 +415,48 @@ class CransLdapObject(object):
self.conn = conn self.conn = conn
self.dn = dn self.dn = dn
orig = {}
if ldif: if ldif:
# Vous précisez un ldif, l'objet est 'ro'
self.mode = 'ro'
self.attrs = ldif self.attrs = ldif
if dn != base_dn: # new_cransldapobject ne donne pas de ldif formaté et utilise un ldif non formaté, donc on formate 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_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é self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = True)
self._modifs = ldif_to_uldif(ldif)
self._modifs = ldif_to_cldif(self._modifs, conn, check_ctxt = False)
orig = ldif
elif dn != base_dn: elif dn != base_dn:
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)
self.dn, self.attrs = res[0] self.dn, self.attrs = res[0]
# Pour test en cas de mode w ou rw
orig = res[0][1]
self.attrs = ldif_to_uldif(self.attrs) self.attrs = ldif_to_uldif(self.attrs)
# L'objet sortant de la base ldap, on ne fait pas de vérifications sur
# l'état des données.
self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False) self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False)
if mode in ['w', 'rw']: self._modifs = ldif_to_cldif(ldif_to_uldif(res[0][1]), conn, check_ctxt = False)
### Vérification que `λv. str(Attr(v))` est bien une projection
### C'est-à-dire que si on str(Attr(str(Attr(v)))) on retombe sur str(Attr(v)) # Je m'interroge sur la pertinence de cette partie, je pense qu'elle n'est
oldif = res[0][1] # pas utile. -- PEB 27/01/2013
nldif = cldif_to_ldif(self.attrs) if mode in ['w', 'rw']:
### Vérification que `λv. str(Attr(v))` est bien une projection
### C'est-à-dire que si on str(Attr(str(Attr(v)))) on retombe sur str(Attr(v))
oldif = orig
nldif = cldif_to_ldif(self.attrs)
for attr, vals in oldif.items():
if nldif[attr] != vals:
for v in nldif[attr]:
if v in vals:
vals.remove(v)
nvals = [nldif[attr][v.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)
for attr, vals in oldif.items():
if nldif[attr] != vals:
for v in nldif[attr]:
if v in vals:
vals.remove(v)
nvals = [nldif[attr][v.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)
self._modifs = ldif_to_cldif(ldif_to_uldif(res[0][1]), conn, check_ctxt = False)
def _get_fields(self): def _get_fields(self):
"""Renvoie la liste des champs LDAP de l'objet""" """Renvoie la liste des champs LDAP de l'objet"""
@ -387,7 +466,7 @@ class CransLdapObject(object):
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.
###ATTENTION : C'est un kludge pour pouvoir continuer à faire "comme avant", ###ATTENTION : C'est un kludge pour pouvoir continuer à faire "comme avant",
### mais on devrait tout recoder pour utiliser l'historique LDAP""" ### mais on devrait tout recoder pour utiliser l'historique LDAP"""
assert isinstance(login, str) or isinstance(login, unicode) assert isinstance(login, str) or isinstance(login, unicode)
assert isinstance(chain, unicode) assert isinstance(chain, unicode)
@ -395,6 +474,16 @@ class CransLdapObject(object):
# Attention, le __setitem__ est surchargé, mais pas .append sur l'historique # Attention, le __setitem__ est surchargé, mais pas .append sur l'historique
self["historique"] = self["historique"] + [new_line] self["historique"] = self["historique"] + [new_line]
def create(self):
"""Crée l'objet dans la base ldap, cette méthode vise à faire en sorte que
l'objet se crée lui-même, si celui qui essaye de le modifier a les droits
de le faire."""
# Création de la requête LDAP
modlist = addModlist(cldif_to_ldif(self.attrs))
# Requête LDAP de création de l'objet
self.add_s(self.dn, modlist)
def save(self): def save(self):
"""Sauvegarde dans la base les modifications apportées à l'objet. """Sauvegarde dans la base les modifications apportées à l'objet.
@ -405,7 +494,10 @@ class CransLdapObject(object):
# On récupère la liste des modifications # On récupère la liste des modifications
modlist = self.get_modlist() modlist = self.get_modlist()
self.conn.modify_s(self.dn, modlist) try:
self.conn.modify_s(self.dn, modlist)
except:
raise EnvironmentError("Impossible de modifier l'objet, peut-être n'existe-t-il pas ?")
# Vérification des modifications # Vérification des modifications
self.attrs = ldif_to_uldif(self.conn.search_s(self.dn, 0)[0][1]) self.attrs = ldif_to_uldif(self.conn.search_s(self.dn, 0)[0][1])
@ -420,6 +512,16 @@ class CransLdapObject(object):
if differences: if differences:
raise EnvironmentError("Les modifications apportées à l'objet %s n'ont pas été correctement sauvegardées\n%s" % (self.dn, differences)) raise EnvironmentError("Les modifications apportées à l'objet %s n'ont pas été correctement sauvegardées\n%s" % (self.dn, differences))
def may_be(self, what, obj):
"""Teste si celui qui est bindé peut effectuer ce qui est dans what, pour
what élément de {create, delete, modify}.
Retourne un booléen
"""
if set(obj.droits).intersection(self.can_be_by[what]) != set([]):
return True
else:
return False
def get_modlist(self): def get_modlist(self):
"""Renvoie un dictionnaire des modifications apportées à l'objet""" """Renvoie un dictionnaire des modifications apportées à l'objet"""
# unicode -> utf-8 # unicode -> utf-8
@ -475,9 +577,9 @@ class CransLdapObject(object):
if res != []: if res != []:
author = res[0].compte() author = res[0].compte()
if attrs['reqType'][0] == 'delete': if attrs['reqType'][0] == deleted:
out.append(u"%s : [%s] Suppression" % (date, author)) out.append(u"%s : [%s] Suppression" % (date, author))
elif attrs['reqType'][0] == 'modify': elif attrs['reqType'][0] == modified:
fields = {} fields = {}
for mod in attrs['reqMod']: for mod in attrs['reqMod']:
mod = mod.decode('utf-8') mod = mod.decode('utf-8')
@ -534,6 +636,11 @@ class CransLdapObject(object):
class proprio(CransLdapObject): class proprio(CransLdapObject):
u""" Un propriétaire de machine (adhérent, club…) """ u""" Un propriétaire de machine (adhérent, club…) """
can_be_by = { created: [nounou, bureau, cableur],
modified: [nounou, bureau, soi, cableur],
deleted: [nounou, bureau],
}
ufields = [ 'nom', 'chbre' ] ufields = [ 'nom', 'chbre' ]
mfields = [ 'paiement', 'info', 'blacklist', 'controle'] mfields = [ 'paiement', 'info', 'blacklist', 'controle']
ofields = [] ofields = []
@ -623,11 +730,16 @@ class proprio(CransLdapObject):
class machine(CransLdapObject): class machine(CransLdapObject):
u""" Une machine """ u""" Une machine """
can_be_by = { created: [nounou, bureau, cableur, parent],
modified: [nounou, bureau, cableur, parent],
deleted: [nounou, bureau, cableur, parent],
}
ufields = ['mid', 'macAddress', 'host', 'midType'] ufields = ['mid', 'macAddress', 'host', 'midType']
ofields = [] ofields = ['rid']
mfields = ['info', 'blacklist', 'hostAlias', 'exempt', mfields = ['info', 'blacklist', 'hostAlias', 'exempt',
'portTCPout', 'portTCPin', 'portUDPout', 'portUDPin','sshFingerprint'] 'portTCPout', 'portTCPin', 'portUDPout', 'portUDPin','sshFingerprint', 'ipHostNumber', 'ip6HostNumber']
xfields = ['ipHostNumber'] xfields = []
def __init__(self, conn, dn, mode='ro', ldif = None): def __init__(self, conn, dn, mode='ro', ldif = None):
super(machine, self).__init__(conn, dn, mode, ldif) super(machine, self).__init__(conn, dn, mode, ldif)
@ -746,14 +858,26 @@ class machineWifi(machine):
ufields = machine.ufields + ['ipsec'] ufields = machine.ufields + ['ipsec']
class machineCrans(machine): class machineCrans(machine):
can_be_by = { created: [nounou],
modified: [nounou],
deleted: [nounou],
}
ufields = machine.ufields + ['prise'] ufields = machine.ufields + ['prise']
ofields = machine.ofields + ['nombrePrises'] ofields = machine.ofields + ['nombrePrises']
class borneWifi(machine): class borneWifi(machine):
can_be_by = { created: [nounou],
modified: [nounou],
deleted: [nounou],
}
ufields = machine.ufields + ['canal', 'puissance', 'hotspot', ufields = machine.ufields + ['canal', 'puissance', 'hotspot',
'prise', 'positionBorne', 'nvram'] 'prise', 'positionBorne', 'nvram']
class facture(CransLdapObject): class facture(CransLdapObject):
can_be_by = { created: [nounou, bureau, cableur],
modified: [nounou, bureau, cableur],
deleted: [nounou, bureau, cableur],
}
ufields = ['fid', 'modePaiement', 'recuPaiement'] ufields = ['fid', 'modePaiement', 'recuPaiement']
class service(CransLdapObject): pass class service(CransLdapObject): pass