patchcenter/migrate_teams_rules_20260506.sql
Admin MPCZ edec1f7db5 feat(teams): mode SharePoint sync (calque .exe Sanef Patch Manager) + rules-based routing
- Migration: ajoute sp_route/mode/is_reboot_channel/is_dynamic_dm sur teams_channels,
  cree table teams_channel_rules (match resp/domain/env/msg_type/hostname pattern)
- Service teams_service.py: format texte plat compatible workflows existants,
  write_sharepoint_notification (ecrit fichier .txt dans <sp_base>/<sp_route>/),
  resolve_channel_for_server rules-based avec priorite reboot,
  send_notification orchestre resolution + envoi
- Settings UI: CRUD canaux etendu (mode SP/webhook + flags reboot/dyn_dm),
  CRUD regles avec match conditions, sharepoint_notif_path en secret app,
  bouton Test ecrit fichier .txt en mode SP
- Mode is_dynamic_dm: prefixe le contenu par 'TO: <email>' pour permettre
  un workflow PA unique qui dispatch dynamiquement aux responsables
- Pas d'OAuth requis: PatchCenter ecrit fichiers, Workflows PA cote SharePoint
  (deja en place pour le .exe) declenchent et postent sur Teams

Mode webhook conserve mais inactif tant qu'OAuth Entra ID pas mis en place chez SANEF
2026-05-06 09:57:42 +02:00

79 lines
4.0 KiB
SQL

-- Migration : table de règles de routage Teams + colonnes additionnelles sur teams_channels
-- Permet de copier le mécanisme Sanef Patch Manager .exe (SharePoint sync + Power Automate)
-- - sp_route : sous-dossier SharePoint où PatchCenter écrit le fichier .txt
-- - mode : 'sharepoint' (écriture fichier) | 'webhook' (POST direct, futur)
-- - is_reboot_channel : canal qui reçoit les notifs reboot (priorité sur tout autre routage)
-- - is_dynamic_dm : la route SharePoint est un router unique (workflow PA lit "TO: <email>" en 1ère ligne)
-- - teams_channel_rules : règles de routage configurables (par responsable / domaine / env / msg_type / hostname pattern)
-- Idempotent.
-- ─── 1) Nouvelles colonnes sur teams_channels ─────────────────
ALTER TABLE public.teams_channels
ADD COLUMN IF NOT EXISTS sp_route text,
ADD COLUMN IF NOT EXISTS mode text NOT NULL DEFAULT 'sharepoint',
ADD COLUMN IF NOT EXISTS is_reboot_channel boolean NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS is_dynamic_dm boolean NOT NULL DEFAULT false;
-- webhook_url devient optionnel (pour les canaux mode='sharepoint' on n'a que sp_route)
ALTER TABLE public.teams_channels
ALTER COLUMN webhook_url DROP NOT NULL;
-- Backfill cohérent : tout canal existant qui a un webhook_url renseigné mais pas de sp_route
-- bascule en mode='webhook' (sinon le CHECK qui suit échouerait)
UPDATE public.teams_channels
SET mode = 'webhook'
WHERE webhook_url IS NOT NULL AND length(webhook_url) > 0
AND (sp_route IS NULL OR length(sp_route) = 0)
AND mode = 'sharepoint';
-- Contrainte cohérence : selon le mode, le champ correspondant doit être renseigné
ALTER TABLE public.teams_channels
DROP CONSTRAINT IF EXISTS teams_channels_mode_check;
ALTER TABLE public.teams_channels
ADD CONSTRAINT teams_channels_mode_check
CHECK (
(mode = 'sharepoint' AND sp_route IS NOT NULL AND length(sp_route) > 0)
OR (mode = 'webhook' AND webhook_url IS NOT NULL AND length(webhook_url) > 0)
);
-- Un seul canal reboot global (unique partial index)
CREATE UNIQUE INDEX IF NOT EXISTS uq_teams_channels_one_reboot
ON public.teams_channels((is_reboot_channel))
WHERE is_reboot_channel = true;
-- ─── 2) Table de règles ───────────────────────────────────────
CREATE TABLE IF NOT EXISTS public.teams_channel_rules (
id SERIAL PRIMARY KEY,
priority INT NOT NULL DEFAULT 100,
name text NOT NULL,
-- Conditions de match (toutes les conditions non-NULL doivent matcher)
match_responsable_contact_id INT REFERENCES public.contacts(id) ON DELETE SET NULL,
match_application_domain text, -- match insensible casse via ILIKE
match_env_in text[], -- env du serveur ∈ ce tableau
match_msg_type_in text[], -- msg_type ∈ ce tableau ; NULL = tous
match_hostname_pattern text, -- substring insensible casse dans hostname (ex 'bst')
-- Résultat
channel_id INT NOT NULL REFERENCES public.teams_channels(id) ON DELETE CASCADE,
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_tc_rules_active_priority
ON public.teams_channel_rules(is_active, priority)
WHERE is_active = true;
CREATE INDEX IF NOT EXISTS idx_tc_rules_channel
ON public.teams_channel_rules(channel_id);
-- ─── 3) GRANTs ────────────────────────────────────────────────
GRANT SELECT, INSERT, UPDATE, DELETE ON public.teams_channel_rules TO patchcenter;
GRANT USAGE, SELECT ON SEQUENCE public.teams_channel_rules_id_seq TO patchcenter;
-- Note : pas besoin de GRANT supplémentaire sur teams_channels (déjà fait dans la migration précédente)