|
#!/usr/bin/python -tt
|
|
# -*- coding: utf-8 -*-
|
|
|
|
""" Programa para actualizar las fotos de los alumnos
|
|
en el servidor ldap a partir del fichero de alumnos generado por
|
|
Rayuela. Tambien depura las entradas del grupo students, eliminando
|
|
aquellas membresias cuyos uids no están en la rama People, si lo queremos.
|
|
|
|
Necesita paquetes instalados python python-ldap python-imaging
|
|
|
|
En los servidores de terminales está todo instalado excepto python-ldap
|
|
que se carga ejecutando la orden como superusuario:
|
|
|
|
apt-get install python-ldap
|
|
|
|
Uso: crearemos una carpeta donde copiaremos este programa y además
|
|
pondremos el ZIP generado por Rayuela, denominado
|
|
ExportacionDatosAlumnado.zip, ejecutaremos el script pasando como
|
|
parámetros como mínimo la contraseña del administrador ldap, por defecto
|
|
el programa establece el URI ldap de nuesto servidor ldap y la ruta a la
|
|
carpeta con el ZIP de rayuela en la propia carpeta.
|
|
|
|
Existe un parámetro, denominado --depurastudents {on|off} el cual si lo
|
|
establecemos a on, eliminará del grupos students de ldap aquellas entradas
|
|
que no tienen un uid en el grupo People, normalmente son residuos de
|
|
uids de alumnos que ya no están en el centro.
|
|
|
|
OJO: Realizar copias de seguridad de ldap antes de ejecutar el script...
|
|
|
|
|
|
Francisco Mora Sánchez
|
|
IES Maestro Juan Calero
|
|
adminies.maestrojuancalero@edu.juntaextremadura.net
|
|
|
|
|
|
"""
|
|
|
|
import sys,os,shutil,zipfile,ldap,Image,glob,time,copy
|
|
import ldap.modlist as modlist
|
|
|
|
# Set debugging level
|
|
#ldap.set_option(ldap.OPT_DEBUG_LEVEL,255)
|
|
#ldap.set_option(ldap.OPT_DEBUG_LEVEL,0)
|
|
#ldapmodule_trace_level = 1
|
|
#ldapmodule_trace_level = 0
|
|
#ldapmodule_trace_file = sys.stderr
|
|
|
|
def descomprime_zip_en_directorio(fichero, carpeta):
|
|
"""Funcion que dado un fichero zip lo descomprime en la
|
|
carpeta indicada."""
|
|
if os.path.exists(carpeta):
|
|
shutil.rmtree(carpeta)
|
|
os.mkdir(carpeta, 0777)
|
|
zfobj = zipfile.ZipFile(fichero)
|
|
for name in zfobj.namelist():
|
|
if name.endswith('/'):
|
|
os.mkdir(os.path.join(carpeta, name))
|
|
else:
|
|
outfile = open(os.path.join(carpeta, name), 'wb')
|
|
outfile.write(zfobj.read(name))
|
|
outfile.close()
|
|
|
|
def lee_parametros(lista,params):
|
|
"""Funcion que crea un diccionario para leer el valor de los
|
|
parametros que se pasan en la linea de comandos."""
|
|
for i in range(1,len(lista)):
|
|
if lista[i][:2] == "--":
|
|
#veamos si tiene valor
|
|
if i+1 < len(lista) and lista[i+1] <> "--":
|
|
#estamos en un parametro y valor
|
|
params[lista[i][2:]] = lista[i+1]
|
|
|
|
def conecta_a_ldap(uri,contra):
|
|
""" Conexión al servidor ldap
|
|
"""
|
|
try:
|
|
usuario_admin = "cn=admin,ou=People,dc=instituto,dc=extremadura,dc=es"
|
|
#conexion_ldap = ldap.initialize(uri,trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
|
|
conexion_ldap = ldap.initialize(uri)
|
|
conexion_ldap.protocol_version=ldap.VERSION3
|
|
conexion_ldap.bind_s(usuario_admin, contra)
|
|
except ldap.LDAPError, e:
|
|
return None
|
|
|
|
return conexion_ldap
|
|
|
|
def desconecta_de_ldap(conexion_ldap):
|
|
""" Desconectar del servidor ldap
|
|
"""
|
|
conexion_ldap.unbind_s()
|
|
|
|
def buscar_en_ldap(conexion_ldap, filtro, atributos, baseDN = "ou=People,dc=instituto,dc=extremadura,dc=es", alcance = ldap.SCOPE_SUBTREE):
|
|
## Realiza una consulta al servidor ldap, utilizando un filtro y delvolviendo unos atributos, la salida es una lista de tuplas
|
|
try:
|
|
return conexion_ldap.search_s(baseDN, alcance, filtro, atributos)
|
|
except:
|
|
pass
|
|
else:
|
|
return []
|
|
|
|
def existeArchivoImagen(archivo):
|
|
""" Funcion que determina si existe un archivo
|
|
"""
|
|
return os.path.exists(archivo)
|
|
|
|
def main():
|
|
params = {}
|
|
lista = sys.argv
|
|
lee_parametros(lista,params)
|
|
#comprobaremos las combinaciones de parametros en linea de comandos
|
|
if not params.has_key("contra"):
|
|
print 'uso: ./actualizafotosldap.py --contra contraseña_ldap [--depurastudents {on,off}] [--urildap ldaps://servidor_ldap:puerto] [--ruta rutaalarchivozipderayuela]'
|
|
sys.exit(1)
|
|
if not params.has_key("urildap"):
|
|
print "No se ha establecido el servidor ldap, usando por defecto 'ldaps://ldap:636'"
|
|
params["urildap"] = "ldaps://ldap:636"
|
|
if not params.has_key("ruta"):
|
|
print "No se ha establecido la ruta del archivo, usando por defecto './ExportacionDatosAlumnado.zip'"
|
|
params["ruta"] = "./ExportacionDatosAlumnado.zip"
|
|
if not params.has_key("depurastudents"):
|
|
print "No se ha establecido depurastudents, no se eliminarán alumnos del grupo students que no existan en la rama People"
|
|
params["depurastudents"] = "off"
|
|
|
|
#Emite mensajes
|
|
print "Los valores pasado son los siguientes:"
|
|
print "URI Servidor ldap: ",params["urildap"]
|
|
print "Ruta al archivo: ",params["ruta"]
|
|
print "Eliminar alumn@s del grupo students no existentes en People:",params["depurastudents"]
|
|
print "Si estás conforme, pulsa intro, sino pulsa CTRL+C y aborta la ejecución"
|
|
raw_input()
|
|
#Comprobemos la existencia del archivo
|
|
if not os.path.exists(params["ruta"]):
|
|
print params['ruta']," no existe"
|
|
exit(2)
|
|
print "Intentando la conexión al URI de ldap '"+params["urildap"]+"'"
|
|
|
|
conexion_ldap = conecta_a_ldap(params["urildap"],params["contra"])
|
|
|
|
if conexion_ldap == None:
|
|
print "Error en la conexión al servidor ldap:",params["urildap"],"revise nombre servidor y/o contraseña"
|
|
exit(3)
|
|
|
|
#busqueda de los alumnos(pertenecen al grupo students
|
|
resultado_busqueda_alumnos = buscar_en_ldap(conexion_ldap, 'member=*', ['member','memberUid'],baseDN="cn=students,ou=Group,dc=instituto,dc=extremadura,dc=es")
|
|
|
|
if resultado_busqueda_alumnos is None:
|
|
print "No existen alumnos que pertenezcan al grupo students..."
|
|
exit(4)
|
|
|
|
print "Descomprimiendo ZIP de alumnos de rayuela en la carpeta actual..."
|
|
descomprime_zip_en_directorio(params["ruta"], "temp")
|
|
|
|
|
|
alumnos = resultado_busqueda_alumnos[0][1]["memberUid"]
|
|
encontrados = 0
|
|
alumnos_a_borrar_grupo_students = []
|
|
print "Total de alumnos encontrados",len(alumnos)
|
|
print "Procesando alumnos..."
|
|
separador = os.sep
|
|
tipos_imagen = ['.jpg', '.png', '.jpeg' , '.bmp', '.tiff','.jpg']
|
|
alumnos_sin_foto = []
|
|
for alumno in alumnos:
|
|
datos_alumno = buscar_en_ldap(conexion_ldap, 'uid='+alumno, ['cn','uid','employeeNumber'])
|
|
if len(datos_alumno) == 0:
|
|
alumnos_a_borrar_grupo_students.append(alumno)
|
|
else:
|
|
encontrados += 1
|
|
try:
|
|
if not datos_alumno[0][1].has_key('employeeNumber'):
|
|
print "El alumno",alumno,"no tiene atributo 'employeeNumber'... saltando"
|
|
continue
|
|
if not datos_alumno[0][1].has_key('uid'):
|
|
print "El alumno",alumno,"no tiene atributo 'uid'... saltando"
|
|
continue
|
|
|
|
nie = datos_alumno[0][1]['employeeNumber'][0]
|
|
print "Actualizando foto del alumno",datos_alumno[0][1]['cn'][0],'Nie:',nie
|
|
archivo_imagen_sin_tipo = '.'+separador+'temp'+separador+nie
|
|
encontrada_foto = False
|
|
for patron in tipos_imagen:
|
|
archivo_imagen = archivo_imagen_sin_tipo+patron
|
|
if existeArchivoImagen(archivo_imagen):
|
|
print "encontrado archivo de imagen",archivo_imagen
|
|
encontrada_foto = True
|
|
break
|
|
if not encontrada_foto:
|
|
alumnos_sin_foto.append(datos_alumno[0][1]['cn'][0]+' Nie:'+nie)
|
|
print "alumno sin archivo de imagen"
|
|
continue
|
|
|
|
foto = Image.open(archivo_imagen)
|
|
if (not foto.format == 'JPEG'):
|
|
foto.save('foto', 'JPEG')
|
|
foto = Image.open('foto')
|
|
foto.thumbnail((80, 100), Image.ANTIALIAS)
|
|
foto.save('foto', 'JPEG')
|
|
uid = datos_alumno[0][1]['uid'][0]
|
|
dn='uid='+uid+',ou=People,dc=instituto,dc=extremadura,dc=es'
|
|
atributos = [ (ldap.MOD_DELETE,'jpegPhoto',None) ]
|
|
conexion_ldap.modify_s(dn,atributos)
|
|
atributos = [ (ldap.MOD_ADD,'jpegPhoto',open('foto',"rb").read()) ]
|
|
conexion_ldap.modify_s(dn,atributos)
|
|
except ldap.LDAPError,e:
|
|
pass
|
|
#puede pasar que no exista el nie o bien no tenga atributo, pero
|
|
#la acción es ignorar los errores...
|
|
|
|
os.remove('foto')
|
|
|
|
print "Se han procesado",encontrados,"alumn@s..."
|
|
print ""
|
|
print ""
|
|
print "No se han encontrado las fotos de estos",len(alumnos_sin_foto),"alumn@s"
|
|
print "Estos son los alumno@s sin foto:"
|
|
for asinfoto in alumnos_sin_foto:
|
|
print asinfoto
|
|
|
|
print ""
|
|
print ""
|
|
print "No se han encontrado en la rama People",len(alumnos)-encontrados,"alumn@s"
|
|
if params["depurastudents"] == "on" and len(alumnos) > encontrados:
|
|
print ""
|
|
print ""
|
|
print "Procediendo al borrado de alumnos del grupo students no existentes en la rama People"
|
|
resultado_busqueda_alumnos_modificado = copy.deepcopy(resultado_busqueda_alumnos)
|
|
for aborrar in alumnos_a_borrar_grupo_students:
|
|
print "Borrando membresía de students para el alumno no existente ...",aborrar
|
|
#Eliminamos de la lista de memberUid ese alumno
|
|
resultado_busqueda_alumnos_modificado[0][1]['memberUid'].remove(aborrar)
|
|
#Eliminamos de la lista de member ese alumno
|
|
resultado_busqueda_alumnos_modificado[0][1]['member'].remove('uid='+aborrar+',ou=People,dc=instituto,dc=extremadura,dc=es')
|
|
|
|
print "Ejecutando modificación en el árbol ldap..."
|
|
dn = 'cn=students,ou=Group,dc=instituto,dc=extremadura,dc=es'
|
|
ldif = modlist.modifyModlist(resultado_busqueda_alumnos[0][1],resultado_busqueda_alumnos_modificado[0][1])
|
|
conexion_ldap.modify_s(dn,ldif)
|
|
|
|
print ""
|
|
print ""
|
|
print "Eliminando carpeta temporal..."
|
|
shutil.rmtree("temp")
|
|
print "Desconectando del servidor ldap '"+params["urildap"]+"'"
|
|
desconecta_de_ldap(conexion_ldap)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|