Datapath stories, grid repairs, menu v2 pure, hero placeholders, fec test

Batch of 2026-10-28/29 plus 2026-11-03:

- NEW vitec:import-datapath-stories: 22 story packages from the agency
  dump (docx + Links/ assets) as usecase records with content, quotes,
  images, customer logos, download cards; --repair-quotes normalizes
  attribution lines; asset backfill for existing stories
- /products grid incident repaired (fix_products_grid, fix_graphics_grid,
  check_grid_page): containers unhidden, 46 duplicate cards soft-deleted,
  section order restored; BuildProductPortfolio and
  ImportProductCategoryPages now GUARD against re-runs on pages that
  already carry vitec_cols_% containers
- ' double-encoding fixed: render-pipeline importers write literal
  apostrophes (ENT_NOQUOTES), fix_double_entities literalizes existing rows
- ticket quick wins (ticket_quickwins_20261028), broadcast market page
  cleanup, AttachCardImages market-card handling, SubmarketWorkbook
  META REPAIR, story content/video fixes (fix_story_*)
- ProvideProductCatalog: transitional v1 fields removed (categories
  uid/link, legacyGroupFields, item products teaser) - pure v2 shape
  (ticket 0024-FE); search renderer keeps its teaser
- BuildProductOverviews: heroes get the numbered placeholder background
  (placeholders/pages/<uid>-01.png, wide grey fallback) - backfill on
  existing pages with empty hero_bgimage, attached at creation for new
  pages; existing references always win (ticket 0026-FE); 40 placeholder
  PNGs shipped to fileadmin (not tracked)
- AttachPageMedia: --depth=3 with sysfolders as pass-through parents for
  the overview pages' -08 menu tiles
- NEW migrations/fec_isolation_test.sh: two-user live test proving
  fe_comment ticket isolation (backend verified tight, cross-user
  sighting traced to the FE page-JSON cache, ticket 0027-BE)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
orascheandClaude Fable 5 committed 2026-11-03 18:29:56 +01:00
1 parent 9211c8a395
commit 77661bf0b6
22 files changed
+2103 -63

No files matched your search

+131
View File
@@ -0,0 +1,131 @@
#!/bin/bash
# fe_comment Isolationstest (2026-11-03): zwei FE-User NACHEINANDER einloggen
# und pruefen, dass /api/fe-comment/state UND das USER_INT-Feld auf
# /_json/ticket-overview jedem User nur die EIGENEN Tickets zeigen.
# Aufruf: bash migrations/fec_isolation_test.sh <user1> <user2>
# (fragt beide Passwoerter unsichtbar ab)
set -e
cd /usr/www/users/vitecevo/live
BASE=https://dev.vitec.com
U1=${1:?Aufruf: fec_isolation_test.sh <user1> <user2>}
U2=${2:?Aufruf: fec_isolation_test.sh <user1> <user2>}
extract_token() {
php -r '
$j = json_decode(file_get_contents($argv[1]), true);
$f = "";
$w = function ($n) use (&$w, &$f) {
if (is_array($n)) {
if (($n["name"] ?? "") === "__RequestToken" && isset($n["value"])) {
$f = (string)$n["value"];
}
foreach ($n as $c) { $w($c); }
} elseif (is_string($n) && $f === "") {
if (preg_match("/name=\"__RequestToken\" value=\"([^\"]+)\"/", $n, $m)) {
$f = $m[1];
}
}
};
$w($j);
echo $f;
' "$1"
}
login() { # $1=user $2=pass $3=jar
rm -f "$3"
curl -sS -c "$3" -o /tmp/fec_form.json "$BASE/_json/fe-user-profile"
TOKEN=$(extract_token /tmp/fec_form.json)
if [ -z "$TOKEN" ]; then echo "KEIN __RequestToken gefunden"; exit 1; fi
curl -sS -b "$3" -c "$3" -o /tmp/fec_login.json \
--data-urlencode "user=$1" \
--data-urlencode "pass=$2" \
--data-urlencode "logintype=login" \
--data-urlencode "pid=520" \
--data-urlencode "__RequestToken=$TOKEN" \
"$BASE/_json/fe-user-profile"
if ! grep -q fe_typo_user "$3"; then
echo "LOGIN FEHLGESCHLAGEN fuer $1 (kein fe_typo_user-Cookie)"; exit 1
fi
}
summarize_state() { # stdin = state json, $1 = label
php -r '
$j = json_decode(stream_get_contents(STDIN), true);
printf("%-28s allowed=%s user=%s summaryUid=%s items=%d\n",
$argv[1],
var_export($j["allowed"] ?? null, true),
$j["user"]["name"] ?? "-",
isset($j["summary"]["uid"]) ? (string)$j["summary"]["uid"] : "-",
is_array($j["summary"]["items"] ?? null) ? count($j["summary"]["items"]) : 0);
foreach (($j["summary"]["items"] ?? []) as $i) {
printf(" item #%d %s\n", $i["uid"], mb_substr($i["url"], 0, 70));
}
' "$1"
}
summarize_overview() { # stdin = page json, $1 = label
php -r '
$j = json_decode(stream_get_contents(STDIN), true);
$fo = null;
foreach (($j["content"]["colPos0"] ?? []) as $el) {
if (($el["type"] ?? "") === "fecomment_overview") {
$fo = $el["content"]["feedbackOverview"] ?? null;
}
}
if ($fo === null) { echo $argv[1] . " KEIN fecomment_overview-Element gefunden\n"; exit; }
printf("%-28s allowed=%s user=%s summaryUid=%s items=%d\n",
$argv[1],
var_export($fo["allowed"] ?? null, true),
$fo["user"]["name"] ?? "-",
isset($fo["summary"]["uid"]) ? (string)$fo["summary"]["uid"] : "-",
is_array($fo["summary"]["items"] ?? null) ? count($fo["summary"]["items"]) : 0);
' "$1"
}
check_user() { # $1=user $2=jar
echo "=== $1 ==="
curl -sS -b "$2" "$BASE/api/fe-comment/state" | summarize_state "state-API"
curl -sS -b "$2" "$BASE/_json/ticket-overview" | summarize_overview "ticket-overview (USER_INT)"
echo
}
read -rsp "Passwort fuer $U1: " P1; echo
read -rsp "Passwort fuer $U2: " P2; echo
login "$U1" "$P1" /tmp/fec_u1.jar
login "$U2" "$P2" /tmp/fec_u2.jar
# Testticket als U1 anlegen, damit es etwas zu sehen (bzw. NICHT zu sehen) gibt
echo "--- lege Testticket als $U1 an ---"
TICKET=$(curl -sS -b /tmp/fec_u1.jar -H 'Content-Type: application/json' \
-d '{"url":"/isolation-test","note":"<p>Isolationstest - bitte ignorieren</p>"}' \
"$BASE/api/fe-comment/feedback" | php -r '
$j = json_decode(stream_get_contents(STDIN), true);
echo (int)($j["uid"] ?? 0);')
echo "Testticket uid=$TICKET"
if [ "$TICKET" = "0" ]; then echo "ANLEGEN FEHLGESCHLAGEN"; exit 1; fi
echo
# beide Sessions leben gleichzeitig - genau wie zwei Browser
check_user "$U1" /tmp/fec_u1.jar
check_user "$U2" /tmp/fec_u2.jar
# Gegenprobe: darf U2 das Ticket von U1 veraendern? (erwartet: Fehler)
echo "--- Gegenprobe: $U2 versucht Ticket #$TICKET von $U1 zu loeschen ---"
curl -sS -b /tmp/fec_u2.jar -X POST "$BASE/api/fe-comment/feedback/$TICKET/delete"; echo
echo "(erwartet: {\"error\":\"feedback not found or not yours\"})"
echo
# aufraeumen: U1 loescht sein eigenes Testticket
echo "--- aufraeumen: $U1 loescht Testticket #$TICKET ---"
curl -sS -b /tmp/fec_u1.jar -X POST "$BASE/api/fe-comment/feedback/$TICKET/delete"; echo
echo
echo "=== anonym (ohne Session) ==="
curl -sS "$BASE/api/fe-comment/state" | summarize_state "state-API"
curl -sS "$BASE/_json/ticket-overview" | summarize_overview "ticket-overview (USER_INT)"
echo
echo "ERWARTUNG: $U1 sieht 1 Item (das Testticket), $U2 sieht 0 Items,"
echo "die Gegenprobe-Loeschung durch $U2 schlaegt fehl, anonym ist allowed=false."
rm -f /tmp/fec_u1.jar /tmp/fec_u2.jar /tmp/fec_form.json /tmp/fec_login.json