mirror of https://github.com/interlegis/sigi.git
Sesóstris Vieira
1 year ago
17 changed files with 814 additions and 823 deletions
@ -0,0 +1,136 @@ |
|||
import ldap |
|||
from django.conf import settings |
|||
from django.utils.translation import gettext as _ |
|||
from django_auth_ldap.config import _DeepStringCoder |
|||
from django_extensions.management.jobs import DailyJob |
|||
from sigi.apps.utils.management.jobs import JobReportMixin |
|||
from sigi.apps.servidores.models import Servico, Servidor |
|||
from sigi.apps.servidores.utils import ( |
|||
servidor_update_from_ldap, |
|||
servidor_create_or_update, |
|||
user_staff_and_group, |
|||
) |
|||
|
|||
|
|||
class Job(JobReportMixin, DailyJob): |
|||
help = _("Sincroniza servidores com o ldap") |
|||
report_data = [] |
|||
|
|||
def do_job(self): |
|||
coder = _DeepStringCoder("utf8") |
|||
|
|||
connect = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) |
|||
connect.protocol_version = 3 |
|||
connect.set_option(ldap.OPT_REFERRALS, 0) |
|||
connect.simple_bind_s( |
|||
settings.AUTH_LDAP_BIND_DN, settings.AUTH_LDAP_BIND_PASSWORD |
|||
) |
|||
page_control = ldap.controls.SimplePagedResultsControl( |
|||
True, size=1000, cookie="" |
|||
) |
|||
|
|||
total_ldap = 0 |
|||
total_create = 0 |
|||
total_update = 0 |
|||
total_deactive = 0 |
|||
|
|||
servidores = { |
|||
s.ldap_dn: s |
|||
for s in Servidor.objects.exclude(ldap_dn="").exclude(externo=True) |
|||
} |
|||
|
|||
while True: |
|||
response = connect.search_ext( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_ONELEVEL, |
|||
settings.LDAP_GET_ALL_USERS, |
|||
serverctrls=[page_control], |
|||
) |
|||
rtype, rdata, rmsgid, serverctrls = connect.result3(response) |
|||
decoded_data = coder.decode(rdata) |
|||
|
|||
controls = [ |
|||
control |
|||
for control in serverctrls |
|||
if control.controlType |
|||
== ldap.controls.SimplePagedResultsControl.controlType |
|||
] |
|||
if not controls: |
|||
raise Exception("The LDAP server ignores RFC 2696 control") |
|||
|
|||
for dn, ldap_user in decoded_data: |
|||
total_ldap += 1 |
|||
resp, servidor = servidor_create_or_update( |
|||
ldap_attrs=ldap_user |
|||
) |
|||
if servidor.user: |
|||
user_staff_and_group(servidor.user, ldap_user) |
|||
if resp == servidor_create_or_update.UPDATED: |
|||
total_update += 1 |
|||
self.report_data.append( |
|||
_(f"{servidor.nome_completo} atualizado") |
|||
) |
|||
elif resp == servidor_create_or_update.CREATED: |
|||
total_create += 1 |
|||
self.report_data.append( |
|||
_(f"{servidor.nome_completo} criado") |
|||
) |
|||
|
|||
if dn in servidores: |
|||
del servidores[dn] |
|||
|
|||
if not controls[0].cookie: |
|||
break |
|||
page_control.cookie = controls[0].cookie |
|||
|
|||
for dn, servidor in servidores.items(): |
|||
rdata = connect.search_s( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_SUBTREE, |
|||
ldap.filter.filter_format("(distinguishedName=%s)", [dn]), |
|||
) |
|||
|
|||
if rdata: |
|||
ldap_attrs = coder.decode(rdata[0][1]) |
|||
if servidor.user: |
|||
user_staff_and_group(servidor.user, ldap_attrs) |
|||
if ( |
|||
servidor_update_from_ldap(servidor, ldap_attrs) |
|||
== servidor_create_or_update.UPDATED |
|||
): |
|||
total_update += 1 |
|||
else: |
|||
if servidor.user: |
|||
servidor.user.is_active = False |
|||
total_deactive += 1 |
|||
|
|||
# Reporta servidores que não estão no LDAP e também não são externos |
|||
|
|||
self.report_data.append("") |
|||
self.report_data.append( |
|||
_( |
|||
"Servidores que não estão no LDAP e também não estão marcados " |
|||
"como Externos" |
|||
) |
|||
) |
|||
self.report_data.append( |
|||
_( |
|||
"=============================================================" |
|||
"=============" |
|||
) |
|||
) |
|||
self.report_data.append("") |
|||
|
|||
for s in Servidor.objects.filter( |
|||
ldap_dn="", externo=False, sigi=False |
|||
).order_by("nome_completo"): |
|||
self.report_data.append(s.nome_completo) |
|||
|
|||
self.report_data.append("") |
|||
self.report_data.append(_("RESUMO")) |
|||
self.report_data.append(_("======")) |
|||
self.report_data.append("") |
|||
self.report_data.append(_(f"{total_ldap} usuários lidos do LDAP")) |
|||
self.report_data.append(_(f"{total_create} novos servidores criados")) |
|||
self.report_data.append(_(f"{total_update} servidores atualizados")) |
|||
self.report_data.append(_(f"{total_deactive} usuários desativados")) |
@ -1,70 +1,61 @@ |
|||
# coding: utf-8 |
|||
from django.contrib.auth.models import User, Group |
|||
from sigi.apps.servidores.models import Servidor |
|||
from django.core.management.base import BaseCommand |
|||
from sigi.apps.servidores.models import Servidor |
|||
from sigi.apps.servidores.utils import mescla_servidores |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = "Transfere os dados do servidor OLD para o servidor NEW." |
|||
args = "old_id new_id" |
|||
help = "Transfere os dados do servidor SOURCE para o servidor TARGET." |
|||
|
|||
def add_arguments(self, parser): |
|||
parser.add_argument( |
|||
"source_id", |
|||
help="ID do servidor que será removido", |
|||
nargs=1, |
|||
type=int, |
|||
) |
|||
parser.add_argument( |
|||
"target_id", |
|||
help="ID do servidor que receberá os dados do que será removido", |
|||
nargs=1, |
|||
type=int, |
|||
) |
|||
|
|||
def handle(self, *args, **options): |
|||
if len(args) != 2: |
|||
self.stderr.write("Informe old_id e new_id") |
|||
return |
|||
|
|||
old_id = args[0] |
|||
new_id = args[1] |
|||
source_id = options["source_id"][0] |
|||
target_id = options["target_id"][0] |
|||
|
|||
old = Servidor.objects.get(id=old_id) |
|||
new = Servidor.objects.get(id=new_id) |
|||
try: |
|||
servidor_source = Servidor.objects.get(id=source_id) |
|||
except Servidor.DoesNotExist: |
|||
self.stdout.write( |
|||
self.style.WARNING(f"Não existe servidor com ID {source_id}") |
|||
) |
|||
return |
|||
try: |
|||
servidor_target = Servidor.objects.get(id=target_id) |
|||
except Servidor.DoesNotExist: |
|||
self.stdout.write( |
|||
self.style.WARNING(f"Não existe servidor com ID {target_id}") |
|||
) |
|||
return |
|||
|
|||
self.stdout.write( |
|||
self.style.WARNING( |
|||
"Transferir dados de {old_name} para {new_name}".format( |
|||
old_name=old.nome_completo, new_name=new.nome_completo |
|||
f"Transferir dados de {servidor_source.nome_completo} " |
|||
f"para {servidor_target.nome_completo}" |
|||
) |
|||
) |
|||
) |
|||
|
|||
self.stdout.write("\t* Transferindo a carteira de atendimento...") |
|||
for casa in old.casas_que_gerencia.all(): |
|||
new.casas_que_gerencia.add(casa) |
|||
old.casas_que_gerencia.remove(casa) |
|||
|
|||
self.stdout.write("\t* Transferindo ocorrências registradas...") |
|||
old.ocorrencia_set.all().update(servidor_registro=new) |
|||
|
|||
self.stdout.write("\t* Transferindo comentários de ocorrências...") |
|||
old.comentario_set.all().update(usuario=new) |
|||
|
|||
self.stdout.write("\t* Transferindo convênios geridos...") |
|||
old.convenio_set.all().update(servidor_gestao=new) |
|||
|
|||
self.stdout.write("\t* Transferindo convênios acompanhados...") |
|||
old.convenio_set.all().update(acompanha=new) |
|||
|
|||
self.stdout.write("\t* Transferindo participação em eventos...") |
|||
old.equipe_evento.all().update(membro=new) |
|||
resp = input("Continuar? [sim / NÃO]: ") |
|||
|
|||
self.stdout.write("\t* Transferindo convites para eventos...") |
|||
old.convite_set.all().update(servidor=new) |
|||
|
|||
self.stdout.write("\t* Transferindo diagnósticos...") |
|||
old.diagnostico_set.all().update(responsavel=new) |
|||
|
|||
self.stdout.write("\t* Transferindo participação em diagnósticos...") |
|||
old.equipe_set.all().update(membro=new) |
|||
|
|||
self.stdout.write("\t* Transferindo dados de autenticação...") |
|||
if resp.lower() != "sim": |
|||
self.stdout.write(self.style.NOTICE("Abortado!")) |
|||
return |
|||
|
|||
if new.user: |
|||
old.user.logentry_set.all().update(user=new) |
|||
old.user.delete() |
|||
else: |
|||
new.user = old.user |
|||
new.save() |
|||
old.user = None |
|||
old.save() |
|||
mescla_servidores( |
|||
servidor_source=servidor_source, |
|||
servidor_target=servidor_target, |
|||
verbose=True, |
|||
) |
|||
|
|||
self.stdout.write("Concluído!") |
|||
|
@ -0,0 +1,62 @@ |
|||
from django.contrib.auth.models import User |
|||
from django.core.management.base import BaseCommand |
|||
from sigi.apps.servidores.models import Servidor |
|||
from sigi.apps.servidores.utils import mescla_users |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = "Transfere os dados do usuário SOURCE para o usuário TARGET." |
|||
|
|||
def add_arguments(self, parser): |
|||
parser.add_argument( |
|||
"source_name", |
|||
help="username do usuário que será removido", |
|||
nargs=1, |
|||
type=str, |
|||
) |
|||
parser.add_argument( |
|||
"target_name", |
|||
help="username do usuário que receberá os dados do que será removido", |
|||
nargs=1, |
|||
type=str, |
|||
) |
|||
|
|||
def handle(self, *args, **options): |
|||
source_name = options["source_name"][0] |
|||
target_name = options["target_name"][0] |
|||
|
|||
try: |
|||
user_source = User.objects.get(username__iexact=source_name) |
|||
except User.DoesNotExist: |
|||
self.stdout.write( |
|||
self.style.WARNING(f"Não existe o usuário {source_name}") |
|||
) |
|||
return |
|||
try: |
|||
user_target = User.objects.get(username__iexact=target_name) |
|||
except User.DoesNotExist: |
|||
self.stdout.write( |
|||
self.style.WARNING(f"Não existe o usuário {target_name}") |
|||
) |
|||
return |
|||
|
|||
self.stdout.write( |
|||
self.style.WARNING( |
|||
f"Transferir dados de {user_source.get_full_name()} " |
|||
f"para {user_target.get_full_name()}" |
|||
) |
|||
) |
|||
|
|||
resp = input("Continuar? [sim / NÃO]: ") |
|||
|
|||
if resp.lower() != "sim": |
|||
self.stdout.write(self.style.NOTICE("Abortado!")) |
|||
return |
|||
|
|||
mescla_users( |
|||
user_source=user_source, |
|||
user_target=user_target, |
|||
verbose=True, |
|||
) |
|||
|
|||
self.stdout.write("Concluído!") |
@ -1,247 +0,0 @@ |
|||
# coding= utf-8 |
|||
import csv |
|||
import re |
|||
|
|||
from datetime import datetime |
|||
from django.contrib.auth.models import User |
|||
from django.core.management.base import BaseCommand |
|||
from django.utils.translation import gettext as _ |
|||
|
|||
from sigi.apps.contatos.models import Municipio |
|||
from sigi.apps.servidores.models import Servidor, Servico, Subsecretaria |
|||
|
|||
|
|||
# Funcao.objects.all().delete() |
|||
# Ferias.objects.all().delete() |
|||
# Licenca.objects.all().delete() |
|||
# for u in User.objects.filter(date_joined__gte=datetime(2011, 12, 9, 10, 58, 49, 83734)).all(): |
|||
# u.servidor_set.all().delete() |
|||
# u.delete() |
|||
|
|||
|
|||
class MigrationError(Exception): |
|||
pass |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = _("Migra usuários do antigo Sistema de RH") |
|||
|
|||
def to_date(self, data): |
|||
return datetime.strptime(data, "%Y-%m-%d 00:00:00") |
|||
|
|||
def handle(self, *args, **options): |
|||
reader = csv.reader( |
|||
open("/tmp/pessoal.csv"), delimiter=",", quotechar='"' |
|||
) |
|||
|
|||
BRASILIA = Municipio.objects.get(codigo_ibge=5300108) |
|||
|
|||
# Read the column names from the first line of the file |
|||
fields = reader.next() |
|||
for row in reader: |
|||
# cria um dict com a primeira e a linha atual |
|||
pessoa = zip(fields, row) |
|||
p = {} |
|||
for name, value in pessoa: |
|||
p[name] = value.strip() |
|||
|
|||
user = None |
|||
if not p["email"]: |
|||
username = "" |
|||
email = "" |
|||
elif not ("@interlegis" in p["email"]): |
|||
username = p["email"].split("@")[0].strip().lower() |
|||
email = "" |
|||
else: |
|||
username = p["email"].split("@")[0].strip().lower() |
|||
email = username + "@interlegis.leg.br" |
|||
|
|||
# buscar usuário e servidor da linha atual |
|||
try: |
|||
# procuro o usuario por email do interlegis |
|||
if email: |
|||
try: |
|||
user = User.objects.get(email=email) |
|||
except User.DoesNotExist: |
|||
email = username + "@interlegis.leg.br" |
|||
try: |
|||
user = User.objects.get(email=email) |
|||
except User.DoesNotExist: |
|||
pass |
|||
|
|||
if not user and username: |
|||
try: |
|||
user = User.objects.get(username=username) |
|||
except User.DoesNotExist: |
|||
try: |
|||
user = User.objects.get(username=username + "__") |
|||
except User.DoesNotExist: |
|||
pass |
|||
|
|||
if not user: |
|||
if not username: |
|||
raise MigrationError |
|||
|
|||
if not email: |
|||
# cria um username a partir do email sem |
|||
# colidir com os usuarios ldap |
|||
username = username + "__" |
|||
|
|||
names = p["nome_completo"].split(" ") |
|||
first_name = names[0] |
|||
last_name = " ".join(names[1:]) |
|||
|
|||
user = User.objects.create( |
|||
username=username, |
|||
email=email, |
|||
first_name=first_name, |
|||
last_name=last_name[:30], |
|||
is_active=False, |
|||
) |
|||
|
|||
servidor = user.servidor |
|||
except Servidor.DoesNotExist: |
|||
servidor = Servidor.objects.create( |
|||
user=user, |
|||
nome_completo="%s %s" % (user.first_name, user.last_name), |
|||
) |
|||
except MigrationError as e: |
|||
continue |
|||
|
|||
# mapeando dados simples |
|||
servidor.nome_completo = p["nome_completo"] |
|||
servidor.cpf = p["cpf"] |
|||
servidor.rg = p["identidade"] |
|||
servidor.apelido = p["username"] |
|||
servidor.matricula = p["matricula"] |
|||
servidor.ato_exoneracao = p["ato_exoneracao"] |
|||
servidor.ato_numero = p["ato_numero"] |
|||
servidor.ramal = p["ramal"] |
|||
|
|||
if p["email"] and not "@interlegis" in p["email"]: |
|||
servidor.email_pessoal = p["email"] |
|||
|
|||
if p["inativo"] == "-1": |
|||
servidor.user.is_active = False |
|||
else: |
|||
servidor.user.is_active = True |
|||
servidor.user.save() |
|||
|
|||
if p["de_fora"] == "-1": |
|||
servidor.de_fora = True |
|||
else: |
|||
servidor.de_fora = False |
|||
|
|||
if p["sexo"].upper() == "M": |
|||
servidor.sexo = "M" |
|||
elif p["sexo"].upper() == "F": |
|||
servidor.sexo = "F" |
|||
|
|||
if p["turno"] == "1": |
|||
servidor.turno = "M" |
|||
elif p["turno"] == "2": |
|||
servidor.turno = "T" |
|||
elif p["turno"] == "3": |
|||
servidor.turno = "N" |
|||
|
|||
if p["aniversario"]: |
|||
servidor.data_nascimento = self.to_date(p["aniversario"]) |
|||
|
|||
if p["data_nomeacao"]: |
|||
servidor.data_nomeacao = self.to_date(p["data_nomeacao"]) |
|||
|
|||
if p["secretaria_sigla"]: |
|||
if " - " in p["secretaria_nome"]: |
|||
secretaria_nome = p["secretaria_nome"].split(" - ")[1] |
|||
else: |
|||
secretaria_nome = p["secretaria_nome"] |
|||
|
|||
secretaria = Subsecretaria.objects.get_or_create( |
|||
sigla=p["secretaria_sigla"], nome=secretaria_nome |
|||
)[0] |
|||
|
|||
if " - " in p["servico_nome"]: |
|||
servico_nome = p["servico_nome"].split(" - ")[1] |
|||
else: |
|||
servico_nome = p["servico_nome"] |
|||
|
|||
servico = Servico.objects.get_or_create( |
|||
sigla=p["servico_sigla"], nome=servico_nome |
|||
)[0] |
|||
|
|||
servico.subsecretaria = secretaria |
|||
servico.save() |
|||
servidor.servico = servico |
|||
|
|||
if p["telefone"]: |
|||
try: |
|||
t = servidor.telefones.get(numero=p["telefone"]) |
|||
except: |
|||
t = servidor.telefones.create(numero=p["telefone"]) |
|||
t.tipo = "F" |
|||
t.save() |
|||
|
|||
if p["celular"]: |
|||
try: |
|||
t = servidor.telefones.get(numero=p["celular"]) |
|||
except: |
|||
t = servidor.telefones.create(numero=p["celular"]) |
|||
t.tipo = "M" |
|||
t.save() |
|||
|
|||
if p["endereco"]: |
|||
try: |
|||
e = servidor.endereco.get(logradouro=p["endereco"]) |
|||
except: |
|||
e = servidor.endereco.create(logradouro=p["endereco"]) |
|||
e.municipio = BRASILIA |
|||
e.bairro = p["cidade"] # bizarro mas é isso mesmo |
|||
e.cep = re.sub("\D", "", p["cep"]) |
|||
e.save() |
|||
|
|||
servidor.apontamentos = p["apontamentos"] |
|||
servidor.obs = p["obs"] |
|||
|
|||
if p["cargo"] or p["funcao"]: |
|||
funcao = servidor.funcao_set.get_or_create( |
|||
funcao=p["funcao"], |
|||
cargo=p["cargo"], |
|||
)[0] |
|||
|
|||
if p["data_bap_entrada"]: |
|||
funcao.data_bap_entrada = self.to_date( |
|||
p["data_bap_entrada"] |
|||
) |
|||
|
|||
if p["data_bap_saida"]: |
|||
funcao.data_bap_saida = self.to_date(p["data_bap_saida"]) |
|||
|
|||
if p["data_entrada"]: |
|||
funcao.inicio_funcao = self.to_date(p["data_entrada"]) |
|||
|
|||
if p["data_saida"]: |
|||
funcao.fim_funcao = self.to_date(p["data_saida"]) |
|||
|
|||
funcao.bap_entrada = p["bap_entrada"] |
|||
funcao.bap_saida = p["bap_saida"] |
|||
funcao.save() |
|||
|
|||
if re.search(r"estagi.ri[o|a]", p["cargo"], re.I): # XXX i18n |
|||
# TODO inserir dados de estagio |
|||
pass |
|||
|
|||
if p["inicio_ferias"] and p["final_ferias"]: |
|||
servidor.ferias_set.get_or_create( |
|||
inicio_ferias=self.to_date(p["inicio_ferias"]), |
|||
fim_ferias=self.to_date(p["final_ferias"]), |
|||
obs=p["obs_ferias"], |
|||
) |
|||
|
|||
if p["inicio_licenca"] and p["fim_licenca"]: |
|||
servidor.licenca_set.get_or_create( |
|||
inicio_licenca=self.to_date(p["inicio_licenca"]), |
|||
fim_licenca=self.to_date(p["fim_licenca"]), |
|||
obs=p["obs_licenca"], |
|||
) |
|||
|
|||
servidor.save() |
@ -1,203 +0,0 @@ |
|||
# coding: utf-8 |
|||
import ldap |
|||
from django.contrib.auth.models import User, Group |
|||
from django.core.management.base import BaseCommand |
|||
|
|||
from sigi.apps.servidores.models import Servidor |
|||
from sigi.settings import * |
|||
|
|||
|
|||
class Command(BaseCommand): |
|||
help = "Sincroniza Usuários e Servidores com o LDAP" |
|||
|
|||
def handle(self, *args, **options): |
|||
self.sync_groups() |
|||
self.sync_users() |
|||
|
|||
def get_ldap_groups(self): |
|||
filter = "(&(objectclass=Group))" |
|||
values = [ |
|||
"cn", |
|||
] |
|||
l = ldap.initialize(AUTH_LDAP_SERVER_URI) |
|||
try: |
|||
l.protocol_version = ldap.VERSION3 |
|||
l.set_option(ldap.OPT_REFERRALS, 0) |
|||
l.simple_bind_s( |
|||
AUTH_LDAP_BIND_DN.encode("utf-8"), AUTH_LDAP_BIND_PASSWORD |
|||
) |
|||
|
|||
page_control = ldap.controls.SimplePagedResultsControl( |
|||
True, size=1000, cookie="" |
|||
) |
|||
result = [] |
|||
pages = 0 |
|||
|
|||
while True: |
|||
pages += 1 |
|||
response = l.search_ext( |
|||
AUTH_LDAP_GROUP, |
|||
ldap.SCOPE_SUBTREE, |
|||
filter, |
|||
values, |
|||
serverctrls=[page_control], |
|||
) |
|||
rtype, rdata, rmsgid, serverctrls = l.result3(response) |
|||
result.extend(rdata) |
|||
controls = [ |
|||
control |
|||
for control in serverctrls |
|||
if control.controlType |
|||
== ldap.controls.SimplePagedResultsControl.controlType |
|||
] |
|||
if not controls: |
|||
raise Exception("The server ignores RFC 2696 control") |
|||
if not controls[0].cookie: |
|||
break |
|||
page_control.cookie = controls[0].cookie |
|||
# result_id = l.search(AUTH_LDAP_GROUP, ldap.SCOPE_SUBTREE, filter, values) |
|||
# result_type, result_data = l.result(result_id, 1) |
|||
finally: |
|||
l.unbind() |
|||
return result |
|||
|
|||
def get_ldap_users(self): |
|||
filter = "(&(objectclass=user)(|(memberof=CN=lgs_ilb,OU=GruposAutomaticosOU,DC=senado,DC=gov,DC=br)(memberof=CN=lgt_ilb,OU=GruposAutomaticosOU,DC=senado,DC=gov,DC=br)(memberof=CN=lge_ilb,OU=GruposAutomaticosOU,DC=senado,DC=gov,DC=br)))" |
|||
values = [ |
|||
"sAMAccountName", |
|||
"userPrincipalName", |
|||
"givenName", |
|||
"sn", |
|||
"cn", |
|||
] |
|||
l = ldap.initialize(AUTH_LDAP_SERVER_URI) |
|||
try: |
|||
l.protocol_version = ldap.VERSION3 |
|||
l.set_option(ldap.OPT_REFERRALS, 0) |
|||
l.simple_bind_s( |
|||
AUTH_LDAP_BIND_DN.encode("utf-8"), AUTH_LDAP_BIND_PASSWORD |
|||
) |
|||
|
|||
page_control = ldap.controls.SimplePagedResultsControl( |
|||
True, size=1000, cookie="" |
|||
) |
|||
|
|||
result = [] |
|||
pages = 0 |
|||
|
|||
while True: |
|||
pages += 1 |
|||
response = l.search_ext( |
|||
AUTH_LDAP_USER.encode("utf-8"), |
|||
ldap.SCOPE_SUBTREE, |
|||
filter, |
|||
values, |
|||
serverctrls=[page_control], |
|||
) |
|||
rtype, rdata, rmsgid, serverctrls = l.result3(response) |
|||
result.extend(rdata) |
|||
controls = [ |
|||
control |
|||
for control in serverctrls |
|||
if control.controlType |
|||
== ldap.controls.SimplePagedResultsControl.controlType |
|||
] |
|||
if not controls: |
|||
raise Exception("The server ignores RFC 2696 control") |
|||
if not controls[0].cookie: |
|||
break |
|||
page_control.cookie = controls[0].cookie |
|||
# result_id = l.search(AUTH_LDAP_USER.encode('utf-8'), ldap.SCOPE_SUBTREE, filter, values) |
|||
# result_type, result_data = l.result(result_id, 1) |
|||
finally: |
|||
l.unbind() |
|||
return result |
|||
|
|||
def sync_groups(self): |
|||
print("Syncing groups...") |
|||
ldap_groups = self.get_ldap_groups() |
|||
print(f"\tFetched groups: {ldap_groups}") |
|||
for ldap_group in ldap_groups: |
|||
try: |
|||
group_name = ldap_group[1]["cn"][0] |
|||
except: |
|||
pass |
|||
else: |
|||
try: |
|||
group = Group.objects.get(name=group_name) |
|||
except Group.DoesNotExist: |
|||
group = Group(name=group_name) |
|||
group.save() |
|||
print(f"\tGroup '{group_name}' created.") |
|||
print("Groups are synchronized.") |
|||
|
|||
def sync_users(self): |
|||
print("Syncing users...") |
|||
ldap_users = self.get_ldap_users() |
|||
print(f"\tFetched users: {ldap_users}") |
|||
|
|||
def get_ldap_property(ldap_user, property_name, default_value=None): |
|||
value = ldap_user[1].get(property_name, None) |
|||
return value[0].decode("utf8") if value else default_value |
|||
|
|||
for ldap_user in ldap_users: |
|||
username = get_ldap_property(ldap_user, "sAMAccountName") |
|||
if username: |
|||
email = get_ldap_property(ldap_user, "userPrincipalName", "") |
|||
first_name = get_ldap_property( |
|||
ldap_user, "givenName", username |
|||
) |
|||
last_name = get_ldap_property(ldap_user, "sn", "")[:30] |
|||
try: |
|||
user = User.objects.get(username=username) |
|||
except User.DoesNotExist: |
|||
try: |
|||
user = User.objects.get(email=email) |
|||
old_username = user.username |
|||
user.username = username |
|||
print( |
|||
f"\tUser with email {email} had his/her username updated from [{old_username}] to [{username}]." |
|||
) |
|||
except User.DoesNotExist: |
|||
user = User.objects.create_user( |
|||
username=username, |
|||
first_name=first_name, |
|||
last_name=last_name, |
|||
email=email, |
|||
) |
|||
print(f"\tUser '{username}' created.") |
|||
|
|||
if not user.first_name == first_name: |
|||
user.first_name = first_name |
|||
print(f"\tUser '{username}' first name updated.") |
|||
if not user.last_name == last_name: |
|||
user.last_name = last_name |
|||
print(f"\tUser '{username}' last name updated.") |
|||
if not user.email == email: |
|||
user.email = email |
|||
print(f"\tUser '{username}' email updated.") |
|||
|
|||
nome_completo = get_ldap_property(ldap_user, "cn", "") |
|||
try: |
|||
servidor = user.servidor |
|||
except Servidor.DoesNotExist: |
|||
try: |
|||
servidor = Servidor.objects.get( |
|||
nome_completo=nome_completo |
|||
) |
|||
except Servidor.DoesNotExist: |
|||
servidor = user.servidor_set.create( |
|||
nome_completo=nome_completo |
|||
) |
|||
print(f"\tServidor '{nome_completo}' created.") |
|||
else: |
|||
if not servidor.nome_completo == nome_completo: |
|||
servidor.nome_completo = nome_completo |
|||
print( |
|||
f"\tFull name of Servidor '{nome_completo}' updated." |
|||
) |
|||
|
|||
servidor.user = user |
|||
servidor.save() |
|||
user.save() |
|||
print("Users are synchronized.") |
@ -1,284 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
import pytest |
|||
from django.contrib.auth.models import User |
|||
from django_dynamic_fixture import G |
|||
|
|||
from sigi.apps.servidores.management.commands.sync_ldap import Command |
|||
|
|||
|
|||
pytestmark = pytest.mark.django_db |
|||
|
|||
|
|||
class StubCommand(Command): |
|||
def __init__(self, users): |
|||
super(StubCommand, self).__init__() |
|||
self.users = users |
|||
|
|||
def get_ldap_users(self): |
|||
return self.users |
|||
|
|||
|
|||
def create_stub_user(username, nome_completo, first_name, last_name, email): |
|||
user = G( |
|||
User, |
|||
username=username, |
|||
first_name=first_name, |
|||
last_name=last_name, |
|||
email=email, |
|||
) |
|||
user.servidor.nome_completo = nome_completo |
|||
return user |
|||
|
|||
|
|||
ALEX_LDAP, BRUNO_LDAP, RITA_LDAP = [ |
|||
( |
|||
"...", |
|||
{ |
|||
"cn": ["Alex Lima"], |
|||
"givenName": ["Alex"], |
|||
"sAMAccountName": ["alexlima"], |
|||
"sn": ["Lima"], |
|||
"userPrincipalName": ["alexlima@interlegis.leg.br"], |
|||
}, |
|||
), |
|||
( |
|||
"...", |
|||
{ |
|||
"cn": ["Bruno Almeida Prado"], |
|||
"givenName": ["Bruno"], |
|||
"sAMAccountName": ["bruno"], |
|||
"sn": ["Almeida Prado"], |
|||
"userPrincipalName": ["bruno@interlegis.leg.br"], |
|||
}, |
|||
), |
|||
( |
|||
"...", |
|||
{ |
|||
"cn": ["Cl\xc3\xa1udia de C\xc3\xa1ssia"], |
|||
"givenName": ["Cl\xc3\xa1udia"], |
|||
"sAMAccountName": ["claudia"], |
|||
"sn": ["de C\xc3\xa1ssia"], |
|||
"userPrincipalName": ["claudia@interlegis.leg.br"], |
|||
}, |
|||
), |
|||
] |
|||
|
|||
|
|||
@pytest.mark.parametrize( |
|||
"before, ldap_users, after, messages", |
|||
[ |
|||
# new user from ldap is created |
|||
( |
|||
[], |
|||
[ALEX_LDAP], |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
) |
|||
], |
|||
""" |
|||
User 'alexlima' created. |
|||
Users are synchronized. |
|||
""", |
|||
), |
|||
# nothing changes |
|||
( |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
) |
|||
], |
|||
[ALEX_LDAP], |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
) |
|||
], |
|||
""" |
|||
Users are synchronized. |
|||
""", |
|||
), |
|||
# unicode encoding from LDAP data works well |
|||
( |
|||
[ |
|||
( |
|||
"claudia", |
|||
"Cláudia de Cássia", |
|||
"Cláudia", |
|||
"de Cássia", |
|||
"claudia@interlegis.leg.br", |
|||
) |
|||
], |
|||
[RITA_LDAP], |
|||
[ |
|||
( |
|||
"claudia", |
|||
"Cláudia de Cássia", |
|||
"Cláudia", |
|||
"de Cássia", |
|||
"claudia@interlegis.leg.br", |
|||
) |
|||
], |
|||
""" |
|||
Users are synchronized. |
|||
""", |
|||
), |
|||
# update: full name, first name, last name, email |
|||
( |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"___", |
|||
"___", |
|||
"___", |
|||
"___", |
|||
), |
|||
( |
|||
"bruno", |
|||
"Bruno Almeida Prado", |
|||
"___", |
|||
"Almeida Prado", |
|||
"___", |
|||
), |
|||
( |
|||
"claudia", |
|||
"___", |
|||
"Cláudia", |
|||
"___", |
|||
"claudia@interlegis.leg.br", |
|||
), |
|||
], |
|||
[ALEX_LDAP, BRUNO_LDAP, RITA_LDAP], |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
), |
|||
( |
|||
"bruno", |
|||
"Bruno Almeida Prado", |
|||
"Bruno", |
|||
"Almeida Prado", |
|||
"bruno@interlegis.leg.br", |
|||
), |
|||
( |
|||
"claudia", |
|||
"Cláudia de Cássia", |
|||
"Cláudia", |
|||
"de Cássia", |
|||
"claudia@interlegis.leg.br", |
|||
), |
|||
], |
|||
""" |
|||
User 'alexlima' first name updated. |
|||
User 'alexlima' last name updated. |
|||
User 'alexlima' email updated. |
|||
Full name of Servidor 'Alex Lima' updated. |
|||
User 'bruno' first name updated. |
|||
User 'bruno' email updated. |
|||
Full name of Servidor 'Bruno Almeida Prado' updated. |
|||
User 'claudia' last name updated. |
|||
Full name of Servidor 'Cláudia de Cássia' updated. |
|||
Users are synchronized. |
|||
""", |
|||
), |
|||
# update username (username from LDAP not in base, so match user by email and update username) |
|||
# TODO: is this functionality really necessary? If not remove this and corresponding code |
|||
# connect servidor with nome_completo to user |
|||
# TODO: is this functionality really necessary? If not remove this and corresponding code |
|||
# create new servidor with nome_completo and connect to user |
|||
# TODO: is this functionality really necessary? If not remove this and corresponding code |
|||
# user not present in ldap is NOT deleted |
|||
( |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
), |
|||
( |
|||
"bruno", |
|||
"Bruno Almeida Prado", |
|||
"Bruno", |
|||
"Almeida Prado", |
|||
"bruno@interlegis.leg.br", |
|||
), |
|||
( |
|||
"claudia", |
|||
"Cláudia de Cássia", |
|||
"Cláudia", |
|||
"de Cássia", |
|||
"claudia@interlegis.leg.br", |
|||
), |
|||
], |
|||
[ALEX_LDAP, RITA_LDAP], |
|||
[ |
|||
( |
|||
"alexlima", |
|||
"Alex Lima", |
|||
"Alex", |
|||
"Lima", |
|||
"alexlima@interlegis.leg.br", |
|||
), |
|||
( |
|||
"bruno", |
|||
"Bruno Almeida Prado", |
|||
"Bruno", |
|||
"Almeida Prado", |
|||
"bruno@interlegis.leg.br", |
|||
), |
|||
( |
|||
"claudia", |
|||
"Cláudia de Cássia", |
|||
"Cláudia", |
|||
"de Cássia", |
|||
"claudia@interlegis.leg.br", |
|||
), |
|||
], |
|||
""" |
|||
Users are synchronized. |
|||
""", |
|||
), |
|||
], |
|||
) |
|||
def test_sync_users(before, ldap_users, after, messages, capsys): |
|||
# setup |
|||
for user_setup in before: |
|||
if type(user_setup) == tuple: |
|||
create_stub_user(*user_setup) |
|||
assert User.objects.count() == len(before) |
|||
|
|||
command = StubCommand(ldap_users) |
|||
command.sync_users() |
|||
users = User.objects.all().order_by("username") |
|||
for user, expected in zip(users, after): |
|||
real = ( |
|||
user.username, |
|||
user.servidor.nome_completo, |
|||
user.first_name, |
|||
user.last_name, |
|||
user.email, |
|||
) |
|||
assert real == expected |
|||
|
|||
# feedbak messages |
|||
out, err = capsys.readouterr() |
|||
assert out.strip() == messages.strip() |
|||
assert err == "" |
@ -0,0 +1,30 @@ |
|||
# Generated by Django 4.2.4 on 2023-10-09 19:31 |
|||
|
|||
from django.conf import settings |
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
dependencies = [ |
|||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
|||
("servidores", "0013_servidor_moodle_userid"), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name="servidor", |
|||
name="ldap_dn", |
|||
field=models.CharField(blank=True, editable=False, max_length=200), |
|||
), |
|||
migrations.AlterField( |
|||
model_name="servidor", |
|||
name="user", |
|||
field=models.ForeignKey( |
|||
blank=True, |
|||
null=True, |
|||
on_delete=django.db.models.deletion.SET_NULL, |
|||
to=settings.AUTH_USER_MODEL, |
|||
), |
|||
), |
|||
] |
@ -0,0 +1,313 @@ |
|||
# Generated by Django 4.2.4 on 2023-10-10 11:26 |
|||
|
|||
import ldap |
|||
from django.db import migrations |
|||
from django.db.models import Q |
|||
from django.conf import settings |
|||
from django.contrib.auth import get_user_model |
|||
from django_auth_ldap.config import _DeepStringCoder |
|||
from sigi.apps.utils import to_ascii |
|||
from sigi.apps.servidores.models import Servidor |
|||
from sigi.apps.servidores.utils import ( |
|||
mescla_users, |
|||
mescla_servidores, |
|||
servidor_update_from_ldap, |
|||
user_staff_and_group, |
|||
) |
|||
|
|||
|
|||
def update_user_from_ldap(user, ldap_attrs): |
|||
for user_attr, ldap_attr in settings.AUTH_LDAP_USER_ATTR_MAP.items(): |
|||
setattr(user, user_attr, ldap_attrs.get(ldap_attr, [""])[0]) |
|||
user.username = ldap_attrs.get("sAMAccountName", [""])[0] |
|||
user_staff_and_group(user, ldap_attrs) |
|||
|
|||
|
|||
def forwards(apps, schema_editor): |
|||
User = get_user_model() |
|||
|
|||
coder = _DeepStringCoder("utf8") |
|||
connect = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) |
|||
connect.protocol_version = 3 |
|||
connect.set_option(ldap.OPT_REFERRALS, 0) |
|||
connect.simple_bind_s( |
|||
settings.AUTH_LDAP_BIND_DN, settings.AUTH_LDAP_BIND_PASSWORD |
|||
) |
|||
|
|||
# Eliminar usuário "administrador", transferindo seu log para usuário |
|||
# "interlegis". |
|||
|
|||
if ( |
|||
User.objects.filter( |
|||
username__in=["administrador", "interlegis"] |
|||
).count() |
|||
== 2 |
|||
): |
|||
user = User.objects.get(username="administrador") |
|||
user_target = User.objects.get(username="interlegis") |
|||
user.logentry_set.update(user=user_target) |
|||
user.delete() |
|||
print( |
|||
f"\n\tUser {user.username} deleted. Logs to {user_target.username}" |
|||
) |
|||
|
|||
# Unificar usuários com nomes iguais minusculos > MAIÚSCULOS |
|||
|
|||
print("\tJoin users with same usernames in upper/lower cases...") |
|||
|
|||
joined_names = set() |
|||
|
|||
for user in User.objects.all(): |
|||
if ( |
|||
user.username.upper() not in joined_names |
|||
and User.objects.filter(username__iexact=user.username) |
|||
.exclude(id=user.id) |
|||
.exists() |
|||
): |
|||
user_source = User.objects.get(username=user.username.lower()) |
|||
user_target = User.objects.get(username=user.username.upper()) |
|||
print(f"\t\t{user_source.username} > {user_target.username}") |
|||
mescla_users(user_source, user_target) |
|||
joined_names.add(user.username.upper()) |
|||
|
|||
# Identificar e atualizar todos os users que existem no LDAP # |
|||
|
|||
valid_users = dict() |
|||
for user in User.objects.all(): |
|||
rdata = connect.search_s( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_SUBTREE, |
|||
ldap.filter.filter_format("(sAMAccountName=%s)", [user.username]), |
|||
) |
|||
if rdata: |
|||
dn, ldap_attrs = coder.decode(rdata[0]) |
|||
valid_users[dn] = user |
|||
update_user_from_ldap(user, ldap_attrs) |
|||
if user.servidor: |
|||
servidor_update_from_ldap(user.servidor, ldap_attrs) |
|||
|
|||
# Identifica servidores que estão no LDAP mas, por algum motivo, não estão |
|||
# vinculados a algum 'valid_user' identificado ali acima |
|||
|
|||
for servidor in Servidor.objects.exclude( |
|||
user__in=valid_users.values() |
|||
).exclude(externo=True): |
|||
ldap_filter = ldap.filter.filter_format( |
|||
"(cn=%s)", [servidor.nome_completo] |
|||
) |
|||
rdata = connect.search_s( |
|||
settings.AUTH_LDAP_USER, ldap.SCOPE_SUBTREE, ldap_filter |
|||
) |
|||
if rdata: |
|||
dn, ldap_attrs = coder.decode(rdata[0]) |
|||
ldap_user_name = ldap_attrs.get("sAMAccountName", [""])[0] |
|||
if servidor.user: |
|||
if User.objects.filter(username=ldap_user_name).exists(): |
|||
user_target = User.objects.get(username=ldap_user_name) |
|||
mescla_users(servidor.user, user_target) |
|||
valid_users[dn] = user_target |
|||
else: |
|||
update_user_from_ldap(servidor.user, ldap_attrs) |
|||
valid_users[dn] = servidor.user |
|||
else: |
|||
if User.objects.filter(username=ldap_user_name).exists(): |
|||
servidor.user = User.objects.get(username=ldap_user_name) |
|||
servidor.save() |
|||
valid_users[dn] = servidor.user |
|||
else: |
|||
servidor.ldap_dn = dn |
|||
servidor.save() |
|||
|
|||
# Eliminar servidores e seus usuários que não têm nenhum vínculo no sigi |
|||
# e não constam na lista de valid_users |
|||
|
|||
print("\tRemoving inactive users and servidores") |
|||
|
|||
filter = ( |
|||
Q(externo=False) |
|||
& Q(casas_que_gerencia=None) |
|||
& Q(chefe=None) |
|||
& Q(comentario=None) |
|||
& Q(convenio=None) |
|||
& Q(convenios_acompanhados=None) |
|||
& Q(equipe_evento=None) |
|||
& Q(itemsolicitado=None) |
|||
& Q(modulo_apresentador=None) |
|||
& Q(modulo_monitor=None) |
|||
& Q(ocorrencia=None) |
|||
& Q(orgao=None) |
|||
& Q(solicitacao=None) |
|||
) |
|||
|
|||
inativos = Servidor.objects.filter(filter).exclude( |
|||
user__in=valid_users.values() |
|||
) |
|||
|
|||
removed = User.objects.filter(servidor__in=inativos).delete() |
|||
print( |
|||
"\n".join( |
|||
[ |
|||
f"\t\t{value} {key} records removed." |
|||
for key, value in removed[1].items() |
|||
] |
|||
) |
|||
) |
|||
removed = inativos.delete() |
|||
print( |
|||
"\n".join( |
|||
[ |
|||
f"\t\t{value} {key} records removed." |
|||
for key, value in removed[1].items() |
|||
] |
|||
) |
|||
) |
|||
|
|||
# Tratar os usuários que têm entrada de log mas não têm Servidor atribuído |
|||
|
|||
for user in User.objects.filter(servidor=None, is_active=True).exclude( |
|||
logentry=None |
|||
): |
|||
nome_completo = user.get_full_name().strip().lower() or user.username |
|||
filter = [ |
|||
Q(nome_completo__icontains=to_ascii(n.strip())) |
|||
for n in nome_completo.split(" ") |
|||
] |
|||
try: |
|||
# Tenta encontrar um servidor que tenha o mesmo nome e transferir |
|||
# todo o log para o usuário desse servidor. |
|||
servidor = Servidor.objects.get(*filter) |
|||
if servidor.user: |
|||
mescla_users(user, servidor.user) |
|||
print( |
|||
f"\tUser {user.username} deleted. " |
|||
f"Logs to {servidor.user.username}" |
|||
) |
|||
else: |
|||
servidor.user = user |
|||
servidor.save() |
|||
print( |
|||
f"\tUser {user.username} linked to " |
|||
f"servidor {servidor.nome_completo}" |
|||
) |
|||
except Servidor.DoesNotExist: |
|||
# Realmente não possui um servidor com o mesmo nome. O que resta é |
|||
# desativar o usuário para que não possa fazer login |
|||
user.is_active = False |
|||
user.save() |
|||
print(f"\tUser {user.username} deactivated.") |
|||
|
|||
# Atualizar o campo ldap_dn dos servidores ativos do ILB |
|||
print("\tUpdating ldap_dn field in servidor objects...", end=" ") |
|||
ldap_filter = ( |
|||
"(&(department=*ILB*)(!(title=*Desligad*))(!(title=*inativ*)))" |
|||
) |
|||
page_control = ldap.controls.SimplePagedResultsControl( |
|||
True, size=1000, cookie="" |
|||
) |
|||
updated = 0 |
|||
|
|||
while True: |
|||
response = connect.search_ext( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_ONELEVEL, |
|||
ldap_filter, |
|||
serverctrls=[page_control], |
|||
) |
|||
|
|||
rtype, rdata, rmsgid, serverctrls = connect.result3(response) |
|||
decoded_data = coder.decode(rdata) |
|||
|
|||
controls = [ |
|||
control |
|||
for control in serverctrls |
|||
if control.controlType |
|||
== ldap.controls.SimplePagedResultsControl.controlType |
|||
] |
|||
if not controls: |
|||
raise Exception("The LDAP server ignores RFC 2696 control") |
|||
|
|||
for dn, ldap_user in decoded_data: |
|||
user_name = ldap_user.get("sAMAccountName", [""])[0] |
|||
if User.objects.filter(username=user_name).exists(): |
|||
user = User.objects.get(username=user_name) |
|||
servidor = user.servidor |
|||
if servidor: |
|||
servidor.ldap_dn = dn |
|||
servidor.save() |
|||
updated += 1 |
|||
|
|||
if not controls[0].cookie: |
|||
break |
|||
page_control.cookie = controls[0].cookie |
|||
|
|||
print(f"{updated} servidores updated.") |
|||
|
|||
# Mesclar usuários duplicados |
|||
print("\tJoin duplicated users ...") |
|||
joined = 0 |
|||
|
|||
for user in User.objects.exclude(Q(first_name="") & Q(last_name="")): |
|||
query = User.objects.filter( |
|||
first_name__iexact=user.first_name, |
|||
last_name__iexact=user.last_name, |
|||
).exclude(id=user.id) |
|||
if query.exists(): |
|||
user2 = query.get() |
|||
dn1 = user.servidor.ldap_dn if user.servidor else "" |
|||
|
|||
if dn1: |
|||
print(f"\t\t{user2} > {user}") |
|||
mescla_users(user_source=user2, user_target=user) |
|||
else: |
|||
print(f"\t\t{user} > {user2}") |
|||
mescla_users(user_source=user, user_target=user2) |
|||
|
|||
# Vincular servidores com seu distinguishedName no LDAP, se existir |
|||
|
|||
print("\tLink servidor with LDAP by distinguishedNames ... ") |
|||
|
|||
for servidor in Servidor.objects.filter(externo=False, ldap_dn=""): |
|||
if servidor.user: |
|||
rdata = connect.search_s( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_SUBTREE, |
|||
ldap.filter.filter_format( |
|||
"(sAMAccountName=%s)", [servidor.user.username] |
|||
), |
|||
) |
|||
else: |
|||
rdata = connect.search_s( |
|||
settings.AUTH_LDAP_USER, |
|||
ldap.SCOPE_SUBTREE, |
|||
ldap.filter.filter_format( |
|||
"(cn=%s*)", [servidor.nome_completo] |
|||
), |
|||
) |
|||
if rdata: |
|||
servidor.ldap_dn = coder.decode(rdata[0][0]) |
|||
servidor.save() |
|||
print(f"\t\t{servidor.nome_completo} > {servidor.ldap_dn}") |
|||
|
|||
manuais = [ |
|||
(1139, 1147), # Ricardo de Oliveira Murta |
|||
(1129, 274), # Adalberto Alves de Oliveira |
|||
(1134, 166), # Cláudio Morale |
|||
(1130, 108), # Janary Carvão Nunes |
|||
] |
|||
|
|||
for source_id, target_id in manuais: |
|||
servidor_source = Servidor.objects.get(id=source_id) |
|||
servidor_target = Servidor.objects.get(id=target_id) |
|||
print( |
|||
f"\tJoining {servidor_source.nome_completo} " |
|||
f"to {servidor_target.nome_completo}" |
|||
) |
|||
mescla_servidores(servidor_source, servidor_target) |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
dependencies = [ |
|||
("servidores", "0014_servidor_ldap_dn_alter_servidor_user"), |
|||
] |
|||
|
|||
operations = [migrations.RunPython(forwards, migrations.RunPython.noop)] |
@ -0,0 +1,207 @@ |
|||
# Define algumas funções para manutenção de usuários e servidores |
|||
|
|||
import ldap |
|||
from django.contrib.auth.models import Group |
|||
from django.conf import settings |
|||
from django.db.models import F |
|||
from django.db.models.fields.reverse_related import ( |
|||
ForeignObjectRel, |
|||
ManyToOneRel, |
|||
ManyToManyRel, |
|||
) |
|||
from django.forms.models import model_to_dict |
|||
from sigi.apps.servidores.models import Servidor, Servico |
|||
|
|||
|
|||
def _message_out(message, verbose): |
|||
"""_message_out Imprime mensagem apenas em modo verboso |
|||
|
|||
Arguments: |
|||
message -- Mensagem |
|||
verbose -- True para imprimir, False para não imprimir |
|||
""" |
|||
if verbose: |
|||
print(message) |
|||
|
|||
|
|||
def mescla_users(user_source, user_target, verbose=False): |
|||
"""mescla_users |
|||
Transfere todos os dados de user_source para user_target e exclui |
|||
user_target e o servidor vinculado a ele. |
|||
|
|||
Arguments: |
|||
user_source -- Usuário a ser eliminado |
|||
user_target -- Usuário que receberá os dados de user_source |
|||
|
|||
Keyword Arguments: |
|||
verbose -- Se True, imprime mensagens de progresso (default: {False}) |
|||
""" |
|||
servidor_source = user_source.servidor |
|||
servidor_target = user_target.servidor |
|||
|
|||
# Transfere registros de log |
|||
_message_out("Transferring log entries...", verbose) |
|||
user_source.logentry_set.update(user=user_target) |
|||
|
|||
# Se a origem não tem servidor, só resta matá-lo agora |
|||
|
|||
if servidor_source is None: |
|||
user_source.delete() |
|||
_message_out(f"User {user_source.username} deleted!", verbose) |
|||
return |
|||
|
|||
# Se só a origem tem servidor |
|||
if servidor_source and not servidor_target: |
|||
# transfere o servidor inteiro e pronto |
|||
servidor_source.user = user_target |
|||
servidor_source.save() |
|||
_message_out( |
|||
f"Servidor {servidor_source.nome_completo} transferred " |
|||
f"to {user_target.username}", |
|||
verbose, |
|||
) |
|||
user_source.delete() |
|||
_message_out(f"User {user_source.username} deleted!", verbose) |
|||
return |
|||
|
|||
# Só chega aqui se ambos tiverem servidor vinculado |
|||
|
|||
_message_out("Merging servidores...", verbose) |
|||
|
|||
mescla_servidores(servidor_source, servidor_target, verbose) |
|||
|
|||
|
|||
def mescla_servidores(servidor_source, servidor_target, verbose=False): |
|||
"""mescla_servidor |
|||
Transfere todos os dados de servidor_source para servidor_target e exclui |
|||
servidor_target e o user vinculado a ele. |
|||
|
|||
|
|||
Arguments: |
|||
servidor_source -- Servidor a ser eliminado |
|||
servidor_target -- Servidor que receberá os dados de servidor_source |
|||
|
|||
Keyword Arguments: |
|||
verbose -- Se True, imprime mensagens de progresso (default: {False}) |
|||
""" |
|||
|
|||
user_source = servidor_source.user |
|||
user_target = servidor_target.user |
|||
|
|||
for field in Servidor._meta.get_fields(): |
|||
if not isinstance(field, ForeignObjectRel): |
|||
continue |
|||
|
|||
accessor = field.get_accessor_name() |
|||
remote_field = field.remote_field.name |
|||
|
|||
if isinstance(field, ManyToOneRel): |
|||
getattr(servidor_source, accessor).update( |
|||
**{remote_field: servidor_target} |
|||
) |
|||
_message_out( |
|||
f"Updating field {remote_field} in " |
|||
f"{field.remote_field.model._meta.verbose_name} " |
|||
f"to {servidor_target}", |
|||
verbose, |
|||
) |
|||
if isinstance(field, ManyToManyRel): |
|||
for obj in getattr(servidor_source, accessor).all(): |
|||
getattr(servidor_target, accessor).add(obj) |
|||
getattr(servidor_source, accessor).remove(obj) |
|||
_message_out( |
|||
f"Transferring {obj} from source {accessor} " |
|||
f"to {servidor_target}", |
|||
verbose, |
|||
) |
|||
|
|||
# Log dos usuários |
|||
if user_source and not user_target: |
|||
servidor_target.user = user_source |
|||
_message_out( |
|||
f"Target has no user. Transferring user {user_source.username} " |
|||
"from source", |
|||
verbose, |
|||
) |
|||
elif user_source and user_target: |
|||
user_source.logentry_set.update(user=user_target) |
|||
_message_out( |
|||
f"Transferring {user_source.username} logentries " |
|||
f"to {user_target.username}", |
|||
verbose, |
|||
) |
|||
user_source.delete() |
|||
_message_out(f"{user_source.username} deleted", verbose) |
|||
|
|||
servidor_source.delete() |
|||
_message_out(f"{servidor_source.nome_completo} deleted", verbose) |
|||
|
|||
|
|||
def user_staff_and_group(user, ldap_attrs): |
|||
dep = ldap_attrs.get("department", [""])[0] |
|||
title = ldap_attrs.get("title", [""])[0] |
|||
deps = dep.split("-") |
|||
titles = [s.strip().upper() for s in title.split("-", 1)] |
|||
group_names = [f"{d}-{t}" for d in deps for t in titles] |
|||
group_names.extend(deps) |
|||
group_names.extend(titles) |
|||
group_names.extend([dep, title.upper()]) |
|||
user.is_staff = "ILB" in dep |
|||
user.save() |
|||
user.groups.clear() |
|||
if user.is_staff: |
|||
# Só cria grupos para o ILB # |
|||
for name in group_names: |
|||
group, created = Group.objects.get_or_create(name=name) |
|||
user.groups.add(group) |
|||
|
|||
|
|||
def servidor_update_from_ldap(servidor, ldap_attrs, commit=True): |
|||
sigla_servico = ldap_attrs.get("department", [""])[0].split("-")[-1] |
|||
nome_cargo = ldap_attrs.get("title", [""])[0].split("-")[-1].strip() |
|||
nome_completo = ldap_attrs.get("name", [""])[0] |
|||
dn = ldap_attrs.get("distinguishedName", [""])[0] |
|||
cargo = f"{nome_cargo} - {sigla_servico}" |
|||
servico = Servico.objects.filter(sigla=sigla_servico).first() |
|||
|
|||
initial = model_to_dict(servidor) |
|||
|
|||
servidor.nome_completo = nome_completo |
|||
servidor.servico = servico |
|||
servidor.cargo = cargo |
|||
servidor.ldap_dn = dn |
|||
|
|||
if servico is not None and nome_cargo.lower() in [ |
|||
"chefe de serviço", |
|||
"coordenador", |
|||
]: |
|||
servidor.save() # Commit is needed to update servico instance |
|||
servico.responsavel = servidor |
|||
servico.save() |
|||
elif commit: |
|||
servidor.save() |
|||
|
|||
return ( |
|||
servidor_create_or_update.UNCHANGED |
|||
if initial == model_to_dict(servidor) |
|||
else servidor_create_or_update.UPDATED |
|||
) |
|||
|
|||
|
|||
def servidor_create_or_update(ldap_attrs, commit=True): |
|||
dn = ldap_attrs.get("distinguishedName", [""])[0] |
|||
|
|||
if dn != "" and Servidor.objects.filter(ldap_dn=dn).exists(): |
|||
servidor = Servidor.objects.get(ldap_dn=dn) |
|||
result_code = servidor_update_from_ldap(servidor, ldap_attrs, commit) |
|||
else: |
|||
servidor = Servidor() |
|||
servidor_update_from_ldap(servidor, ldap_attrs, commit) |
|||
result_code = servidor_create_or_update.CREATED |
|||
|
|||
return (result_code, servidor) |
|||
|
|||
|
|||
servidor_create_or_update.UNCHANGED = "unchanged" |
|||
servidor_create_or_update.UPDATED = "updated" |
|||
servidor_create_or_update.CREATED = "created" |
Loading…
Reference in new issue