diff --git a/README.md b/README.md index e0c535e..bcd89f6 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ timeout = 30 [notification] max_tickets = 50 +max_message_chars = 3500 ticket_url_template = {odoo_url}/web#id={id}&model={model}&view_type=form ``` @@ -97,7 +98,7 @@ La cle API est utilisee comme mot de passe d'API Odoo pour authentifier `usernam `odoo.limit = 0` force la recuperation de tous les tickets. `odoo.order = id asc` stabilise la comparaison avec l'etat local. -`notification.max_tickets` limite le nombre de tickets affiches dans Rocket.Chat. `notification.ticket_url_template` controle le lien d'ouverture du ticket ; les variables disponibles sont `{odoo_url}`, `{id}` et `{model}`. +`notification.max_tickets` limite le nombre de tickets affiches dans Rocket.Chat. `notification.max_message_chars` limite la taille totale du message pour eviter les rejets Rocket.Chat sur les gros audits. `notification.ticket_url_template` controle le lien d'ouverture du ticket ; les variables disponibles sont `{odoo_url}`, `{id}` et `{model}`. ## Protocole Odoo @@ -138,6 +139,7 @@ Lecture des tickets : Quand des tickets changent, Rocket.Chat recoit un message avec : - une ligne compacte par ticket affiche, limitee par `notification.max_tickets` ; +- une taille totale limitee par `notification.max_message_chars` ; - l'ID, le sujet, la personne assignee et un lien d'ouverture direct dans Odoo ; - une ligne de resume si tous les tickets modifies ne sont pas affiches. diff --git a/TRAVAIL.md b/TRAVAIL.md index 03ec87f..cd2b3d4 100644 --- a/TRAVAIL.md +++ b/TRAVAIL.md @@ -135,3 +135,11 @@ Ce fichier consigne les interventions Codex sur le projet afin de garder une tra - Ajout explicite de `order = id asc` pour stabiliser la liste des tickets comparee avec l'etat local. - Ajout de logs d'audit indiquant le nombre de tickets recuperes et le nombre de tickets modifies detectes. - Incrementation de la version WAPT de `0.1-13` a `0.1-14`. + +### Limitation taille Rocket.Chat + +- Analyse d'une erreur Rocket.Chat `400 Bad Request` sur VM avec 144 tickets modifies detectes. +- Ajout de `notification.max_message_chars`, valeur par defaut `3500`, pour limiter la taille totale du message envoye. +- Conservation du resume indiquant combien de tickets supplementaires ne sont pas affiches. +- Ajout du corps de reponse Rocket.Chat dans les logs en cas d'erreur HTTP. +- Incrementation de la version WAPT de `0.1-15` a `0.1-16`. diff --git a/WAPT/control b/WAPT/control index e2aadaf..c764c84 100644 --- a/WAPT/control +++ b/WAPT/control @@ -1,5 +1,5 @@ package : comi-odoo-ticketing -version : 0.1-14 +version : 0.1-16 architecture : all section : base priority : optional @@ -29,7 +29,7 @@ editor : keywords : licence : homepage : -package_uuid : 94cab12e-61fb-4a49-fcd2-c1d160d18b22 +package_uuid : 26501dce-4f1c-c379-c701-370a6908dd53 valid_from : valid_until : forced_install_on : @@ -39,6 +39,6 @@ max_os_version : icon_sha256sum : signer : pcosson_key signer_fingerprint: a25582410cf03bad179a60c189f459a0b03821c92c0cedf209e82448a66a9b4e -signature_date : 2026-07-24T07:48:26.000000 +signature_date : 2026-07-24T08:27:24.000000 signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes -signature : FGra+/RipOk5jmR4CkBmu4s9DQkzJ3u8bGhssL3zpRgzynMdnfNDSgVkBIM5XoQsqb+GluNnvqzGT19jvhOr1OVxF4Fk6ErMK/oXezLe/lX2vezTfRGoSUzVG+KPZrzqcuM0Q0g6gu2sctASMw0RuMMdMVgXWrZt/zVu+wS6P6O5MpCoOVRLMoV22jXAuXSz888rwBmSOyVU860Un1wPm4zin+gaJgvsy3GZQSSMhJBR8CGAj8QmeL6cjJrspJ0LDiE8m4UJXHJvlAsRIGxs9Y928L6x2Tg0pl6j02wNnZTKeh3mAM5KZRy5UJR8fbqXbBDuJJR7R1gux2WTw7mEeQ== +signature : HUbxaUjEjN7gWHV0cfLtO0ofdC4NYqFZp4+0+Lq2bv6f7wD+U3cNXIOj1tvnrXZEs9RKWKcsNVgmq7bwWz0wpWCOTT2TDZ/PI0srd6NEq7jkBg4l6AE6ssjVjr/SRDFKB2bPEcQI7e0Mgj7uG6ho2eCvZFV2txH5pW4vV78GTZffTxvmZddi6PVKXMk4SBmWB8FFNCAPPvS50NVvmPQio7JHgRy4EBMWSSjcTLMcDAcHvcWp8BYGXy3csbpIxKfe8RIIkMLPT7cWQiIJRMzWurXanGXwXD8YF1lSwrXNmz5sOCmJ5MII9ljA/irbp3OsCvO9T5zgJkRWpw0wD/KGRw== diff --git a/setup.py b/setup.py index 6ccd433..4de7b30 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ STATE_FILE = "tickets_state.json" DEFAULT_TIMEOUT = 30 DEFAULT_TICKET_FIELDS = ["id", "name", "stage_id", "partner_id", "user_id", "write_date"] DEFAULT_MAX_NOTIFIED_TICKETS = 50 +DEFAULT_MAX_MESSAGE_CHARS = 3500 DEFAULT_TICKET_URL_TEMPLATE = "{odoo_url}/web#id={id}&model={model}&view_type=form" DEFAULT_ODOO_ORDER = "id asc" @@ -44,6 +45,7 @@ def audit(): tickets_updated, previous_tickets_state, get_max_notified_tickets(conf_wapt), + get_max_message_chars(conf_wapt), get_ticket_url_template(conf_wapt), conf_wapt.get("odoo", "url").rstrip("/"), conf_wapt.get("odoo", "model", fallback="helpdesk.ticket"), @@ -117,6 +119,10 @@ def get_max_notified_tickets(conf_wapt): return conf_wapt.getint("notification", "max_tickets", fallback=DEFAULT_MAX_NOTIFIED_TICKETS) +def get_max_message_chars(conf_wapt): + return conf_wapt.getint("notification", "max_message_chars", fallback=DEFAULT_MAX_MESSAGE_CHARS) + + def get_ticket_url_template(conf_wapt): return conf_wapt.get("notification", "ticket_url_template", fallback=DEFAULT_TICKET_URL_TEMPLATE) @@ -297,20 +303,28 @@ def format_detailed_ticket_line(ticket, previous_tickets_state): return "- " + " | ".join(parts) -def build_notification_message(tickets_updated, previous_tickets_state, max_tickets, ticket_url_template, odoo_url, model): +def build_notification_message(tickets_updated, previous_tickets_state, max_tickets, max_message_chars, ticket_url_template, odoo_url, model): if not tickets_updated: return "Aucun ticket n'a ete mis a jour depuis la derniere verification." displayed_tickets = tickets_updated[:max_tickets] - hidden_count = len(tickets_updated) - len(displayed_tickets) lines = [ "Les tickets suivants ont ete mis a jour depuis la derniere verification :", ] - lines.extend([ - format_ticket_line(ticket, ticket_url_template, odoo_url, model) - for ticket in displayed_tickets - ]) + displayed_count = 0 + for ticket in displayed_tickets: + ticket_line = format_ticket_line(ticket, ticket_url_template, odoo_url, model) + candidate_lines = lines + [ticket_line] + candidate_message = "\n".join(candidate_lines) + + if max_message_chars > 0 and len(candidate_message) > max_message_chars: + break + + lines.append(ticket_line) + displayed_count += 1 + + hidden_count = len(tickets_updated) - displayed_count if hidden_count > 0: lines.extend([ "", @@ -346,5 +360,7 @@ def send_to_rocket(message_text, attachments=None, conf_wapt=None): headers={"Content-Type": "application/json"}, timeout=get_http_timeout(conf_wapt), ) + if response.status_code >= 400: + print("Erreur Rocket.Chat : %s" % response.text) response.raise_for_status() print("Message envoye avec succes.") diff --git a/tests/test_ticketing.py b/tests/test_ticketing.py index 63b7823..d470b0a 100644 --- a/tests/test_ticketing.py +++ b/tests/test_ticketing.py @@ -43,6 +43,8 @@ def make_config(): config.set("rocket", "webhook_url", "https://rocket.example.test/webhook-test") config.add_section("http") config.set("http", "timeout", "5") + config.add_section("notification") + config.set("notification", "max_message_chars", "3500") return config @@ -98,6 +100,7 @@ class TicketingStateTest(unittest.TestCase): tickets, previous_state, 1, + 3500, "{odoo_url}/web#id={id}&model={model}&view_type=form", "https://odoo.example.test", "helpdesk.ticket", @@ -113,6 +116,26 @@ class TicketingStateTest(unittest.TestCase): self.assertIn("1 ticket(s) supplementaire(s) non affiche(s) sur 2 au total", message) self.assertNotIn("Nouveau ticket", message) + def test_build_notification_message_is_limited_by_message_size(self): + tickets = [ + {"id": 1, "name": "Premier ticket avec sujet assez long", "user_id": False}, + {"id": 2, "name": "Deuxieme ticket avec sujet assez long", "user_id": False}, + ] + + message = ticketing.build_notification_message( + tickets, + {}, + 50, + 260, + "{odoo_url}/web#id={id}&model={model}&view_type=form", + "https://odoo.example.test", + "helpdesk.ticket", + ) + + self.assertIn("1 : Sujet : Premier ticket", message) + self.assertNotIn("2 : Sujet : Deuxieme ticket", message) + self.assertIn("1 ticket(s) supplementaire(s) non affiche(s) sur 2 au total", message) + def test_format_ticket_line_uses_personne_when_no_assignee(self): line = ticketing.format_ticket_line( {"id": 2, "name": "Nouveau ticket", "user_id": False}, @@ -192,6 +215,7 @@ class TicketingStateTest(unittest.TestCase): @patch("ticketing_setup.requests.post") def test_send_to_rocket_raises_for_http_errors(self, post): response = Mock() + response.status_code = 200 post.return_value = response ticketing.send_to_rocket("message de test", conf_wapt=make_config()) diff --git a/ticketing.ini.example b/ticketing.ini.example index f1e2606..1bf1b47 100644 --- a/ticketing.ini.example +++ b/ticketing.ini.example @@ -16,4 +16,5 @@ timeout = 30 [notification] max_tickets = 50 +max_message_chars = 3500 ticket_url_template = {odoo_url}/web#id={id}&model={model}&view_type=form