User Management Export Modernized - sebiboga/testlink-upgraded GitHub Wiki
Modernization of the legacy User Management Export screen
(lib/usermanagement/usersExport.php,
gui/templates/dashio/usermanagement/usersExport.tpl) — tracked in
#920, closing the
open feature gap #880
(user export to XML missing).
The legacy Smarty screen (a form submitting to usersExport.php) is replaced by a
standalone Dashio page (gui/templates/usermanagement/usersExport.html) backed by
a plain-PHP REST BFF API (api/usersexport/index.php). The User Management →
Export toolbar button now opens the modern screen instead of the legacy
usersExport.php form submit — the last legacy action still reachable from the
modern UI.
Path: System → User Management → toolbar Export
URL: gui/templates/usermanagement/usersExport.html?tproject_id=..&tplan_id=..
BFF API: GET ?action=info + POST ?action=export on /api/usersexport/
Rights: mgt_users (exactly like the legacy screen — only the admin role
holds it).

The BFF reproduces lib/usermanagement/usersExport.php:
-
Content: full user list — one entry per account with the exact legacy 10
fields:
id,login,role_id,email,first,last,locale,default_testproject_id,active,expiration_date. -
Formats: XML (legacy default; ADODB_XML generator, root
<users>, row<user>,text/xml; charset=ISO-8859-1) or Markdown (Refs #922) — a GitHub-flavoured table with the same 10 fields, pipe/backslash/newline-escaped cells, servedtext/markdown; charset=utf-8. -
Default filename:
users.xmlfor XML,users.mdfor MD; selecting a format auto-rolls the pre-filled name (applyTypeDefaultFilename) while the select still honours any user-typed custom name. -
Filename override: any custom name is honored in
Content-Dispositionafter being sanitized bybasename()(path-traversal safe).
-
GET ?action=info(requiresmgt_users) returns the default filename, the number of users to export, theexportTypesmap (XML,MD) and the grants map. The screen shows them in the export card. - User picks the File type (XML or Markdown) and clicks Export.
-
POST ?action=export(withexportType) streams the dump astext/xml; charset=ISO-8859-1ortext/markdown; charset=utf-8withContent-Disposition: attachment(Pragma: public,Cache-Control: must-revalidate). - Browser saves the file via blob download (
X-Requested-With: XMLHttpRequest); JSON errors surface as a toast. -
Back to User Management returns to
usersView.htmlin the same context.


- No
mgt_usersright → HTTP 403{"status":"error","message":"No rights", "right":"mgt_users"}on BOTH routes; the screen shows the lock warn-box "You do not have the mgt_users right required to export users." and disables the Export button and leaves the file-type select empty. - Unauthenticated → HTTP 401
"Not authenticated". - Empty file name → client-side toast "Please provide a filename.", no POST.
- Unknown export type (e.g.
CSV) → HTTP 400"Unsupported export type: CSV".
-
Filename:
basename()+ CR/LF/quote strip (no path traversal, no header injection). -
XSS: all DOM values escaped via
esc()/.text()/.val(); server messages inserted as text. -
SQL injection: ids
intval()-cast, no raw concatenation. -
CSRF / same-origin:
bffSameOriginGuard()+X-Requested-Withheader.
-
usersView.htmltoolbar gained an Export button (data-i18n="user.export") wired togotoExport(), which navigates the mainframe tousersExport.htmlcarrying the currenttproject_id/tplan_id. -
lib/usermanagement/usersExport.phpis kept for backward compatibility.
All strings use userexport.* keys present in all ten locale bundles
(en/de/es/fr/it/ja/pt/ro/ru/zh), plus the user.export toolbar key. The MD
feature adds userexport.fileType, userexport.type.xml, userexport.type.md
(Refs #922).
Suite 71 in tmp/TLU_Test_Cases.md — 13/13 PASS (BFF info/export parity,
filename override + sanitization, empty-filename validation, 403 no-right both
routes + browser warn state, 401 unauthenticated, i18n in all bundles, Event
Viewer clean).
Suite 1520 (Refs #922) in tmp/TLU_Test_Cases.md — 14/14 PASS (info
exportTypes map, browser format selector + filename rollover, MD export
payload/headers, custom MD filename, XML regression, UI blob download, unknown-
type 400, empty-filename client guard, guest 403 warn state, anonymous 401,
i18n keys in all 10 bundles, Event Viewer clean).