Search Requirement Specifications Form - sebiboga/testlink-upgraded GitHub Wiki

Search Requirement Specifications — Criteria Form (Modernized Screen)

Issue: #1825 (enhancement) — bugs found while testing: #1826, #1827 Path: the criteria page in front of Search Requirement Specifications (results screen) URL: gui/templates/requirements/reqSpecSearchForm.html?tproject_id=<id>[&doc_id=…&name=…&reqSpecType=…&scope=…&log_message=…&custom_field_id=…&custom_field_value=…] BFF API: api/reqspecsearchform/index.php — GET|HEAD ?action=init&tproject_id=<id>… (session-based auth, JSON I/O) Prerequisite: mgt_view_req or mgt_modify_req on the addressed test project; anything else is HTTP 403 Replaces: lib/requirements/reqSpecSearchForm.php + gui/templates/dashio/requirements/reqSpecSearchForm.tpl (and its still-legacy target lib/requirements/reqSpecSearch.php)

Criteria form


What it does

Collects the seven requirement-specification search criteria of TestLink 1.9.20 and hands them to the modern results screen (searchReqSpec.html) with auto_search=1, so the search runs on arrival. The criteria themselves are unchanged:

Criterion Behavior
Doc ID offered only when the project has req specs containing requirements (testproject::GET_NOT_EMPTY_REQSPEC, legacy reqSpecSearchForm.php:37); otherwise hidden and a no_req_specs card explains why
Title LIKE '%value%' on the spec name
Type exact match; domain from config_get('req_spec_cfg')->type_labels, localized server-side, exactly as legacy
Scope / Log message LIKE on the revision
Custom field + value design-time custom fields linked to requirement_spec (cfield_mgr::get_linked_cfields_at_design(..., ENABLED, null, 'requirement_spec')); the value box appears only once a field is picked

All criteria are combined with a logical AND, stated above the grid.

Context card

Test project, prefix, current user, requirements on/off chip, requirement specifications yes/no chip, the result cap (req_cfg.search.max_qty_for_display) and the number of available custom fields — so it is never unclear which project a search will be restricted to.

Toolbar

Find (validate-free hand-off, asks first when nothing is filled in) / Open search results (jump to the grid without a search) / Refresh / Reset / Back to Search Test Cases / Close (closes the window, or returns to the opener).

The results screen received the matching Criteria form button (openCriteriaForm()), so the two entry points now reach each other in both directions — legacy had none in either direction.

Deep links

Every criterion travels in the query string and is echoed back trimmed and length-capped (255 chars for the short fields, 2000 for scope / log message / custom-field value), so the page is bookmarkable and shareable — legacy 1.9.20 was none of those: it listed the criteria and POSTed them, and the URL never changed.

Deep-linked, pre-filled form

An unknown reqSpecType or custom_field_id in the URL is dropped rather than forwarded — a form must not hand the results screen a filter the server will refuse (400 Unknown custom field).

Security — the reason this screen was worth re-doing

The legacy controller authorized nothing but a session: it read the test project from $_SESSION['testprojectID'] and listed that project's design-time custom fields to any authenticated user, a global <no rights> role (role_id = 3) included. Sibling class of #1696 / #1765 / #1770.

The BFF now enforces mgt_view_req or mgt_modify_req on the ADDRESSED project, and does it before resolving the project, so the endpoint is not even a test-project existence oracle — an unauthorized caller gets 403, never 404 (the #1697 lesson). Both rights are tested because propagateRights() copies global project rights wholesale and establishes no modify→view implication of its own; a requirement author must reach this page too.

Verified with a real guest-role login: 403 no_right, the "Access denied" card, no project data in the payload, and the attempt recorded in the Event Viewer.

Response contract

Situation Status Machine code
anonymous 401 not_authenticated
no mgt_view_req / mgt_modify_req 403 no_right
unknown test project 404 tproject_not_found
POST / any write verb 405 + Allow: GET, HEAD wrong_method
unknown action 400 unknown_action
missing / non-numeric / zero tproject_id 400 invalid_tproject
repeated parameter (?scope[]=x) 400 invalid_parameter

Bugs found and fixed while testing

Issue Symptom Fix
#1827 a deep link opened a blank form — load() built the first /init from the still-empty controls, so the echo was always empty initQuery() sends the incoming criteria with the first /init; the form is still filled from the server echo, never a client-side copy
#1826 ?scope[]=x was cast with trim((string)$v) → the literal "Array" plus an Array to string conversion E_WARNING per request (an Event Viewer row), and the polluted value went on into LIKE '%Array%' is_scalar() guard on action, tproject_id and every criterion → 400 invalid_parameter + one WARNING; both shims drop such keys

The mandatory code review (no blocker) additionally found and fixed: Refresh silently discarded a Type / Custom-field choice (it now snapshots and restores both selects), the Criteria form button was labelled with another action's i18n key (new rssf.criteria), $actions->reqSpecSearchForm was dead code (now wired into frmWorkArea.php's $feature_map), and the response carried a grant payload the read-only screen never read.

Legacy controllers retired (both)

Legacy file Now
lib/requirements/reqSpecSearchForm.php (242 lines) session-guarded 302 to the modern page, forwarding every criterion a bookmark carried so a legacy link lands on a pre-filled form; 405 for a write verb; 405 retired_endpoint JSON for an XHR/crawler; anonymous → login.php?note=expired
lib/requirements/reqSpecSearch.php (242 lines) session-guarded 302 to searchReqSpec.html, translating the legacy criterion names (requirement_document_id → doc_id) and adding auto_search=1 when criteria were supplied. coverage is deliberately dropped: legacy init_args() collected it and no query ever read it, so no row changes

Neither shim holds state or runs a legacy code path.

i18n

50 new keys (49 rssf.* + footers.reqSpecSearchForm), translated in all 10 bundles (en, ro, de, es, fr, it, ja, pt, ru, zh). The prefix is rssf.* and not rsf.* — Reorder Requirements already owns the latter.

Test coverage

Suite “Issue #1825” (23 cases) in tmp/TLU_Test_Cases.md: the admin happy path and the config-driven criteria domain, the Find/Results hand-off, the empty-criteria confirm, Reset, Refresh, deep-link pre-fill, server-side length caps, the three project states (requirements disabled / no req spec / no right → 403), every error code above, both shims (navigation / write verb / XHR / anonymous) and the results↔form round trip. Browser console clean; Event Viewer gained no Error or Warning rows — only the intentional mgt_view_req missing and BFF shim: refused POST entries.

See also

⚠️ **GitHub.com Fallback** ⚠️