root/update-fotos-ldap/trunk/actualizafotosldap.py @ 259
47 | pkom | #!/usr/bin/python -tt
|
|
# -*- coding: utf-8 -*-
|
|||
52 | pkom | # Project: update-fotos-ldap
|
|
# Module: actualizafotoldap.py
|
|||
# Purpose: Actualiza fotos de alumnos en el directorio LDAP desde datos de Rayuela
|
|||
# Language: Python 2.5
|
|||
# Date: 03-Feb-2011.
|
|||
# Ver: 07-Feb-2011.
|
|||
# Author: Francisco Mora Sánchez
|
|||
# Copyright: 2011 - Francisco Mora Sánchez <adminies.maestrojuancalero@edu.juntaextremadura.net>
|
|||
#
|
|||
# update-fotos-ldap is free software: you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation, either version 3 of the License, or
|
|||
# (at your option) any later version.
|
|||
53 | pkom | # update-fotos-ldap is distributed in the hope that it will be useful,
|
|
52 | pkom | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
# You should have received a copy of the GNU General Public License
|
|||
53 | pkom | # along with update-fotos-ldap. If not, see <http://www.gnu.org/licenses/>.
|
|
47 | pkom | ||
""" 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()
|