mirror of
https://github.com/Deutscher-Tischfussballbund/com_sportsmanager.git
synced 2026-06-10 06:27:52 +00:00
5843fda2d6
Applies 6 fixes to sync.php found during QA of the player-sync feature:
1. Normalise non-UTF-8 (latin1/Win-1252) payloads -> fixes silent 0-row imports
2. Fail loudly (success=false) when N rows parse but nothing is added/updated
3. Remove dead \ block (undefined-variable notice)
4. Gate mass-deactivation: skip the sweep when a payload carries < 50% of an
org's currently-active members (configurable via sync_deactivation_min_ratio,
default 0.5); adds/updates still proceed, skipped sweeps return warnings
5. Use a single DB clock (NOW()) for staging session id/cleanup
6. Enforce Passnummer format ^[0-9]{2}-[0-9]{4,6}\$ (parity with manual import)
Adds tests/dtfb-player-sync/FINDINGS.md documenting the findings and fixes.
End-to-end validation is to be done on the staging environments.
2.7 KiB
2.7 KiB
DTFB Player Sync — QA findings & applied fixes
Concise record of the defects found while reviewing the player-sync receiver
(syncReceiveSpielerImport() in sync.php) and the six fixes applied in this PR.
The exploratory test harness used to find these has been removed — the
authoritative next test is the staging end-to-end sync (see the PR description).
The six issues fixed
| # | Issue | Impact | Fix in sync.php |
|---|---|---|---|
| 1 | Receiver did not normalise input encoding. A latin1 / Windows-1252 CSV (the legacy manual export) has ß as the single byte 0xDF. Staging the org name into the utf8mb4 table truncated it at that byte, so the org lookup missed and every row was skipped. |
Critical — silent data loss (e.g. 2964 rows parsed, 0 imported, success=true). |
Transcode the payload to UTF-8 when it is not already valid UTF-8, before staging. |
| 2 | A zero-effect import reported success. When N rows parsed but nothing was added or updated, the function returned success=true. |
Critical — masks encoding/mapping failures. | Return success=false with a diagnostic message when rows>0 but added==0 && updated==0. |
| 3 | Dead $naechste_spielernr block referenced an undefined variable in the insert branch. |
Runtime notice; incoming rows already carry their Passnummer. | Removed the block. |
| 4 | Unconditional mass-deactivation. A partial CSV deactivated every member not listed. | High — a broken/partial export could wipe an org's roster. | Per organisation, skip the deactivation sweep when the incoming count is below sync_deactivation_min_ratio (default 0.5) of the org's currently-active members; adds/updates still proceed and a warning is returned. |
| 5 | Split clock for staging. session_id came from PHP date() while stale-row cleanup used MySQL NOW(); a PHP/MySQL timezone gap could delete in-flight staging rows. |
Medium — another silent 0-row path. | Derive session_id from the DB clock (NOW()), with date() fallback. |
| 6 | No Passnummer format check. The manual import UI enforces ^[0-9]{2}-[0-9]{4,6}$; the sync receiver did not. |
Medium — inconsistent data quality vs the manual flow. | Apply the same regex to spielernr / spielernr_alt (blank/reject on mismatch). |
Confirmed by design (not bugs)
- No contact / personal data (email, phone, address) is ever exported or imported.
- Existing players keep their
lizenznrandgeburtsjahron update; only name / sex / Passnummer-driven fields change. - An unknown organisation aborts the whole import with no mutation.
- The sync path itself (export → cURL push → receive) is UTF-8 end-to-end; the encoding defect (#1) only affected ingesting a legacy latin1 manual file.