Task Issue 943 Assign Plan Roles demoMode Gating Verified - sebiboga/testlink-upgraded GitHub Wiki
Task 943 — demoMode read-only gating in Assign Test Plan Roles (gap vs legacy)
Issue: #943
Status: IMPLEMENTED & VERIFIED, issue CLOSED (2026-09-21) — branch task/issue-943
The gap (as filed)
Auto-generated gap-analysis issue against the modernized Assign Test Plan
Roles screen. It reported that neither usersAssignPlan.html nor the
api/roles BFF tplan-roles routes honour $tlCfg->demoMode, whereas legacy
usersAssign.tpl turns the whole form read-only in demo mode (Save button
replaced by the localized warn_demo note, submit blocked).
Investigation outcome
The gating was already implemented on the default branch when #943 was
picked: the shared usersAssign.tpl demo-path was ported for both project
and plan contexts in commit 661329532 (feat(roles): demoMode read-only gating in Assign Test Project/Plan Roles (Refs #932), 2026-09-18) — the
plan-context gap described by #943 (filed 2026-09-05) was a stale duplicate of
that fix. This run therefore verified the feature end-to-end, re-ran the
parity suite, documented the closure and closed the issue.
Legacy source of truth
config.inc.php:2060—$tlCfg->demoMode;gui/templates/tl-classic/usermanagement/usersAssign.tpl:111-112— formonsubmit="alert('{$labels.warn_demo}'); return false;"in demoMode;gui/templates/tl-classic/usermanagement/usersAssign.tpl:248-249— Save submit button replaced by{$labels.warn_demo}in demoMode.
Modern implementation (on the default branch, committed under #932)
- BFF
api/roles/index.php:demoModeBlockedWrite()(:280-292) → HTTP 403code=demo_mode+ localized message whenconfig_get('demoMode');PUT /roles/tplan-rolesgated FIRST (:823-828) withdemoModeBlockedWrite('warn_demo','assign.demoDisabled');PUT /roles/tproject-rolesgated the same way (:682);GET /roles/meta/tplan-rolesexposesdemoMode(:819), plusGET /roles(:414) andGET /roles/meta/tproject-roles(:670).
- Screen
gui/templates/usermanagement/usersAssignPlan.html:demoModevar (:142);applyDemoMode()(:180-187) toggles#demoBanner, hides#saveBtn, shows#demoNote(warn_demo text), disables Save;- demo state pulled from the meta responses on project load (:234) and plan load (:407);
- save guard (:541-544), row-change guard (:458) and bulk-Do guard (:518)
keep Save locked in demoMode;
saveAssignments()renders the warn_demo toast, mirroring the legacyonsubmitalert.
- i18n:
assign.demoDisabledin all 10 bundles.
Screenshots

Plan screen with demoMode ON — banner + the localized warn_demo note replace the Save button; grid stays usable (legacy usersAssign.tpl:286-292).

Plan screen with demoMode OFF — normal Save button (regression).
Verification evidence (this run, 2026-09-21)
- demoMode=ON (config.inc.php:2060 flipped to ON, restored after): banner +
#demoNoterender "We are sorry. This feature is disabled for Demo.",#saveBtnabsent; grid/selects stay usable. - Browser fetch, demoMode ON: GET meta tplan-roles → 200
demoMode:true; PUT tplan-roles → 403{code:"demo_mode",messageKey:"assign.demoDisabled",message:"We are sorry. This feature is disabled for Demo."}; access log pair[403](demo ON) vs[200](demo OFF) on the same PUT. - Client guard:
saveAssignments()with demoMode ON → demo toast, no PUT. - demoMode=OFF regression: Save visible; a role change (u941designer → leader)
enabled Save, PUT returned 200 + "User Roles updated" toast and wrote
user_testplan_roles (2,2,9). - Event Viewer: only AUDIT (log_level 16) rows; 0 rows ≥ 32 (Error/Warning).
- Task suite:
tmp/TLU_Test_Cases.md— "Task — Issue #943" — 6/6 PASS.
Refs #943.