Browse Source

Aprimora log dos JOBS

pull/160/head
Sesostris Vieira 2 years ago
parent
commit
ae2f2a84b6
  1. 52
      sigi/apps/casas/jobs/daily/usuario_contato.py
  2. 92
      sigi/apps/contatos/jobs/monthly/atualiza_ibge.py
  3. 28
      sigi/apps/convenios/jobs/daily/importa_gescon.py
  4. 112
      sigi/apps/servicos/jobs/daily/sincroniza_dns.py
  5. 185
      sigi/apps/servicos/jobs/daily/sincroniza_rancher.py
  6. 30
      sigi/apps/servicos/templates/servicos/emails/report_sincroniza_dns.rst
  7. 11
      sigi/apps/servicos/templates/servicos/emails/report_sincroniza_rancher.rst
  8. 34
      sigi/apps/servidores/migrations/0012_add_user_interlegis.py
  9. 112
      sigi/apps/utils/mixins.py
  10. 1
      sigi/templates/emails/base_email.rst
  11. 17
      sigi/templates/emails/base_report.rst
  12. 3
      sigi/templates/emails/report_error.rst

52
sigi/apps/casas/jobs/daily/usuario_contato.py

@ -1,13 +1,21 @@
from django.db.models import Q
from django.contrib.auth.models import User
from django.utils.translation import gettext as _
from django_extensions.management.jobs import DailyJob
from sigi.apps.casas.models import Orgao, Funcionario
from sigi.apps.casas.models import Funcionario
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils.mixins import JobReportMixin
class Job(DailyJob):
class Job(JobReportMixin, DailyJob):
help = "Ativa / desativa usuários para os Contatos Interlegis"
def execute(self):
def do_job(self):
self.report_data = []
tot_news = 0
tot_updates = 0
tot_deactivated = 0
# Seleciona contatos interlegis com mínimo de informações
# (nome, cpf, email). Elegíveis para fazer login no sistema
contatos = Funcionario.objects.filter(
@ -29,13 +37,37 @@ class Job(DailyJob):
},
username=email,
)
print(
f"{['Updated', 'Created'][created]} user {user.username} for contato {contato.id}"
if created:
tot_news += 1
self.admin_log_addition(user, "Novo contato técnico habilitado")
else:
tot_updates += 1
self.admin_log_change(user, "Contato técnico atualizado")
self.report_data.append(
_(
f"Usuário '{user.username}' "
f"{['atualizado', 'criado'][created]} "
f"para o contato {contato.id}"
)
)
# Desativa usuários de contatos que não estão na lista de elegíveis
qtd_desativados = (
User.objects.filter(username__contains="@", is_active=True)
.exclude(username__in=contatos.values_list("email", flat=True))
.update(is_active=False)
for user in User.objects.filter(
username__contains="@", is_active=True
).exclude(username__in=contatos.values_list("email", flat=True)):
user.is_active = False
user.save()
self.admin_log_change(
user,
_("Desativado pelo sistema - Não é mais contato técnico"),
)
print(f"{qtd_desativados} usuários desativados")
tot_deactivated += 1
self.report_data.append("")
self.report_data.append(_("RESUMO"))
self.report_data.append("------")
self.report_data.append("")
self.report_data.append(_(f"{tot_news} novos usuários"))
self.report_data.append(_(f"{tot_updates} usuários atualizados"))
self.report_data.append(_(f"{tot_deactivated} usuários desativados"))

92
sigi/apps/contatos/jobs/monthly/atualiza_ibge.py

@ -1,7 +1,6 @@
import docutils.core
from datetime import datetime
from django_extensions.management.jobs import MonthlyJob
from django.conf import settings
from django.contrib.admin.models import ADDITION, CHANGE
from django.core.mail import mail_admins
from django.template.loader import render_to_string
from django.utils.translation import gettext as _
@ -12,13 +11,16 @@ from sigi.apps.contatos.models import (
Microrregiao,
Municipio,
)
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils.mixins import JobReportMixin
class Job(MonthlyJob):
class Job(JobReportMixin, MonthlyJob):
help = _(
"Atualiza Unidades Federativas, mesorregiões, microrregiões e "
"municípios com dados do IBGE"
)
report_template = "contatos/emails/report_atualiza_ibge.rst"
uf_novas = []
uf_atualizadas = []
@ -28,25 +30,27 @@ class Job(MonthlyJob):
meso_atualizadas = []
micro_novas = []
micro_atualizadas = []
sigi_user = None
def execute(self):
print(
"Atualizando dados do IBGE. "
f"Início: {datetime.now(): %d/%m/%Y %H:%M:%S}"
)
def do_job(self):
self.atualiza_ufs()
self.atualiza_municipios()
self.report()
print(f"Término: {datetime.now(): %d/%m/%Y %H:%M:%S}")
self.report_data = {
"uf_novas": self.uf_novas,
"uf_atualizadas": self.uf_atualizadas,
"municipios_novos": self.municipios_novos,
"municipios_atualizados": self.municipios_atualizados,
"meso_novas": self.meso_novas,
"meso_atualizadas": self.meso_atualizadas,
"micro_novas": self.micro_novas,
"micro_atualizadas": self.micro_atualizadas,
}
def atualiza_ufs(self):
ibge_ufs = Estados().json()
regioes_map = {"N": "NO", "NE": "NE", "SE": "SE", "S": "SL", "CO": "CO"}
self.uf_novas = []
self.uf_atualizadas = []
for ibge_uf in ibge_ufs:
for ibge_uf in Estados().json():
regiao = regioes_map[ibge_uf["regiao"]["sigla"]]
try:
sigi_uf = UnidadeFederativa.objects.get(
@ -62,6 +66,7 @@ class Job(MonthlyJob):
)
sigi_uf.save()
self.uf_novas.append(sigi_uf)
self.admin_log_addition(sigi_uf, "Nova UF encontrada no IBGE")
if (
sigi_uf.nome != ibge_uf["nome"]
or sigi_uf.sigla != ibge_uf["sigla"]
@ -72,19 +77,10 @@ class Job(MonthlyJob):
sigi_uf.regiao = regiao
sigi_uf.save()
self.uf_atualizadas.append(sigi_uf)
self.admin_log_change(sigi_uf, "Atualizada pelo IBGE")
def atualiza_municipios(self):
ibge_municipios = Municipios().json()
self.municipios_novos = []
self.municipios_atualizados = []
self.meso_novas = []
self.meso_atualizadas = []
self.micro_novas = []
self.micro_atualizadas = []
for ibge_mun in ibge_municipios:
for ibge_mun in Municipios().json():
uf_id = ibge_mun["microrregiao"]["mesorregiao"]["UF"]["id"]
cod_meso = ibge_mun["microrregiao"]["mesorregiao"]["id"]
cod_micro = int(
@ -101,10 +97,14 @@ class Job(MonthlyJob):
)
meso.save()
self.meso_novas.append(meso)
self.admin_log_addition(
meso, "Nova mesorregião encontrada no IBGE"
)
if meso.nome != ibge_mun["microrregiao"]["mesorregiao"]["nome"]:
meso.nome = ibge_mun["microrregiao"]["mesorregiao"]["nome"]
meso.save()
self.meso_atualizadas.append(meso)
self.admin_log_change(meso, "Atualizada pelo IBGE")
# Atualiza ou cria a microrregião #
try:
micro = Microrregiao.objects.get(codigo_ibge=cod_micro)
@ -115,6 +115,10 @@ class Job(MonthlyJob):
nome=ibge_mun["microrregiao"]["nome"],
)
micro.save()
self.micro_novas.append(micro)
self.admin_log_addition(
micro, "Nova microrregião encontrada no IBGE"
)
if (
micro.nome != ibge_mun["microrregiao"]["nome"]
or micro.mesorregiao != meso
@ -123,6 +127,7 @@ class Job(MonthlyJob):
micro.mesorregiao = meso
micro.save()
self.micro_atualizadas.append(micro)
self.admin_log_change(micro, "Atualizada pelo IBGE")
# Atualiza ou cria o município #
try:
sigi_mun = Municipio.objects.get(codigo_ibge=ibge_mun["id"])
@ -137,6 +142,9 @@ class Job(MonthlyJob):
)
sigi_mun.save()
self.municipios_novos.append(sigi_mun)
self.admin_log_addition(
sigi_mun, "Novo município encontrado no IBGE"
)
if (
sigi_mun.nome != ibge_mun["nome"]
or sigi_mun.uf_id != uf_id
@ -147,34 +155,4 @@ class Job(MonthlyJob):
sigi_mun.microrregiao = micro
sigi_mun.save()
self.municipios_atualizados.append(sigi_mun)
def report(self):
rst = render_to_string(
"contatos/emails/report_atualiza_ibge.rst",
{
"title": self.help,
"uf_novas": self.uf_novas,
"uf_atualizadas": self.uf_atualizadas,
"municipios_novos": self.municipios_novos,
"municipios_atualizados": self.municipios_atualizados,
"meso_novas": self.meso_novas,
"meso_atualizadas": self.meso_atualizadas,
"micro_novas": self.micro_novas,
"micro_atualizadas": self.micro_atualizadas,
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=self.help,
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)
self.admin_log_change(sigi_mun, "Atualizada pelo IBGE")

28
sigi/apps/convenios/jobs/daily/importa_gescon.py

@ -4,33 +4,13 @@ from django.core.mail import mail_admins
from django.utils.translation import gettext as _
from django_extensions.management.jobs import DailyJob
from sigi.apps.convenios.models import Gescon
from sigi.apps.utils.mixins import JobReportMixin
class Job(DailyJob):
class Job(JobReportMixin, DailyJob):
help = "Carga de dados do Gescon."
def execute(self):
now = datetime.datetime.now()
print(f"Import gescon data started at {now:%Y-%m-%d %H:%M:%S}")
def do_job(self):
gescon = Gescon.load()
gescon.importa_contratos()
self.report(gescon, now)
now = datetime.datetime.now()
print(f"Import gescon data finished at {now:%Y-%m-%d %H:%M:%S}")
def report(self, gescon, now):
rst = gescon.ultima_importacao
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=_(f"Importação do GESCON em {now:%d/%m/%Y às %Hh%M}"),
message=rst,
html_message=html,
fail_silently=True,
)
self.report_data = gescon.ultima_importacao.splitlines()

112
sigi/apps/servicos/jobs/daily/sincroniza_dns.py

@ -12,6 +12,7 @@ from sigi.apps.servicos import generate_instance_name
from sigi.apps.servicos.models import Servico, TipoServico
from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.utils.mixins import JobReportMixin
LOG_GERAL = _("Mensagens gerais")
IGNORES = ["_psl", "k8s", "www.", "sapl."]
@ -35,33 +36,30 @@ def get_log_entry():
}
class Job(DailyJob):
class Job(JobReportMixin, DailyJob):
help = _("Sincronização dos registros de DNS da infraestrutura")
_nomes_gerados = None
_log = {}
report_template = "servicos/emails/report_sincroniza_dns.rst"
nomes_gerados = None
report_data = {}
def execute(self):
print(
_(
"Sincroniza os registros de domínio a partir do DNS."
f" Início: {datetime.datetime.now(): %d/%m/%Y %H:%M:%S}"
)
)
def do_job(self):
# TODO: Resolver
print("Este CRON está desativado até resolvermos questões internas")
return
raise Exception(
"Este CRON está desativado até resolvermos questões internas"
)
self._log[LOG_GERAL] = get_log_entry()
self.report_data[LOG_GERAL] = get_log_entry()
self.report_data["reativados"] = get_log_entry() # TODO: Remover
self.info("id,nome do orgao,instancia,tipo,url", "reativados")
if (
not settings.REGISTRO_PATH.exists()
or not settings.REGISTRO_PATH.is_dir()
):
self.error(_(f"Arquivos de DNS não encontrados."))
self.report()
return
self._nomes_gerados = {
self.nomes_gerados = {
generate_instance_name(o): o
for o in Orgao.objects.filter(tipo__legislativo=True)
}
@ -71,7 +69,7 @@ class Job(DailyJob):
).update(flag_confirmado=False)
for uf in UnidadeFederativa.objects.all():
self._log[uf] = get_log_entry()
self.report_data[uf] = get_log_entry()
self.processa_uf(uf)
self.processa_zones()
@ -80,15 +78,11 @@ class Job(DailyJob):
try:
shutil.rmtree(settings.REGISTRO_PATH)
except Exception as e:
print(_(f"Erro ao excluir diretório {settings.REGISTRO_PATH}"))
print("Relatório final:\n================")
self.report()
print(_(f" Término: {datetime.datetime.now():%H:%M:%S}."))
self.info(_(f"Erro ao excluir diretório {settings.REGISTRO_PATH}"))
def processa_rec(self, dns_rec, log_entry=LOG_GERAL):
dominio = dns_rec["name"][:-1]
nivel = len(dominio.split("."))
nivel = dominio.count(".") + 1
iname = get_iname(dominio)
sigla_srv = get_sigla_serv(dominio)
@ -104,6 +98,25 @@ class Job(DailyJob):
# Ignorar esses registros sem fazer log #
return
apps = []
if "rrsets" in dns_rec:
apps = [
r["name"].split(".")[0]
for r in dns_rec["rrsets"]
if r["type"] != "TXT" and r["name"][:-1].count(".") + 1 > nivel
]
else:
detail_file = settings.REGISTRO_PATH / f"{dominio}."
if detail_file.exists() and detail_file.is_file():
detail_data = json.loads(detail_file.read_text())
if "rrsets" in detail_data:
apps = [
r["name"].split(".")[0]
for r in detail_data["rrsets"]
if r["type"] != "TXT"
and r["name"][:-1].count(".") + 1 > nivel
]
try:
tipo = TipoServico.objects.get(sigla=sigla_srv, modo="R")
except TipoServico.DoesNotExist:
@ -146,6 +159,7 @@ class Job(DailyJob):
tipo_servico=tipo, url=dominio, data_desativacao=None
).first()
if servico is not None:
servico.instancia = iname
self.log_update(servico)
else:
# Tenta encontrar um registro desativado com mesmo domínio #
@ -153,13 +167,14 @@ class Job(DailyJob):
tipo_servico=tipo, url=dominio
).first()
if servico is not None:
servico.data_desativacao = None
servico.instancia = iname
self.log_reativa(servico)
if servico is None:
# Tenta criar o registro #
if iname in self._nomes_gerados:
orgao = self._nomes_gerados[iname]
if iname in self.nomes_gerados:
orgao = self.nomes_gerados[iname]
log_entry = orgao.municipio.uf
servico = Servico(
casa_legislativa=orgao,
@ -182,6 +197,7 @@ class Job(DailyJob):
# atualiza o serviço no SIGI
servico.url = dominio
servico.instancia = iname
servico.apps = "\n".join(apps)
servico.hospedagem_interlegis = True
servico.data_verificacao = timezone.localtime()
servico.resultado_verificacao = "F" # Funcionando
@ -195,7 +211,7 @@ class Job(DailyJob):
return
registros = json.loads(file_path.read_text())["rrsets"]
self._log[uf]["sumario"]["total"] = len(registros)
self.report_data[uf]["sumario"]["total"] = len(registros)
# Atualiza registros existentes e cria novos #
for rec in registros:
@ -239,12 +255,11 @@ class Job(DailyJob):
def processa_files(self):
file_list = list(settings.REGISTRO_PATH.iterdir())
self._log[LOG_GERAL]["sumario"]["total"] = len(file_list)
self.report_data[LOG_GERAL]["sumario"]["total"] = len(file_list)
for file_path in file_list:
if not file_path.is_file():
self._log[LOG_GERAL]["sumario"]["total"] -= 1
self.report_data[LOG_GERAL]["sumario"]["total"] -= 1
continue
print(file_path)
data = json.loads(file_path.read_text())
self.processa_rec(data)
file_path.unlink()
@ -262,36 +277,11 @@ class Job(DailyJob):
servico.save()
self.log_remove(servico)
def report(self):
rst = render_to_string(
"servicos/emails/report_sincroniza_dns.rst",
{
"log": self._log,
"title": _("Resultado da sincronização do SIGI com o DNS"),
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=self.help,
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)
def error(self, message, log_entry=LOG_GERAL):
self._log[log_entry]["erros"].append(message)
self.report_data[log_entry]["erros"].append(message)
def info(self, message, log_entry=LOG_GERAL):
self._log[log_entry]["infos"].append(message)
self.report_data[log_entry]["infos"].append(message)
def log_novo(self, srv):
orgao = srv.casa_legislativa
@ -301,15 +291,15 @@ class Job(DailyJob):
f"para {orgao.nome} ({uf.sigla})"
)
self.info(msg, uf)
self._log[uf]["sumario"]["novos"] += 1
self.report_data[uf]["sumario"]["novos"] += 1
def log_ignore(self, dominio, motivo, log_entry=LOG_GERAL):
self.error(_(f"Registro {dominio} ignorado pois {motivo}"), log_entry)
self._log[log_entry]["sumario"]["ignorados"] += 1
self.report_data[log_entry]["sumario"]["ignorados"] += 1
def log_update(self, srv):
uf = srv.casa_legislativa.municipio.uf
self._log[uf]["sumario"]["atualizados"] += 1
self.report_data[uf]["sumario"]["atualizados"] += 1
def log_reativa(self, srv):
orgao = srv.casa_legislativa
@ -318,13 +308,15 @@ class Job(DailyJob):
f"Instância {srv.instancia} de {srv.tipo_servico.nome} "
f"para {orgao.nome} ({uf.sigla}) reativada no SIGI"
)
self._log[uf]["sumario"]["atualizados"] += 1
self.report_data[uf]["sumario"]["atualizados"] += 1
self.info(msg, uf)
msg = f"{srv.id},{orgao.nome},{srv.instancia},{srv.tipo_servico.nome},{srv.url}"
self.info(msg, "reativados")
def log_remove(self, srv):
orgao = srv.casa_legislativa
uf = orgao.municipio.uf
self._log[uf]["sumario"]["desativados"] += 1
self.report_data[uf]["sumario"]["desativados"] += 1
self.info(
_(
f"Registro {srv.tipo_servico.sigla} {srv.instancia} ({srv.url})"

185
sigi/apps/servicos/jobs/daily/sincroniza_rancher.py

@ -11,72 +11,49 @@ from django_extensions.management.jobs import DailyJob
from sigi.apps.servicos import generate_instance_name
from sigi.apps.servicos.models import Servico, TipoServico
from sigi.apps.casas.models import Orgao
from sigi.apps.utils.mixins import JobReportMixin
class Job(DailyJob):
class Job(JobReportMixin, DailyJob):
help = _("Sincronização dos Serviços SEIT na infraestrutura")
_nomes_gerados = None
_errors = {}
_infos = {}
report_template = "servicos/emails/report_sincroniza_rancher.rst"
nomes_gerados = None
errors = {}
infos = {}
def execute(self):
try:
print(
_(
"Sincroniza os serviços SEIT a partir da infraestrutura."
f" Início: {datetime.datetime.now(): %d/%m/%Y %H:%M:%S}"
)
)
self._nomes_gerados = {
def do_job(self):
self.nomes_gerados = {
generate_instance_name(o): o
for o in Orgao.objects.filter(tipo__legislativo=True)
}
print(
_(
f"\t{len(self._nomes_gerados)} órgãos que podem ter instâncias."
)
)
for tipo in TipoServico.objects.filter(modo="H").exclude(
tipo_rancher=""
):
print(
_(
f"\tProcessando {tipo.nome}."
f" Início: {datetime.datetime.now():%H:%M:%S}."
),
end="",
)
self.process(tipo)
print(_(f" Término: {datetime.datetime.now():%H:%M:%S}."))
try:
shutil.rmtree(settings.HOSPEDAGEM_PATH)
except Exception as e:
print(
_(f"Erro ao excluir diretório {settings.HOSPEDAGEM_PATH}")
)
print("Relatório final:\n================")
self.report()
pass
print(_(f"Término: {datetime.datetime.now(): %d/%m/%Y %H:%M:%S}"))
except Exception as e:
self.report_error(e)
self.report_data = {
"erros": self.errors,
"infos": self.infos,
}
def process(self, tipo):
self.nomeia_instancias(tipo)
NAO_CONSTA = "*não-consta-no-rancher*"
self._errors[tipo] = []
self._infos[tipo] = []
self.errors[tipo] = []
self.infos[tipo] = []
file_path = settings.HOSPEDAGEM_PATH / tipo.arquivo_rancher
if not file_path.exists() or not file_path.is_file():
self._errors[tipo].append(_(f"Arquivo {file_path} não encontado."))
self.errors[tipo].append(_(f"Arquivo {file_path} não encontado."))
return
with open(file_path, "r") as f:
json_data = json.load(f)
json_data = json.loads(file_path.read_text())
portais = [
item
@ -88,7 +65,7 @@ class Job(DailyJob):
novos = 0
desativados = 0
self._infos[tipo].append(
self.infos[tipo].append(
_(f"{len(portais)} {tipo.nome} encontrados no Rancher")
)
@ -104,7 +81,7 @@ class Job(DailyJob):
hostname = p["spec"]["values"][tipo.spec_rancher]["domain"]
else:
hostname = NAO_CONSTA
self._errors[tipo].append(
self.errors[tipo].append(
_(
f"Instância {iname} de {tipo.nome} sem URL no "
"rancher"
@ -120,17 +97,27 @@ class Job(DailyJob):
hostname = f"{tipo.prefixo_padrao}.{hostname}"
else:
hostname = NAO_CONSTA
self._errors[tipo].append(
self.errors[tipo].append(
_(f"Instância {iname} de {tipo.nome} sem URL no rancher")
)
nova_versao = (
p["spec"]["values"]["image"]["tag"]
if "image" in p["spec"]["values"]
else ""
)
if NAO_CONSTA in hostname:
nova_url = ""
else:
nova_url = f"https://{hostname}/"
try:
portal = Servico.objects.get(
instancia=iname, tipo_servico=tipo, data_desativacao=None
)
encontrados += 1
except Servico.MultipleObjectsReturned:
self._errors[tipo].append(
self.errors[tipo].append(
_(
f"Existe mais de um registro ativo da instância {iname}"
f" de {tipo}."
@ -138,23 +125,28 @@ class Job(DailyJob):
)
continue
except Servico.DoesNotExist:
if iname in self._nomes_gerados:
orgao = self._nomes_gerados[iname]
if iname in self.nomes_gerados:
orgao = self.nomes_gerados[iname]
portal = Servico(
casa_legislativa=orgao,
tipo_servico=tipo,
instancia=iname,
url=nova_url,
versao=nova_versao,
data_ativacao=p["spec"]["info"]["firstDeployed"][:10],
hospedagem_interlegis=True,
)
self._infos[tipo].append(
portal.save()
self.admin_log_addition(portal, "Criado no Rancher")
novos += 1
self.infos[tipo].append(
_(
f"Criada instância {iname} de {tipo.nome} para "
f"{orgao.nome} ({orgao.municipio.uf.sigla})"
)
)
novos += 1
else:
self._errors[tipo].append(
self.errors[tipo].append(
_(
f"{iname} ({hostname}) não parece pertencer a "
"nenhum órgão."
@ -162,17 +154,34 @@ class Job(DailyJob):
)
continue
# atualiza o serviço no SIGI
portal.versao = (
p["spec"]["values"]["image"]["tag"]
if "image" in p["spec"]["values"]
if (
nova_versao != portal.versao
or nova_url != portal.url
or not portal.hospedagem_interlegis
):
message = (
"Atualizado no Rancher: "
+ (
f"Versão: de '{portal.versao}' para '{nova_versao}' "
if portal.versao != nova_versao
else ""
)
if NAO_CONSTA in hostname:
portal.url = ""
else:
portal.url = f"https://{hostname}/"
+ (
f"Url: de '{portal.url}' para '{nova_url}' "
if portal.url != nova_url
else ""
)
+ (
f"hospedagem interlegis"
if not portal.hospedagem_interlegis
else ""
)
)
portal.versao = nova_versao
portal.url = nova_url
portal.hospedagem_interlegis = True
portal.save()
self.admin_log_change(portal, message)
# Desativa portais registrados no SIGI que não estão no Rancher #
nomes_instancias = [p["metadata"]["name"] for p in portais]
@ -186,20 +195,19 @@ class Job(DailyJob):
portal.data_desativacao = timezone.localdate()
portal.motivo_desativacao = _("Não encontrado no Rancher")
portal.save()
self._infos[tipo].append(
self.admin_log_change(portal, "Desativado no Rancher")
self.infos[tipo].append(
f"{portal.instancia} ({portal.url}) de "
f"{portal.casa_legislativa.nome} desativado pois não "
"foi encontrado no Rancher."
)
desativados += 1
self._infos[tipo].append(
self.infos[tipo].append(
_(f"{encontrados} {tipo.nome} do Rancher encontrados no SIGI")
)
self._infos[tipo].append(
_(f"{novos} novos {tipo.nome} criados no SIGI")
)
self._infos[tipo].append(
self.infos[tipo].append(_(f"{novos} novos {tipo.nome} criados no SIGI"))
self.infos[tipo].append(
_(f"{desativados} {tipo.nome} desativados no SIGI")
)
@ -211,55 +219,4 @@ class Job(DailyJob):
):
s.instancia = generate_instance_name(s.casa_legislativa)
s.save()
def report(self):
rst = render_to_string(
"servicos/emails/report_sincroniza_rancher.rst",
{
"erros": self._errors,
"infos": self._infos,
"title": _("Resultado da sincronização do SIGI com o Rancher"),
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=self.help,
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)
def report_error(self, error):
import traceback
rst = render_to_string(
"emails/report_error.rst",
{
"title": _("Resultado da sincronização do SIGI com o Rancher"),
"process_name": self.help,
"traceback": traceback.format_exception(error),
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=self.help,
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)
self.admin_log_change(s, "Adicionado nome automático da instância")

30
sigi/apps/servicos/templates/servicos/emails/report_sincroniza_dns.rst

@ -1,43 +1,39 @@
{% extends 'emails/base_email.rst' %}
{% extends 'emails/base_report.rst' %}
{% load i18n %}
{% block content %}
{% trans "Resultado da sincronização dos dados de serviços de registro do SIGI com os registros encontrados no DNS." %}
* {% trans "Data/hora de execução" %}: {% now 'SHORT_DATETIME_FORMAT' %}
{% for uf, dados in log.items %}
{% for uf, dados in report_data.items %}
{% if dados.erros or dados.infos or dados.sumario.total > 0 or dados.sumario.novos > 0 or dados.sumario.atualizados > 0 or dados.sumario.desativados > 0 or dados.sumario.ignorados > 0 %}
**{{ uf|upper }}**
=========================================
**SUMÁRIO:**
{% if dados.sumario.total > 0 or dados.sumario.novos > 0 or dados.sumario.atualizados > 0 or dados.sumario.desativados > 0 or dados.sumario.ignorados > 0%}
**{% trans "SUMÁRIO" %}:**
- Total de registros no DNS: {{ dados.sumario.total }}
- Registros criados no SIGI: {{ dados.sumario.novos }}
- Registros atualizados no SIGI: {{ dados.sumario.atualizados }}
- Registros desativados no SIGI: {{ dados.sumario.desativados }}
- Registros do DNS ignorados: {{ dados.sumario.ignorados }}
{% endif %}
{% if dados.erros %}
**ERROS:**
**{% trans "ERROS" %}:**
{% for m in dados.erros %}
* {{ m }}
{% empty %}
*{% trans "Nenhum erro encontrado" %}*
{% endfor %}
{% endif %}
{% if dados.infos %}
**{% trans "INFORMAÇÕES ADICIONAIS" %}**
**{% trans "INFORMAÇÕES ADICIONAIS" %}:**
{% for m in dados.infos %}
* {{ m }}
{% empty %}
*{% trans "Nenhuma informação adicional gerada" %}*
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endblock content %}

11
sigi/apps/servicos/templates/servicos/emails/report_sincroniza_rancher.rst

@ -1,16 +1,11 @@
{% extends 'emails/base_email.rst' %}
{% extends 'emails/base_report.rst' %}
{% load i18n %}
{% block content %}
{% trans "Resultado da sincronização dos dados de serviços do SIGI com as instâncias instaladas no Rancher." %}
* {% trans "Data/hora de execução" %}: {% now 'SHORT_DATETIME_FORMAT' %}
**{% trans "ERROS ENCONTRADOS" %}**
=====================
{% for tipo, mensagens in erros.items %}
{% for tipo, mensagens in report_data.erros.items %}
**{{ tipo.nome|upper }} - {{ tipo.sigla|upper }}**
{% for m in mensagens %}
* {{ m }}
@ -22,7 +17,7 @@
**{% trans "INFORMAÇÕES ADICIONAIS" %}**
==========================
{% for tipo, mensagens in infos.items %}
{% for tipo, mensagens in report_data.infos.items %}
{{ tipo.nome|upper }} - {{ tipo.sigla|upper }}
{% for m in mensagens %}
* {{ m }}

34
sigi/apps/servidores/migrations/0012_add_user_interlegis.py

@ -0,0 +1,34 @@
# Generated by Django 4.1.5 on 2023-01-26 14:35
from django.db import migrations
from django.contrib.auth import get_user_model
def forwards_migration(apps, schema_editor):
Servidor = apps.get_model("servidores", "Servidor")
User = get_user_model()
sigi = Servidor.objects.get(sigi=True)
if sigi.user is not None:
# everything is already fine
return
try:
usuario = User.objects.get_by_natural_key("interlegis")
except User.DoesNotExist:
usuario = User.objects.create_superuser("interlegis")
sigi.user_id = usuario.id
sigi.save()
class Migration(migrations.Migration):
dependencies = [
("servidores", "0011_add_servidor_sigi"),
]
operations = [
migrations.RunPython(forwards_migration, migrations.RunPython.noop),
]

112
sigi/apps/utils/mixins.py

@ -1,13 +1,20 @@
import datetime
import docutils.core
import traceback
from collections import OrderedDict
from functools import update_wrapper
from django import forms
from django.contrib import admin
from django.contrib.admin import helpers
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE
from django.contrib.admin.options import csrf_protect_m
from django.contrib.admin.utils import pretty_name
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from django.core.mail import mail_admins
from django.http import Http404
from django.http.response import HttpResponse, HttpResponseRedirect
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
from django.urls import path
from django.utils.translation import gettext as _, ngettext
@ -19,6 +26,10 @@ from import_export.signals import post_export
from sigi.apps.utils import field_label
class MisconfiguredError(Exception):
pass
class ValueField(Field):
def get_value(self, obj):
if self.attribute is None:
@ -323,3 +334,104 @@ class ReturnMixin:
if self._return_path:
return HttpResponseRedirect(self._return_path)
return response
class JobReportMixin:
error_report_template = "emails/report_error.rst"
report_template = "emails/base_report.rst"
report_data = None
sys_user = None
def execute(self):
start_time = datetime.datetime.now()
try:
from sigi.apps.servidores.models import Servidor
self.sys_user = Servidor.objects.get(sigi=True).user
except Exception:
pass
try:
self.do_job()
except Exception as e:
self.report_error(e)
return
end_time = datetime.datetime.now()
self.report(start_time, end_time)
def do_job(self):
raise NotImplementedError("Job needs to implement the 'do_job' method")
def _admin_log(self, object, action_flag, message=""):
if self.sys_user is None:
return # No admin log
LogEntry.objects.log_action(
user_id=self.sys_user.id,
content_type_id=ContentType.objects.get_for_model(type(object)).pk,
object_id=object.id,
object_repr=str(object),
action_flag=action_flag,
change_message=message,
)
def admin_log_addition(self, object, message=""):
self._admin_log(object, ADDITION, message)
def admin_log_change(self, object, message=""):
self._admin_log(object, CHANGE, message)
def report_error(self, error):
rst = render_to_string(
self.error_report_template,
{
"title": self.help,
"traceback": traceback.format_exception(error),
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=self.help,
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)
def report(self, start_time, end_time):
if self.report_data is None:
raise MisconfiguredError(
"Job needs to define 'report_data' property"
)
rst = render_to_string(
self.report_template,
{
"title": self.help,
"start_time": start_time,
"end_time": end_time,
"report_data": self.report_data,
},
)
html = docutils.core.publish_string(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
mail_admins(
subject=f"JOB: {self.help}",
message=rst,
html_message=html,
fail_silently=True,
)
print(rst)

1
sigi/templates/emails/base_email.rst

@ -2,6 +2,7 @@
{% for s in title %}={% endfor %}
{{ title }}
{% for s in title %}={% endfor %}
{% endblock title %}

17
sigi/templates/emails/base_report.rst

@ -0,0 +1,17 @@
{% extends 'emails/base_email.rst' %}
{% load i18n %}
{% block title %}
{{ block.super }}
**{% trans "Início:" %} {{ start_time|date:"SHORT_DATETIME_FORMAT" }}**
**{% trans "Término:" %} {{ end_time|date:"SHORT_DATETIME_FORMAT" }}**
{% endblock %}
{% block content %}
{% trans "RESULTADO" %}
=========
{% for row in report_data %}{{ row }}
{% endfor %}
{% endblock content %}

3
sigi/templates/emails/report_error.rst

@ -2,7 +2,7 @@
{% load i18n %}
{% block content %}
{% blocktrans %}UM ERRO OCORREU NO PROCESSO DE IMPORTAÇÃO DE {{ process_name }}{% endblocktrans %}
{% blocktrans %}UM ERRO OCORREU NA EXECUÇÃO DA TAREFA{% endblocktrans %}
{% trans "VERIFIQUE O LOG DO SIGI PARA MAIORES DETALHES" %}
@ -11,6 +11,7 @@
::{% autoescape off %}{% for error_row in traceback %}
{{ error_row }}
{% endfor %}
{% endautoescape %}
{% endblock content %}
Loading…
Cancel
Save