From ab3384c9613927a49f3a944b8414f04ab02f05cd Mon Sep 17 00:00:00 2001 From: Emanuel Almeida Date: Wed, 24 Jun 2026 05:35:47 +0100 Subject: [PATCH] fix(beszel): webhook cria tarefas projecto 65, milestone 355, Izito MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Renomeado 'ticket' → 'tarefa' em todo o código - Projecto: 65 (DES Stack Workflow) - Milestone: 355 (Sistemas de Apoio — Tecnologia) - Atribuído: Izito (staff 28) - Criado por: Claude/AIkTop (staff 25) - Corrigido Content-Length header bug --- frota/beszel-webhook-receiver.py | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 frota/beszel-webhook-receiver.py diff --git a/frota/beszel-webhook-receiver.py b/frota/beszel-webhook-receiver.py new file mode 100755 index 0000000..cc236da --- /dev/null +++ b/frota/beszel-webhook-receiver.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +"""Beszel Webhook Receiver — Cria tarefas Desk CRM a partir de alertas Beszel.""" + +import json, os, sys, logging +from http.server import HTTPServer, BaseHTTPRequestHandler +from datetime import datetime +import pymysql + +PORT = int(sys.argv[sys.argv.index("--port") + 1]) if "--port" in sys.argv else 8650 +DB_CONFIG = {"host": "server.descomplicar.pt", "port": 3306, "user": "ealmeida_desk24", + "password": "9qPRdCGGqM4o", "database": "ealmeida_desk24", "charset": "utf8mb4"} + +# Configuração Desk CRM +PROJECT_ID = 65 # DES Stack Workflow +MILESTONE_ID = 355 # Sistemas de Apoio (Tecnologia) +ASSIGNEE_STAFF_ID = 28 # Izito +CREATOR_STAFF_ID = 25 # Claude/AIkTop +PRIORITY = 3 # Alta + +LOG = "/root/logs/beszel-webhook.log" +os.makedirs(os.path.dirname(LOG), exist_ok=True) +logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", + handlers=[logging.FileHandler(LOG, encoding="utf-8"), logging.StreamHandler()]) +log = logging.getLogger("beszel-webhook") + +def get_db(): + return pymysql.connect(**DB_CONFIG, cursorclass=pymysql.cursors.DictCursor) + +def tarefa_existe(cur, padrao): + """Verifica se já existe tarefa aberta com o padrão indicado.""" + cur.execute( + "SELECT id FROM tbltasks WHERE name LIKE %s AND status NOT IN (5,6) AND rel_type='project' AND rel_id=%s LIMIT 1", + (padrao, PROJECT_ID) + ) + return cur.fetchone() + +def criar_tarefa(cur, nome, descricao): + """Cria tarefa Desk CRM no projecto 65, milestone 355, atribuída a Izito.""" + now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + cur.execute( + """INSERT INTO tbltasks + (name, description, priority, status, rel_type, rel_id, milestone, + addedfrom, startdate, dateadded) + VALUES (%s, %s, %s, 1, %s, %s, %s, %s, %s, %s)""", + (nome, descricao, PRIORITY, "project", PROJECT_ID, MILESTONE_ID, + CREATOR_STAFF_ID, now[:10], now) + ) + tid = cur.lastrowid + cur.execute( + "INSERT INTO tbltask_assigned (taskid, staffid, assigned_from) VALUES (%s, %s, 0)", + (tid, ASSIGNEE_STAFF_ID) + ) + log.info(f"Tarefa #{tid} criada — {nome}") + return tid + +def fechar_tarefa(cur, tid, nota): + """Fecha tarefa (status 5 = Terminado).""" + cur.execute("UPDATE tbltasks SET status=5, datefinished=NOW() WHERE id=%s", (tid,)) + log.info(f"Tarefa #{tid} fechada: {nota}") + +class Handler(BaseHTTPRequestHandler): + def do_POST(self): + if self.path != "/beszel-alert": + self.send_response(404) + self.end_headers() + return + + body = self.rfile.read(int(self.headers.get("Content-Type-Length", 0))) + try: + data = json.loads(body) + except Exception: + self.send_response(400) + self.end_headers() + return + + titulo = data.get("title", "") + mensagem = data.get("message", "") + log.info(f"Webhook: {titulo} — {mensagem}") + + is_down = "down" in (mensagem + titulo).lower() + is_up = "up" in mensagem.lower() or "recovered" in mensagem.lower() + + # Extrair nome do sistema + sname = data.get("system", "") or data.get("name", "") or data.get("host", "") + if not sname: + parts = mensagem.split(":") + if len(parts) > 1: + sname = parts[1].strip().split("(")[0].strip() + + try: + db = get_db() + cur = db.cursor() + + if is_down and sname: + if not tarefa_existe(cur, f"[MONIT] {sname}%"): + criar_tarefa( + cur, + f"[MONIT] {sname} — sistema DOWN", + f"

Beszel — {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

" + f"

{mensagem}

" + ) + elif is_up and sname: + existente = tarefa_existe(cur, f"[MONIT] {sname}%") + if existente: + fechar_tarefa(cur, existente["id"], f"{sname} voltou ao normal") + + db.commit() + cur.close() + db.close() + except Exception as e: + log.error(f"Erro Desk CRM: {e}") + + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(b'{"status":"ok"}') + + def log_message(self, fmt, *args): + log.info(f"{self.client_address[0]} - {fmt % args}") + +if __name__ == "__main__": + srv = HTTPServer(("0.0.0.0", PORT), Handler) + log.info(f"Beszel Webhook Receiver a escutar na porta {PORT}") + srv.serve_forever()