erplibre/script/odoo/migration/fix_migration_odoo120_to_odoo130.sql

88 lines
3.2 KiB
MySQL
Raw Normal View History

[ADD] migration: decode percent-encoded page anchors before the 13 bump OpenUpgrade's website post-migration gathers the href of every page anchor and glues them into a CSS selector: "selector": ", ".join([link.attrib["href"] for link in links]) An href is not a selector. A French anchor written #principes-mn%C3%A9- moniques puts a % in it, which no CSS identifier may hold, and the whole migration dies on SelectorSyntaxError. Proven by replaying that exact code on the database: three views failed before, one of them with the % at position 53 -- the very position in the log. After the fix, three views processed, none failed. Decoding is enough: the parser accepts #principes-mnémoniques and refuses the encoded form. Only page views, only anchor hrefs, only %XX in hex. A % elsewhere in a URL is legitimate and stays. The decoder lives in pg_temp and leaves nothing behind. --- FR --- La post-migration website d'OpenUpgrade ramasse les href des ancres d'une page et les recolle en sélecteur CSS. Or un href n'est pas un sélecteur : une ancre française encodée y met un %, interdit dans un identifiant CSS, et la migration meurt. Prouvé en rejouant ce code exact sur la base : trois vues échouaient, dont une avec le % en position 53 — celle du journal. Après correctif, trois vues traitées, zéro échec. Décoder suffit : le parseur accepte #principes-mnémoniques et refuse la forme encodée. Seulement les vues de page, seulement les href d'ancre, seulement les %XX hexadécimaux. Un % ailleurs dans une URL est légitime et reste. Le décodeur vit dans pg_temp et ne laisse rien derrière lui. Assisted-by: Claude Opus 5
2026-08-23 00:00:22 -04:00
-- © 2021-2026 TechnoLibre (http://www.technolibre.ca)
-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
--
-- Correctifs à appliquer AVANT qu'OpenUpgrade ne migre vers Odoo 13.
--
-- En SQL et non en Python : ce fichier tourne sur une base encore en 12,
-- que le code de la 13 ne saurait pas charger.
-- Ancres de page encodées en pourcentage.
--
-- Le script d'OpenUpgrade `website/migrations/13.0.1.0/post-migration.py`
-- ramasse les `href` des ancres d'une page et les RECOLLE en sélecteur CSS :
--
-- links = doc.cssselect(r"a[href^=\#]:not([href=\#])")
-- "selector": ", ".join([link.attrib["href"] for link in links])
--
-- Or un `href` n'est pas un sélecteur. Une ancre française encodée —
-- `#principes-mn%C3%A9moniques` — y introduit un `%`, interdit dans un
-- identifiant CSS, et la migration meurt :
--
-- cssselect.parser.SelectorSyntaxError: Expected selector, got <DELIM '%'>
--
-- Éprouvé avec le parseur d'Odoo 13 : `#principes-mnémoniques` passe,
-- `#principes-mn%C3%A9moniques` non. Décoder suffit donc, et un accent
-- reste un identifiant CSS valide.
--
-- On ne touche QUE les vues qu'OpenUpgrade parcourt — celles qui portent
-- une page — et QUE les `href` d'ancre. Un `%` ailleurs dans une URL est
-- légitime et reste intact.
--
-- Rejouable : une fois décodé il n'y a plus de `%XX` à trouver.
-- Le décodeur vit dans `pg_temp` : il disparaît avec la session psql, et
-- ne laisse rien derrière lui dans la base du client.
CREATE FUNCTION pg_temp.el_url_decode(entree text) RETURNS text AS $decode$
DECLARE
octets bytea = '';
morceau text;
BEGIN
-- Deux à deux : « %C3 » devient un octet, tout autre caractère se
-- recopie tel quel. On rassemble en bytea AVANT de convertir, car un
-- caractère accenté tient sur deux octets et les décoder séparément
-- rendrait deux caractères illisibles.
FOR morceau IN
SELECT (regexp_matches(entree, '(%[0-9A-Fa-f]{2}|.)', 'g'))[1]
LOOP
IF length(morceau) = 3 AND left(morceau, 1) = '%' THEN
octets = octets || decode(substring(morceau, 2, 2), 'hex');
ELSE
octets = octets || convert_to(morceau, 'UTF8');
END IF;
END LOOP;
RETURN convert_from(octets, 'UTF8');
END
$decode$ LANGUAGE plpgsql IMMUTABLE STRICT;
DO $$
DECLARE
ancre RECORD;
combien integer := 0;
BEGIN
IF to_regclass('ir_ui_view') IS NULL THEN
RETURN;
END IF;
FOR ancre IN
SELECT DISTINCT trouve[1] AS brut
FROM ir_ui_view v
JOIN website_page p ON p.view_id = v.id,
LATERAL regexp_matches(
v.arch_db, 'href="(#[^"]*%[0-9A-Fa-f]{2}[^"]*)"', 'g'
) AS trouve
LOOP
UPDATE ir_ui_view
SET arch_db = replace(
arch_db,
'href="' || ancre.brut || '"',
'href="' || pg_temp.el_url_decode(ancre.brut) || '"'
)
WHERE position('href="' || ancre.brut || '"' IN arch_db) > 0;
combien := combien + 1;
RAISE NOTICE 'ancre decodee : % -> %',
ancre.brut, pg_temp.el_url_decode(ancre.brut);
END LOOP;
IF combien > 0 THEN
RAISE NOTICE '% ancre(s) de page decodee(s)', combien;
END IF;
END $$;