Repository navigation
Bugfix Issue 1636 Dead Second Import Path
Issue: #1636 · Fix commit:
7202a16f6 (branch fix/issue-1636) · Screens affected: Platform Management
(gui/templates/platforms/platformsView.html), Assign Platforms
(gui/templates/platforms/platformsAssign.html) — routes untouched; Import Platforms
(gui/templates/platforms/platformsImport.html) — the surviving canonical path.
After the Import Platforms modernization (#1632) moved the UI to
gui/templates/platforms/platformsImport.html + api/platformsimport/index.php, a second,
weaker import implementation stayed registered and kept answering: the POST /import branch of
api/platforms/index.php. Nothing in the repository called it any more, so it was dead weight and
a divergent code path for the same operation — and it was the one with the sharpest edges.
| Call | Answer |
|---|---|
POST /api/platforms/index.php/import + valid XML |
200 {"status":"ok","imported":1,"updated":0,"skipped":1} — it really imported |
POST /api/platforms/index.php/import + malformed XML |
200 + raw HTML Please give this text to your TestLink Administrator<br> - Failed to load XML<br>…
|
POST /api/platformsimport/index.php?action=import + valid XML |
200 full contract: ok[], ko[], imported_total
|
POST /api/platformsimport/index.php?action=import + malformed XML |
422 {"error_code":"WRONG_FORMAT","xml_errors":[…]} |
- #1632 removed the inline import modal from
platformsView.htmland pointed the Import button atplatformsImport.html→api/platformsimport/index.php, but left the old branch atapi/platforms/index.php:384-472. - The router is generic (
api/platforms/index.php:45-49builds$segmentsfrom the path and the guard is only$method === 'POST' && $segments[0] === 'import'), so the branch was reachable. It was dead in the product sense only: 0 callers repo-wide (platformsView.htmlcallsAPI + '/'for list/flags/get/PUT/DELETE at lines 197/285/314/350/384;platformsAssign.html:117is assign-only; the legacy Smarty page posts to its own$SCRIPT_NAME). - The worst symptom: the branch called
@simplexml_load_file_wrapper()→lib/functions/xml.inc.php:33-41, which on a parse failure echoes a localized HTML sentence anddie()s. The caller's ownWRONG_FORMAT/ 422 answer atapi/platforms/index.php:428-432is therefore unreachable, and theContent-Type: application/jsonheader set at line 26 is a lie. -
api/platforms/index.php:462-463discardedcreate()'s return status and unconditionally$imported++, so a platform that was never written was still reported as imported.
Also worth recording: the URL in the issue body (?action=import) never reached the branch at all —
it fell through to the POST create branch and answered 400 Invalid test project id. The live
route was the path-segment form POST /api/platforms/index.php/import.
api/platforms/index.php lost lines 384-472 and the require_once('xml.inc.php') that only the
removed branch used (the export branch builds its XML through ADODB_XML, verified by R9). The file
header now states the scope split: view/CRUD/flags/assign/export only, import lives in
api/platformsimport. Diff: 9 insertions, 91 deletions, one file.
Deleting was chosen over making the old route a thin delegation because a pass-through would keep a
second public entry point for the operation that exists to have exactly one hardened
implementation, cannot preserve the multipart field rename (targetFilename vs uploadedFile at
api/platforms/index.php:400) without inventing a mapping, and would keep 422-for-TOO_LARGE on
the public surface forever. With zero callers and no legacy deep link into the BFF, the removal's
blast radius is zero lines outside this file.
-
POST /api/platforms/index.php/import→404 {"status":"error","message":"Not found"}, the JSON fallback the file already ended with (pre-existing, backup line 682 → now 600). No new 404 branch was introduced, so there is no scope creep. Nothing is imported, and the raw-HTML-on-error failure mode is gone with the branch. -
POST /api/platformsimport/index.php?action=import→ unchanged: 200 withok[]/ko[]/BAD_LINEandimported_total; 422WRONG_FORMAT+xml_errors[]on malformed XML; 403NO_RIGHTSfor aplatform_view-only user (which also writes the legacyaudit_security_user_right_missingevent). - All other routes of the file unchanged: list, create, update,
PUT /{id}/flags, delete,assign,export, 401 without a session. - Browser: Platform Management renders (0 console messages) and the Import screen imports
pimp_ui.xml→Imported: 1 / Updated: 0 / Skipped: 1 / Platforms now: 2, with the nameless<platform>reported asSkipped (line skipped: no name element). -
eventstable: 3 rows, alllog_level=16(audit INFO) — no new Error/Warning.
tmp/TLU_Test_Cases.md → Suite 1636, 12 matrix rows (R1–R12) plus the pre-fix reproduction.
-
docs/screenshots/issue-1636-platforms-view.png— Platform Management after the fix -
docs/screenshots/issue-1636-import-result.png— the surviving import path reporting Imported/Updated/Skipped + the per-line BAD_LINE message
While reviewing this fix, the subagent surfaced a pre-existing, unrelated data-integrity bug in
the same file, which I measured and filed separately rather than drive-by changing:
#1637 — DELETE bypasses the
DELETE_BLOCKED guard when the platform has is_open = 0 or enable_on_execution = 0, so a still
linked platform is deleted and an orphan testplan_platforms row is left behind
(api/platforms/index.php:335 calls getAll() without the null flag overrides the list route
passes at :131-133). The two other out-of-diff findings from that review — catch (Exception) at
:211 not catching a PHP 8 Error, and $p['name'] dereferenced without an is_array() guard at
:332/345 — are recorded in the closure comment of #1636 as remaining work.